diff options
1503 files changed, 43600 insertions, 15718 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 <adurbin@google.com> +Adam Oldham <oldhamca@gmail.com> +Adam Radford <aradford@gmail.com> +Adrian Bunk <bunk@stusta.de> +Alan Cox <alan@lxorguk.ukuu.org.uk> +Alan Cox <root@hraefn.swansea.linux.org.uk> +Aleksey Gorelov <aleksey_gorelov@phoenix.com> +Al Viro <viro@ftp.linux.org.uk> +Al Viro <viro@zenIV.linux.org.uk> +Andreas Herrmann <aherrman@de.ibm.com> +Andrew Morton <akpm@osdl.org> +Andrew Vasquez <andrew.vasquez@qlogic.com> +Andy Adamson <andros@citi.umich.edu> +Arnaud Patard <arnaud.patard@rtp-net.org> +Arnd Bergmann <arnd@arndb.de> +Axel Dyks <xl@xlsigned.net> +Ben Gardner <bgardner@wabtec.com> +Ben M Cahill <ben.m.cahill@intel.com> +Björn Steinbrink <B.Steinbrink@gmx.de> +Brian Avery <b.avery@hp.com> +Brian King <brking@us.ibm.com> +Christoph Hellwig <hch@lst.de> +Corey Minyard <minyard@acm.org> +David Brownell <david-b@pacbell.net> +David Woodhouse <dwmw2@shinybook.infradead.org> +Domen Puncer <domen@coderock.org> +Douglas Gilbert <dougg@torque.net> +Ed L. Cashin <ecashin@coraid.com> +Evgeniy Polyakov <johnpol@2ka.mipt.ru> +Felipe W Damasio <felipewd@terra.com.br> +Felix Kuhling <fxkuehl@gmx.de> +Felix Moeller <felix@derklecks.de> +Filipe Lautert <filipe@icewall.org> +Franck Bui-Huu <vagabon.xyz@gmail.com> +Frank Zago <fzago@systemfabricworks.com> +Greg Kroah-Hartman <greg@echidna.(none)> +Greg Kroah-Hartman <gregkh@suse.de> +Greg Kroah-Hartman <greg@kroah.com> +Henk Vergonet <Henk.Vergonet@gmail.com> +Henrik Kretzschmar <henne@nachtwindheim.de> +Herbert Xu <herbert@gondor.apana.org.au> +Jacob Shin <Jacob.Shin@amd.com> +James Bottomley <jejb@mulgrave.(none)> +James Bottomley <jejb@titanic.il.steeleye.com> +James E Wilson <wilson@specifix.com> +James Ketrenos <jketreno@io.(none)> +Jean Tourrilhes <jt@hpl.hp.com> +Jeff Garzik <jgarzik@pretzel.yyz.us> +Jens Axboe <axboe@suse.de> +Jens Osterkamp <Jens.Osterkamp@de.ibm.com> +John Stultz <johnstul@us.ibm.com> +Juha Yrjola <at solidboot.com> +Juha Yrjola <juha.yrjola@nokia.com> +Juha Yrjola <juha.yrjola@solidboot.com> +Kay Sievers <kay.sievers@vrfy.org> +Kenneth W Chen <kenneth.w.chen@intel.com> +Koushik <raghavendra.koushik@neterion.com> +Leonid I Ananiev <leonid.i.ananiev@intel.com> +Linas Vepstas <linas@austin.ibm.com> +Matthieu CASTET <castet.matthieu@free.fr> +Michel Dänzer <michel@tungstengraphics.com> +Mitesh shah <mshah@teja.com> +Morten Welinder <terra@gnome.org> +Morten Welinder <welinder@anemone.rentec.com> +Morten Welinder <welinder@darter.rentec.com> +Morten Welinder <welinder@troll.com> +Nguyen Anh Quynh <aquynh@gmail.com> +Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> +Patrick Mochel <mochel@digitalimplant.org> +Peter A Jonsson <pj@ludd.ltu.se> +Praveen BP <praveenbp@ti.com> +Rajesh Shah <rajesh.shah@intel.com> +Ralf Baechle <ralf@linux-mips.org> +Ralf Wildenhues <Ralf.Wildenhues@gmx.de> +Rémi Denis-Courmont <rdenis@simphalempin.com> +Rudolf Marek <R.Marek@sh.cvut.cz> +Rui Saraiva <rmps@joel.ist.utl.pt> +Sachin P Sant <ssant@in.ibm.com> +Sam Ravnborg <sam@mars.ravnborg.org> +Simon Kelley <simon@thekelleys.org.uk> +Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr> +Stephen Hemminger <shemminger@osdl.org> +Tejun Heo <htejun@gmail.com> +Thomas Graf <tgraf@suug.ch> +Tony Luck <tony.luck@intel.com> +Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com> +Valdis Kletnieks <Valdis.Kletnieks@vt.edu> diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 09dd510..576ce46 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -78,7 +78,8 @@ 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. +"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 @@ -139,10 +140,10 @@ 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, these calls will be ignored for GPIOs that can't safely -be accessed wihtout sleeping (see below). +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 optimise the two +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), @@ -239,7 +240,8 @@ 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(). +with gpio_get_value(), for example to initialize or update driver state +when the IRQ is edge-triggered. @@ -260,9 +262,10 @@ 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 dependednt: for GPIOs sharing the same bank. (GPIOs are +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.) Code relying on such mechanisms will necessarily be nonportable. +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. 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/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.txt b/Documentation/hrtimers/hrtimers.txt index ce31f65..ce31f65 100644 --- a/Documentation/hrtimers.txt +++ b/Documentation/hrtimers/hrtimers.txt 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 devices: * (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 <kmalkki@cc.hut.fi>, Mark D. Studebaker <mdsxyz123@yahoo.com>, @@ -44,6 +47,7 @@ Your lspci -n listing must show one of these : 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 structures can be removed after 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/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d25acd5..abd575c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -104,6 +104,9 @@ loader, and have no meaning to the kernel directly. Do not modify the syntax of boot loader parameters without extreme need or coordination with <Documentation/i386/boot.txt>. +There are also arch-specific kernel-parameters not documented here. +See for example <Documentation/x86_64/boot-options.txt>. + 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. It is defined in the file 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. It is defined in the file 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. It is defined in the file 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 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 flattened-device-tree model. 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 : <a b> where a is the interrupt number and b is a @@ -1367,6 +1370,7 @@ platforms are moved over to use the flattened-device-tree model. #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 <grant.likely at secretlab.ca> ********** DRAFT *********** @@ -20,11 +20,11 @@ described in Documentation/powerpc/booting-without-of.txt), or passed 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 -<chip>-<device>[-<mode>]. 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 +<chip>-<device>[-<mode>]. 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-<device>". + +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-<device>\0mpc5200-<device>". 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-<device>. + +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 match as generically as possible. 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 booting-without-of. 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 <baseaddr 10000> +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 "<chip>-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 <chip> 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-<device>\0mpc5200-<device> form. Required soc5200 child nodes: name device_type compatible Description ---- ----------- ---------- ----------- -cdm@<addr> cdm *-cmd Clock Distribution -pic@<addr> interrupt-controller *-pic need an interrupt +cdm@<addr> cdm mpc5200-cmd Clock Distribution +pic@<addr> interrupt-controller mpc5200-pic need an interrupt controller to boot -bestcomm@<addr> dma-controller *-bestcomm 52xx pic also requires - the bestcomm device +bestcomm@<addr> 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@<addr> gpt *-gpt General purpose timers -rtc@<addr> rtc *-rtc Real time clock -mscan@<addr> mscan *-mscan CAN bus controller -pci@<addr> pci *-pci PCI bridge -serial@<addr> serial *-psc-uart PSC in serial mode -i2s@<addr> sound *-psc-i2s PSC in i2s mode -ac97@<addr> sound *-psc-ac97 PSC in ac97 mode -spi@<addr> spi *-psc-spi PSC in spi mode -irda@<addr> irda *-psc-irda PSC in IrDA mode -spi@<addr> spi *-spi MPC52xx spi device -ethernet@<addr> network *-fec MPC52xx ethernet device -ata@<addr> ata *-ata IDE ATA interface -i2c@<addr> i2c *-i2c I2C controller -usb@<addr> usb-ohci-be *-ohci,ohci-be USB controller -xlb@<addr> xlb *-xlb XLB arbritrator +name device_type compatible Description +---- ----------- ---------- ----------- +gpt@<addr> gpt mpc5200-gpt General purpose timers +rtc@<addr> rtc mpc5200-rtc Real time clock +mscan@<addr> mscan mpc5200-mscan CAN bus controller +pci@<addr> pci mpc5200-pci PCI bridge +serial@<addr> serial mpc5200-psc-uart PSC in serial mode +i2s@<addr> sound mpc5200-psc-i2s PSC in i2s mode +ac97@<addr> sound mpc5200-psc-ac97 PSC in ac97 mode +spi@<addr> spi mpc5200-psc-spi PSC in spi mode +irda@<addr> irda mpc5200-psc-irda PSC in IrDA mode +spi@<addr> spi mpc5200-spi MPC5200 spi device +ethernet@<addr> network mpc5200-fec MPC5200 ethernet device +ata@<addr> ata mpc5200-ata IDE ATA interface +i2c@<addr> i2c mpc5200-i2c I2C controller +usb@<addr> usb-ohci-be mpc5200-ohci,ohci-be USB controller +xlb@<addr> 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 L2 level> 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/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=<PCI bus number>] +IOMMU (input/output memory management unit) + + Currently four x86-64 PCI-DMA mapping implementations exist: + + 1. <arch/x86_64/kernel/pci-nommu.c>: use no hardware/software IOMMU at all + (e.g. because you have < 3 GB memory). + Kernel boot message: "PCI-DMA: Disabling IOMMU" + + 2. <arch/x86_64/kernel/pci-gart.c>: AMD GART based hardware IOMMU. + Kernel boot message: "PCI-DMA: using GART IOMMU" + + 3. <arch/x86_64/kernel/pci-swiotlb.c> : 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. <arch/x86_64/pci-calgary.c> : 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=[<size>][,noagp][,off][,force][,noforce][,leak[=<nr_of_leak_pages>] + [,memaper[=<order>]][,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: + <size> 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[=<order>] Allocate an own aperture over RAM with size 32MB<<order. + (default: order=1, i.e. 64MB) + merge Do scatter-gather (SG) merging. Implies "force" + (experimental). + nomerge Don't do scatter-gather (SG) merging. + noaperture Ask the IOMMU not to touch the aperture for AGP. + forcesac Force single-address cycle (SAC) mode for masks <40bits + (experimental). + noagp Don't initialize the AGP driver and use full aperture. + allowdac Allow double-address cycle (DAC) mode, i.e. DMA >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=<pages>[,force] + <pages> 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=<PCI bus number>] + 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 Linux/x86-64 --------------------------------------------------- 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 space the kernel stack is empty 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 available on i386, the ability 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 f85c603..5a546e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -247,6 +247,13 @@ L: linux-acpi@vger.kernel.org W: http://acpi.sourceforge.net/ S: Supported +ACPI VIDEO DRIVER +P: Luming Yu +M: luming.yu@intel.com +L: linux-acpi@vger.kernel.org +W: http://acpi.sourceforge.net/ +S: Supported + AD1816 SOUND DRIVER P: Thorsten Knabe M: Thorsten Knabe <linux@thorsten-knabe.de> @@ -620,6 +627,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 @@ -2523,6 +2535,12 @@ 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 @@ -3768,6 +3786,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 @@ -825,9 +825,6 @@ include/config/kernel.release: include/config/auto.conf FORCE # 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) @@ -860,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 @@ -931,6 +928,12 @@ headers_install: include/linux/version.h scripts_basic FORCE $(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/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, unsigned int portbase, unsigned int por 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/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_imx = { .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_ixp4xx = { .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_netx = { .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/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_pxa = { .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/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index d47e39f..5974768 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -8,7 +8,6 @@ * published by the Free Software Foundation. */ #include <linux/clk.h> -#include <linux/device.h> #include <linux/etherdevice.h> #include <linux/init.h> #include <linux/kernel.h> @@ -36,12 +35,11 @@ static struct eth_addr __initdata hw_addr[2]; static struct eth_platform_data __initdata eth_data[2]; extern struct lcdc_platform_data atstk1000_fb0_data; -static struct spi_board_info spi_board_info[] __initdata = { +static struct spi_board_info spi0_board_info[] __initdata = { { + /* QVGA display */ .modalias = "ltv350qv", - .controller_data = (void *)GPIO_PIN_PA(4), .max_speed_hz = 16000000, - .bus_num = 0, .chip_select = 1, }, }; @@ -149,8 +147,7 @@ static int __init atstk1002_init(void) set_hw_addr(at32_add_device_eth(0, ð_data[0])); - spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); - 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/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 a2f74af..c10833f 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -37,7 +37,7 @@ static struct clocksource clocksource_avr32 = { .read = read_cycle_count, .mask = CLOCKSOURCE_MASK(32), .shift = 16, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; /* diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index c1e477e..bc23550 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -8,6 +8,7 @@ #include <linux/clk.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/spi/spi.h> #include <asm/io.h> @@ -310,8 +311,6 @@ static void genclk_mode(struct clk *clk, int enabled) { 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(struct clk *clk) 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 *clk, unsigned long rate, int apply) 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, struct clk *parent) { 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, struct clk *parent) 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 * -------------------------------------------------------------------- */ @@ -750,8 +752,41 @@ static struct resource atmel_spi1_resource[] = { 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) { @@ -760,14 +795,7 @@ struct platform_device *__init at32_add_device_spi(unsigned int id) select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */ - - /* NPCS[2:0] */ - at32_select_gpio(GPIO_PIN_PA(3), - AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); - at32_select_gpio(GPIO_PIN_PA(4), - AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); - at32_select_gpio(GPIO_PIN_PA(5), - AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_spi_setup_slaves(0, b, n, spi0_pins); break; case 1: @@ -775,20 +803,14 @@ struct platform_device *__init at32_add_device_spi(unsigned int id) select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */ select_peripheral(PB(5), PERIPH_B, 0); /* SCK */ - - /* NPCS[2:0] */ - at32_select_gpio(GPIO_PIN_PB(2), - AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); - at32_select_gpio(GPIO_PIN_PB(3), - AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); - at32_select_gpio(GPIO_PIN_PB(4), - AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + 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; } @@ -872,6 +894,50 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data) 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, @@ -908,6 +974,11 @@ struct clk *at32_clock_list[] = { &atmel_spi1_spi_clk, &lcdc0_hclk, &lcdc0_pixclk, + &gclk0, + &gclk1, + &gclk2, + &gclk3, + &gclk4, }; unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); @@ -936,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/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 @@ unsigned long sleep_phys_sp(void *sp) * 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, int __user *name, int nlen, 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/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 @@ static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp, */ 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/i386/Kconfig b/arch/i386/Kconfig index 63d5e84..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 @@ -74,6 +86,8 @@ source "init/Kconfig" menu "Processor type and features" +source "kernel/time/Kconfig" + config SMP bool "Symmetric multi-processing support" ---help--- @@ -203,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 @@ -1263,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 bb0c376..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_MPENTIUMIII=y # 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_250=y 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 @@ CONFIG_PM_SYSFS_DEPRECATED=y # 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 # @@ -466,8 +470,7 @@ CONFIG_FW_LOADER=y # # Plug and Play support # -CONFIG_PNP=y -CONFIG_PNPACPI=y +# CONFIG_PNP is not set # # Block devices @@ -515,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 # @@ -547,6 +551,7 @@ CONFIG_BLK_DEV_AMD74XX=y # 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 @@ -557,6 +562,7 @@ CONFIG_BLK_DEV_PIIX=y # 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 @@ -655,6 +661,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0 # 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 @@ -670,6 +677,7 @@ CONFIG_SATA_SIL=y # 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 @@ -687,6 +695,7 @@ CONFIG_SATA_INTEL_COMBINED=y # 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 @@ -739,9 +748,7 @@ 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 @@ -767,6 +774,11 @@ CONFIG_IEEE1394_RAWIO=y # CONFIG_I2O is not set # +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -833,6 +845,7 @@ CONFIG_8139TOO=y # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) @@ -855,11 +868,13 @@ CONFIG_SKY2=y 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 @@ -1090,6 +1105,7 @@ CONFIG_SOUND=y # 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 @@ -1103,6 +1119,7 @@ CONFIG_SOUND_ICH=y # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -1117,10 +1134,8 @@ CONFIG_USB=y # 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 # @@ -1130,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 @@ -1183,6 +1200,7 @@ CONFIG_USB_HID=y # 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 @@ -1288,6 +1306,10 @@ CONFIG_USB_MON=y # # +# Auxiliary Display support +# + +# # Virtualization # # CONFIG_KVM is not set @@ -1480,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 @@ -1488,7 +1511,6 @@ CONFIG_DETECT_SOFTLOCKUP=y # 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 @@ -1533,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_printk.o 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 7ac7b67..e5eb97a 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/acpi.h> +#include <linux/acpi_pmtmr.h> #include <linux/efi.h> #include <linux/cpumask.h> #include <linux/module.h> @@ -615,6 +616,7 @@ static int __init acpi_parse_sbf(struct acpi_table_header *table) } #ifdef CONFIG_HPET_TIMER +#include <asm/hpet.h> static int __init acpi_parse_hpet(struct acpi_table_header *table) { @@ -645,24 +647,11 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table) hpet_res->end = (1 * 1024) - 1; } -#ifdef CONFIG_X86_64 - vxtime.hpet_address = hpet_tbl->address.address; - + hpet_address = hpet_tbl->address.address; printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, vxtime.hpet_address); - - res_start = vxtime.hpet_address; -#else /* X86 */ - { - extern unsigned long hpet_address; - - hpet_address = hpet_tbl->address.address; - printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, hpet_address); + hpet_tbl->id, hpet_address); - res_start = hpet_address; - } -#endif /* X86 */ + res_start = hpet_address; if (hpet_res) { hpet_res->start = res_start; @@ -676,10 +665,6 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table) #define acpi_parse_hpet NULL #endif -#ifdef CONFIG_X86_PM_TIMER -extern u32 pmtmr_ioport; -#endif - static int __init acpi_parse_fadt(struct acpi_table_header *table) { 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 <linux/kernel_stat.h> #include <linux/sysdev.h> #include <linux/cpu.h> +#include <linux/clockchips.h> +#include <linux/acpi_pmtmr.h> #include <linux/module.h> #include <asm/atomic.h> @@ -36,6 +38,7 @@ #include <asm/hpet.h> #include <asm/i8253.h> #include <asm/nmi.h> +#include <asm/idle.h> #include <mach_apic.h> #include <mach_apicdef.h> @@ -44,128 +47,549 @@ #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 @@ void clear_local_APIC(void) 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 @@ void __devinit setup_local_APIC(void) 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 @@ void __devinit setup_local_APIC(void) "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 @@ fake_ioapic_page: } /* - * 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(struct pt_regs *regs) 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 pt_regs *regs) 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 db99a89..064bbf2 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -211,6 +211,7 @@ #include <linux/slab.h> #include <linux/stat.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/miscdevice.h> #include <linux/apm_bios.h> #include <linux/init.h> @@ -235,7 +236,6 @@ #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 @@ static void check_events(void) 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 @@ static void check_events(void) break; case APM_UPDATE_TIME: - set_time(); break; case APM_CRITICAL_SUSPEND: @@ -1636,9 +1593,8 @@ static int do_open(struct inode * inode, struct file * filp) 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 **start, off_t fpos, int length) 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 **start, off_t fpos, int length) -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 **start, off_t fpos, int length) 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; @@ -2341,9 +2307,9 @@ static int __init apm_init(void) 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 @@ void __init early_cpu_init(void) 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 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) __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) += powernow-k6.o 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/cpufreq.h> +#include <linux/ioport.h> +#include <linux/slab.h> + +#include <asm/msr.h> +#include <asm/tsc.h> +#include <asm/timex.h> +#include <asm/io.h> +#include <asm/delay.h> + +#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 <rafalbilski@interia.pl>"); +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 a3db933..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_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,26 +166,47 @@ static void do_longhaul1(unsigned int clock_ratio_index) 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(); @@ -193,12 +216,29 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index) 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; + } } /** @@ -257,26 +297,19 @@ static void longhaul_setstate(unsigned int clock_ratio_index) /* * 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 */ @@ -301,6 +334,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) local_irq_restore(flags); preempt_enable(); + freqs.new = calc_speed(longhaul_get_cpu_mult()); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } @@ -315,31 +349,19 @@ static void longhaul_setstate(unsigned int clock_ratio_index) #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; } @@ -347,67 +369,40 @@ 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, @@ -455,6 +450,7 @@ static void __init longhaul_setup_voltagescaling(void) 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)) { @@ -468,14 +464,14 @@ static void __init longhaul_setup_voltagescaling(void) 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. " @@ -491,20 +487,59 @@ static void __init longhaul_setup_voltagescaling(void) 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"); } @@ -573,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) { @@ -599,16 +665,20 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 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]"; @@ -616,8 +686,10 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 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; @@ -632,24 +704,24 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 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; @@ -658,6 +730,13 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 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) { @@ -670,15 +749,18 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 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; } @@ -688,8 +770,11 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 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 @@ -698,18 +783,18 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) } 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; @@ -797,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 <davej@codemonkey.org.uk>"); 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_ratio[32] = { 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[32] = { 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 (unsigned int cpu) 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 <asm/io.h> #include <asm/processor.h> #include <asm/timer.h> +#include <asm/pci-direct.h> #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(void) } -#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 cpuinfo_x86 *c) 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 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) 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(struct cpuinfo_x86 * c) 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 <asm/processor.h> #include <asm/system.h> +#include <asm/mce.h> #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 <linux/init.h> +#include <asm/mce.h> 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_x86 *c); /* 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 <asm/system.h> #include <asm/msr.h> #include <asm/apic.h> +#include <asm/idle.h> #include <asm/therm_throt.h> @@ -59,6 +60,7 @@ static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_therm 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 ee771f3..c7d8f17 100644 --- a/arch/i386/kernel/cpu/mtrr/if.c +++ b/arch/i386/kernel/cpu/mtrr/if.c @@ -211,6 +211,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) 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 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) 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 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) 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 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) 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); 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 *m, void *v) 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 *m, void *v) /* 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 *m, void *v) 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 *m, void *v) "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(struct cpuinfo_x86 *c) { 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(struct cpuinfo_x86 *c) 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 4da75fa..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_block) { 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 reg, u32 * data) 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(); } 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 <asm/pgtable.h> #include <asm/page.h> #include <asm/e820.h> +#include <asm/setup.h> #ifdef CONFIG_EFI int efi_enabled = 0; @@ -156,21 +157,22 @@ static struct resource standard_io_resources[] = { { .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 @@ VM_MASK = 0x00020000 #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 @@ VM_MASK = 0x00020000 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 @@ VM_MASK = 0x00020000 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 @@ sysenter_past_esp: 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 @@ ldt_ss: 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 @@ work_notifysig_v86: 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 @@ syscall_badsys: 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 cb9abdf..3fa7f93 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -53,6 +53,7 @@ * 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 @@ -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 @@ ENTRY(startup_32_smp) 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 @@ ignore_int: #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 0b29d41..e1006b7 100644 --- a/arch/i386/kernel/hpet.c +++ b/arch/i386/kernel/hpet.c @@ -1,4 +1,5 @@ #include <linux/clocksource.h> +#include <linux/clockchips.h> #include <linux/errno.h> #include <linux/hpet.h> #include <linux/init.h> @@ -6,17 +7,278 @@ #include <asm/hpet.h> #include <asm/io.h> +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 __iomem *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,28 +286,17 @@ static struct clocksource clocksource_hpet = { .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 = 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 @@ -61,11 +312,218 @@ static int __init init_hpet_clocksource(void) 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 <linux/mc146818rtc.h> +#include <linux/rtc.h> + +#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 <linux/clocksource.h> +#include <linux/clockchips.h> #include <linux/spinlock.h> #include <linux/jiffies.h> #include <linux/sysdev.h> @@ -19,17 +19,97 @@ 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 int); 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 ba8d302..4ccebd4 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -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, int vector, unsigned long trigger) 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 * dummy) 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 @@ static void __init setup_ioapic_ids_from_mpc(void) 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(void) 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); diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 3201d42..0f2ca590 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -10,7 +10,6 @@ * io_apic.c.) */ -#include <asm/uaccess.h> #include <linux/module.h> #include <linux/seq_file.h> #include <linux/interrupt.h> @@ -19,19 +18,36 @@ #include <linux/cpu.h> #include <linux/delay.h> +#include <asm/idle.h> + +#include <asm/apic.h> +#include <asm/uaccess.h> + 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 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) 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_handler(struct pt_regs *regs) 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 381252b..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; diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index 4e14264..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 *eax, u32 *edx) #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_block) { 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 reg, u32 eax, u32 edx) 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 reg, u32 * eax, u32 * edx) 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]; 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 <linux/dmi.h> #include <linux/kprobes.h> #include <linux/cpumask.h> +#include <linux/kernel_stat.h> #include <asm/smp.h> #include <asm/nmi.h> @@ -185,7 +186,8 @@ static __cpuinit inline int nmi_known_cpu(void) { 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 *data) } #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 @@ static int __init check_nmi_watchdog(void) 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(unsigned int perfctr_msr, const char *descr) 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(void) /* 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 *unused) 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 pt_regs * regs, unsigned reason) 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 pt_regs * regs, unsigned reason) 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 pt_regs * regs, unsigned reason) * 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, u16 clobbers, void *insns, unsigned len) 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_debugreg(int regno) 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_read_cr4_safe(void) 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 native_read_msr(unsigned int msr, int *err) 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(unsigned int msr, unsigned long long val) 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(void *dt, int entry, u32 entry_low, u32 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(struct tss_struct *tss, } } -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(void) * 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_present(struct mm_struct *mm, unsigned long 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(pmd_t *pmd) #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 @@ struct paravirt_ops paravirt_ops = { .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 @@ struct paravirt_ops paravirt_ops = { .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 <linux/platform_device.h> +#include <linux/errno.h> +#include <linux/init.h> + +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 <linux/ptrace.h> #include <linux/random.h> #include <linux/personality.h> +#include <linux/tick.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -48,6 +49,7 @@ #include <asm/i387.h> #include <asm/desc.h> #include <asm/vm86.h> +#include <asm/idle.h> #ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #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 @@ EXPORT_SYMBOL(default_idle); */ 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 eax, unsigned long ecx) __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 *), void * arg, unsigned long flags) 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 clone_flags, unsigned long esp, 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, struct user * dump) 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_to(struct task_struct *prev_p, struct tas 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_to(struct task_struct *prev_p, struct tas * 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_to(struct task_struct *prev_p, struct tas 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_to(struct task_struct *prev_p, struct tas 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_to(struct task_struct *prev_p, struct tas 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 *child, 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 *child, 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_struct *child, 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 4694ac9..122623d 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -33,7 +33,6 @@ #include <linux/initrd.h> #include <linux/bootmem.h> #include <linux/seq_file.h> -#include <linux/platform_device.h> #include <linux/console.h> #include <linux/mca.h> #include <linux/root_dev.h> @@ -60,6 +59,7 @@ #include <asm/io_apic.h> #include <asm/ist.h> #include <asm/io.h> +#include <asm/vmi.h> #include <setup_arch.h> #include <bios_ebda.h> @@ -581,6 +581,14 @@ void __init setup_arch(char **cmdline_p) 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 @@ void __init setup_arch(char **cmdline_p) #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 <linux/suspend.h> #include <linux/ptrace.h> #include <linux/elf.h> +#include <linux/binfmts.h> #include <asm/processor.h> #include <asm/ucontext.h> #include <asm/uaccess.h> @@ -128,8 +129,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax 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 __user *sc, struct _fpstate __user *fpstate, { 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_sigaction *ka, 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 <asm/mtrr.h> #include <asm/tlbflush.h> +#include <asm/idle.h> #include <mach_apic.h> /* @@ -374,8 +375,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, /* * 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 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, 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_interrupt(struct pt_regs *regs) /* * 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 8c6c8c52..48bfcaa1 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -63,6 +63,7 @@ #include <mach_apic.h> #include <mach_wakecpu.h> #include <smpboot_hooks.h> +#include <asm/vmi.h> /* 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(void *unused) * 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, unsigned long start_eip) /* * 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, unsigned long start_eip) 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(int cpu) 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(int cpu) 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(unsigned int max_cpus) 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 @@ int __cpuinit __cpu_up(unsigned int cpu) } 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/sysenter.c b/arch/i386/kernel/sysenter.c index bc882a2..13ca54a 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c @@ -78,7 +78,7 @@ int __init sysenter_setup(void) 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 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 *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 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) 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 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) 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 long dummy) 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/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(void); 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 @@ * 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(void) 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_cpufreq_notifier_block = { 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 @@ core_initcall(cpufreq_tsc); /* 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_tsc = { .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 bad_tsc_dmi_table[] = { {} }; -#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(void) /* 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 vm86_regs __user *user, { 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(struct kernel_vm86_regs *regs, { 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(struct kernel_vm86_regs * regs) 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_vm86_struct *info, struct task_struct *tsk */ 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_vm86_struct *info, struct task_struct *tsk */ 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_vm86_struct *info, struct task_struct *tsk __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 <linux/module.h> +#include <linux/license.h> +#include <linux/cpu.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <asm/vmi.h> +#include <asm/io.h> +#include <asm/fixmap.h> +#include <asm/apicdef.h> +#include <asm/apic.h> +#include <asm/processor.h> +#include <asm/timer.h> +#include <asm/vmi_time.h> + +/* 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 <linux/spinlock.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/jiffies.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/rcupdate.h> +#include <linux/clocksource.h> + +#include <asm/timer.h> +#include <asm/io.h> +#include <asm/apic.h> +#include <asm/div64.h> +#include <asm/timer.h> +#include <asm/desc.h> + +#include <asm/vmi.h> +#include <asm/vmi_time.h> + +#include <mach_timer.h> +#include <io_ports.h> + +#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 5038a73..ca516109 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 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_interrupt, IRQF_DISABLED, CPU_MASK_NONE, **/ void __init time_init_hook(void) { + irq0.mask = cpumask_of_cpu(0); setup_irq(0, &irq0); } 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 @@ static long pm_address(u_char FPU_modrm, u_char segment, 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 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 cba9b38..b8c4e25 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -46,17 +46,17 @@ int unregister_page_fault_notifier(struct notifier_block *nb) } 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); + return atomic_notifier_call_chain(¬ify_page_fault_chain, + DIE_PAGE_FAULT, &args); } /* @@ -327,8 +327,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, 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 @@ -337,8 +336,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, 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/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(pgd_t *pgd) #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_init(pmd_t *pmd) { 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 @@ static void __init pagetable_init (void) /* 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 e223b1d..412ebbd 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c @@ -60,6 +60,7 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot, 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, pgprot_t prot) 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); } 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 idx, unsigned long phys, pgprot_t flags) 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_cache *cache, unsigned long unused) 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_cache *cache, unsigned long unused) { 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 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_msrs const * const msrs) 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_msrs const * const msrs) 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_regs * const regs, 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 <linux/pci.h> +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/bitmap.h> +#include <asm/e820.h> + +#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 5700220..bb1afd9 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -15,55 +15,33 @@ #include <asm/e820.h> #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_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 != 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->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 == 0 && - (cfg->start_bus_number | cfg->end_bus_number) == 0) - return cfg->address; - /* Fall back to type 0 */ return 0; } @@ -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_SIG_MCFG, acpi_parse_mcfg); - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].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].address, - pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, - E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n", - (unsigned long)pci_mmcfg_config[0].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 db185f3..d51f0f1 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -22,6 +22,7 @@ config IA64 config 64BIT bool + select ATA_NONSTANDARD if ATA default y config ZONE_DMA diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c index 37bb16f..5cdd2f5 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c @@ -222,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/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/perfmon.c b/arch/ia64/kernel/perfmon.c index 9860794..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; @@ -6688,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/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_timelimit = 120; 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/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/mips/Kconfig b/arch/mips/Kconfig index 5fe195a..a92ce6b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -598,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 @@ -883,9 +881,6 @@ config DMA_NONCOHERENT config DMA_NEED_PCI_MAP_STATE bool -config OWN_DMA - bool - config EARLY_PRINTK bool 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_disable(int controller); 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 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file, 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/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_BINFMT_ELF=y 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/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 @@ 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/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 @@ #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/linux32.c b/arch/mips/kernel/linux32.c index ca7ad78..fc4dd6c 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -39,6 +39,7 @@ #include <net/sock.h> #include <net/scm.h> +#include <asm/compat-signal.h> #include <asm/ipc.h> #include <asm/sim.h> #include <asm/uaccess.h> @@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs) 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/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 ee8802b..2ceda46 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -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/signal-common.h b/arch/mips/kernel/signal-common.h index 9a8abd6..fdbdbdc 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -19,37 +19,7 @@ # define DEBUGP(fmt, args...) #endif -/* - * 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 sigframe { - u32 sf_ass[4]; /* argument save space for o32 */ - u32 sf_code[2]; /* signal trampoline */ - struct sigcontext sf_sc; - sigset_t sf_mask; -}; - -#else /* ICACHE_REFILLS_WORKAROUND_WAR */ - -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 */ -}; - -#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ - -/* - * handle hardware context - */ -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))) /* * Determine which stack to use.. diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 54398af..b2e9ab1 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -34,10 +34,20 @@ #include "signal-common.h" -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - +/* + * 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 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 */ @@ -47,6 +57,14 @@ struct rt_sigframe { #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]; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 183fc7e..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 <linux/cache.h> +#include <linux/compat.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> @@ -24,6 +25,7 @@ #include <asm/abi.h> #include <asm/asm.h> +#include <asm/compat-signal.h> #include <linux/bitops.h> #include <asm/cacheflush.h> #include <asm/sim.h> @@ -104,8 +106,6 @@ typedef struct compat_siginfo { #define __NR_O32_rt_sigreturn 4193 #define __NR_O32_restart_syscall 4253 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - /* 32-bit compatibility types */ #define _NSIG_BPW32 32 @@ -139,8 +139,20 @@ 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 */ @@ -150,6 +162,14 @@ struct rt_sigframe32 { #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]; @@ -493,13 +513,13 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) 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); @@ -536,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 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); @@ -581,7 +601,7 @@ badframe: 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)); @@ -591,7 +611,8 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 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; @@ -650,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 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; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 57456e6..7ca2a07 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -31,6 +31,7 @@ #include <asm/asm.h> #include <asm/cacheflush.h> +#include <asm/compat-signal.h> #include <asm/sim.h> #include <asm/uaccess.h> #include <asm/ucontext.h> @@ -47,7 +48,9 @@ #define __NR_N32_rt_sigreturn 6211 #define __NR_N32_restart_syscall 6214 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); +extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); + /* IRIX compatible stack_t */ typedef struct sigaltstack32 { @@ -61,7 +64,7 @@ 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 @@ -127,7 +130,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 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); @@ -193,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka, 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; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 545fcbc..e5e56bd 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -307,7 +307,7 @@ static unsigned int __init calibrate_hpt(void) struct clocksource clocksource_mips = { .name = "MIPS", .mask = 0xffffffff, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init init_mips_clocksource(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(void) 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/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-r5k.o 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(unsigned long addr) 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/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 <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include <linux/types.h> -#include <linux/dma-mapping.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/string.h> - -#include <asm/cache.h> -#include <asm/io.h> - -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 <linux/pci.h> - -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-noncoherent.c b/arch/mips/mm/dma-default.c index 8cecef0..4a32e93 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-default.c @@ -4,28 +4,39 @@ * for more details. * * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> + * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org> * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. */ + #include <linux/types.h> +#include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/string.h> -#include <linux/dma-mapping.h> #include <asm/cache.h> #include <asm/io.h> +#include <dma-coherence.h> + /* * 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); @@ -35,7 +46,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, if (ret != NULL) { memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); + *dma_handle = plat_map_dma_mem(dev, ret, size); } return ret; @@ -48,10 +59,21 @@ void *dma_alloc_coherent(struct device *dev, size_t size, { void *ret; - ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); + /* 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) { - dma_cache_wback_inv((unsigned long) ret, size); - ret = UNCAC_ADDR(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; @@ -72,7 +94,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, { unsigned long addr = (unsigned long) vaddr; - addr = CAC_ADDR(addr); + if (!plat_device_is_coherent(dev)) + addr = CAC_ADDR(addr); + free_pages(addr, get_order(size)); } @@ -104,9 +128,10 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, { unsigned long addr = (unsigned long) ptr; - __dma_sync(addr, size, direction); + if (!plat_device_is_coherent(dev)) + __dma_sync(addr, size, direction); - return virt_to_phys(ptr); + return plat_map_dma_mem(dev, ptr, size); } EXPORT_SYMBOL(dma_map_single); @@ -114,10 +139,11 @@ 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; + if (cpu_is_noncoherent_r10000(dev)) + __dma_sync(plat_dma_addr_to_phys(dma_addr) + PAGE_OFFSET, size, + direction); - //__dma_sync(addr, size, direction); + plat_unmap_dma_mem(dma_addr); } EXPORT_SYMBOL(dma_unmap_single); @@ -133,11 +159,10 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, unsigned long addr; addr = (unsigned long) page_address(sg->page); - if (addr) { + if (!plat_device_is_coherent(dev) && addr) __dma_sync(addr + sg->offset, sg->length, direction); - sg->dma_address = (dma_addr_t)page_to_phys(sg->page) - + sg->offset; - } + sg->dma_address = plat_map_dma_mem_page(dev, sg->page) + + sg->offset; } return nents; @@ -148,14 +173,16 @@ 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); + if (!plat_device_is_coherent(dev)) { + unsigned long addr; + + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, size); + } - return page_to_phys(page) + offset; + return plat_map_dma_mem_page(dev, page) + offset; } EXPORT_SYMBOL(dma_map_page); @@ -165,12 +192,14 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, { BUG_ON(direction == DMA_NONE); - if (direction != DMA_TO_DEVICE) { + if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) { unsigned long addr; - addr = dma_address + PAGE_OFFSET; + 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); @@ -183,13 +212,15 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, 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); + 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); } } @@ -198,12 +229,14 @@ 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); + 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); @@ -211,12 +244,14 @@ 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); + 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); @@ -224,12 +259,14 @@ 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); + 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); @@ -237,12 +274,14 @@ 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); + 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); @@ -255,9 +294,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, 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); + 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); @@ -270,9 +312,12 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nele 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); + 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); @@ -301,70 +346,18 @@ EXPORT_SYMBOL(dma_supported); int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) { - return 1; + 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) + enum dma_data_direction direction) { - if (direction == DMA_NONE) - return; + BUG_ON(direction == DMA_NONE); - dma_cache_wback_inv((unsigned long)vaddr, size); + if (!plat_device_is_coherent(dev)) + dma_cache_wback_inv((unsigned long)vaddr, size); } EXPORT_SYMBOL(dma_cache_sync); - -/* The DAC routines are a PCIism.. */ - -#ifdef CONFIG_PCI - -#include <linux/pci.h> - -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/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 <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/pci.h> - -#include <asm/cache.h> -#include <asm/pci/bridge.h> - -#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 <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> - * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com> - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - * IP32 changes by Ilya. - */ -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/dma-mapping.h> - -#include <asm/cache.h> -#include <asm/io.h> -#include <asm/ip32/crime.h> - -/* - * 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/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/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 <ajoshi@unixbox.com> + * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org> + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ + +#include <linux/types.h> +#include <linux/dma-mapping.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/string.h> + +#include <asm/cache.h> +#include <asm/io.h> + +#include <dma-coherence.h> + +#include <linux/pci.h> + +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/powerpc/Kconfig b/arch/powerpc/Kconfig index 0088c5e..340d9be 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -876,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 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 <g.liakhovetski@gmx.de> + * + * 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 = <bebc200>; /* 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 = <e100>; + interrupts = <a 0>; + 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 = <fec00000 400000>; + 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 = <f800 0 0 7>; + 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 <grant.likely@secretlab.ca> * * 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 = <f0000000 00010000>; 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 = <b00 40>; interrupts = <1 7 0>; interrupt-parent = <500>; }; gpio-wkup@b00 { - compatible = "mpc5200-gpio-wkup\0mpc52xx-gpio-wkup"; + compatible = "mpc5200-gpio-wkup"; reg = <c00 40>; 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 = <d00 100>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = <c000 0 0 1 500 0 0 3 @@ -194,7 +209,7 @@ spi@f00 { device_type = "spi"; - compatible = "mpc5200-spi\0mpc52xx-spi"; + compatible = "mpc5200-spi"; reg = <f00 20>; 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 <grant.likely@secretlab.ca> * * 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 = <f0000000 00010000>; 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 = <b00 40>; 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 = <c00 40>; 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 = <d00 100>; interrupt-map-mask = <f800 0 0 7>; interrupt-map = <c000 0 0 1 500 0 0 3 // 1st slot @@ -199,7 +214,7 @@ spi@f00 { device_type = "spi"; - compatible = "mpc5200b-spi\0mpc52xx-spi"; + compatible = "mpc5200b-spi\0mpc5200-spi"; reg = <f00 20>; 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/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 = <e0000000 00000200>; + 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 = <e 8>; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = <f 8>; + 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 = <a 8>; + interrupt-parent = <700>; + }; + + pci@8500 { + interrupt-map-mask = <f800 0 0 7>; + 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 = <b 8>; + interrupt-parent = <700>; + /* Rev. 2.2 */ + num-channels = <1>; + channel-fifo-len = <18>; + exec-units-mask = <0000004c>; + descriptor-types-mask = <0122003f>; + }; + + /* IPIC + * interrupts cell = <intr #, sense> + * 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 = <e0000000 00000200>; + 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 = <e 8>; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = <f 8>; + 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 = <a 8>; + interrupt-parent = <700>; + }; + + pci@8600 { + interrupt-map-mask = <f800 0 0 7>; + 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 = <b 8>; + 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/mpc8349emds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index efceb34..dc121b3 100644 --- a/arch/powerpc/boot/dts/mpc8349emds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -39,6 +39,11 @@ reg = <00000000 10000000>; // 256MB at 0 }; + bcsr@e2400000 { + device_type = "board-control"; + reg = <e2400000 8000>; + }; + soc8349@e0000000 { #address-cells = <1>; #size-cells = <1>; @@ -103,6 +108,7 @@ #size-cells = <0>; interrupt-parent = <700>; interrupts = <26 2>; + dr_mode = "otg"; phy_type = "ulpi"; }; 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 = <f8000000 8000>; + }; + + soc8568@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = <e0000000 00100000>; + 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 = <d 2 e 2 12 2>; + 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 = <e0100 100>; + device_type = "par_io"; + num-ports = <7>; + + ucc_pin@01 { + linux,phandle = <e010001>; + 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 = <e010002>; + 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 = <e0080000 480>; + 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 = <e010001>; + }; + + 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 = <e010002>; + }; + + 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/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_SPLIT_PTLOCK_CPUS=4 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_NF_CONNTRACK_PROC_COMPAT=y 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 @@ CONFIG_MTD_PARTITIONS=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 @@ -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 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1 # 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_ATA=y # 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_TUN=m # # 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_NET_RADIO=y # 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_DUMMY_CONSOLE=y # # HID Devices # -CONFIG_HID=y +CONFIG_HID=m # # USB support @@ -1115,7 +1143,6 @@ CONFIG_USB=y 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 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # 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_437=m # 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 @@ CONFIG_NLS_UTF8=m # 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/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/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig index 7902806..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 -# Fri Jan 26 00:19:02 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_DEFAULT_UIMAGE=y 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 @@ -178,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 @@ -303,7 +302,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" 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 # @@ -523,6 +521,7 @@ CONFIG_SCSI_SPI_ATTRS=y # 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 @@ -647,37 +646,7 @@ CONFIG_CICADA_PHY=y # # 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) @@ -693,7 +662,6 @@ CONFIG_E100=y # 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 @@ -746,26 +714,7 @@ CONFIG_GFAR_NAPI=y # # 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 @@ -784,7 +733,7 @@ CONFIG_INPUT=y # 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 @@ -887,7 +836,7 @@ CONFIG_I2C_MPC=y # 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 @@ -901,7 +850,6 @@ CONFIG_I2C_MPC=y # SPI support # CONFIG_SPI=y -# CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y # @@ -922,52 +870,8 @@ CONFIG_SPI_MPC83xx=y # # 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 @@ -983,7 +887,7 @@ CONFIG_HWMON=y # # 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 @@ -994,11 +898,6 @@ CONFIG_FIRMWARE_EDID=y # CONFIG_SOUND is not set # -# HID Devices -# -CONFIG_HID=y - -# # USB support # CONFIG_USB_ARCH_HAS_HCD=y @@ -1023,10 +922,8 @@ CONFIG_USB_EHCI_HCD=y # 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 # @@ -1058,25 +955,10 @@ CONFIG_USB_STORAGE=y # # 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 @@ -1133,25 +1015,7 @@ CONFIG_USB_MON=y # # 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 @@ -1273,8 +1137,11 @@ CONFIG_DNOTIFY=y # # 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 # @@ -1340,7 +1207,7 @@ CONFIG_PARTITION_ADVANCED=y # 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 @@ -1356,7 +1223,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 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 @@ -1388,27 +1294,9 @@ CONFIG_ENABLE_MUST_CHECK=y # 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 9eaed3a..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 -# Fri Jan 26 00:19:27 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_DEFAULT_UIMAGE=y 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_PPC_GEN550=y # # 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 diff --git a/arch/powerpc/configs/mpc8568mds_defconfig b/arch/powerpc/configs/mpc8568mds_defconfig new file mode 100644 index 0000000..058e06d8 --- /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/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 <asm/io.h> #include <asm/lmb.h> #include <asm/processor.h> +#include <asm/udbg.h> #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/cputable.c b/arch/powerpc/kernel/cputable.c index dd17dff..7ec4ac7 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -44,7 +44,7 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); 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(unsigned long offset, struct cpu_spec* spec); +extern void __restore_cpu_pa6t(void); extern void __restore_cpu_ppc970(void); #endif /* CONFIG_PPC64 */ 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 <asm/page.h> #include <asm/mmu.h> #include <asm/pgtable.h> -#include <asm/ibm4xx.h> -#include <asm/ibm44x.h> #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> 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 @@ skpinv: addi r6,r6,1 /* Increment */ 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 @@ skpinv: addi r6,r6,1 /* Increment */ 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 @@ load_up_spe: REST_GPR(9, r11) REST_GPR(12, r11) lwz r11,GPR11(r11) - SYNC rfi /* @@ -953,7 +955,6 @@ _GLOBAL(giveup_altivec) _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/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 89f46f3..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(struct device_node *np, 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(void) 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));) { diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 520ef42f..4fb5938 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2117,11 +2117,92 @@ static void __init fixup_device_tree_pmac(void) #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/setup_32.c b/arch/powerpc/kernel/setup_32.c index 6a19fa4..44a6a3c 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -116,12 +116,8 @@ unsigned long __init early_init(unsigned long dt_ptr) */ 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/udbg.c b/arch/powerpc/kernel/udbg.c index 194a93e..7e09718 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -49,6 +49,8 @@ void __init udbg_early_init(void) 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 } diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 50149ec..e46c31b 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -49,24 +49,23 @@ /* Max supported size for symbol names */ #define MAX_SYMNAME 64 -#define VDSO32_MAXPAGES (((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2) -#define VDSO64_MAXPAGES (((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2) - extern char vdso32_start, vdso32_end; static void *vdso32_kbase = &vdso32_start; -unsigned int vdso32_pages; -static struct page *vdso32_pagelist[VDSO32_MAXPAGES]; +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 struct page *vdso64_pagelist[VDSO64_MAXPAGES]; +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 @@ -182,6 +181,9 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, unsigned long vdso_base; int rc; + if (!vdso_ready) + return 0; + #ifdef CONFIG_PPC64 if (test_thread_flag(TIF_32BIT)) { vdso_pagelist = vdso32_pagelist; @@ -661,7 +663,7 @@ static void __init vdso_setup_syscall_map(void) } -void __init vdso_init(void) +static int __init vdso_init(void) { int i; @@ -716,11 +718,13 @@ void __init vdso_init(void) #ifdef CONFIG_PPC64 vdso64_pages = 0; #endif - return; + return 0; } /* Make sure pages are in the correct state */ - BUG_ON(vdso32_pages + 2 > VDSO32_MAXPAGES); + 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); @@ -731,7 +735,9 @@ void __init vdso_init(void) vdso32_pagelist[i] = NULL; #ifdef CONFIG_PPC64 - BUG_ON(vdso64_pages + 2 > VDSO64_MAXPAGES); + 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); @@ -743,7 +749,13 @@ void __init vdso_init(void) #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/mm/mem.c b/arch/powerpc/mm/mem.c index 77b4637..52f397c1 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -384,9 +384,6 @@ void __init mem_init(void) initsize >> 10); mem_init_done = 1; - - /* Initialize the vDSO */ - vdso_init(); } /* diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index bd02272..c284bda 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -295,7 +295,7 @@ void __init mapin_ram(void) } /* is x a power of 4? */ -#define is_power_of_4(x) is_power_of_2(x) && (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/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 "../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 @@ static struct { #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_LOCK_UNLOCKED; 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 node) 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 event, u32 unit_mask) /* 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 event, u32 unit_mask) 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 event, u32 unit_mask) 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 long data) 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 long data) == 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 long data) * 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 *ctr, 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 *ctr, 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_counter_config *cntr) 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_counter_config *ctr) } } - 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 *regs, struct op_counter_config *ctr) 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/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index 795b713..07cdbca 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile @@ -6,5 +6,5 @@ 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 <linux/kernel.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/sections.h> -#include <asm/pci-bridge.h> -#include <asm/rtas.h> - -#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 <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/utsrelease.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> -#include <linux/timer.h> -#include <linux/pci.h> - -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/time.h> -#include <asm/machdep.h> -#include <asm/rtas.h> -#include <asm/of_device.h> -#include <asm/of_platform.h> -#include <asm/mpc52xx.h> - -#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 <linux/errno.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/utsrelease.h> +#include <linux/seq_file.h> +#include <linux/string.h> +#include <linux/root_dev.h> +#include <linux/initrd.h> +#include <linux/timer.h> +#include <linux/pci.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/sections.h> +#include <asm/pci-bridge.h> +#include <asm/pgtable.h> +#include <asm/prom.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/rtas.h> +#include <asm/of_device.h> +#include <asm/of_platform.h> +#include <asm/mpc52xx.h> + + +#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 cdb16bf..cc3b40d 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -51,13 +51,13 @@ */ 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,7 @@ static void __init lite52xx_setup_arch(void) /* 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"); @@ -126,7 +126,7 @@ static void __init lite52xx_setup_arch(void) } -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; @@ -143,25 +143,26 @@ void lite52xx_show_cpuinfo(struct seq_file *m) /* * 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_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/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 @@ # 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/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 <r43300@freescale.com> + * + * 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 <linux/pci.h> + +#include <asm/time.h> +#include <asm/ipic.h> +#include <asm/udbg.h> + +#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/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 2446dea..443a317 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -38,8 +38,6 @@ #include "mpc83xx.h" -#include <platforms/83xx/mpc834x_sys.h> - #ifndef CONFIG_PCI unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index f30393f..d2736da 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -1,7 +1,7 @@ /* - * arch/powerpc/platforms/83xx/mpc834x_sys.c + * arch/powerpc/platforms/83xx/mpc834x_mds.c * - * MPC834x SYS board specific routines + * MPC834x MDS board specific routines * * Maintainer: Kumar Gala <galak@kernel.crashing.org> * @@ -43,17 +43,87 @@ 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_sys_setup_arch(void) +static void __init mpc834x_mds_setup_arch(void) { struct device_node *np; if (ppc_md.progress) - ppc_md.progress("mpc834x_sys_setup_arch()", 0); + ppc_md.progress("mpc834x_mds_setup_arch()", 0); np = of_find_node_by_type(NULL, "cpu"); if (np != 0) { @@ -65,6 +135,7 @@ static void __init mpc834x_sys_setup_arch(void) 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); @@ -72,6 +143,8 @@ static void __init mpc834x_sys_setup_arch(void) ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif + mpc834x_usb_cfg(); + #ifdef CONFIG_ROOT_NFS ROOT_DEV = Root_NFS; #else @@ -79,7 +152,7 @@ static void __init mpc834x_sys_setup_arch(void) #endif } -static void __init mpc834x_sys_init_IRQ(void) +static void __init mpc834x_mds_init_IRQ(void) { struct device_node *np; @@ -119,7 +192,7 @@ late_initcall(mpc834x_rtc_hookup); /* * Called very early, MMU is off, device-tree isn't unflattened */ -static int __init mpc834x_sys_probe(void) +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 @@ -127,11 +200,11 @@ static int __init mpc834x_sys_probe(void) 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, +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, 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 <galak@kernel.crashing.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __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/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 @@ #include <linux/init.h> #include <linux/device.h> +/* 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 <afleming@freescale.com> + * + * Based on 83xx/mpc8360e_pb.c by: + * Li Yang <LeoLi@freescale.com> + * Yin Olivia <Hong-hua.Yin@freescale.com> + * + * 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 <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/initrd.h> +#include <linux/module.h> +#include <linux/fsl_devices.h> + +#include <asm/of_device.h> +#include <asm/of_platform.h> +#include <asm/system.h> +#include <asm/atomic.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/bootinfo.h> +#include <asm/pci-bridge.h> +#include <asm/mpc85xx.h> +#include <asm/irq.h> +#include <mm/mmu_decl.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <sysdev/fsl_soc.h> +#include <asm/qe.h> +#include <asm/qe_ic.h> +#include <asm/mpic.h> + +#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 irq, struct irq_desc *desc) #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 @@ static void __init mpc85xx_ads_setup_arch(void) #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 @@ unsigned long isa_mem_base = 0; static int cds_pci_slot = 2; static volatile u8 *cadmus; - #ifdef CONFIG_PCI #define ARCADIA_HOST_BRIDGE_IDSEL 17 @@ -64,8 +63,7 @@ static volatile u8 *cadmus; 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_char devfn) 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(unsigned int irq, struct irq_desc *desc) #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 @@ void __init mpc85xx_cds_pic_init(void) #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 @@ mpc85xx_cds_setup_arch(void) #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/Makefile b/arch/powerpc/platforms/Makefile index 65e6123..4520042 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -5,9 +5,9 @@ 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/ 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_interrupts); 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_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index d8b39fe..e34599f 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -59,63 +59,6 @@ static u64 __init find_spu_unit_number(struct device_node *spe) return 0; } -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; - - ret = __add_pages(zone, start_pfn, nr_pages); - - 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) { if (!firmware_has_feature(FW_FEATURE_LPAR)) @@ -157,6 +100,23 @@ static int __init spu_map_interrupts_old(struct spu *spu, 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; @@ -175,7 +135,7 @@ static int __init spu_map_device_old(struct spu *spu) /* we use local store as ram, not io memory */ spu->local_store = (void __force *) - map_spe_prop(spu, node, "local-store"); + spu_map_prop_old(spu, node, "local-store"); if (!spu->local_store) goto out; @@ -184,16 +144,16 @@ static int __init spu_map_device_old(struct spu *spu) goto out_unmap; spu->problem_phys = *(unsigned long *)prop; - spu->problem = map_spe_prop(spu, node, "problem"); + spu->problem = spu_map_prop_old(spu, node, "problem"); if (!spu->problem) goto out_unmap; - spu->priv2 = map_spe_prop(spu, node, "priv2"); + spu->priv2 = spu_map_prop_old(spu, node, "priv2"); if (!spu->priv2) goto out_unmap; if (!firmware_has_feature(FW_FEATURE_LPAR)) { - spu->priv1 = map_spe_prop(spu, node, "priv1"); + spu->priv1 = spu_map_prop_old(spu, node, "priv1"); if (!spu->priv1) goto out_unmap; } @@ -245,34 +205,20 @@ static int spu_map_resource(struct spu *spu, int nr, void __iomem** virt, unsigned long *phys) { struct device_node *np = 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; - + return ret; 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; - - ret = __add_pages(zone, start_pfn, nr_pages); - -out: - return ret; + return -EINVAL; + return 0; } static int __init spu_map_device(struct spu *spu) 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(struct spu_gang *gang) } 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(struct spu_gang *gang) 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 *kref) { 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 af9e9455..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, struct file *file) 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 char __user *buffer, 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 vm_area_struct *vma) 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); @@ -152,49 +151,42 @@ static const struct file_operations spufs_mem_fops = { .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 *file, struct vm_area_struct *vma) 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,8 +235,8 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) 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"); } @@ -728,8 +720,8 @@ static int spufs_signal1_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 = 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(struct file *file, const char __user *buf, 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 file *file, struct vm_area_struct *vma) 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); @@ -835,8 +827,8 @@ static int spufs_signal2_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 = 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(struct file *file, const char __user *buf, } #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 file *file, struct vm_area_struct *vma) 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); @@ -1000,14 +992,14 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 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 *file, struct vm_area_struct *vma) 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,8 +1024,11 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) 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); } @@ -1042,14 +1037,14 @@ static const struct file_operations spufs_mss_fops = { .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 *file, struct vm_area_struct *vma) 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,8 +1066,11 @@ static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) 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); } @@ -1083,14 +1081,14 @@ static const struct file_operations spufs_psmap_fops = { #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 *file, struct vm_area_struct *vma) 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 *inode, struct file *file) 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 file *file, const char __user *buffer, 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 { 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 spu_context *ctx, u32 * npc) 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 spu_context *ctx, u32 * npc) 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 spu_context *ctx, u32 * npc) (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 spu_context *ctx, u32 * npc, { 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, struct spu_context *ctx, } 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 <asm/spu_priv1.h> #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 notifier_block * 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 spu *spu, struct spu_context *ctx) 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 spu *spu, struct spu_context *ctx) 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 *spu, struct spu_context *ctx) 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 spu_context *ctx, u64 flags) 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 5686446..0c43789 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -23,7 +23,7 @@ #define SPUFS_H #include <linux/kref.h> -#include <linux/rwsem.h> +#include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/fs.h> @@ -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 { @@ -159,6 +171,16 @@ void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); 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 *ctx); 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/htab.c b/arch/powerpc/platforms/celleb/htab.c index ffa7c2c..279d733 100644 --- a/arch/powerpc/platforms/celleb/htab.c +++ b/arch/powerpc/platforms/celleb/htab.c @@ -95,7 +95,6 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, unsigned long lpar_rc; unsigned long slot; unsigned long hpte_v, hpte_r; - unsigned long flags; /* same as iseries */ if (vflags & HPTE_V_SECONDARY) @@ -115,17 +114,17 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) hpte_r &= ~_PAGE_COHERENT; - spin_lock_irqsave(&beat_htab_lock, flags); + 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_irqrestore(&beat_htab_lock, flags); + 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_irqrestore(&beat_htab_lock, flags); + spin_unlock(&beat_htab_lock); /* * Since we try and ioremap PHBs we don't own, the pte insert @@ -189,7 +188,6 @@ static long beat_lpar_hpte_updatepp(unsigned long slot, { unsigned long lpar_rc; unsigned long dummy0, dummy1, want_v; - unsigned long flags; want_v = hpte_encode_v(va, psize); @@ -197,17 +195,17 @@ static long beat_lpar_hpte_updatepp(unsigned long slot, "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", want_v & HPTE_V_AVPN, slot, psize, newpp); - spin_lock_irqsave(&beat_htab_lock, flags); + spin_lock(&beat_htab_lock); dummy0 = beat_lpar_hpte_getword0(slot); if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) { DBG_LOW("not found !\n"); - spin_unlock_irqrestore(&beat_htab_lock, flags); + spin_unlock(&beat_htab_lock); return -1; } lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0, &dummy1); - spin_unlock_irqrestore(&beat_htab_lock, flags); + spin_unlock(&beat_htab_lock); if (lpar_rc != 0 || dummy0 == 0) { DBG_LOW("not found !\n"); return -1; @@ -256,18 +254,17 @@ static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, int psize) { unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1; - unsigned long flags; vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); - spin_lock_irqsave(&beat_htab_lock, flags); + 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_irqrestore(&beat_htab_lock, flags); + spin_unlock(&beat_htab_lock); BUG_ON(lpar_rc != 0); } 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 <linux/kernel.h> #include <linux/pci.h> #include <linux/initrd.h> -#include <linux/root_dev.h> #include <linux/mtd/physmap.h> #include <asm/time.h> @@ -91,17 +90,6 @@ static void __init linkstation_setup_arch(void) 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/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_host *h, unsigned int virq, 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/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index d192972..a397e4e 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -170,31 +170,6 @@ static int __init construct_spu(struct spu *spu) 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,8 +222,8 @@ static int __init setup_areas(struct spu *spu) fail_ioremap: spu_unmap(spu); -fail_add: - return result; + + return -ENOMEM; } static int __init setup_interrupts(struct spu *spu) 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/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 <asm/firmware.h> - -extern void __init fw_feature_init(void); - -#endif /* _PSERIES_FIRMWARE_H */ 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 <asm/machdep.h> +#include <asm/page.h> +#include <asm/firmware.h> +#include <asm/kexec.h> +#include <asm/mpic.h> + +#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/pci.c b/arch/powerpc/platforms/pseries/pci.c index c69bd15..fa59124 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -98,6 +98,10 @@ static void fixup_winbond_82c105(struct pci_dev* dev) 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 <asm/udbg.h> #include <asm/firmware.h> -#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/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 <asm/dma.h> #include <asm/machdep.h> #include <asm/irq.h> -#include <asm/kexec.h> #include <asm/time.h> #include <asm/nvram.h> #include "xics.h" @@ -65,10 +64,10 @@ #include <asm/i8259.h> #include <asm/udbg.h> #include <asm/smp.h> +#include <asm/firmware.h> #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 @@ #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(void) 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(void) 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 <asm/vdso_datapage.h> #include "plpar_wrappers.h" +#include "pseries.h" #ifdef DEBUG #include <asm/udbg.h> diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 9f2a9a4..34161bc 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -441,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; @@ -507,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); @@ -699,7 +739,7 @@ static int __init fs_enet_of_init(void) if (ret) goto unreg; } - + of_node_put(phy); of_node_put(mdio); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index aa701cc..4e54a09 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1395,4 +1395,25 @@ void smp_mpic_message_pass(int target, int msg) 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/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 * us_info, struct ucc_slow_private ** ucc 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 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc 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 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* 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/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 *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/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/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 @@ skpinv: addi r6,r6,1 /* Increment */ 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 @@ skpinv: addi r6,r6,1 /* Increment */ 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 @@ load_up_spe: REST_GPR(9, r11) REST_GPR(12, r11) lwz r11,GPR11(r11) - SYNC rfi /* @@ -953,7 +955,6 @@ _GLOBAL(giveup_altivec) _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 1f49503..1318b6f 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -271,7 +271,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ 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/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 82b06a1..c023b72 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -314,7 +314,7 @@ void __init mapin_ram(void) } /* is x a power of 4? */ -#define is_power_of_4(x) is_power_of_2(x) && (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 <sr@denx.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/initrd.h> +#include <linux/seq_file.h> +#include <linux/root_dev.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/platform_device.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/ndfc.h> +#include <linux/mtd/physmap.h> + +#include <asm/machdep.h> +#include <asm/ocp.h> +#include <asm/bootinfo.h> +#include <asm/ppcboot.h> + +#include <syslib/gen550.h> +#include <syslib/ibm440gx_common.h> + +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 <sr@denx.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 <platforms/4xx/ibm440gx.h> + +/* 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/syslib/Makefile b/arch/ppc/syslib/Makefile index d84f0466..0991111 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_SANDPOINT) += pci_auto.o todc_time.o 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..1e5a00a4 100644 --- a/arch/ppc/syslib/i8259.c +++ b/arch/ppc/syslib/i8259.c @@ -154,7 +154,7 @@ static struct resource pic_edgectrl_iores = { 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/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_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 c9da7d1..0c3cf4b 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -506,7 +506,7 @@ int appldata_register_ops(struct appldata_ops *ops) 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/kernel/debug.c b/arch/s390/kernel/debug.c index 51653d8..eca3fe5 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -852,7 +852,6 @@ debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level, static int debug_stoppable=1; static int debug_active=1; -#define CTL_S390DBF 5677 #define CTL_S390DBF_STOPPABLE 5678 #define CTL_S390DBF_ACTIVE 5679 @@ -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"); diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 3b91f27..ee9fd7b 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -312,7 +312,7 @@ static struct clocksource clocksource_tod = { .mask = -1ULL, .mult = 1000, .shift = 12, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index f93a056..c5b2f4f 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -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[]; @@ -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/sh/Kconfig b/arch/sh/Kconfig index 4f38912..4d16d89 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -135,12 +135,6 @@ config SH_HP6XX More information (hardware only) at <http://www.hp.com/jornada/>. -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 @@ -156,9 +150,6 @@ config SH_DREAMCAST <http://www.m17n.org/linux-sh/dreamcast/>. There is a Dreamcast project is at <http://linuxdc.sourceforge.net/>. -config SH_BIGSUR - bool "BigSur" - config SH_MPC1211 bool "Interface MPC1211" help @@ -481,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. @@ -510,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 @@ -596,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. 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) := se/7300 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 <gbanks@pocketpenguins.com> - * (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 <linux/kernel.h> -#include <linux/module.h> -#include <asm/machvec.h> -#include <asm/io.h> -#include <asm/bigsur/bigsur.h> - -/* 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)-1) -#define BIGSUR_IOMAP_LO_NMAP (BIGSUR_IOMAP_LO_THRESH>>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)-1) -#define BIGSUR_IOMAP_HI_NMAP (BIGSUR_IOMAP_HI_THRESH>>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)) { - pr_debug(" maplo[0x%x] = 0x%08x\n", port, addr); - bigsur_iomap_lo[port>>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)) { - pr_debug(" maphi[0x%x] = 0x%08x\n", port, addr); - bigsur_iomap_hi[port>>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)) { - bigsur_iomap_lo[port>>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)) { - bigsur_iomap_hi[port>>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 <gbanks@pocketpenguins.com> - * Copyright (c) 2000 PocketPenguins Inc - * - * Derived from setup_hd64465.c which bore the message: - * Greg Banks <gbanks@pocketpenguins.com> - * 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 <linux/sched.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/bitops.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#include <asm/bigsur/io.h> -#include <asm/hd64465/hd64465.h> -#include <asm/bigsur/bigsur.h> - -//#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<BIGSUR_IRQ_HIGH;i++) - make_bigsur_l1isr(i); - - printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n", - BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH); - - for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++) - make_bigsur_l2isr(i); - - printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n", - BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH); - -} diff --git a/arch/sh/boards/bigsur/led.c b/arch/sh/boards/bigsur/led.c deleted file mode 100644 index d221439..0000000 --- a/arch/sh/boards/bigsur/led.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/arch/sh/boards/bigsur/led.c - * - * By Dustin McIntire (dustin@sensoria.com) (c)2001 - * Derived from led_se.c and led.c, which bore the message: - * Copyright (C) 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. - * - * This file contains Big Sur specific LED code. - */ - -#include <asm/io.h> -#include <asm/bigsur/bigsur.h> - -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 <linux/sched.h> - -/* 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<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; - dist = period / 4; - } -} -#endif /* CONFIG_HEARTBEAT */ - diff --git a/arch/sh/boards/bigsur/setup.c b/arch/sh/boards/bigsur/setup.c deleted file mode 100644 index 9711c20..0000000 --- a/arch/sh/boards/bigsur/setup.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * By Dustin McIntire (dustin@sensoria.com) (c)2001 - * - * Setup and IRQ handling code for the HD64465 companion chip. - * by Greg Banks <gbanks@pocketpenguins.com> - * Copyright (c) 2000 PocketPenguins Inc - * - * Derived from setup_hd64465.c which bore the message: - * Greg Banks <gbanks@pocketpenguins.com> - * 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 <linux/sched.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/bitops.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/machvec.h> -#include <asm/bigsur/io.h> -#include <asm/hd64465/hd64465.h> -#include <asm/bigsur/bigsur.h> - -/*===========================================================*/ -// 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 <prumpf@tux.org> - * - */ -/* 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 <linux/kernel.h> -#include <linux/types.h> -#include <asm/io.h> -#include <asm/page.h> -#include <asm/ec3104/ec3104.h> - -/* - * 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 <prumpf@tux.org> - * - */ - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/ec3104/ec3104.h> - -/* 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<<bit))) - p += sprintf(p, "%s ", ec3104_name(bit)); - - p += sprintf(p, ")\n"); - - return p - buf; -} - -static inline u32 ec3104_irq2mask(unsigned int irq) -{ - return (1 << (irq - EC3104_IRQBASE)); -} - -static inline void mask_ec3104_irq(unsigned int irq) -{ - u32 mask; - - mask = ctrl_readl(EC3104_IMR); - - mask |= ec3104_irq2mask(irq); - - ctrl_writel(mask, EC3104_IMR); -} - -static inline void unmask_ec3104_irq(unsigned int irq) -{ - u32 mask; - - mask = ctrl_readl(EC3104_IMR); - - mask &= ~ec3104_irq2mask(irq); - - ctrl_writel(mask, EC3104_IMR); -} - -static void disable_ec3104_irq(unsigned int irq) -{ - mask_ec3104_irq(irq); -} - -static void enable_ec3104_irq(unsigned int irq) -{ - unmask_ec3104_irq(irq); -} - -static void mask_and_ack_ec3104_irq(unsigned int irq) -{ - mask_ec3104_irq(irq); -} - -static void end_ec3104_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - unmask_ec3104_irq(irq); -} - -static unsigned int startup_ec3104_irq(unsigned int irq) -{ - unmask_ec3104_irq(irq); - - return 0; -} - -static void shutdown_ec3104_irq(unsigned int irq) -{ - mask_ec3104_irq(irq); - -} - -static struct hw_interrupt_type ec3104_int = { - .typename = "EC3104", - .enable = enable_ec3104_irq, - .disable = disable_ec3104_irq, - .ack = mask_and_ack_ec3104_irq, - .end = end_ec3104_irq, - .startup = startup_ec3104_irq, - .shutdown = shutdown_ec3104_irq, -}; - -/* Yuck. the _demux API is ugly */ -int ec3104_irq_demux(int irq) -{ - if (irq == EC3104_IRQ) { - unsigned int mask; - - mask = ctrl_readl(EC3104_IRR); - - if (mask == 0xffffffff) - return EC3104_IRQ; - else - return EC3104_IRQBASE + ffz(mask); - } - - return irq; -} diff --git a/arch/sh/boards/ec3104/setup.c b/arch/sh/boards/ec3104/setup.c deleted file mode 100644 index 902bc97..0000000 --- a/arch/sh/boards/ec3104/setup.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * linux/arch/sh/boards/ec3104/setup.c - * EC3104 companion chip support - * - * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> - * - */ -/* 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 <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/types.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/machvec.h> -#include <asm/mach/ec3104.h> - -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/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 <linux/sched.h> - -/* 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<<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; - -} -#endif /* CONFIG_HEARTBEAT */ diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c index 7c3d1d3..1a0604b 100644 --- a/arch/sh/boards/mpc1211/setup.c +++ b/arch/sh/boards/mpc1211/setup.c @@ -10,6 +10,7 @@ #include <linux/hdreg.h> #include <linux/ide.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/machvec.h> #include <asm/mpc1211/mpc1211.h> @@ -281,6 +282,32 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no) 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 __initmv = { .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 <linux/pci.h> #include <linux/kernel.h> #include <linux/types.h> +#include <linux/io.h> #include <asm/r7780rp.h> #include <asm/addrspace.h> -#include <asm/io.h> - -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(unsigned int port, int flag) 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, void *dst, unsigned long count) 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, void *dst, unsigned long count) 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, const void *src, unsigned long count) 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, const void *src, unsigned long count) 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 <linux/sched.h> -#include <asm/io.h> -#include <asm/r7780rp/r7780rp.h> - -/* 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<<FSHIFT))); - - *p = 1 << bit_pos[bit]; - if (up) - if (bit == 7) { - bit--; - up = 0; - } else - bit++; - else if (bit == 0) - up = 1; - else - bit--; -} diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c index 9f89c8d..0d74db9 100644 --- a/arch/sh/boards/renesas/r7780rp/setup.c +++ b/arch/sh/boards/renesas/r7780rp/setup.c @@ -2,7 +2,7 @@ * arch/sh/boards/renesas/r7780rp/setup.c * * Copyright (C) 2002 Atom Create Engineering Co., Ltd. - * Copyright (C) 2005, 2006 Paul Mundt + * Copyright (C) 2005 - 2007 Paul Mundt * * Renesas Solutions Highlander R7780RP-1 Support. * @@ -12,12 +12,12 @@ */ #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/pata_platform.h> #include <asm/machvec.h> #include <asm/r7780rp.h> #include <asm/clock.h> #include <asm/io.h> -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_host_device = { 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 @@ static struct resource cf_ide_resources[] = { }, }; +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 **cmdline_p) #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 __initmv = { .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 <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/io.h> -#include <asm/rts7751r2d.h> -#include <asm/addrspace.h> - -/* - * 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 <linux/init.h> +#include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <asm/rts7751r2d.h> @@ -22,79 +24,31 @@ static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0}; 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 <linux/io.h> -#include <linux/sched.h> -#include <asm/rts7751r2d.h> - -/* 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<<FSHIFT))); - - *p = 1 << bit; - if (up) - if (bit == 7) { - bit--; - up = 0; - } else - bit++; - else if (bit == 0) - up = 1; - else - bit--; -} diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c index 5c042d3..44b4208 100644 --- a/arch/sh/boards/renesas/rts7751r2d/setup.c +++ b/arch/sh/boards/renesas/rts7751r2d/setup.c @@ -1,8 +1,8 @@ /* * Renesas Technology Sales RTS7751R2D Support. * - * Copyright (C) 2002 Atom Create Engineering Co., Ltd. - * Copyright (C) 2004 - 2006 Paul Mundt + * Copyright (C) 2002 - 2006 Atom Create Engineering Co., Ltd. + * Copyright (C) 2004 - 2007 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 @@ -10,33 +10,13 @@ */ #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/pata_platform.h> #include <linux/serial_8250.h> #include <linux/pm.h> #include <asm/machvec.h> -#include <asm/mach/rts7751r2d.h> -#include <asm/io.h> +#include <asm/rts7751r2d.h> #include <asm/voyagergx.h> - -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 <asm/io.h> static void __init voyagergx_serial_init(void) { @@ -45,32 +25,96 @@ static void __init voyagergx_serial_init(void) /* * 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_setup(void) 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 __initmv = { .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 63950f4f..63e7ed6 100644 --- a/arch/sh/boards/se/7206/Makefile +++ b/arch/sh/boards/se/7206/Makefile @@ -3,5 +3,3 @@ # 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 <stuart.menefy@st.com> - * - * 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 <linux/config.h> -#include <asm/se7206.h> - -#ifdef CONFIG_HEARTBEAT - -#include <linux/sched.h> - -/* 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<<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); - -} -#endif /* CONFIG_HEARTBEAT */ diff --git a/arch/sh/boards/se/7206/setup.c b/arch/sh/boards/se/7206/setup.c index 0f42e91..ca71487 100644 --- a/arch/sh/boards/se/7206/setup.c +++ b/arch/sh/boards/se/7206/setup.c @@ -3,6 +3,7 @@ * linux/arch/sh/boards/se/7206/setup.c * * Copyright (C) 2006 Yoshinori Sato + * Copyright (C) 2007 Paul Mundt * * Hitachi 7206 SolutionEngine Support. * @@ -34,15 +35,37 @@ static struct platform_device smc91x_device = { .resource = smc91x_resources, }; +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 *se7206_devices[] __initdata = { + &smc91x_device, + &heartbeat_device, +}; + static int __init se7206_devices_setup(void) { - return platform_device_register(&smc91x_device); + return platform_add_devices(se7206_devices, ARRAY_SIZE(se7206_devices)); } - __initcall(se7206_devices_setup); -void heartbeat_se(void); - /* * The Machine Vector */ @@ -72,8 +95,5 @@ struct sh_machine_vector mv_se __initmv = { .mv_outsl = se7206_outsl, .mv_init_irq = init_se7206_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_se, -#endif }; ALIAS_MV(se) diff --git a/arch/sh/boards/se/7300/Makefile b/arch/sh/boards/se/7300/Makefile index 0fbd4f4..4624736 100644 --- a/arch/sh/boards/se/7300/Makefile +++ b/arch/sh/boards/se/7300/Makefile @@ -3,5 +3,3 @@ # obj-y := setup.o io.o irq.o - -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/se/7300/led.c b/arch/sh/boards/se/7300/led.c deleted file mode 100644 index 4d03bb7..0000000 --- a/arch/sh/boards/se/7300/led.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/arch/sh/boards/se/7300/led.c - * - * Derived from linux/arch/sh/boards/se/770x/led.c - * - * Copyright (C) 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. - * - * This file contains Solution Engine specific LED code. - */ - -#include <linux/sched.h> -#include <asm/se7300.h> - -/* 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 6f082a72..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 <linux/init.h> +#include <linux/platform_device.h> #include <asm/machvec.h> #include <asm/se7300.h> -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 __initmv = { .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 @@ # 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 <stuart.menefy@st.com> - * - * 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 <linux/sched.h> -#include <asm/mach/se73180.h> - -/* 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 <linux/init.h> +#include <linux/platform_device.h> #include <asm/machvec.h> #include <asm/se73180.h> #include <asm/irq.h> -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 __initmv = { .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 @@ # 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 <linux/sched.h> -#include <asm/mach/se7343.h> - -/* 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 <asm/mach/se7343.h> #include <asm/irq.h> -void heartbeat_7343se(void); void init_7343se_IRQ(void); static struct resource smc91x_resources[] = { @@ -31,14 +30,30 @@ static struct platform_device smc91x_device = { .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 __initmv = { .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 @@ # 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 <linux/init.h> +#include <linux/interrupt.h> #include <linux/irq.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/se.h> +/* + * 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 @@ void __init init_se_IRQ(void) 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 <stuart.menefy@st.com> - * - * 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 <linux/sched.h> -#include <asm/se.h> - -/* 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<<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/770x/setup.c b/arch/sh/boards/se/770x/setup.c index a1d51d5..45cbc36 100644 --- a/arch/sh/boards/se/770x/setup.c +++ b/arch/sh/boards/se/770x/setup.c @@ -1,5 +1,4 @@ -/* $Id: setup.c,v 1.1.2.4 2002/03/02 21:57:07 lethal Exp $ - * +/* * linux/arch/sh/boards/se/770x/setup.c * * Copyright (C) 2000 Kazumoto Kojima @@ -8,12 +7,12 @@ * */ #include <linux/init.h> +#include <linux/platform_device.h> #include <asm/machvec.h> #include <asm/se.h> #include <asm/io.h> #include <asm/smc37c93x.h> -void heartbeat_se(void); void init_se_IRQ(void); /* @@ -36,11 +35,6 @@ static void __init smsc_setup(char **cmdline_p) 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 **cmdline_p) 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 @@ struct sh_machine_vector mv_se __initmv = { .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 <stuart.menefy@st.com> - * - * 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 <linux/sched.h> -#include <asm/se7751.h> - -/* 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<<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/7751/setup.c b/arch/sh/boards/se/7751/setup.c index f7e1dd3..e3feae6 100644 --- a/arch/sh/boards/se/7751/setup.c +++ b/arch/sh/boards/se/7751/setup.c @@ -9,11 +9,11 @@ * Ian da Silva and Jeremy Siegel, 2001. */ #include <linux/init.h> +#include <linux/platform_device.h> #include <asm/machvec.h> #include <asm/se7751.h> #include <asm/io.h> -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 __initmv = { .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 @@ # 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 <linux/sched.h> - -/* 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<<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; - -} diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c index 5ad1e19..c069c44 100644 --- a/arch/sh/boards/sh03/setup.c +++ b/arch/sh/boards/sh03/setup.c @@ -8,6 +8,7 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/rtc.h> #include <asm/sh03/io.h> @@ -48,15 +49,36 @@ static void __init sh03_setup(char **cmdline_p) 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 <asm/irq.h> #include <asm/io.h> -#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(unsigned int irq) 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(unsigned int irq) } 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_SYSVIPC=y # 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_DEFAULT_IOSCHED="anticipatory" # 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_RTS7751R2D=y # 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 @@ CONFIG_CPU_SH4=y # 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 @@ CONFIG_CPU_SUBTYPE_SH7751R=y # # 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 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 # 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 @@ CONFIG_SH_TMU=y # 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_VOYAGERGX=y 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_IP_FIB_HASH=y # 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 @@ CONFIG_WIRELESS_EXT=y # 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_BLK_DEV_RAM_BLOCKSIZE=1024 # 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 @@ CONFIG_IDE_GENERIC=y # 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_8139TOO=y # 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_8139TOO=y # 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_NET_WIRELESS=y # 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_NET_WIRELESS=y # # 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_HW_RANDOM=y # 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 @@ CONFIG_HW_RANDOM=y # TPM devices # # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set # # I2C support @@ -698,6 +843,7 @@ CONFIG_HW_RANDOM=y # # 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_VERBOSE_PROCFS=y 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_AC97_BUS=m # 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_AC97_BUS=m # 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 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # 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 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # +# 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_CODEPAGE_932=y # 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_LOG_BUF_SHIFT=14 # # 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_BSD_PROCESS_ACCT=y # 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_SOLUTION_ENGINE=y # 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 @@ CONFIG_CPU_SH4=y # 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 @@ CONFIG_CPU_SUBTYPE_SH7750=y # # 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 @@ CONFIG_CF_BASE_ADDR=0xb8000000 # 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_SH_PCLK_FREQ=50000000 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_PREEMPT_NONE=y 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_IP_PNP_BOOTP=y # 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_MTD_ROM=y # 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_HW_RANDOM=y # # 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 @@ CONFIG_FIRMWARE_EDID=y # # +# 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_RAMFS=y # 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_PARTITION_ADVANCED=y # 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_PARTITION_ADVANCED=y # # 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_LOG_BUF_SHIFT=14 # # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set CONFIG_CRC32=y @@ -915,3 +1014,4 @@ CONFIG_CRC32=y 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 <asm/io.h> #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_channel *chan) 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_channel *chan, unsigned long chcr) 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 <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/io.h> + +#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-sh7780.o ops-sh4.o 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 <lethal@linux-sh.org>. - * - * 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 <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <asm/io.h> -#include "pci-sh4.h" -#include <asm/bigsur/bigsur.h> - -#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_pci_address_map *map) 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 2f6d2bc..ff30d7f 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -6,7 +6,8 @@ extra-y := head.o init_task.o vmlinux.lds 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/ 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 <linux/init.h> #include <linux/kernel.h> +#include <linux/mm.h> +#include <asm/mmu_context.h> #include <asm/processor.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -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 @@ static void __init cache_init(void) 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 @@ static void __init cache_init(void) 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 @@ static void __init cache_init(void) 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 @@ static void __init cache_init(void) #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 @@ static void __init cache_init(void) #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 @@ asmlinkage void __init sh_cpu_init(void) /* 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 @@ asmlinkage void __init sh_cpu_init(void) 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 d51fa5e9..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 @@ trap_entry: #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 @@ 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(void) } __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 @@ 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(void) * 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(void) } __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 <linux/linkage.h> #include <asm/asm-offsets.h> #include <asm/thread_info.h> -#include <asm/unistd.h> #include <asm/cpu/mmu_context.h> -#include <asm/pgtable.h> -#include <asm/page.h> +#include <asm/unistd.h> ! 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 @@ call_dae: #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=<unused>, 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 @@ skip_save: 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 @@ skip_save: 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(void) 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 @@ int __init detect_cpu_and_cache_system(void) /* * 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(void) 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 <linux/init.h> +#include <linux/io.h> #include <asm/processor.h> #include <asm/cache.h> -#include <asm/io.h> int __init detect_cpu_and_cache_system(void) { @@ -36,20 +35,20 @@ int __init detect_cpu_and_cache_system(void) /* * 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(void) */ 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(void) */ 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 @@ int __init detect_cpu_and_cache_system(void) 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(void) } __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 <linux/sys.h> +#include <linux/linkage.h> + +#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 @@ int __init setup_early_printk(char *buf) 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 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 <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/machvec.h> +#include <asm/cacheflush.h> #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, void *dst, unsigned long count) while (count--) *buf++ = *port_addr; + flush_dcache_all(); dummy_read(); } @@ -170,6 +171,7 @@ void generic_outsw(unsigned long port, const void *src, unsigned long count) 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 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) } /* 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_regs *regs) 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 <linux/module.h> -#include <linux/unistd.h> #include <linux/mm.h> #include <linux/elfcore.h> -#include <linux/a.out.h> -#include <linux/slab.h> #include <linux/pm.h> -#include <linux/ptrace.h> #include <linux/kallsyms.h> #include <linux/kexec.h> - -#include <asm/io.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> -#include <asm/elf.h> #include <asm/ubc.h> -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 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) 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 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, 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 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, } /* 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 @@ ubc_set_tracing(int asid, unsigned long pc) 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 @@ ubc_set_tracing(int asid, unsigned long pc) #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 @@ ubc_set_tracing(int asid, unsigned long pc) * 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 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne #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 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne 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 clone_flags, unsigned long newsp, 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 @@ asmlinkage void break_point_trap(void) 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 d6b817a..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 <linux/screen_info.h> #include <linux/ioport.h> #include <linux/init.h> @@ -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_file *m, const char *type, */ 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 *m, void *v) * 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 @@ EXPORT_SYMBOL(__flush_purge_region); 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 sigcontext __user *sc) { 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(struct sigcontext __user *sc, { 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 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p #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/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 pt_regs *regs) { } #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/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 909dcfa..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_file *file, void *iter) 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; } /* 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, int size) 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, int size) 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, int size) 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(void) 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 addr) : /* 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(unsigned long start, * 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(unsigned long start, /* * 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_struct *mm, unsigned long start, 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_struct *vma, unsigned long address, 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_struct *vma, unsigned long address, 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_struct *vma, unsigned long start, * 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 long addr, unsigned long phys, 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(unsigned long start, 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(unsigned long start, 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(unsigned long start, 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 <linux/init.h> #include <linux/mman.h> @@ -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 long phys) 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 long phys) 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 long phys) } } - 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 long phys) */ 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 <linux/kprobes.h> #include <asm/system.h> #include <asm/mmu_context.h> +#include <asm/tlbflush.h> #include <asm/kgdb.h> 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 bf0c263..ae957a9 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -39,11 +39,6 @@ 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 addr, unsigned long phys, pgprot_t prot) set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); - __flush_tlb_page(get_asid(), addr); + flush_tlb_one(get_asid(), addr); } /* 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 phys_addr, unsigned long size, 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..969efece 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c @@ -13,7 +13,7 @@ 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 @@ extern struct mutex p3map_mutex[]; */ 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 long address, struct page *page) 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 long address, struct page *page) 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, unsigned long address, 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, unsigned long address, 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 <linux/init.h> #include <linux/mman.h> #include <linux/mm.h> @@ -45,13 +43,13 @@ static inline void __flush_purge_virtual_region(void *p1, void *virt, int size) 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_region(void *p1, void *virt, int size) 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 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) { clear_page(to); __flush_wback_region(to, PAGE_SIZE); @@ -95,12 +92,11 @@ void clear_user_page(void *to, unsigned long address, struct page *pg) * @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, unsigned long address, struct page *pg __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/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 <linux/mm.h> +#include <linux/io.h> #include <asm/mmu_context.h> #include <asm/tlbflush.h> +#include <asm/cacheflush.h> -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_struct *vma, unsigned long page) 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_struct *vma, unsigned long start, 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_struct *vma, unsigned long start, } } -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 long start, unsigned long end) 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 @@ /* * 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_struct * vma, { 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 <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> - +#include <linux/io.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/pgalloc.h> #include <asm/mmu_context.h> -#include <asm/cacheflush.h> -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, unsigned long page) 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, unsigned long page) 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 <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> - +#include <linux/io.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/pgalloc.h> #include <asm/mmu_context.h> -#include <asm/cacheflush.h> -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, unsigned long page) 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 0104e44..ebee7e2 100644 --- a/arch/sh/oprofile/op_model_sh7750.c +++ b/arch/sh/oprofile/op_model_sh7750.c @@ -259,7 +259,7 @@ static struct oprofile_operations sh7750_perf_counter_ops = { 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/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 @@ static int misaligned_fixup(struct pt_regs *regs) } 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/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 *unused) 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/x86_64/Kconfig b/arch/x86_64/Kconfig index 02dd394..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 @@ -152,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 <http://www.intel.com/technology/64bitextensions/>. - 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. @@ -458,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. @@ -496,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_NEED_MULTIPLE_NODES=y 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_ATIIXP=y # 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_PDC202XX_NEW=y # 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 @@ CONFIG_MEGARAID_SAS=y # 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_SIL=y # 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_SATA_INTEL_COMBINED=y # 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 @@ 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 @@ -707,6 +714,11 @@ CONFIG_IEEE1394_RAWIO=y # 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_8139TOO=y # 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_E1000=y 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 @@ CONFIG_SOUND=y # 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 @@ CONFIG_SOUND_ICH=y # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -1142,10 +1159,8 @@ CONFIG_USB=y # 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_HID=y # 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 @@ CONFIG_USB_MON=y # # +# 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_DETECT_SOFTLOCKUP=y # 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 6efe04f..071100e 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -344,20 +344,30 @@ EXPORT_SYMBOL(ia32_setup_arg_pages); #include <linux/sysctl.h> 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 <linux/stddef.h> #include <linux/personality.h> #include <linux/compat.h> +#include <linux/binfmts.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/i387.h> @@ -449,7 +450,11 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, /* 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_sigaction *ka, 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 k_sigaction *ka, siginfo_t *info, 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 5f32cf4..eda7a0d 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -718,4 +718,5 @@ ia32_sys_call_table: .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/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 traps.o irq.o \ 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 <asm/idle.h> #include <asm/proto.h> #include <asm/timex.h> +#include <asm/hpet.h> #include <asm/apic.h> int apic_mapped; @@ -763,7 +764,7 @@ static void setup_APIC_timer(unsigned int clocks) 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 int clocks) /* 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 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size) 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(void) } /* + * 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/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 @@ startup_64: */ 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 @@ startup_64: 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/i386/kernel/time_hpet.c b/arch/x86_64/kernel/hpet.c index 1e4702d..65a0edd 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/x86_64/kernel/hpet.c @@ -1,224 +1,138 @@ -/* - * 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 <linux/errno.h> #include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> +#include <linux/sched.h> #include <linux/init.h> -#include <linux/smp.h> +#include <linux/mc146818rtc.h> +#include <linux/time.h> +#include <linux/clocksource.h> +#include <linux/ioport.h> +#include <linux/acpi.h> +#include <linux/hpet.h> +#include <asm/pgtable.h> +#include <asm/vsyscall.h> +#include <asm/timex.h> +#include <asm/hpet.h> -#include <asm/timer.h> -#include <asm/fixmap.h> -#include <asm/apic.h> +int nohpet __initdata; -#include <linux/timex.h> +unsigned long hpet_address; +unsigned long hpet_period; /* fsecs / HPET clock */ +unsigned long hpet_tick; /* HPET clocks / interrupt */ -#include <asm/hpet.h> -#include <linux/hpet.h> +int hpet_use_timer; /* Use counter of hpet for time keeping, + * otherwise PIT + */ -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; +#ifdef CONFIG_HPET +static __init int late_hpet_init(void) +{ + struct hpet_data hd; + unsigned int ntimer; -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 */ + if (!hpet_address) + return 0; -#define FSEC_TO_USEC (1000000000UL) + memset(&hd, 0, sizeof(hd)); -int hpet_readl(unsigned long a) -{ - return readl(hpet_virt_address + a); -} + ntimer = hpet_readl(HPET_ID); + ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; + ntimer++; -static void hpet_writel(unsigned long d, unsigned long a) -{ - writel(d, hpet_virt_address + a); -} + /* + * 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; -#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); + hpet_alloc(&hd); + return 0; } +fs_initcall(late_hpet_init); #endif -static int hpet_timer_stop_set_go(unsigned long tick) +int hpet_timer_stop_set_go(unsigned long tick) { unsigned int cfg; - /* - * Stop the timers and reset the main counter. - */ +/* + * Stop the timers and reset the main counter. + */ + cfg = hpet_readl(HPET_CFG); - cfg &= ~HPET_CFG_ENABLE; + 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) { - /* - * 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) + 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; } -/* - * Check whether HPET was found by ACPI boot parse. If yes setup HPET - * counter 0 for kernel base timer. - */ -int __init hpet_enable(void) +int hpet_arch_init(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) + 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. + */ - 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; + if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER)) 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; + if (hpet_period < 100000 || hpet_period > 100000000) 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; - } + hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period; - use_hpet = 1; + hpet_use_timer = (id & HPET_ID_LEGSUP); -#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; + return hpet_timer_stop_set_go(hpet_tick); } int hpet_reenable(void) @@ -226,28 +140,51 @@ int hpet_reenable(void) return hpet_timer_stop_set_go(hpet_tick); } -int is_hpet_enabled(void) -{ - return use_hpet; -} +/* + * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing + * it to the HPET timer of known frequency. + */ -int is_hpet_capable(void) +#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) { - if (!boot_hpet_disable && hpet_address) - return 1; - return 0; + 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 int __init hpet_setup(char* str) +unsigned int __init hpet_calibrate_tsc(void) { - if (str) { - if (!strncmp("disable", str, 7)) - boot_hpet_disable = 1; - } - return 1; -} + int tsc_start, hpet_start; + int tsc_now, hpet_now; + unsigned long flags; + + local_irq_save(flags); + + read_hpet_tsc(&hpet_start, &tsc_start); -__setup("hpet=", hpet_setup); + 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 @@ -264,7 +201,6 @@ __setup("hpet=", hpet_setup); * For (3), we use interrupts at 64Hz or user specified periodic * frequency, whichever is higher. */ -#include <linux/mc146818rtc.h> #include <linux/rtc.h> #define DEFAULT_RTC_INT_FREQ 64 @@ -283,6 +219,11 @@ 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. @@ -367,8 +308,9 @@ static void hpet_rtc_timer_reinit(void) if (PIE_on) PIE_count += lost_ints; - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", - hpet_rtc_int_freq); + if (printk_ratelimit()) + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", + hpet_rtc_int_freq); } } @@ -450,7 +392,7 @@ int hpet_rtc_dropped_irq(void) return 1; } -irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) +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; @@ -495,3 +437,75 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) } #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 int); 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 6be6730..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, int vector, unsigned long trigger) 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 apic, int pin, int idx, int irq) 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 apic, int pin, int idx, int irq) 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 apic, int pin, int idx, int irq) 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(unsigned int apic, unsigned int pin, in */ 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(void) 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; @@ -2131,7 +2127,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p 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 level, struct pt_regs *regs) 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 <asm/uaccess.h> #include <asm/io_apic.h> #include <asm/idle.h> +#include <asm/smp.h> atomic_t irq_err_count; @@ -120,9 +121,14 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) 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 bdb54a2..8011a8e 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -19,6 +19,7 @@ #include <linux/cpu.h> #include <linux/percpu.h> #include <linux/ctype.h> +#include <linux/kmod.h> #include <asm/processor.h> #include <asm/msr.h> #include <asm/mce.h> @@ -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 mce *m, struct pt_regs *regs) } } +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 * regs, long error_code) } /* 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). */ @@ -606,17 +627,42 @@ DEFINE_PER_CPU(struct sys_device, device_mce); } \ 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(unsigned int cpu) 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 int cpu) { 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 93c7072..d0bd5d6 100644 --- a/arch/x86_64/kernel/mce_amd.c +++ b/arch/x86_64/kernel/mce_amd.c @@ -37,6 +37,8 @@ #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(struct cpuinfo_x86 *c) 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(struct cpuinfo_x86 *c) 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(void) /* 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(void) 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_blocks(unsigned int cpu, return 0; if (rdmsr_safe(address, &low, &high)) - goto recurse; + return 0; if (!(high & MASK_VALID_HI)) { if (block) @@ -394,8 +408,8 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, 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); 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_cpu(void) { 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 *data) } #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 @@ int __init check_nmi_watchdog (void) 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(void) /* 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 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) 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_offsets[] = { #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_table *tbl, dma_addr_t dma_addr, { 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_regions(struct pci_dev *dev) 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 mask) } 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 <Documentation/x86_64/boot-options.txt> 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 @@ static void iommu_full(struct device *dev, size_t size, int dir) 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 device *dev, unsigned long addr, size_t size 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/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 <asm/msr.h> #include <asm/vsyscall.h> -/* 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 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } 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 6047724..3d98b69 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -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 @@ -444,6 +322,11 @@ void __init setup_arch(char **cmdline_p) /* 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 @@ void __init setup_arch(char **cmdline_p) 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 *m, void *v) 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 *m, void *v) /* 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 *m, void *v) 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 *m, void *v) "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 <linux/platform_device.h> -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 - 1, (unsigned long) idt_table }; 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(int id) 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 max_cpus) 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 *data, unsigned long addr) 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_ops = { 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 335cc91..a87c517 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -42,10 +42,8 @@ #include <linux/cpufreq.h> #include <linux/hpet.h> #include <asm/apic.h> +#include <asm/hpet.h> -#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 nowtime) } -/* 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,40 +201,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) 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; @@ -545,159 +252,6 @@ static unsigned long get_cmos_time(void) 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 <linux/workqueue.h> - -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_tsc(void) 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_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; -} - -/* - * 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_device *dev) 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_device *dev) 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 <linux/rtc.h> - -#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 <linux/kernel.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/clocksource.h> +#include <linux/time.h> +#include <linux/acpi.h> +#include <linux/cpufreq.h> + +#include <asm/timex.h> + +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 <linux/workqueue.h> + +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 <linux/spinlock.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/nmi.h> +#include <asm/tsc.h> + +/* + * 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 c360c42..b73212c 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -88,31 +88,25 @@ SECTIONS __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; 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 <linux/seqlock.h> #include <linux/jiffies.h> #include <linux/sysctl.h> +#include <linux/clocksource.h> #include <linux/getcpu.h> #include <linux/cpu.h> #include <linux/smp.h> @@ -34,6 +35,7 @@ #include <asm/vsyscall.h> #include <asm/pgtable.h> #include <asm/page.h> +#include <asm/unistd.h> #include <asm/fixmap.h> #include <asm/errno.h> #include <asm/io.h> @@ -44,56 +46,41 @@ #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 <asm/unistd.h> - -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(struct timeval *tv, struct timezone *tz) 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(long *t) 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 timeval * tv, struct timezone * tz) * 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_table *ctl, int write, struct file * filp, 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_table *t, int __user *name, int nlen, 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..8d5f835a 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 <linux/linkage.h> +#include <asm/dwarf2.h> + +#define FIX_ALIGNMENT 1 + +#include <asm/current.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/cpufeature.h> + +/* + * 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 49e8cf2..6ada723 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -56,17 +56,17 @@ int unregister_page_fault_notifier(struct notifier_block *nb) } 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); + return atomic_notifier_call_chain(¬ify_page_fault_chain, + DIE_PAGE_FAULT, &args); } /* Sometimes the CPU reports invalid exceptions on prefetch. @@ -355,8 +355,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, 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 @@ -365,8 +364,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, 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 @@ int kern_addr_valid(unsigned long addr) 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_APIC] __cpuinitdata = { 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 bootnode *nodes, int numnodes, int shift) 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<<PAGE_SHIFT, + nodemap_size); + if (nodemap_addr == -1UL) { + printk(KERN_ERR + "NUMA: Unable to allocate Memory to Node hash map\n"); + nodemap_addr = nodemap_size = 0; + return -1; + } + pad_addr = (nodemap_addr + pad) & ~pad; + memnodemap = phys_to_virt(pad_addr); + + printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n", + nodemap_addr, nodemap_addr + nodemap_size); + return 0; +} - while (populate_memnodemap(nodes, numnodes, shift + 1) >= 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)<<PAGE_SHIFT) / numa_fake; + unsigned long sz, old_sz; + unsigned long hole_size; + unsigned long start, end; + unsigned long max_addr = (end_pfn << PAGE_SHIFT); + + start = (start_pfn << PAGE_SHIFT); + hole_size = e820_hole_size(start, max_addr); + sz = (max_addr - start - hole_size) / numa_fake; /* Kludge needed for the hash function */ - if (hweight64(sz) > 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<<PAGE_SHIFT) + i*sz; + /* + * In case we are not able to allocate enough memory for all + * the nodes, we reduce the number of fake nodes. + */ + if (end >= 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<<PAGE_SHIFT) - nodes[i].start; - nodes[i].end = nodes[i].start + sz; + sz = max_addr - start; + end = nodes[i].start + sz; + /* + * Fir "big" number of nodes get extra granule. + */ + if (i < big) + end += FAKE_NODE_MIN_SIZE; + /* + * Iterate over the range to ensure that this node gets at + * least sz amount of RAM (excluding holes) + */ + while ((end - start - e820_hole_size(start, end)) < sz) { + end += FAKE_NODE_MIN_SIZE; + if (end >= 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 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) 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_bootmem(void) 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 address, pgprot_t ref_prot) 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 address, pgprot_t ref_prot) 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/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 98202cb..65d8273 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -13,16 +13,6 @@ #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_mcfg_allocation *cfg; @@ -32,30 +22,17 @@ static struct mmcfg_virt *pci_mmcfg_virt; static char __iomem *get_virt(unsigned int seg, unsigned bus) { - int cfg_num = -1; 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 != 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 == 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 int seg, unsigned bus) 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,81 +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; - - if (acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg)) - return; - - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].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].address, - pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, - E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n", - (unsigned long)pci_mmcfg_config[0].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].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); - return; + return 0; } - printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n", - (unsigned long)pci_mmcfg_config[i].address); } - - unreachable_devices(); - raw_pci_ops = &pci_mmcfg; - pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; + return 1; } 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 <linux/module.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/kernel.h> diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c index 157d8b7..d276fd1 100644 --- a/drivers/acorn/char/i2c.c +++ b/drivers/acorn/char/i2c.c @@ -14,7 +14,6 @@ */ #include <linux/capability.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/time.h> #include <linux/miscdevice.h> #include <linux/rtc.h> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 20eacc2..2d21fed 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -13,6 +13,7 @@ config ACPI depends on IA64 || X86 depends on PCI depends on PM + select PNP default y ---help--- Advanced Configuration and Power Interface (ACPI) support for diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 40a2f4c..84de088 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -141,6 +141,7 @@ struct asus_hotk { W5A, //W5A W3V, //W3030V xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N + A4S, //Z81sp //(Centrino) END_MODEL } model; //Models currently supported @@ -397,7 +398,16 @@ static struct model_data model_conf[END_MODEL] = { .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", - .display_get = "\\ADVG"} + .display_get = "\\ADVG"}, + + { + .name = "A4S", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .mt_bt_switch = "BLED", + .mt_wled = "WLED" + } + }; /* procdir we use */ @@ -1117,6 +1127,8 @@ static int asus_model_match(char *model) return W3V; else if (strncmp(model, "W5A", 3) == 0) return W5A; + else if (strncmp(model, "A4S", 3) == 0) + return A4S; else return END_MODEL; } diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 36dcb89..fb3f31b 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -45,18 +45,6 @@ MODULE_LICENSE("GPL"); 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 = "bay", - .class = ACPI_BAY_CLASS, - .ids = ACPI_BAY_HID, - .ops = { - .add = acpi_bay_add, - .remove = acpi_bay_remove, - }, -}; struct bay { acpi_handle handle; @@ -232,14 +220,6 @@ int eject_removable_drive(struct device *dev) } 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; @@ -301,7 +281,7 @@ static int bay_add(acpi_handle handle, int id) /* initialize platform device stuff */ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); - if (pdev == NULL) { + if (IS_ERR(pdev)) { printk(KERN_ERR PREFIX "Error registering bay device\n"); goto bay_add_err; } @@ -337,52 +317,6 @@ bay_add_err: 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 @@ -392,38 +326,19 @@ static struct acpi_device * bay_create_acpi_device(acpi_handle handle) */ static void bay_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *dev; + struct bay *bay_dev = (struct bay *)data; + struct device *dev = &bay_dev->pdev->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? - */ + kobject_uevent(&dev->kobj, KOBJ_CHANGE); break; default: - printk("unknown event %d\n", event); + printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); } } @@ -455,10 +370,6 @@ static int __init bay_init(void) 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; @@ -479,8 +390,6 @@ static void __exit bay_exit(void) kfree(bay->name); kfree(bay); } - - acpi_bus_unregister_driver(&acpi_bay_driver); } postcore_initcall(bay_init); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c1f6251..ab68883 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -279,8 +279,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + mutex_unlock(&ec->lock); return -ENODEV; + } } /* Make sure GPE is enabled before doing transaction */ diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index dfac3ec..635ba44 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -636,17 +636,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) } } - 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 diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7b6c9ff..4334c20 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -241,3 +241,65 @@ static int __init init_acpi_device_notify(void) } arch_initcall(init_acpi_device_notify); + + +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) + +/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find + * its device node and pass extra config data. This helps its driver use + * capabilities that the now-obsolete mc146818 didn't have, and informs it + * that this board's RTC is wakeup-capable (per ACPI spec). + */ +#include <linux/mc146818rtc.h> + +static struct cmos_rtc_board_info rtc_info; + + +/* PNP devices are registered in a subsys_initcall(); + * ACPI specifies the PNP IDs to use. + */ +#include <linux/pnp.h> + +static int __init pnp_match(struct device *dev, void *data) +{ + static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", }; + struct pnp_dev *pnp = to_pnp_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(ids); i++) { + if (compare_pnp_id(pnp->id, ids[i]) != 0) + return 1; + } + return 0; +} + +static struct device *__init get_rtc_dev(void) +{ + return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match); +} + +static int __init acpi_rtc_init(void) +{ + struct device *dev = get_rtc_dev(); + + if (dev) { + rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm; + rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm; + rtc_info.rtc_century = acpi_gbl_FADT.century; + + /* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */ + + dev->platform_data = &rtc_info; + + /* RTC always wakes from S1/S2/S3, and often S4/STD */ + device_init_wakeup(dev, 1); + + put_device(dev); + } else + pr_debug("ACPI: RTC unavailable?\n"); + return 0; +} +/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ +fs_initcall(acpi_rtc_init); + +#endif diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index a29b827..acab4a4 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -14,7 +14,6 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/acpi.h> @@ -339,6 +338,7 @@ static int acpi_ec_hc_add(struct acpi_device *device) 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/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index c6144ca..2429e11 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -496,6 +496,10 @@ static int ibm_acpi_driver_init(void) printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); + if (ibm_thinkpad_ec_found) + printk(IBM_INFO "ThinkPad EC firmware %s\n", + ibm_thinkpad_ec_found); + return 0; } @@ -2617,7 +2621,7 @@ static void __init ibm_handle_init(char *name, ibm_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) -static int set_ibm_param(const char *val, struct kernel_param *kp) +static int __init set_ibm_param(const char *val, struct kernel_param *kp) { unsigned int i; @@ -2659,7 +2663,8 @@ static void acpi_ibm_exit(void) for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) ibm_exit(&ibms[i]); - remove_proc_entry(IBM_DIR, acpi_root_dir); + if (proc_dir) + remove_proc_entry(IBM_DIR, acpi_root_dir); if (ibm_thinkpad_ec_found) kfree(ibm_thinkpad_ec_found); @@ -2710,9 +2715,6 @@ static int __init acpi_ibm_init(void) /* Models with newer firmware report the EC in DMI */ ibm_thinkpad_ec_found = check_dmi_for_ec(); - if (ibm_thinkpad_ec_found) - printk(IBM_INFO "ThinkPad EC firmware %s\n", - ibm_thinkpad_ec_found); /* these handles are not required */ IBM_HANDLE_INIT(vid); @@ -2742,6 +2744,7 @@ static int __init acpi_ibm_init(void) proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); if (!proc_dir) { printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); + acpi_ibm_exit(); return -ENODEV; } proc_dir->owner = THIS_MODULE; diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 326af8f..33db224 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -45,6 +45,7 @@ #include <acpi/acnamesp.h> #include <acpi/acdispat.h> #include <acpi/acinterp.h> +#include <linux/nmi.h> #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsinit") @@ -534,7 +535,15 @@ acpi_ns_init_one_device(acpi_handle obj_handle, 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/osl.c b/drivers/acpi/osl.c index 851ac49..ee0b9f7 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -205,7 +205,7 @@ 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 0; + return NULL; } if (acpi_gbl_permanent_mmap) /* @@ -890,26 +890,6 @@ u32 acpi_os_get_line(char *buffer) } #endif /* ACPI_FUTURE_USAGE */ -/* Assumes no unreadable holes inbetween */ -u8 acpi_os_readable(void *ptr, acpi_size len) -{ -#if defined(__i386__) || defined(__x86_64__) - char tmp; - return !__get_user(tmp, (char __user *)ptr) - && !__get_user(tmp, (char __user *)ptr + len - 1); -#endif - return 1; -} - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *ptr, acpi_size len) -{ - /* could do dummy write (racy) or a kernel page table lookup. - The later may be difficult at early boot when kmap doesn't work yet. */ - return 1; -} -#endif - acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 911fc8c..99d1516 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -403,7 +403,7 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { /* First check against id */ if (lsapic->processor_id == acpi_id) { - *apic_id = lsapic->id; + *apic_id = (lsapic->id << 8) | lsapic->eid; return 1; /* Check against optional uid */ } else if (entry->length >= 16 && @@ -1004,7 +1004,7 @@ static int __init acpi_processor_init(void) #ifdef CONFIG_SMP if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, (struct acpi_table_header **)&madt))) - madt = 0; + madt = NULL; #endif acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 92f5185..6077300 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -39,6 +39,25 @@ #include <linux/moduleparam.h> #include <linux/sched.h> /* need_resched() */ #include <linux/latency.h> +#include <linux/clockchips.h> + +/* + * 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 <asm/apic.h> +#endif + +/* + * 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). + */ +#ifdef CONFIG_X86 +#include <asm/apic.h> +#endif #include <asm/io.h> #include <asm/uaccess.h> @@ -237,6 +256,81 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate) } } +#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; @@ -381,6 +475,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ 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_gbl_FADT.xpm_timer_block.address); @@ -395,6 +490,7 @@ static void acpi_processor_idle(void) /* 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: @@ -416,6 +512,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ 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_gbl_FADT.xpm_timer_block.address); @@ -435,6 +532,7 @@ static void acpi_processor_idle(void) /* 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: @@ -903,11 +1001,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) 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]; @@ -919,21 +1013,14 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) 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; } @@ -941,10 +1028,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) 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); } 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 <linux/pm.h> #include <linux/init.h> #include <acpi/acpi_bus.h> -#include <linux/sched.h> #include <linux/sysdev.h> #include <asm/io.h> #include "sleep.h" diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 4ed6400..849e2c3 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -25,7 +25,6 @@ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/smp.h> #include <linux/string.h> #include <linux/types.h> diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 807978d..417ef5f 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -338,9 +338,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) int i; acpi_status status = AE_NOT_EXIST; - ACPI_FUNCTION_TRACE(acpi_unload_table); + ACPI_FUNCTION_TRACE(acpi_unload_table_id); - /* Find table from the requested type list */ + /* Find table in the global table list */ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { if (id != acpi_gbl_root_table_list.tables[i].owner_id) { continue; @@ -352,8 +352,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) * simply a position within the hierarchy */ acpi_tb_delete_namespace_by_owner(i); - acpi_tb_release_owner_id(i); + status = acpi_tb_release_owner_id(i); acpi_tb_set_table_loaded_flag(i, FALSE); + break; } return_ACPI_STATUS(status); } @@ -408,7 +409,7 @@ acpi_get_table(char *signature, } if (!acpi_gbl_permanent_mmap) { - acpi_gbl_root_table_list.tables[i].pointer = 0; + acpi_gbl_root_table_list.tables[i].pointer = NULL; } return (status); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f50a405..15022bc 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -36,7 +36,8 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/proc_fs.h> -#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/jiffies.h> #include <linux/kmod.h> #include <linux/seq_file.h> #include <asm/uaccess.h> @@ -268,7 +269,7 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", - tz->polling_frequency)); + tz->polling_frequency/10)); return 0; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index d9b651f..0208d3a 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -125,7 +125,7 @@ static int write_acpi_int(const char *methodName, int val) union acpi_object in_objs[1]; acpi_status status; - params.count = sizeof(in_objs) / sizeof(in_objs[0]); + params.count = ARRAY_SIZE(in_objs); params.pointer = in_objs; in_objs[0].type = ACPI_TYPE_INTEGER; in_objs[0].integer.value = val; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 92cdb0c..6a3543e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -39,7 +39,6 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/dma-mapping.h> #include <linux/device.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 25d8d3f..2cf8251 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1410,7 +1410,16 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, } 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); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 4223e10..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 all ISA port ranges */ 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_port *ap, struct ata_device **unused) 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; @@ -695,6 +697,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl void __iomem *io_addr, *ctrl_addr; int pio_modes = pio_mask; u32 mask = (1 << port); + u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; int ret; pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0); @@ -715,6 +718,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl if (ht6560a & mask) { ops = &ht6560a_port_ops; pio_modes = 0x07; + iordy = ATA_FLAG_NO_IORDY; } if (ht6560b & mask) { ops = &ht6560b_port_ops; @@ -750,6 +754,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl 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 { @@ -767,6 +772,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl /* 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; @@ -776,7 +782,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ae.pio_mask = pio_modes; ae.irq = irq; ae.irq_flags = 0; - ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; + 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; @@ -945,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_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index d7378df..29e1809 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -484,10 +484,8 @@ mpc52xx_ata_resume(struct of_device *op) static struct of_device_id mpc52xx_ata_of_match[] = { { - .compatible = "mpc5200-ata", - }, - { - .compatible = "mpc52xx-ata", + .type = "ata", + .compatible = "mpc5200-ata", }, {}, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index ca8c965..f2e7115 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -241,7 +241,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) probe.port_ops = &mpiix_port_ops; probe.sht = &mpiix_sht; probe.pio_mask = 0x1F; - probe.irq_flags = SA_SHIRQ; + probe.irq_flags = IRQF_SHARED; probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; probe.n_ports = 1; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index acfc09f..36468ec 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -264,7 +264,7 @@ 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_addr; ae.port[0].altstatus_addr = ctl_addr; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index ffa7f47f..6153787 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -796,7 +796,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops; probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; + probe_ent->irq_flags = IRQF_SHARED; probe_ent->iomap = pcim_iomap_table(pdev); mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 1b3b4ed..4362141 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -264,16 +264,18 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i 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_addr; ae.port[0].altstatus_addr = ctl_addr; ae.port[0].ctl_addr = ctl_addr; diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index f2fa158..96e890f 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -187,7 +187,9 @@ static void sl82c105_bmdma_start(struct ata_queued_cmd *qc) { 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 ata_queued_cmd *qc) ata_bmdma_stop(qc); sl82c105_reset_engine(ap); + udelay(100); /* This will redo the initial setup of the DMA device to matching PIO timings */ diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index b4ed8ce..857ac23 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -39,7 +39,6 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/device.h> #include <scsi/scsi_host.h> #include <linux/libata.h> diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index c5335f4..31b636f 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -710,7 +710,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->n_ports = NR_PORTS; probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; + probe_ent->irq_flags = IRQF_SHARED; probe_ent->iomap = iomap; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 769eca5..d689df5 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -28,7 +28,6 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/dma-mapping.h> #include <linux/device.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 095ef1b..ab92f20 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -827,7 +827,8 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) /* freeze if hotplugged or controller error */ if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG | - NV_ADMA_STAT_TIMEOUT))) { + NV_ADMA_STAT_TIMEOUT | + NV_ADMA_STAT_SERROR))) { struct ata_eh_info *ehi = &ap->eh_info; ata_ehi_clear_desc(ehi); @@ -841,6 +842,9 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) } 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); continue; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 3be4cc3..cf9ed8c 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -37,7 +37,6 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/device.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -120,9 +119,7 @@ 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_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); @@ -216,12 +213,12 @@ static const struct ata_port_operations pdc_pata_ops = { .dev_select = ata_std_dev_select, .check_atapi_dma = pdc_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, .data_xfer = ata_data_xfer, - .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, @@ -254,7 +251,7 @@ static const struct ata_port_info pdc_port_info[] = { /* 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 */ @@ -390,14 +387,6 @@ static void pdc_pata_cbl_detect(struct ata_port *ap) 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 || ap->cbl != ATA_CBL_SATA) @@ -565,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; @@ -577,7 +573,7 @@ static void pdc_error_handler(struct ata_port *ap) 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); } @@ -593,43 +589,6 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) 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) { diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index bfa35ed..6097d8f 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -34,7 +34,6 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/device.h> #include <scsi/scsi_host.h> #include <linux/libata.h> diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 06e87a3..0ebd77b 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -37,7 +37,6 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 3d9daf2..2fd037b 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -346,6 +346,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d 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"); @@ -383,9 +384,12 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d INIT_LIST_HEAD(&probe_ent->node); /* - * 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); diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c index ac2c108..8d60c4eb 100644 --- a/drivers/atm/adummy.c +++ b/drivers/atm/adummy.c @@ -13,7 +13,6 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <asm/io.h> 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 <linux/slab.h> #include <linux/init.h> #include <linux/capability.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/bitops.h> #include <linux/pci.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/errno.h> 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 <linux/module.h> -#include <linux/sched.h> /* for jiffies */ #include <linux/mm.h> #include <linux/errno.h> #include <linux/atmdev.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/pci.h> 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 <linux/module.h> #include <linux/errno.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/fs.h> #include <linux/kernel.h> 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 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; #include <linux/blkpg.h> #include <linux/kernel.h> #include <asm/uaccess.h> -#include <linux/sched.h> #include <linux/workqueue.h> static DEFINE_SPINLOCK(pd_lock); 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 <linux/sched.h> #include <linux/fs.h> #include <linux/bio.h> #include <linux/kernel.h> 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 <linux/init.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/skbuff.h> 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 <linux/init.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/ptrace.h> 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 <linux/init.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/ptrace.h> 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 <linux/init.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/ptrace.h> 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 <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/unistd.h> #include <linux/types.h> #include <linux/interrupt.h> 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 <linux/module.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/timer.h> #include <linux/fs.h> 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 @@ History: #include <linux/errno.h> /* These include what we really need */ #include <linux/delay.h> #include <linux/string.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/cdrom.h> 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 <linux/slab.h> #include <linux/errno.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/fs.h> #include <linux/mm.h> diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index bf5aef4e5..5409fca 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -60,7 +60,6 @@ #include <linux/module.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/timer.h> #include <linux/fs.h> 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 @@ struct agp_bridge_data { #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 @@ extern struct aper_size_info_16 agp3_generic_sizes[]; 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_generic_bridge = { .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_m1541_bridge = { .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(struct agp_memory *mem, off_t pg_start, 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_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, }; 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_irongate_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, }; 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 agp_memory *mem, off_t pg_start, int type) { 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 agp_memory *mem, off_t pg_start, int type) 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_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, }; /* 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_generic_bridge = { .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 @@ * 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 <linux/kernel.h> +#include <linux/pci.h> +#include <linux/agpgart.h> +#include <asm/uaccess.h> +#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 <linux/compat.h> +#include <linux/agpgart.h> + +#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_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, }; 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 <asm/pgtable.h> #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(int prot) 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 agp_memory * temp) /* 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(struct agp_file_private * priv) * 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_controller_for_client(pid_t id) 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_client *client) 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_client(pid_t id) 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_file_private *priv, void __user *arg) 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 agp_file_private *priv) 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 agp_file_private *priv, void __user *arg) 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 agp_file_private *priv, void __user *arg) 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 agp_file_private *priv, void __user *arg) 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_fops = .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 scratch_pages) 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 scratch_pages) 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 *curr) 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 *curr) 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(struct agp_bridge_data *bridge, 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_memory * mem, off_t pg_start, int type) 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_memory * mem, off_t pg_start, int type) 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_memory * mem, off_t pg_start, int type) } 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_memory *mem, off_t pg_start, int type) { 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_memory *mem, off_t pg_start, int type) 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_memory *mem, off_t pg_start, int type) } 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(struct agp_bridge_data *bridge, } 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_page (struct agp_memory *mem, 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_page (struct agp_memory *mem, 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 @@ struct agp_bridge_driver intel_i460_driver = { #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 <linux/module.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/kernel.h> #include <linux/pagemap.h> #include <linux/agp_backend.h> #include "agp.h" @@ -24,6 +25,9 @@ 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_i810_sizes[] = #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 *addr) 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_alloc_by_type(size_t pg_count, int type) 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(struct agp_memory *curr) 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(struct agp_memory *mem,off_t pg_start, int { 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(struct agp_memory *mem,off_t pg_start, int 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_alloc_by_type(size_t pg_count,int type) { 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(struct agp_memory *mem,off_t pg_start, { 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(struct agp_memory *mem,off_t pg_start, 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(struct agp_memory *mem,off_t pg_start, */ 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_generic_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, }; static struct agp_bridge_driver intel_810_driver = { @@ -1408,6 +1452,7 @@ static struct agp_bridge_driver intel_810_driver = { .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_815_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, }; static struct agp_bridge_driver intel_830_driver = { @@ -1455,6 +1501,7 @@ static struct agp_bridge_driver intel_830_driver = { .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_820_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, }; static struct agp_bridge_driver intel_830mp_driver = { @@ -1501,6 +1549,7 @@ static struct agp_bridge_driver intel_830mp_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, }; static struct agp_bridge_driver intel_840_driver = { @@ -1524,6 +1573,7 @@ static struct agp_bridge_driver intel_840_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, }; static struct agp_bridge_driver intel_845_driver = { @@ -1547,6 +1597,7 @@ static struct agp_bridge_driver intel_845_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, }; static struct agp_bridge_driver intel_850_driver = { @@ -1570,6 +1621,7 @@ static struct agp_bridge_driver intel_850_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, }; static struct agp_bridge_driver intel_860_driver = { @@ -1593,6 +1645,7 @@ static struct agp_bridge_driver intel_860_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, }; static struct agp_bridge_driver intel_915_driver = { @@ -1617,6 +1670,7 @@ static struct agp_bridge_driver intel_915_driver = { .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_i965_driver = { .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_7505_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, }; 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_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, }; 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_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/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_driver = { .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_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, }; 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_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, }; 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_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, }; @@ -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 2ded7a28..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_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, }; static struct agp_bridge_driver via_driver = { @@ -214,6 +215,7 @@ static struct agp_bridge_driver via_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, }; static struct agp_device_ids via_agp_device_ids[] __devinitdata = diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index 7f60a18..8dcf9d2 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c @@ -8,7 +8,6 @@ #include <linux/types.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/tty.h> #include <linux/timer.h> #include <linux/kernel.h> 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 <linux/sched.h> #include <asm/upa.h> #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 "ffb_drv.h" -#include <linux/sched.h> #include <linux/smp_lock.h> #include <asm/shmparam.h> #include <asm/oplib.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/miscdevice.h> #include <linux/smp_lock.h> #include <linux/delay.h> 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 <linux/module.h> #include <linux/slab.h> /* for kmalloc() and kfree() */ -#include <linux/sched.h> /* for struct wait_queue etc */ #include <linux/major.h> #include <linux/types.h> #include <linux/errno.h> 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_reboot); __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, unsigned int cmd, unsigned long arg) 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/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 <linux/module.h> #include <linux/major.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/sysrq.h> #include <linux/tty.h> 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 <linux/moduleparam.h> #include <linux/errno.h> #include <asm/system.h> -#include <linux/sched.h> #include <linux/poll.h> #include <linux/spinlock.h> #include <linux/slab.h> diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 3aff5e9..8e222f2 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -34,7 +34,6 @@ #include <linux/module.h> #include <linux/errno.h> #include <asm/system.h> -#include <linux/sched.h> #include <linux/poll.h> #include <linux/spinlock.h> #include <linux/mutex.h> diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 9d23136e..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/keyboard.c b/drivers/char/keyboard.c index c654a3e..cb8d691 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -596,7 +596,6 @@ static void fn_spawn_con(struct vc_data *vc) static void fn_SAK(struct vc_data *vc) { struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; - PREPARE_WORK(SAK_work, vc_SAK); schedule_work(SAK_work); } 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 <linux/module.h> -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/nvram.h> 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 <linux/mm.h> #include <linux/delay.h> #include <linux/proc_fs.h> -#include <linux/sched.h> #include <linux/miscdevice.h> #include <linux/spinlock.h> #include <linux/rwsem.h> 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 <linux/module.h> /* For EXPORT_SYMBOL */ #include <linux/errno.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index b6d3072d..c7dac9b 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -282,7 +282,7 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id) */ 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_header; static int __init init_sysctl(void) { - sysctl_header = register_sysctl_table(dev_root, 0); + sysctl_header = register_sysctl_table(dev_root); return 0; } 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 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/input.h> #include <linux/pci.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/miscdevice.h> diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 3757610..1d8c4ae6 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -36,6 +36,7 @@ #include <linux/workqueue.h> #include <linux/kexec.h> #include <linux/irq.h> +#include <linux/hrtimer.h> #include <asm/ptrace.h> #include <asm/irq_regs.h> @@ -89,7 +90,6 @@ static struct sysrq_key_op sysrq_loglevel_op = { static void sysrq_handle_SAK(int key, struct tty_struct *tty) { struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; - PREPARE_WORK(SAK_work, vc_SAK); schedule_work(SAK_work); } static struct sysrq_key_op sysrq_SAK_op = { @@ -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_table[36] = { /* 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 <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index c346ec5..5422f99 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -58,7 +58,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/miscdevice.h> diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 2f572b9..e5a254a 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -23,7 +23,6 @@ * */ -#include <linux/sched.h> #include <linux/poll.h> #include <linux/spinlock.h> #include "tpm.h" diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 65672c5..5289254 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3442,7 +3442,6 @@ void do_SAK(struct tty_struct *tty) { if (!tty) return; - PREPARE_WORK(&tty->SAK_work, do_SAK_work); schedule_work(&tty->SAK_work); } @@ -3568,7 +3567,7 @@ static void initialize_tty_struct(struct tty_struct *tty) 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); } /* 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 <linux/major.h> #include <linux/errno.h> #include <linux/tty.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/init.h> 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 <linux/kdev_t.h> #include <asm/io.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/errno.h> diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 94ce3e7..c3f8e38 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2635,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/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 <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/miscdevice.h> -#include <linux/watchdog.h> -#include <linux/fs.h> -#include <linux/ioport.h> -#include <linux/notifier.h> -#include <linux/reboot.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/system.h> +/* + * Includes, defines, variables, module parameters, ... + */ +/* Includes */ +#include <linux/module.h> /* For module specific items */ +#include <linux/moduleparam.h> /* For new moduleparam's */ +#include <linux/types.h> /* For standard types (like size_t) */ +#include <linux/errno.h> /* For the -ENODEV/... values */ +#include <linux/kernel.h> /* For printk/panic/... */ +#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ +#include <linux/watchdog.h> /* For the watchdog specific items */ +#include <linux/fs.h> /* For file operations */ +#include <linux/ioport.h> /* For io-port access */ +#include <linux/platform_device.h> /* For platform_driver framework */ +#include <linux/init.h> /* For __init/__exit/... */ + +#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ +#include <asm/io.h> /* 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, struct file *file, unsigned int cmd, { .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, struct file *file) } /* - * 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_fops = { .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 <linux/watchdog.h> #include <linux/fs.h> #include <linux/ioport.h> -#include <linux/notifier.h> -#include <linux/reboot.h> +#include <linux/platform_device.h> #include <linux/init.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> +#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 timeout in seconds. 1<= timeout <=63, defaul 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 file *file, unsigned int cmd, 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 file *file, unsigned int cmd, 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 file *file) } /* - * 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 advwdt_fops = { }; 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 timeout in seconds. (0<timeout<18000, defaul 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 e5b2c2e..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 data) 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", 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 long unused) 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 @@ static char *ev = "int"; 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 heartbeat in seconds. (1<heartbeat<2046, 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) ")"); /* * 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 heartbeat in seconds. (2<heartbeat<39, 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) ")"); /* * Some TCO specific functions diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index fd8a44a..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 <wim@iguana.be>. + * (c) Copyright 2006-2007 Wim Van Sebroeck <wim@iguana.be>. * * 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 heartbeat in seconds. (2<heartbeat<39 (TCO 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 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 <chowes@vsol.net> * - * 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 <marekm@linux.org.pl> * @@ -25,9 +25,9 @@ * * (c) Copyright 1995 Alan Cox <alan@redhat.com> * - * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Added timeout module option to override default + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default * */ @@ -36,22 +36,24 @@ #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/ioport.h> -#include <linux/notifier.h> #include <linux/fs.h> -#include <linux/reboot.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/moduleparam.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> +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 file *file, unsigned int cmd, 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 file *file, unsigned int cmd, 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 file *file, unsigned int cmd, 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 file *file) /* 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 @@ static int __init ibwdt_init(void) 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 @@ static int indydog_alive; 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 4d730fd..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"); } @@ -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 @@ static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 }; #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 long d) { 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 *inode, struct file *file) 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/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c index a77a907..3d3deae 100644 --- a/drivers/char/watchdog/pc87413_wdt.c +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -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 <asm/io.h> /* 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_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 base_addr) /* 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 base_addr) /* 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 <wim@iguana.be>. + * (c) Copyright 2003-2007 Wim Van Sebroeck <wim@iguana.be>. * * Based on source code of the following authors: * Ken Hollis <kenji@bitgate.com>, @@ -51,8 +51,8 @@ #include <asm/io.h> /* 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_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<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 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 @@ -286,7 +298,9 @@ static int pcipcwd_stop(void) static int pcipcwd_keepalive(void) { /* Re-trigger watchdog by writing to port 0 */ + spin_lock(&pcipcwd_private.io_lock); outb_p(0x42, pcipcwd_private.io_addr); /* send out any data */ + spin_unlock(&pcipcwd_private.io_lock); if (debug >= DEBUG) printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n"); @@ -373,7 +387,9 @@ static int pcipcwd_get_temperature(int *temperature) 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(struct pci_dev *pdev, /* 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(void) 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 <wim@iguana.be>. + * (c) Copyright 2004-2007 Wim Van Sebroeck <wim@iguana.be>. * * Based on source code of the following authors: * Ken Hollis <kenji@bitgate.com>, @@ -24,26 +24,25 @@ * http://www.berkprod.com/ or http://www.pcwatchdog.com/ */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/miscdevice.h> -#include <linux/watchdog.h> -#include <linux/notifier.h> -#include <linux/reboot.h> -#include <linux/fs.h> -#include <linux/smp_lock.h> -#include <linux/completion.h> -#include <asm/uaccess.h> -#include <linux/usb.h> -#include <linux/mutex.h> +#include <linux/module.h> /* For module specific items */ +#include <linux/moduleparam.h> /* For new moduleparam's */ +#include <linux/types.h> /* For standard types (like size_t) */ +#include <linux/errno.h> /* For the -ENODEV/... values */ +#include <linux/kernel.h> /* For printk/panic/... */ +#include <linux/delay.h> /* For mdelay function */ +#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ +#include <linux/watchdog.h> /* For the watchdog specific items */ +#include <linux/notifier.h> /* For notifier support */ +#include <linux/reboot.h> /* For reboot_notifier stuff */ +#include <linux/init.h> /* For __init/__exit/... */ +#include <linux/fs.h> /* For file operations */ +#include <linux/usb.h> /* For USB functions */ +#include <linux/slab.h> /* For kmalloc, ... */ +#include <linux/mutex.h> /* For mutex locking */ #include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */ +#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ + #ifdef CONFIG_USB_DEBUG static int debug = 1; @@ -57,8 +56,8 @@ /* 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 <wim@iguana.be>" #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. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 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) ")"); /* The vendor and product id's for the USB-PC Watchdog card */ #define USB_PCWD_VENDOR_ID 0x0c98 @@ -110,6 +109,18 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table); #define CMD_ENABLE_WATCHDOG 0x30 /* Enable / Disable Watchdog */ #define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG +/* 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; @@ -682,6 +693,10 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi ((option_switches & 0x10) ? "ON" : "OFF"), ((option_switches & 0x08) ? "ON" : "OFF")); + /* If heartbeat = 0 then we use the heartbeat from the dip-switches */ + if (heartbeat == 0) + heartbeat = heartbeat_tbl[(option_switches & 0x07)]; + /* Check that the heartbeat value is within it's range ; if not reset to the default */ if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) { usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT); diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c index ff6f1ca..5991add 100644 --- a/drivers/char/watchdog/pnx4008_wdt.c +++ b/drivers/char/watchdog/pnx4008_wdt.c @@ -283,7 +283,8 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) wdt_base = (void __iomem *)IO_ADDRESS(res->start); 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 b467883..5c921e4 100644 --- a/drivers/char/watchdog/rm9k_wdt.c +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -192,7 +192,7 @@ static int wdt_gpi_open(struct inode *inode, struct file *file) 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 tmr_margin in seconds. default=" __MODULE 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 platform_device *pdev) 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 platform_device *pdev) 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 platform_device *pdev) 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 platform_device *pdev) } 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 timeout in seconds. (1<=timeout<=3600, defau 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 data) /* 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 @@ static int epx_c3_alive; 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-255 minutes, default is 1"); 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 timeout in seconds. (1<=timeout<=3600, defau 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 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON 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 data) 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_CKS_4096; #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 a9681d5..d3cb0a7 100644 --- a/drivers/char/watchdog/smsc37b787_wdt.c +++ b/drivers/char/watchdog/smsc37b787_wdt.c @@ -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 soft_margin in seconds. (0<soft_margin<6 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 timeout in seconds. 1<= timeout <=63, defaul 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 c960ec1..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 timeout in seconds. 1<= timeout <=255, defau 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/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 timeout in seconds. (1<=timeout<=3600, defau 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 data) 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 testmode (1 = no reboot), default=0"); 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 timeout in seconds. 1<= timeout <=255, defau 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 heartbeat in seconds. (0<heartbeat<65536, 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 testmode (1 = no reboot), default=0"); 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 heartbeat in seconds. (0<heartbeat<65536, 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 <linux/acpi_pmtmr.h> #include <linux/clocksource.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/pci.h> #include <asm/io.h> -/* 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 @@ */ 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(void) } 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_acpi_pm = { .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_setup); 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_cyclone = { .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_driver; 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 @@ static ssize_t store_##file_name \ 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, "<unknown>"); return sprintf(buf, "%u\n", cur_freq); @@ -479,18 +534,12 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, &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 * kobj, struct attribute * attr ,char * buf) 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 * kobj, struct attribute * attr, 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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) */ 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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) &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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) 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 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) 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 @@ 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; + 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 int cpu) 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 int cpu) 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 cpu) } } - 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_notifier); *********************************************************************/ -/* 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_policy *policy, 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_policy *policy) 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_policy *policy, unsigned int cpu) 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_policy *policy) 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_policy *policy) 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 cpu) 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 cpu) 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 notifier_block *nfb, 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 cpufreq_driver *driver) 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 <linux/fs.h> #include <linux/sysfs.h> #include <linux/cpu.h> -#include <linux/sched.h> #include <linux/kmod.h> #include <linux/workqueue.h> #include <linux/jiffies.h> @@ -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 @@ static unsigned int def_sampling_rate; 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_info_s *this_dbs_info) 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_info_s *this_dbs_info) 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_struct *work) 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_struct *work) 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 cpufreq_policy *policy, 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 cpufreq_policy *policy, 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 cpufreq_policy *policy, 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 cpufreq_policy *policy, 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_gov_dbs = { 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 <nanhai.zou@intel.com>"); 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, struct cpufreq_policy *policy) 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, struct cpufreq_policy *policy) err: mutex_unlock(&userspace_mutex); - unlock_cpu_hotplug(); return ret; } diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 31ea405..0eb6284 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -8,7 +8,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/crypto.h> 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 @@ #ifdef CONFIG_MODULES -#include <linux/sched.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8c7d48e..7452399 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -18,7 +18,6 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/list.h> #include <linux/mm.h> #include <linux/smp_lock.h> 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 *adapter) 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 <linux/pci.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/ioport.h> #include <linux/i2c.h> @@ -475,6 +474,7 @@ static const struct i2c_algorithm smbus_algorithm = { 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_adapter * a) } -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(struct pci_dev * dev) 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 ali1563_algorithm = { 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(struct pci_dev * dev, 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 <linux/pci.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -470,6 +469,7 @@ static const struct i2c_algorithm smbus_algorithm = { 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 <linux/kernel.h> #include <linux/delay.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> @@ -301,6 +300,7 @@ static const struct i2c_algorithm smbus_algorithm = { 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 <linux/pci.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/i2c.h> @@ -76,7 +75,8 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus) 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(struct amd_smbus *smbus) 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 amd_smbus *smbus, unsigned char address, 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 @@ static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, #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_adapter * adap, u16 addr, unsigned short fl 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_adapter * adap, u16 addr, unsigned short fl 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_adapter * adap, u16 addr, unsigned short fl 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_adapter * adap, u16 addr, unsigned short fl 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_adapter * adap, u16 addr, unsigned short fl 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_adapter * adap, u16 addr, unsigned short fl 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(struct pci_dev *dev, const struct pci_device_ 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(struct pci_dev *dev, const struct pci_device_ /* 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(struct pci_dev *dev, const struct pci_device_ 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 <linux/kernel.h> #include <linux/stddef.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/i2c.h> @@ -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_algorithm = { 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_bit_data = { 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_bit_data = { 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 ocp_device *ocp){ /* 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 <linux/slab.h> #include <linux/init.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/platform_device.h> #include <linux/i2c.h> 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 <linux/i2c.h> #include <linux/i2c-isa.h> #include <linux/platform_device.h> +#include <linux/completion.h> 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 *pd) 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 <linux/pci.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/i2c.h> @@ -57,7 +56,6 @@ MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver"); 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 (struct pci_dev *dev, int bar, 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 (struct pci_dev *dev, int bar, 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 <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/platform_device.h> 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 <linux/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <asm/io.h> + +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 <olof@lixom.net>"); +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 <linux/kernel.h> #include <linux/delay.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> @@ -383,6 +383,7 @@ static const struct i2c_algorithm smbus_algorithm = { 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..1425d224 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -25,7 +25,6 @@ #include <linux/types.h> #include <linux/i2c.h> #include <linux/init.h> -#include <linux/completion.h> #include <linux/device.h> #include <linux/platform_device.h> #include <asm/prom.h> 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 <linux/init.h> #include <linux/time.h> #include <linux/interrupt.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/err.h> 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_bit_data = { 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_algorithm = { 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_algorithm = { 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 <linux/kernel.h> #include <linux/delay.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> @@ -249,6 +248,7 @@ static const struct i2c_algorithm smbus_algorithm = { 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 <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>, Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2005 - 2007 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -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_algorithm = { 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_bit_data = { 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_bit_data = { 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(struct scx200_acb_iface *iface) } 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 *scx200_create_iface(const char *text, 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(const char *text, struct pci_dev *pdev, 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(const char *text, unsigned long base, 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_i2c_data = { 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 <linux/init.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/mutex.h> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b05378a3..21fe140 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -32,6 +32,7 @@ #include <linux/seq_file.h> #include <linux/platform_device.h> #include <linux/mutex.h> +#include <linux/completion.h> #include <asm/uaccess.h> @@ -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 *adap) */ 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/ide/ide-proc.c b/drivers/ide/ide-proc.c index 30a5780..afb71c6 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -26,7 +26,6 @@ #include <asm/uaccess.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/mm.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 <linux/errno.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/stddef.h> 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 <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/ide.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/errno.h> 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 <linux/pci.h> -#include <linux/sched.h> #include <linux/slab.h> #include "hosts.h" diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 5729e41..e982d60 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -102,7 +102,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <asm/irq.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/vmalloc.h> #include <linux/init.h> diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index fbb7f14..0742bef 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -1434,6 +1434,7 @@ static int __devinit add_card(struct pci_dev *dev, i2c_adapter_data = bit_data; i2c_ad->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/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/Kconfig" 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/mthca/ 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 d2bb5a9..a91001c 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -373,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 <linux/module.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/sched.h> /* INIT_WORK, schedule_work(), flush_scheduled_work() */ #include <rdma/ib_cache.h> 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, struct rdma_id_private *id_priv, 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_private *id_priv) 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 <linux/module.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/kernel.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/mutex.h> @@ -93,7 +94,7 @@ static int ib_device_check_mandatory(struct ib_device *device) }; 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/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_dev *pcidev, 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/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 <http://www.chelsio.com>. + + For customer support, please visit our customer support page at + <http://www.chelsio.com/support.htm>. + + Please send feedback to <linux-bugs@chelsio.com>. + + 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 <linux/types.h> +#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 <asm/delay.h> + +#include <linux/mutex.h> +#include <linux/netdevice.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/pci.h> + +#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 <linux/list.h> +#include <linux/mutex.h> + +#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 <linux/kernel.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/kfifo.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#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 <linux/kernel.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/kfifo.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/genalloc.h> +#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 <asm/io.h> +#include <linux/pci.h> +#include <linux/timer.h> +#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<<size_log2)-((wptr)-(rptr))) +#define Q_COUNT(rptr,wptr) ((wptr)-(rptr)) +#define Q_PTR2IDX(ptr,size_log2) (ptr & ((1UL<<size_log2)-1)) + +static inline void ring_doorbell(void __iomem *doorbell, u32 qpid) +{ + writel(((1<<31) | qpid), doorbell); +} + +#define SEQ32_GE(x,y) (!( (((u32) (x)) - ((u32) (y))) & 0x80000000 )) + +enum t3_wr_flags { + T3_COMPLETION_FLAG = 0x01, + T3_NOTIFY_FLAG = 0x02, + T3_SOLICITED_EVENT_FLAG = 0x04, + T3_READ_FENCE_FLAG = 0x08, + T3_LOCAL_FENCE_FLAG = 0x10 +} __attribute__ ((packed)); + +enum t3_wr_opcode { + T3_WR_BP = FW_WROPCODE_RI_BYPASS, + T3_WR_SEND = FW_WROPCODE_RI_SEND, + T3_WR_WRITE = FW_WROPCODE_RI_RDMA_WRITE, + T3_WR_READ = FW_WROPCODE_RI_RDMA_READ, + T3_WR_INV_STAG = FW_WROPCODE_RI_LOCAL_INV, + T3_WR_BIND = FW_WROPCODE_RI_BIND_MW, + T3_WR_RCV = FW_WROPCODE_RI_RECEIVE, + T3_WR_INIT = FW_WROPCODE_RI_RDMA_INIT, + T3_WR_QP_MOD = FW_WROPCODE_RI_MODIFY_QP +} __attribute__ ((packed)); + +enum t3_rdma_opcode { + T3_RDMA_WRITE, /* IETF RDMAP v1.0 ... */ + T3_READ_REQ, + T3_READ_RESP, + T3_SEND, + T3_SEND_WITH_INV, + T3_SEND_WITH_SE, + T3_SEND_WITH_SE_INV, + T3_TERMINATE, + T3_RDMA_INIT, /* CHELSIO RI specific ... */ + T3_BIND_MW, + T3_FAST_REGISTER, + T3_LOCAL_INV, + T3_QP_MOD, + T3_BYPASS +} __attribute__ ((packed)); + +static inline enum t3_rdma_opcode wr2opcode(enum t3_wr_opcode wrop) +{ + switch (wrop) { + case T3_WR_BP: return T3_BYPASS; + case T3_WR_SEND: return T3_SEND; + case T3_WR_WRITE: return T3_RDMA_WRITE; + case T3_WR_READ: return T3_READ_REQ; + case T3_WR_INV_STAG: return T3_LOCAL_INV; + case T3_WR_BIND: return T3_BIND_MW; + case T3_WR_INIT: return T3_RDMA_INIT; + case T3_WR_QP_MOD: return T3_QP_MOD; + default: break; + } + return -1; +} + + +/* Work request id */ +union t3_wrid { + struct { + u32 hi; + u32 low; + } id0; + u64 id1; +}; + +#define WRID(wrid) (wrid.id1) +#define WRID_GEN(wrid) (wrid.id0.wr_gen) +#define WRID_IDX(wrid) (wrid.id0.wr_idx) +#define WRID_LO(wrid) (wrid.id0.wr_lo) + +struct fw_riwrh { + __be32 op_seop_flags; + __be32 gen_tid_len; +}; + +#define S_FW_RIWR_OP 24 +#define M_FW_RIWR_OP 0xff +#define V_FW_RIWR_OP(x) ((x) << S_FW_RIWR_OP) +#define G_FW_RIWR_OP(x) ((((x) >> 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_OOO) + +#define S_CQE_QPID 12 +#define M_CQE_QPID 0x7FFFF +#define G_CQE_QPID(x) ((((x) >> S_CQE_QPID)) & M_CQE_QPID) +#define V_CQE_QPID(x) ((x)<<S_CQE_QPID) + +#define S_CQE_SWCQE 11 +#define M_CQE_SWCQE 0x1 +#define G_CQE_SWCQE(x) ((((x) >> S_CQE_SWCQE)) & M_CQE_SWCQE) +#define V_CQE_SWCQE(x) ((x)<<S_CQE_SWCQE) + +#define S_CQE_GENBIT 10 +#define M_CQE_GENBIT 0x1 +#define G_CQE_GENBIT(x) (((x) >> S_CQE_GENBIT) & M_CQE_GENBIT) +#define V_CQE_GENBIT(x) ((x)<<S_CQE_GENBIT) + +#define S_CQE_STATUS 5 +#define M_CQE_STATUS 0x1F +#define G_CQE_STATUS(x) ((((x) >> S_CQE_STATUS)) & M_CQE_STATUS) +#define V_CQE_STATUS(x) ((x)<<S_CQE_STATUS) + +#define S_CQE_TYPE 4 +#define M_CQE_TYPE 0x1 +#define G_CQE_TYPE(x) ((((x) >> S_CQE_TYPE)) & M_CQE_TYPE) +#define V_CQE_TYPE(x) ((x)<<S_CQE_TYPE) + +#define S_CQE_OPCODE 0 +#define M_CQE_OPCODE 0xF +#define G_CQE_OPCODE(x) ((((x) >> S_CQE_OPCODE)) & M_CQE_OPCODE) +#define V_CQE_OPCODE(x) ((x)<<S_CQE_OPCODE) + +#define SW_CQE(x) (G_CQE_SWCQE(be32_to_cpu((x).header))) +#define CQE_OOO(x) (G_CQE_OOO(be32_to_cpu((x).header))) +#define CQE_QPID(x) (G_CQE_QPID(be32_to_cpu((x).header))) +#define CQE_GENBIT(x) (G_CQE_GENBIT(be32_to_cpu((x).header))) +#define CQE_TYPE(x) (G_CQE_TYPE(be32_to_cpu((x).header))) +#define SQ_TYPE(x) (CQE_TYPE((x))) +#define RQ_TYPE(x) (!CQE_TYPE((x))) +#define CQE_STATUS(x) (G_CQE_STATUS(be32_to_cpu((x).header))) +#define CQE_OPCODE(x) (G_CQE_OPCODE(be32_to_cpu((x).header))) + +#define CQE_LEN(x) (be32_to_cpu((x).len)) + +/* used for RQ completion processing */ +#define CQE_WRID_STAG(x) (be32_to_cpu((x).u.rcqe.stag)) +#define CQE_WRID_MSN(x) (be32_to_cpu((x).u.rcqe.msn)) + +/* used for SQ completion processing */ +#define CQE_WRID_SQ_WPTR(x) ((x).u.scqe.wrid_hi) +#define CQE_WRID_WPTR(x) ((x).u.scqe.wrid_low) + +/* generic accessor macros */ +#define CQE_WRID_HI(x) ((x).u.scqe.wrid_hi) +#define CQE_WRID_LOW(x) ((x).u.scqe.wrid_low) + +#define TPT_ERR_SUCCESS 0x0 +#define TPT_ERR_STAG 0x1 /* STAG invalid: either the */ + /* STAG is offlimt, being 0, */ + /* or STAG_key mismatch */ +#define TPT_ERR_PDID 0x2 /* PDID mismatch */ +#define TPT_ERR_QPID 0x3 /* QPID mismatch */ +#define TPT_ERR_ACCESS 0x4 /* Invalid access right */ +#define TPT_ERR_WRAP 0x5 /* Wrap error */ +#define TPT_ERR_BOUND 0x6 /* base and bounds voilation */ +#define TPT_ERR_INVALIDATE_SHARED_MR 0x7 /* attempt to invalidate a */ + /* shared memory region */ +#define TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND 0x8 /* attempt to invalidate a */ + /* shared memory region */ +#define TPT_ERR_ECC 0x9 /* ECC error detected */ +#define TPT_ERR_ECC_PSTAG 0xA /* ECC error detected when */ + /* reading PSTAG for a MW */ + /* Invalidate */ +#define TPT_ERR_PBL_ADDR_BOUND 0xB /* pbl addr out of bounds: */ + /* software error */ +#define TPT_ERR_SWFLUSH 0xC /* SW FLUSHED */ +#define TPT_ERR_CRC 0x10 /* CRC error */ +#define TPT_ERR_MARKER 0x11 /* Marker error */ +#define TPT_ERR_PDU_LEN_ERR 0x12 /* invalid PDU length */ +#define TPT_ERR_OUT_OF_RQE 0x13 /* out of RQE */ +#define TPT_ERR_DDP_VERSION 0x14 /* wrong DDP version */ +#define TPT_ERR_RDMA_VERSION 0x15 /* wrong RDMA version */ +#define TPT_ERR_OPCODE 0x16 /* invalid rdma opcode */ +#define TPT_ERR_DDP_QUEUE_NUM 0x17 /* invalid ddp queue number */ +#define TPT_ERR_MSN 0x18 /* MSN error */ +#define TPT_ERR_TBIT 0x19 /* tag bit not set correctly */ +#define TPT_ERR_MO 0x1A /* MO not 0 for TERMINATE */ + /* or READ_REQ */ +#define TPT_ERR_MSN_GAP 0x1B +#define TPT_ERR_MSN_RANGE 0x1C +#define TPT_ERR_IRD_OVERFLOW 0x1D +#define TPT_ERR_RQE_ADDR_BOUND 0x1E /* RQE addr out of bounds: */ + /* software error */ +#define TPT_ERR_INTERNAL_ERR 0x1F /* internal error (opcode */ + /* mismatch) */ + +struct t3_swsq { + __u64 wr_id; + struct t3_cqe cqe; + __u32 sq_wptr; + __be32 read_len; + int opcode; + int complete; + int signaled; +}; + +/* + * A T3 WQ implements both the SQ and RQ. + */ +struct t3_wq { + union t3_wr *queue; /* DMA accessable memory */ + dma_addr_t dma_addr; /* DMA address for HW */ + DECLARE_PCI_UNMAP_ADDR(mapping) /* unmap kruft */ + u32 error; /* 1 once we go to ERROR */ + u32 qpid; + u32 wptr; /* idx to next available WR slot */ + u32 size_log2; /* total wq size */ + struct t3_swsq *sq; /* SW SQ */ + struct t3_swsq *oldest_read; /* tracks oldest pending read */ + u32 sq_wptr; /* sq_wptr - sq_rptr == count of */ + u32 sq_rptr; /* pending wrs */ + u32 sq_size_log2; /* sq size */ + u64 *rq; /* SW RQ (holds consumer wr_ids */ + u32 rq_wptr; /* rq_wptr - rq_rptr == count of */ + u32 rq_rptr; /* pending wrs */ + u64 *rq_oldest_wr; /* oldest wr on the SW RQ */ + u32 rq_size_log2; /* rq size */ + u32 rq_addr; /* rq adapter address */ + void __iomem *doorbell; /* kernel db */ + u64 udb; /* user db if any */ +}; + +struct t3_cq { + u32 cqid; + u32 rptr; + u32 wptr; + u32 size_log2; + dma_addr_t dma_addr; + DECLARE_PCI_UNMAP_ADDR(mapping) + struct t3_cqe *queue; + struct t3_cqe *sw_queue; + u32 sw_rptr; + u32 sw_wptr; +}; + +#define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \ + CQE_GENBIT(*cqe)) + +static inline void cxio_set_wq_in_error(struct t3_wq *wq) +{ + wq->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 <linux/module.h> +#include <linux/moduleparam.h> + +#include <rdma/ib_verbs.h> + +#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 <linux/mutex.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/idr.h> + +#include <rdma/ib_verbs.h> + +#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 <linux/module.h> +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/skbuff.h> +#include <linux/timer.h> +#include <linux/notifier.h> + +#include <net/neighbour.h> +#include <net/netevent.h> +#include <net/route.h> + +#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 <linux/inet.h> +#include <linux/wait.h> +#include <linux/spinlock.h> +#include <linux/kref.h> + +#include <rdma/ib_verbs.h> +#include <rdma/iw_cm.h> + +#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<<wscale) < win) + wscale++; + return wscale; +} + +/* CM prototypes */ + +int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param); +int iwch_create_listen(struct iw_cm_id *cm_id, int backlog); +int iwch_destroy_listen(struct iw_cm_id *cm_id); +int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len); +int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param); +int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp); +int iwch_quiesce_tid(struct iwch_ep *ep); +int iwch_resume_tid(struct iwch_ep *ep); +void __free_ep(struct kref *kref); +void iwch_rearp(struct iwch_ep *ep); +int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, struct l2t_entry *l2t); + +int __init iwch_cm_init(void); +void __exit iwch_cm_term(void); + +#endif /* _IWCH_CM_H_ */ diff --git a/drivers/infiniband/hw/cxgb3/iwch_cq.c b/drivers/infiniband/hw/cxgb3/iwch_cq.c new file mode 100644 index 0000000..98b3bdb --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_cq.c @@ -0,0 +1,225 @@ +/* + * 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" + +/* + * Get one cq entry from cxio and map it to openib. + * + * Returns: + * 0 EMPTY; + * 1 cqe returned + * -EAGAIN caller must try again + * any other -errno fatal error + */ +static int iwch_poll_cq_one(struct iwch_dev *rhp, struct iwch_cq *chp, + struct ib_wc *wc) +{ + struct iwch_qp *qhp = NULL; + struct t3_cqe cqe, *rd_cqe; + struct t3_wq *wq; + u32 credit = 0; + u8 cqe_flushed; + u64 cookie; + int ret = 1; + + rd_cqe = cxio_next_cqe(&chp->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..a6efa8fe --- /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 <linux/slab.h> +#include <linux/mman.h> +#include <net/sock.h> +#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 <asm/byteorder.h> + +#include <rdma/iw_cm.h> +#include <rdma/ib_verbs.h> + +#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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/ethtool.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/byteorder.h> + +#include <rdma/iw_cm.h> +#include <rdma/ib_verbs.h> +#include <rdma/ib_smi.h> +#include <rdma/ib_user_verbs.h> + +#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<<chp->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 <linux/list.h> +#include <linux/spinlock.h> +#include <rdma/ib_verbs.h> +#include <asm/types.h> +#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_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 *shca, /* 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 *shca, 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 @@ void ehca_destroy_comp_pool(void) 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/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 968d151..7131446 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1051,7 +1051,11 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, 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); 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 *dev, struct mthca_uar *uar); 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_dev *mdev) 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_dev *mdev, (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_dev *mdev, 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_dev *mdev, 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_dev *mdev, 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_dev *mdev, 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_dev *mdev, 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_dev *mdev, 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_dev *mdev, 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_dev *mdev, 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_dev *mdev) 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_dev *mdev) 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 <linux/mm.h> +#include <linux/scatterlist.h> + +#include <asm/page.h> #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 *dev, struct mthca_icm *icm) 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 mthca_dev *dev, int npages, 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 mthca_dev *dev, int npages, } } - 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 mthca_dev *dev, int npages, 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 *dev, struct mthca_icm_table *table, int ob 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 *dev, struct mthca_icm_table *table, int ob 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 *dev, struct mthca_icm_table *table, int o 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_table *table, int obj) 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_dev *dev, struct mthca_icm_table *table, 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(struct mthca_dev *dev, 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(struct mthca_dev *dev, 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_dev *dev, struct mthca_icm_table *table) 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 *dev, struct mthca_mtt *mtt) 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 *dev, u32 pd, 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 *dev, u32 pd, 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_fmr *ibfmr, u64 *page_list, 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_dev *dev, struct mthca_fmr *fmr) 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 *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) 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 *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(struct ib_pd *pd, struct ib_umem *region, 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(struct ib_pd *pd, struct ib_umem *region, 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(struct ib_pd *pd, struct ib_umem *region, 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 mthca_flags) 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_dev *dev, 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 *pdev, unsigned short pkey); 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 @@ extern int ipoib_debug_level; #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 <rdma/ib_cm.h> +#include <rdma/ib_cache.h> +#include <net/dst.h> +#include <net/icmp.h> +#include <linux/icmpv6.h> + +#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_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 net_device *dev, struct ib_wc *wc) 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 net_device *dev, struct ib_wc *wc) 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 sk_buff *skb, 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, struct sk_buff *skb, 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 *dev) 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 *dev) 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 af5ee2e..18d27fd 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -49,8 +49,6 @@ #include <net/dst.h> -#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 *dev) 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_device *dev, int new_mtu) { 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 status, 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_buff *skb, struct net_device *dev) 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_buff *skb, struct net_device *dev) 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(struct neighbour *neighbour) 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 *dev, struct ipoib_neigh *neigh) ++priv->stats.tx_dropped; dev_kfree_skb_any(skb); } + if (ipoib_cm_get(neigh)) + ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); kfree(neigh); } @@ -1080,6 +1131,8 @@ static struct net_device *ipoib_add_port(const char *format, 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 (device_create_file(&priv->dev->dev, &dev_attr_create_child)) 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_struct *work) 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 7b717c64..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_device *dev, struct ib_device *ca) .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_device *dev, struct ib_device *ca) 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 net_device *dev) 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 085eafe..6762988 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -115,6 +115,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) 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; 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 <linux/module.h> #include <linux/mutex.h> #include <linux/spinlock.h> -#include <linux/sched.h> +#include <linux/jiffies.h> #include "fixp-arith.h" diff --git a/drivers/input/input.c b/drivers/input/input.c index 14d4c049..efa1b1f 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -11,7 +11,6 @@ */ #include <linux/init.h> -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/input.h> #include <linux/module.h> diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 3a8f1b4..7ad479e 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -78,7 +78,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) int irq = IRQ_GPIO(pdata->buttons[i].gpio); set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); - error = request_irq(irq, gpio_keys_isr, SA_SAMPLE_RANDOM, + error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", pdev); if (error) { 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 <linux/module.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/interrupt.h> #include <linux/init.h> 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 <linux/init.h> #include <linux/interrupt.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/list.h> MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); 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 <linux/hp_sdc.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index cd251ef..0a26e06 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -546,7 +546,7 @@ static void ads7846_rx(void *ads) ts->spi->dev.bus_id, ts->tc.ignore, Rt); #endif hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_REL); + HRTIMER_MODE_REL); return; } @@ -578,7 +578,8 @@ static void ads7846_rx(void *ads) #endif } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL); + hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), + HRTIMER_MODE_REL); } static int ads7846_debounce(void *ads, int data_idx, int *val) @@ -667,7 +668,7 @@ static void ads7846_rx_val(void *ads) status); } -static int ads7846_timer(struct hrtimer *handle) +static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) { struct ads7846 *ts = container_of(handle, struct ads7846, timer); int status = 0; @@ -724,7 +725,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) disable_irq(ts->spi->irq); ts->pending = 1; hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_REL); + HRTIMER_MODE_REL); } } spin_unlock_irqrestore(&ts->lock, flags); @@ -862,7 +863,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->spi = spi; ts->input = input_dev; - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = ads7846_timer; spin_lock_init(&ts->lock); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 8cec9c3..2a49cea 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -13,7 +13,6 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/fs.h> diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile index 835b806..077e297 100644 --- a/drivers/isdn/gigaset/Makefile +++ b/drivers/isdn/gigaset/Makefile @@ -5,4 +5,4 @@ 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_M105) += ser_gigaset.o gigaset.o +obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o gigaset.o 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 <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c index 6b2940e..4aba5c5 100644 --- a/drivers/isdn/hardware/eicon/divamnt.c +++ b/drivers/isdn/hardware/eicon/divamnt.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/poll.h> #include <asm/uaccess.h> diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index b365e44..5e862e2 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/ioport.h> 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 <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 42bbae2..9f44d3e 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -38,7 +38,6 @@ #include <linux/usb.h> #include <linux/kernel.h> #include <linux/smp_lock.h> -#include <linux/sched.h> #include "hisax.h" #include "hisax_if.h" #include "hfc_usb.h" 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 <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index a1206498..84dccd5 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -14,7 +14,6 @@ * */ -#include <linux/sched.h> #include <linux/signal.h> #include <linux/kernel.h> #include <linux/ioport.h> 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 <linux/sched.h> #include <linux/signal.h> #include <linux/kernel.h> #include <linux/ioport.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/sched.h> #include <linux/string.h> #include <linux/kernel.h> diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c index bef321d0..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 <linux/sched.h> #include <linux/string.h> #include <linux/kernel.h> diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 386c5ce..8c66bcb 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -19,7 +19,6 @@ #include <linux/module.h> -#include <linux/sched.h> #include <linux/kernel.h> diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c index 1ad8b07..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 <linux/sched.h> #include <linux/string.h> #include <linux/kernel.h> diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 58eee50..5ba2a87 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -24,7 +24,6 @@ * re-write/remove debug printks */ -#include <linux/sched.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/types.h> diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c index 7b7b177..04ea241 100644 --- a/drivers/isdn/pcbit/module.c +++ b/drivers/isdn/pcbit/module.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/skbuff.h> diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 1e640b8..fd4e9173 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -1879,12 +1879,6 @@ again: asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - /* - * 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) { kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; @@ -1907,6 +1901,12 @@ again: 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); 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/apm_emu.c b/drivers/macintosh/apm_emu.c index a6d50f4..c5e4d43 100644 --- a/drivers/macintosh/apm_emu.c +++ b/drivers/macintosh/apm_emu.c @@ -102,7 +102,7 @@ static struct pmu_sleep_notifier apm_sleep_notifier = { 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[] = { 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 @@ 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 <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <asm/prom.h> diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 3d3bf16..a7ce5592 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 <colin@colino.net>"); 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 <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/adb.h> #include <linux/cuda.h> #include <linux/spinlock.h> @@ -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 <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/adb.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -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 <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/adb.h> #include <linux/cuda.h> #include <linux/delay.h> @@ -63,10 +62,10 @@ static volatile unsigned char *via; #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 96bea4b62..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); @@ -2776,7 +2776,7 @@ pmu_polled_request(struct adb_request *req) #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) { @@ -2816,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 4f5b6fa..356c721 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -22,7 +22,6 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/miscdevice.h> #include <linux/blkdev.h> #include <linux/pci.h> @@ -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); diff --git a/drivers/md/md.c b/drivers/md/md.c index e85fa75..05febfd 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -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/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_device *fc) 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 <linux/vmalloc.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/sched.h> #include <linux/poll.h> #include <linux/ioctl.h> #include <linux/wait.h> 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 <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/device.h> 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 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) #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 <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/smp_lock.h> #include <linux/fs.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/fs.h> 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 <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/smp_lock.h> #include <linux/fs.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/fs.h> 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 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i #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/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c index c93490e..aed1147 100644 --- a/drivers/media/radio/miropcm20-rds.c +++ b/drivers/media/radio/miropcm20-rds.c @@ -14,7 +14,6 @@ #include <linux/slab.h> #include <linux/fs.h> #include <linux/miscdevice.h> -#include <linux/sched.h> /* current, TASK_*, schedule_timeout() */ #include <linux/delay.h> #include <asm/uaccess.h> #include "miropcm20-rds-core.h" diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 9bba6eb..e67b7f2 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -22,7 +22,6 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/sched.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/mutex.h> diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 00a2f31..6beeb74 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -35,7 +35,6 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/sched.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/mutex.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/kdev_t.h> #include <asm/io.h> diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index fb1410c..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_camera *cam) 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) 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 <linux/pci.h> #include <linux/signal.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/vmalloc.h> 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 <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/usb.h> 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 <linux/major.h> #include <linux/module.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/videodev.h> 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 <linux/moduleparam.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 9528e10..98681da 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -28,7 +28,6 @@ */ #include <linux/module.h> #include <linux/pci.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/videodev.h> #include <media/v4l2-common.h> diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index d38d3dc..b5a67f0 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -28,7 +28,6 @@ #include <linux/ioport.h> #include <linux/init.h> #include <asm/io.h> -#include <linux/sched.h> #include <linux/videodev.h> #include <media/v4l2-common.h> #include <linux/mutex.h> 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 *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/saa5246a.c b/drivers/media/video/saa5246a.c index 0b5d159..76f5f5d 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -40,7 +40,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/i2c.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <asm/uaccess.h> #include <linux/videodev.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> 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 <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/input.h> 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 <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/videodev.h> 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 <linux/major.h> #include <linux/module.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/videodev.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> 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 <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index e2747bd..7ea9132 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -4,7 +4,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/module.h> #include <linux/init.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/module.h> #include <linux/init.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/list.h> #include <linux/timer.h> #include <linux/slab.h> 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 <asm/uaccess.h> #include <linux/ioport.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/usb.h> #include <linux/i2c.h> #include "usbvision.h" @@ -258,6 +257,7 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) 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 4eb7330..af33653 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -46,7 +46,6 @@ #include <linux/version.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/list.h> #include <linux/timer.h> #include <linux/slab.h> 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 <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/string.h> diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 30c3822..a786c1f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -30,7 +30,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/string.h> diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 6e64af2..8f31613 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -1573,6 +1573,7 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam) 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...") 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/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b7d4c72..0caaf64 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -53,7 +53,6 @@ #include <linux/delay.h> /* for mdelay */ #include <linux/interrupt.h> /* needed for in_interrupt() proto */ #include <linux/reboot.h> /* notifier code */ -#include <linux/sched.h> #include <linux/workqueue.h> #include <linux/sort.h> diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 84b8b48..404c014 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -48,7 +48,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/errno.h> -#include <linux/sched.h> +#include <linux/jiffies.h> #include <linux/workqueue.h> #include <linux/delay.h> /* for mdelay */ diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index c417ae0..2a3e9e66 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -54,7 +54,6 @@ #include <linux/delay.h> /* for mdelay */ #include <linux/interrupt.h> /* needed for in_interrupt() proto */ #include <linux/reboot.h> /* notifier code */ -#include <linux/sched.h> #include <linux/workqueue.h> #include <scsi/scsi.h> diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index c31a9e3..85f21b5 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -54,7 +54,6 @@ #include <linux/delay.h> /* for mdelay */ #include <linux/interrupt.h> /* needed for in_interrupt() proto */ #include <linux/reboot.h> /* notifier code */ -#include <linux/sched.h> #include <linux/workqueue.h> #include <linux/raid_class.h> diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index e21e490..bc60e2f 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -367,7 +367,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, 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; diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 05ba8ac..86439a0 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <asm/io.h> #include <asm/byteorder.h> 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 <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/types.h> #include <linux/bitops.h> 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 <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/types.h> #include <linux/bitops.h> 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 <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/types.h> 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 <linux/module.h> #include <asm/uaccess.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/ptrace.h> #include <linux/slab.h> 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 <asm/uaccess.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 @@ /*#define PSYCHO_DEBUG */ #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nftl.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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(struct pci_dev *pdev, 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 <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/hdreg.h> 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/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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 72c41f5..61f574a 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -28,7 +28,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/errno.h> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 61a6fa4..a7c8f98 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -35,7 +35,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/interrupt.h> diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 878f7aa..a122baa 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -22,7 +22,6 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/sysdev.h> #include <linux/fs.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/types.h> #include <linux/fcntl.h> diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index c67f7d3..43583ed65 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -757,7 +757,8 @@ static int cxgb_up(struct adapter *adap) t3_intr_handler(adap, adap->sge.qs[0].rspq. polling), - (adap->flags & USING_MSI) ? 0 : SA_SHIRQ, + (adap->flags & USING_MSI) ? + 0 : IRQF_SHARED, adap->name, adap))) goto irq_err; 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 net_device *dev) , "%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 net_device *dev) 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 net_device *dev) "%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 ibmebus_dev *dev, (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/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 <linux/kernel.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/errno.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 0d6943d..7b411c1 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -16,7 +16,6 @@ */ #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/slab.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/interrupt.h> 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 <linux/module.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/sched.h> #include <net/irda/irda.h> diff --git a/drivers/net/macb.c b/drivers/net/macb.c index e67361e..a41418b 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1077,7 +1077,7 @@ static int __devinit macb_probe(struct platform_device *pdev) } 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 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 <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/delay.h> #include <linux/slab.h> 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 <linux/kernel.h> #include <linux/module.h> #include <linux/netdevice.h> -#include <linux/sched.h> #include <linux/etherdevice.h> #include <linux/netdevice.h> #include <linux/platform_device.h> 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_device *netdev) } 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/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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 2429b27..a142cdf 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -3228,7 +3228,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) { 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)) { @@ -3247,7 +3247,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) } 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; } } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 8646b64..e8e0d94 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -59,7 +59,6 @@ #include <linux/stddef.h> #include <linux/ioctl.h> #include <linux/timex.h> -#include <linux/sched.h> #include <linux/ethtool.h> #include <linux/workqueue.h> #include <linux/if_vlan.h> diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 7f800fe..4a926f2 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1035,7 +1035,7 @@ static int sc92031_open(struct net_device *dev) priv->tx_head = priv->tx_tail = 0; err = request_irq(pdev->irq, sc92031_interrupt, - SA_SHIRQ, dev->name, dev); + IRQF_SHARED, dev->name, dev); if (unlikely(err < 0)) goto out_request_irq; 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e136bae..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, @@ -64,8 +64,8 @@ #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 @@ -1175,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; @@ -1340,7 +1350,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) 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))) { @@ -3724,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); } @@ -6583,8 +6604,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) 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); } } @@ -7408,8 +7430,9 @@ static unsigned long calc_crc_errors(struct tg3 *tp) 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; @@ -10779,7 +10802,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) 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) @@ -11314,6 +11339,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) 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 @@ -11325,8 +11351,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp) 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; @@ -12016,6 +12047,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) 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_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 <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/delay.h> #include <linux/crc32.h> diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 31c97a6..a2fc2bb 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3939,8 +3939,8 @@ static void ugeth_phy_startup_timer(unsigned long data) /* 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); diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c index 6fda6d8..9373d895 100644 --- a/drivers/net/ucc_geth_phy.c +++ b/drivers/net/ucc_geth_phy.c @@ -18,7 +18,6 @@ */ #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/slab.h> 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 <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ -#include <linux/sched.h> /* for jiffies, HZ, etc. */ #include <linux/cycx_drv.h> /* API definitions */ #include <linux/cycx_cfm.h> /* CYCX firmware module definitions */ #include <linux/delay.h> /* udelay, msleep_interruptible */ 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 <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/in.h> 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 @@ static ctl_table arlan_table[MAX_ARLANS + 1] = 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 <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 <net/ieee80211softmac.h> #include <net/ieee80211softmac_wx.h> #include <linux/capability.h> -#include <linux/sched.h> /* for capable() */ #include <linux/delay.h> #include "bcm43xx.h" 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 <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/eisa.h> 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 <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> 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 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/interrupt.h> 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 @@ static int do_hardware_modes (ctl_table *table, int write, 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 *port) 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 @@ int parport_device_proc_register(struct pardevice *device) 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(struct pardevice *device) 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/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index 05e4f5a..600ed7b6 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -28,7 +28,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> 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 pcie_device *dev, } /* 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/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 <linux/sched.h> #include <linux/errno.h> #include <linux/pci.h> #include <linux/smp_lock.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/platform_device.h> #include <linux/errno.h> #include <linux/init.h> 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 <linux/timer.h> #include <linux/slab.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/ioport.h> #include <asm/io.h> diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 72ff2f6..71b3370 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -40,7 +40,6 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/ioport.h> #include <linux/delay.h> 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 <linux/kernel.h> #include <linux/errno.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/ioport.h> #include <linux/delay.h> diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 4dbef07..67d28ee 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/ioport.h> #include <linux/delay.h> 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 <linux/kernel.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/timer.h> #include <linux/ioport.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/platform_device.h> #include <linux/errno.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/init.h> #include <linux/delay.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/interrupt.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/device.h> #include <linux/init.h> 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 <linux/interrupt.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/platform_device.h> diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index a61d768..20853a0 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -12,7 +12,6 @@ */ #include <linux/init.h> #include <linux/pci.h> -#include <linux/sched.h> #include <linux/workqueue.h> #include <linux/interrupt.h> #include <linux/delay.h> diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig index ad27e5e..b04767c 100644 --- a/drivers/pnp/pnpacpi/Kconfig +++ b/drivers/pnp/pnpacpi/Kconfig @@ -2,17 +2,5 @@ # Plug and Play ACPI configuration # config PNPACPI - bool "Plug and Play ACPI support" - depends on PNP && ACPI - default y - ---help--- - Linux uses the PNPACPI to autodetect built-in - mainboard resources (e.g. parallel port resources). - - Some features (e.g. real hotplug) are not currently - implemented. - - If you would like the kernel to detect and allocate resources to - your mainboard devices (on some systems they are disabled by the - BIOS) say Y here. Also the PNPACPI can help prevent resource - conflicts between mainboard devices and other bus devices. + bool + default (PNP && ACPI) 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 <linux/rio.h> #include <linux/rio_drv.h> #include <linux/stat.h> -#include <linux/sched.h> /* for capable() */ #include "rio.h" 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_adapter *adapter, int address, int kind) 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-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(struct platform_device *pdev) 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 038118b..0242d80 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -279,7 +279,7 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) 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; diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index e7851e3..09bbe575 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -499,7 +499,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) 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 *dev) 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 *dev) } 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-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_adapter *adapter, int address, int kind) 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/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 90536f6..076816b 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -13,7 +13,6 @@ #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> -#include <linux/sched.h> #include <linux/wait.h> #include <linux/slab.h> #include <linux/err.h> diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 544f137..f77dc33 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -16,7 +16,6 @@ #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/major.h> diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 5a84fbb..0d6d5fc 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -45,7 +45,6 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/bitops.h> #include <linux/signal.h> diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 6387b48..594320c 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -41,7 +41,6 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/bitops.h> #include <linux/signal.h> diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 0cfd1e4..022e869 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -20,7 +20,6 @@ #include <linux/major.h> #include <linux/init.h> #include <linux/miscdevice.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/timer.h> diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index e877623..eec28c1 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -31,7 +31,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 4d1a505..45cf5bc 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -5,7 +5,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 37a04a0..8bfb67c 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -19,7 +19,6 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/smp_lock.h> #include <linux/delay.h> diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 88e061d..cb02656 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -121,7 +121,6 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/completion.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/blkdev.h> 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 <linux/errno.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/proc_fs.h> #include <linux/stat.h> 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/interrupt.h> 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/spinlock.h> diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index ddb33b0..d789e61 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> 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 <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index df67ba6..ae34768 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -32,7 +32,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> 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 <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index c632d93..d242e26 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -31,7 +31,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 8535db0..6f1a178 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -31,7 +31,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> 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 <linux/module.h> -#include <linux/sched.h> #include <asm/irq.h> #include <linux/io.h> #include <linux/blkdev.h> 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 <linux/kernel.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/blkdev.h> diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index bc7744e..27852b4 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -653,7 +653,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, 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", 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/zorro.h> #include <linux/stat.h> 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 *pdev, 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 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/signal.h> #include <linux/errno.h> 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 <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/unistd.h> #include <linux/stat.h> 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 <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/blkdev.h> 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 <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/interrupt.h> 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 @@ #include <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> 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 <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/interrupt.h> 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 <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/bitops.h> 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 <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/blkdev.h> 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 <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/interrupt.h> 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 <linux/delay.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/nvram.h> 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/zorro.h> #include <asm/setup.h> diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index d02759f..2a2cc6c 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/fs.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/major.h> #include <linux/string.h> 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 @@ #include <asm/system.h> #include <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/stat.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/slab.h> 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 @@ #include <asm/system.h> #include <asm/io.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/blkdev.h> #include "scsi.h" #include <scsi/scsi_host.h> diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index a199292..8c81cec 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -387,7 +387,6 @@ #include <linux/ctype.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/in.h> #include <linux/proc_fs.h> 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/interrupt.h> 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_queue *queue, struct srp_target *target) } 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 <linux/string.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/dma-mapping.h> diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 2aae1b0..5c32a69 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -38,7 +38,6 @@ #include <linux/stat.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/dma-mapping.h> 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 <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/blkdev.h> 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <asm/page.h> 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 <linux/types.h> #include <linux/mm.h> #include <linux/blkdev.h> -#include <linux/sched.h> #include <asm/page.h> #include <asm/pgtable.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> 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 <asm/system.h> #include <linux/signal.h> #include <linux/proc_fs.h> -#include <linux/sched.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/blkdev.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/ioport.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/ioport.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/ioport.h> diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 5b458d24..ffe75c4 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -54,7 +54,6 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/ioport.h> 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 <linux/ioport.h> #include <linux/delay.h> #include <linux/timer.h> -#include <linux/sched.h> #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/stat.h> 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_adapter(struct pci_dev *pdev, 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 f33e2eb..1c89ee3 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -40,7 +40,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 5adbbee..3e2930b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -28,7 +28,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/types.h> 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_table_header; 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_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 <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> /* workqueue stuff, HZ */ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h> 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 <linux/module.h> #include <linux/fs.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/bio.h> #include <linux/genhd.h> 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 <linux/module.h> #include <linux/fs.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/bio.h> #include <linux/string.h> 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 <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/errno.h> 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 <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/time.h> #include <linux/pci.h> #include <linux/blkdev.h> 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 <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/blkdev.h> diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index bb0c9fd9..7cb4a31 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/blkdev.h> 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 <linux/init.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/proc_fs.h> 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 @@ #include <asm/system.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/io.h> #include <linux/blkdev.h> #include <linux/interrupt.h> 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 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/ioport.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/init.h> diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 2964ca9..98ec861 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -364,6 +364,23 @@ serial_out(struct uart_8250_port *up, int offset, int value) } } +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 @@ -1045,7 +1062,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) #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 @@ -1451,6 +1468,12 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) 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 @@ -1460,16 +1483,51 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) 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); + } - timeout = up->port.timeout; - timeout = timeout > 6 ? (timeout / 2 - 2) : 1; - mod_timer(&up->timer, jiffies + timeout); + 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); + + /* 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) @@ -1540,6 +1598,37 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) 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; @@ -1613,18 +1702,50 @@ static int serial8250_startup(struct uart_port *port) 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) @@ -1740,9 +1861,9 @@ static void serial8250_shutdown(struct uart_port *port) */ (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); } @@ -2212,37 +2333,6 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) #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 *ec, const struct ecard_id *id) 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 a2dac37..6d7d616 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -16,7 +16,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -1628,7 +1627,7 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) nr_ports = rc; } - priv = kmalloc(sizeof(struct serial_private) + + priv = kzalloc(sizeof(struct serial_private) + sizeof(unsigned int) * nr_ports, GFP_KERNEL); if (!priv) { @@ -1636,9 +1635,6 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) goto err_deinit; } - memset(priv, 0, sizeof(struct serial_private) + - sizeof(unsigned int) * nr_ports); - priv->dev = dev; priv->quirk = quirk; 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 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) 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 5cc6b91..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 @@ -999,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-pl010.o 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_serial.o 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/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 <linux/kernel.h> #include <linux/errno.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> @@ -1417,14 +1416,12 @@ static int __devinit icom_alloc_adapter(struct icom_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, struct ioc3_driver_data *idd) 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, struct ioc3_driver_data *idd) /* 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 f540212..0c17938 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1076,13 +1076,12 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd) /* 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 @@ -2811,7 +2810,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) (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_driver_data *idd) 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_driver_data *idd) 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; 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/delay.h> #include <linux/tty.h> @@ -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 *pdev, const struct pci_device_id *ent) 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 *pdev, const struct pci_device_id *ent) * 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 *pdev, const struct pci_device_id *ent) 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 *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 @@ static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id); #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 <arnd@arndb.de>, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> + +#include <asm/of_platform.h> +#include <asm/prom.h> + +/* + * 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 <arnd@arndb.de>"); +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 <vitalywool@gmail.com> + * + * 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 <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/serial_pnx8xxx.h> + +#include <asm/io.h> +#include <asm/irq.h> + +/* 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(struct uart_driver *drv, int line) } 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 @@ static const char *uart_type(struct uart_port *port) 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, struct uart_driver *drv, int i) 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 *drv, struct uart_state *state, 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_driver *drv) * 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 <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> @@ -334,10 +333,9 @@ static int serial_probe(struct pcmcia_device *link) 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/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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/tty.h> #include <linux/tty_flip.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/tty.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/delay.h> #include <linux/tty.h> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9052f4c..7e54e48e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -51,6 +51,13 @@ config SPI_MASTER 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 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bf271fe..3c280ad 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -12,6 +12,7 @@ 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 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/spi/spi.h> + +#include <asm/io.h> +#include <asm/arch/board.h> +#include <asm/arch/gpio.h> + +#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 <hskinnemoen@atmel.com>"); +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/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 <linux/errno.h> -#include <linux/sched.h> #include <linux/tty.h> #include <linux/kernel.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index f390501..36b36e0 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -30,7 +30,6 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> 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 <linux/kernel.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 22e3c94..04e6b85 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -27,7 +27,6 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index e873cf4..7b3a326 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -29,7 +29,6 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 7617ff7..49d7377 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -53,7 +53,6 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 1401043..8f9a2b6 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -28,7 +28,6 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/timer.h> diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 0d22536..27904a5 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -33,7 +33,6 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/delay.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/timer.h> @@ -2614,7 +2613,7 @@ lubbock_fail0: #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/serial.c b/drivers/usb/gadget/serial.c index 6c742a9..e6c19aa 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index ebe04e0..8c85e33 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -66,7 +66,6 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/errno.h> diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index f0ffb89..32f7caf 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -7,7 +7,6 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/unistd.h> diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 44c60fba..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 struct hc_driver *driver, 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; diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 893b172..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_probe(struct platform_device *pdev) 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; diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c index de45eb0..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 hc_driver *driver, 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; 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 <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 49b9d39..ded4df3 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -28,7 +28,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/ioport.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/unistd.h> 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 <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/signal.h> #include <linux/errno.h> #include <linux/random.h> 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 <linux/module.h> #include <linux/init.h> #include <linux/usb/input.h> -#include <linux/sched.h> #include <asm/uaccess.h> #include <asm/unaligned.h> diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 84983d1..4d8ed3d 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -18,7 +18,6 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/list.h> #include <linux/mm.h> #include <linux/smp_lock.h> 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 <linux/sched.h> #include <linux/input.h> #include <linux/usb.h> diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 32f0e3a..e573c8b 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,8 +281,8 @@ static int appledisplay_probe(struct usb_interface *iface, /* 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, - pdata, &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/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 <linux/module.h> #include <linux/kernel.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/poll.h> #include <linux/init.h> 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 <linux/module.h> #include <linux/kernel.h> #include <linux/signal.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/tty.h> #include <linux/console.h> diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 4206df2..bd357e1 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -25,7 +25,6 @@ #include <linux/module.h> #include <linux/kmod.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index e5cdafa..5a21f06 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -22,7 +22,6 @@ // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> 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 <linux/module.h> #include <linux/kmod.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index 31e5fe3..d257a8e 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -22,7 +22,6 @@ // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 36a9891..de95268 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -46,7 +46,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/init.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index be888d2..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 <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> 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 <linux/sched.h> #include <linux/init.h> #include <linux/signal.h> #include <linux/slab.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> 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 <linux/module.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/ethtool.h> 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 <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> 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 <linux/sched.h> #include <linux/errno.h> #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 <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> 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 <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> 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 <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/cdrom.h> diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 602db66..bffe2b9 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -49,7 +49,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index 1490e5e..a8f60c3 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -3,7 +3,6 @@ * ATI Mach64 Hardware Acceleration */ -#include <linux/sched.h> #include <linux/delay.h> #include <linux/fb.h> #include <video/mach64.h> diff --git a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c index 2045639..10c988a 100644 --- a/drivers/video/aty/mach64_gx.c +++ b/drivers/video/aty/mach64_gx.c @@ -5,7 +5,6 @@ #include <linux/delay.h> #include <linux/fb.h> -#include <linux/sched.h> #include <asm/io.h> diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index e7c5b21..5084799 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -1,6 +1,5 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index ce5ac26..be3f2c3 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -60,7 +60,6 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/delay.h> /* MSch: for IRQ probe */ diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index eb4d03f..124ecbe 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -27,7 +27,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 4a9bde2..91a2078 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -35,7 +35,6 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/console.h> diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 3cfea31..2822526 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -16,7 +16,6 @@ #include <linux/compat.h> #include <linux/types.h> #include <linux/errno.h> -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/major.h> diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c index 1b981b6..ca93a75 100644 --- a/drivers/video/g364fb.c +++ b/drivers/video/g364fb.c @@ -16,7 +16,6 @@ #include <linux/module.h> #include <linux/console.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 3dc4942..756c0ce 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index 9ab9b83..b18486a 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -7,7 +7,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c index 961f4d4..7787c33 100644 --- a/drivers/video/i810/i810-i2c.c +++ b/drivers/video/i810/i810-i2c.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 0f9b2fd..267c1ff 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/interrupt.h> diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 33bc41f..f4ede5f 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -27,7 +27,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index a958368..c1eb18b 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -1990,7 +1990,8 @@ int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { if (!test_and_set_bit(0, &dinfo->irq_flags)) { - if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) { + if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, + "intelfb", dinfo)) { clear_bit(0, &dinfo->irq_flags); return -EINVAL; } diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c index f0d614a..1c55799 100644 --- a/drivers/video/kyro/fbdev.c +++ b/drivers/video/kyro/fbdev.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> #include <linux/string.h> diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index 180d94c..f7d647d 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index f64c4a0..5ec718a 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -115,6 +115,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, minfo->fbcon.node); i2c_set_adapdata(&b->adapter, b); b->adapter.algo_data = &b->bac; + b->adapter.dev.parent = &ACCESS_FBINFO(pcidev)->dev; b->bac = matrox_i2c_algo_template; b->bac.data = b; err = i2c_bit_add_bus(&b->adapter); diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c index 38c8d38..5e91c2b 100644 --- a/drivers/video/maxinefb.c +++ b/drivers/video/maxinefb.c @@ -25,7 +25,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 5162eab..3e51794 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/fb.h> -#include <linux/sched.h> #undef DEBUG diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index 8454adf..b858897 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c index 181875f..163a774 100644 --- a/drivers/video/nvidia/nv_of.c +++ b/drivers/video/nvidia/nv_of.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c index 68ca3cc..a864438 100644 --- a/drivers/video/pmag-aa-fb.c +++ b/drivers/video/pmag-aa-fb.c @@ -24,7 +24,6 @@ */ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/timer.h> diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c index 01b85e3..0405e83 100644 --- a/drivers/video/riva/rivafb-i2c.c +++ b/drivers/video/riva/rivafb-i2c.c @@ -14,7 +14,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ccef56d..ed34260 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -791,6 +791,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; + info->dev = &pdev->dev; + platform_set_drvdata(pdev, fbinfo); dprintk("devinit\n"); diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 1411f3b..8db066c 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/fb.h> diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index b604859..7478d0e 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> @@ -1864,20 +1864,14 @@ config CIFS file servers such as Windows 2000 (including Windows 2003, NT 4 and Windows XP) as well by Samba (which provides excellent CIFS server support for Linux and many other operating systems). Limited - support for Windows ME and similar servers is provided as well. - You must use the smbfs client filesystem to access older SMB servers - such as OS/2 and DOS. + support for OS/2 and Windows ME and similar servers is provided as well. The intent of the cifs module is to provide an advanced - network file system client for mounting to CIFS compliant servers, + network file system client for mounting to CIFS compliant servers, including support for dfs (hierarchical name space), secure per-user session establishment, safe distributed caching (oplock), optional - packet signing, Unicode and other internationalization improvements, - and optional Winbind (nsswitch) integration. You do not need to enable - cifs if running only a (Samba) server. It is possible to enable both - smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003 - and Samba 3 servers, and smbfs for accessing old servers). If you need - to mount to Samba or Windows from this machine, say Y. + packet signing, Unicode and other internationalization improvements. + If you need to mount to Samba or Windows from this machine, say Y. config CIFS_STATS bool "CIFS statistics" @@ -1970,14 +1964,13 @@ config CIFS_EXPERIMENTAL depends on CIFS && EXPERIMENTAL help Enables cifs features under testing. These features are - experimental and currently include support for writepages - (multipage writebehind performance improvements) and directory - change notification ie fcntl(F_DNOTIFY) as well as some security - improvements. Some also depend on setting at runtime the - pseudo-file /proc/fs/cifs/Experimental (which is disabled by - default). See the file fs/cifs/README for more details. - - If unsure, say N. + experimental and currently include DFS support and directory + change notification ie fcntl(F_DNOTIFY), as well as the upcall + mechanism which will be used for Kerberos session negotiation + and uid remapping. Some of these features also may depend on + setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental + (which is disabled by default). See the file fs/cifs/README + for more details. If unsure, say N. config CIFS_UPCALL bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" diff --git a/fs/afs/cell.c b/fs/afs/cell.c index bfc1fd2..1fc5783 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/slab.h> #include <rxrpc/peer.h> #include <rxrpc/connection.h> diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 9908462..b6dc2eb 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> diff --git a/fs/afs/file.c b/fs/afs/file.c index eeff14c..b176345 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 6f37754..9d9bca6 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> diff --git a/fs/afs/main.c b/fs/afs/main.c index 913c689..f2704ba 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/completion.h> #include <rxrpc/rxrpc.h> #include <rxrpc/transport.h> diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index fdf23b2..68495f0 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 86463ec..ae6b85b 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/proc_fs.h> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 669dbe5..51db118 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -76,7 +76,8 @@ static struct linux_binfmt elf_format = { .load_binary = load_elf_binary, .load_shlib = load_elf_library, .core_dump = elf_core_dump, - .min_coredump = ELF_EXEC_PAGESIZE + .min_coredump = ELF_EXEC_PAGESIZE, + .hasvdso = 1 }; #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 85e3850..5fe1359 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,8 +1,15 @@ Version 1.47 ------------ Fix oops in list_del during mount caused by unaligned string. +Fix file corruption which could occur on some large file +copies caused by writepages page i/o completion bug. Seek to SEEK_END forces check for update of file size for non-cached -files. +files. Allow file size to be updated on remote extend of locally open, +non-cached file. Fix reconnect to newer Samba servers (or other servers +which support the CIFS Unix/POSIX extensions) so that we again tell the +server the Unix/POSIX cifs capabilities which we support (SetFSInfo). +Add experimental support for new POSIX Open/Mkdir (which returns +stat information on the open, and allows setting the mode). Version 1.46 ------------ diff --git a/fs/cifs/TODO b/fs/cifs/TODO index fc34c74..6837294 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -128,3 +128,11 @@ negotiated size) and send larger write sizes to modern servers. 4) More exhaustively test against less common servers. More testing against Windows 9x, Windows ME servers. + +DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too) + +mount check for unmatched uids - and uid override + +Add mount option for Linux extension disable per mount, and partial disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?) + +Free threads at umount --force that are stuck on the sesSem diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 01ae24a..c97c08e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.47" +#define CIFS_VERSION "1.48" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 068ef51e..7d95054 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifspdu.h * - * Copyright (c) International Business Machines Corp., 2002,2005 + * Copyright (c) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -544,7 +544,8 @@ typedef union smb_com_session_setup_andx { /* unsigned char * NativeOS; */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/ + } __attribute__((packed)) resp; /* NTLM response + (with or without extended sec) */ struct { /* request format */ struct smb_hdr hdr; /* wct = 10 */ @@ -795,6 +796,8 @@ typedef struct smb_com_openx_rsp { __u16 ByteCount; } __attribute__((packed)) OPENX_RSP; +/* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */ + /* Legacy write request for older servers */ typedef struct smb_com_writex_req { struct smb_hdr hdr; /* wct = 12 */ @@ -1352,11 +1355,13 @@ struct smb_t2_rsp { #define SMB_QUERY_FILE_UNIX_BASIC 0x200 #define SMB_QUERY_FILE_UNIX_LINK 0x201 #define SMB_QUERY_POSIX_ACL 0x204 -#define SMB_QUERY_XATTR 0x205 +#define SMB_QUERY_XATTR 0x205 /* e.g. system EA name space */ #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ #define SMB_QUERY_POSIX_PERMISSION 0x207 #define SMB_QUERY_POSIX_LOCK 0x208 -/* #define SMB_POSIX_OPEN 0x209 */ +/* #define SMB_POSIX_OPEN 0x209 */ +/* #define SMB_POSIX_UNLINK 0x20a */ +#define SMB_QUERY_FILE__UNIX_INFO2 0x20b #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ @@ -1377,8 +1382,10 @@ struct smb_t2_rsp { #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ #define SMB_SET_POSIX_LOCK 0x208 #define SMB_POSIX_OPEN 0x209 +#define SMB_POSIX_UNLINK 0x20a +#define SMB_SET_FILE_UNIX_INFO2 #define SMB_SET_FILE_BASIC_INFO2 0x3ec -#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ +#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */ #define SMB_FILE_ALL_INFO2 0x3fa #define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb #define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc @@ -1428,7 +1435,7 @@ typedef struct smb_com_transaction2_qpi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; - __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ + __u16 Reserved2; /* parameter word is present for infolevels > 100 */ } __attribute__((packed)) TRANSACTION2_QPI_RSP; typedef struct smb_com_transaction2_spi_req { @@ -1461,7 +1468,7 @@ typedef struct smb_com_transaction2_spi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; - __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ + __u16 Reserved2; /* parameter word is present for infolevels > 100 */ } __attribute__((packed)) TRANSACTION2_SPI_RSP; struct set_file_rename { @@ -1627,6 +1634,7 @@ typedef struct smb_com_transaction2_fnext_rsp_parms { #define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105 #define SMB_QUERY_CIFS_UNIX_INFO 0x200 #define SMB_QUERY_POSIX_FS_INFO 0x201 +#define SMB_QUERY_POSIX_WHO_AM_I 0x202 #define SMB_QUERY_LABEL_INFO 0x3ea #define SMB_QUERY_FS_QUOTA_INFO 0x3ee #define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef @@ -1659,9 +1667,21 @@ typedef struct smb_com_transaction_qfsi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; - __u8 Pad; /* may be three bytes *//* followed by data area */ + __u8 Pad; /* may be three bytes? *//* followed by data area */ } __attribute__((packed)) TRANSACTION2_QFSI_RSP; +typedef struct whoami_rsp_data { /* Query level 0x202 */ + __u32 flags; /* 0 = Authenticated user 1 = GUEST */ + __u32 mask; /* which flags bits server understands ie 0x0001 */ + __u64 unix_user_id; + __u64 unix_user_gid; + __u32 number_of_supplementary_gids; /* may be zero */ + __u32 number_of_sids; /* may be zero */ + __u32 length_of_sid_array; /* in bytes - may be zero */ + __u32 pad; /* reserved - MBZ */ + /* __u64 gid_array[0]; */ /* may be empty */ + /* __u8 * psid_list */ /* may be empty */ +} __attribute__((packed)) WHOAMI_RSP_DATA; /* SETFSInfo Levels */ #define SMB_SET_CIFS_UNIX_INFO 0x200 @@ -1858,8 +1878,11 @@ typedef struct { #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */ +#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based + calls including posix open + and posix unlink */ #ifdef CONFIG_CIFS_POSIX -#define CIFS_UNIX_CAP_MASK 0x0000001b +#define CIFS_UNIX_CAP_MASK 0x0000003b #else #define CIFS_UNIX_CAP_MASK 0x00000013 #endif /* CONFIG_CIFS_POSIX */ @@ -1946,7 +1969,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */ __le32 AlignmentRequirement; __le32 FileNameLength; char FileName[1]; -} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ +} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ /* defines for enumerating possible values of the Unix type field below */ #define UNIX_FILE 0 @@ -1970,11 +1993,11 @@ typedef struct { __u64 UniqueId; __le64 Permissions; __le64 Nlinks; -} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ +} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ typedef struct { char LinkDest[1]; -} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ +} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ /* The following three structures are needed only for setting time to NT4 and some older servers via @@ -2011,7 +2034,7 @@ typedef struct { __le64 ChangeTime; __le32 Attributes; __u32 Pad; -} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ +} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ struct file_allocation_info { __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ @@ -2020,7 +2043,7 @@ struct file_allocation_info { struct file_end_of_file_info { __le64 FileSize; /* offset to end of file */ -} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ +} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ struct file_alt_name_info { __u8 alt_name[1]; @@ -2075,6 +2098,19 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ /* end of POSIX ACL definitions */ +typedef struct { + __u32 OpenFlags; /* same as NT CreateX */ + __u32 PosixOpenFlags; + __u32 Mode; + __u16 Level; /* reply level requested (see QPathInfo levels) */ + __u16 Pad; /* reserved - MBZ */ +} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ + +typedef struct { + /* reply varies based on requested level */ +} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ + + struct file_internal_info { __u64 UniqueId; /* inode number */ } __attribute__((packed)); /* level 0x3ee */ @@ -2238,7 +2274,8 @@ struct data_blob { 1) PosixCreateX - to set and return the mode, inode#, device info and perhaps add a CreateDevice - to create Pipes and other special .inodes Also note POSIX open flags - 2) Close - to return the last write time to do cache across close more safely + 2) Close - to return the last write time to do cache across close + more safely 3) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) 4) Mkdir - set mode @@ -2273,7 +2310,8 @@ struct data_blob { TRANSACTION2 (18 cases) SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2 (BB verify that never need to set allocation size) - SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?) + SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via + Unix ext?) COPY (note support for copy across directories) - FUTURE, OPTIONAL setting/getting OS/2 EAs - FUTURE (BB can this handle @@ -2293,13 +2331,13 @@ struct data_blob { T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields Actually need QUERY_FILE_UNIX_INFO since has inode num BB what about a) blksize/blkbits/blocks - b) i_version - c) i_rdev - d) notify mask? - e) generation - f) size_seqcount + b) i_version + c) i_rdev + d) notify mask? + e) generation + f) size_seqcount T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX - TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended + TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL @@ -2338,7 +2376,7 @@ typedef struct file_xattr_info { __u32 xattr_value_len; char xattr_name[0]; /* followed by xattr_value[xattr_value_len], no pad */ -} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ +} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ /* flags for chattr command */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f1f8225..6148b82 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -23,6 +23,7 @@ #include <linux/nls.h> struct statfs; +struct smb_vol; /* ***************************************************************** @@ -57,7 +58,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ , int * /* bytes returned */); extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); -extern int is_size_safe_to_change(struct cifsInodeInfo *); +extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); @@ -147,6 +148,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, unsigned int *pnum_referrals, unsigned char ** preferrals, int remap); +extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, + struct super_block * sb, struct smb_vol * vol); extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData); extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 472e33e..b8e9147 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -158,9 +158,15 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, nls_codepage); if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { mark_open_files_invalid(tcon); - rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon - , nls_codepage); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, + tcon, nls_codepage); up(&tcon->ses->sesSem); + /* tell server which Unix caps we support */ + if (tcon->ses->capabilities & CAP_UNIX) + reset_cifs_unix_caps(0 /* no xid */, + tcon, + NULL /* we do not know sb */, + NULL /* no vol info */); /* BB FIXME add code to check if wsize needs update due to negotiated smb buffer size shrinking */ @@ -298,6 +304,12 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); up(&tcon->ses->sesSem); + /* tell server which Unix caps we support */ + if (tcon->ses->capabilities & CAP_UNIX) + reset_cifs_unix_caps(0 /* no xid */, + tcon, + NULL /* do not know sb */, + NULL /* no vol info */); /* BB FIXME add code to check if wsize needs update due to negotiated smb buffer size shrinking */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2caca06..20ba7dc 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1613,6 +1613,76 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) return rc; } +void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon, + struct super_block * sb, struct smb_vol * vol_info) +{ + /* if we are reconnecting then should we check to see if + * any requested capabilities changed locally e.g. via + * remount but we can not do much about it here + * if they have (even if we could detect it by the following) + * Perhaps we could add a backpointer to array of sb from tcon + * or if we change to make all sb to same share the same + * sb as NFS - then we only have one backpointer to sb. + * What if we wanted to mount the server share twice once with + * and once without posixacls or posix paths? */ + __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); + + + if(!CIFSSMBQFSUnixInfo(xid, tcon)) { + __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); + + /* check for reconnect case in which we do not + want to change the mount behavior if we can avoid it */ + if(vol_info == NULL) { + /* turn off POSIX ACL and PATHNAMES if not set + originally at mount time */ + if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0) + cap &= ~CIFS_UNIX_POSIX_ACL_CAP; + if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) + cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; + + + + + } + + cap &= CIFS_UNIX_CAP_MASK; + if(vol_info && vol_info->no_psx_acl) + cap &= ~CIFS_UNIX_POSIX_ACL_CAP; + else if(CIFS_UNIX_POSIX_ACL_CAP & cap) { + cFYI(1,("negotiated posix acl support")); + if(sb) + sb->s_flags |= MS_POSIXACL; + } + + if(vol_info && vol_info->posix_paths == 0) + cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; + else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + cFYI(1,("negotiate posix pathnames")); + if(sb) + CIFS_SB(sb)->mnt_cifs_flags |= + CIFS_MOUNT_POSIX_PATHS; + } + + cFYI(1,("Negotiate caps 0x%x",(int)cap)); +#ifdef CONFIG_CIFS_DEBUG2 + if(cap & CIFS_UNIX_FCNTL_CAP) + cFYI(1,("FCNTL cap")); + if(cap & CIFS_UNIX_EXTATTR_CAP) + cFYI(1,("EXTATTR cap")); + if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) + cFYI(1,("POSIX path cap")); + if(cap & CIFS_UNIX_XATTR_CAP) + cFYI(1,("XATTR cap")); + if(cap & CIFS_UNIX_POSIX_ACL_CAP) + cFYI(1,("POSIX ACL cap")); +#endif /* CIFS_DEBUG2 */ + if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { + cFYI(1,("setting capabilities failed")); + } + } +} + int cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, char *mount_data, const char *devname) @@ -1928,20 +1998,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (tcon == NULL) rc = -ENOMEM; else { - /* check for null share name ie connect to dfs root */ + /* check for null share name ie connecting to + * dfs root */ - /* BB check if this works for exactly length three strings */ + /* BB check if this works for exactly length + * three strings */ if ((strchr(volume_info.UNC + 3, '\\') == NULL) && (strchr(volume_info.UNC + 3, '/') == NULL)) { rc = connect_to_dfs_path(xid, pSesInfo, - "", cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + "", cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); kfree(volume_info.UNC); FreeXid(xid); return -ENODEV; } else { + /* BB Do we need to wrap sesSem around + * this TCon call and Unix SetFS as + * we do on SessSetup and reconnect? */ rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, tcon, cifs_sb->local_nls); @@ -1962,6 +2037,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ } + /* BB FIXME fix time_gran to be larger for LANMAN sessions */ sb->s_time_gran = 100; /* on error free sesinfo and tcon struct if needed */ @@ -2006,45 +2082,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* do not care if following two calls succeed - informational */ CIFSSMBQFSDeviceInfo(xid, tcon); CIFSSMBQFSAttributeInfo(xid, tcon); - - if (tcon->ses->capabilities & CAP_UNIX) { - if(!CIFSSMBQFSUnixInfo(xid, tcon)) { - __u64 cap = - le64_to_cpu(tcon->fsUnixInfo.Capability); - cap &= CIFS_UNIX_CAP_MASK; - if(volume_info.no_psx_acl) - cap &= ~CIFS_UNIX_POSIX_ACL_CAP; - else if(CIFS_UNIX_POSIX_ACL_CAP & cap) { - cFYI(1,("negotiated posix acl support")); - sb->s_flags |= MS_POSIXACL; - } - - if(volume_info.posix_paths == 0) - cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; - else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { - cFYI(1,("negotiate posix pathnames")); - cifs_sb->mnt_cifs_flags |= - CIFS_MOUNT_POSIX_PATHS; - } - - cFYI(1,("Negotiate caps 0x%x",(int)cap)); -#ifdef CONFIG_CIFS_DEBUG2 - if(cap & CIFS_UNIX_FCNTL_CAP) - cFYI(1,("FCNTL cap")); - if(cap & CIFS_UNIX_EXTATTR_CAP) - cFYI(1,("EXTATTR cap")); - if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) - cFYI(1,("POSIX path cap")); - if(cap & CIFS_UNIX_XATTR_CAP) - cFYI(1,("XATTR cap")); - if(cap & CIFS_UNIX_POSIX_ACL_CAP) - cFYI(1,("POSIX ACL cap")); -#endif /* CIFS_DEBUG2 */ - if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { - cFYI(1,("setting capabilities failed")); - } - } - } + + /* tell server which Unix caps we support */ + if (tcon->ses->capabilities & CAP_UNIX) + reset_cifs_unix_caps(xid, tcon, sb, &volume_info); + if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) cifs_sb->wsize = min(cifs_sb->wsize, (tcon->ses->server->maxBuf - diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e9dcf5e..07ff935 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1954,7 +1954,7 @@ static int cifs_readpage(struct file *file, struct page *page) refreshing the inode only on increases in the file size but this is tricky to do without racing with writebehind page caching in the current Linux kernel design */ -int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) +int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) { struct cifsFileInfo *open_file = NULL; @@ -1976,6 +1976,9 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) return 1; } + if(i_size_read(&cifsInode->vfs_inode) < end_of_file) + return 1; + return 0; } else return 1; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index c4fa91b..3f5bc83 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -140,7 +140,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_gid = le64_to_cpu(findData.Gid); inode->i_nlink = le64_to_cpu(findData.Nlinks); - if (is_size_safe_to_change(cifsInfo)) { + if (is_size_safe_to_change(cifsInfo, end_of_file)) { /* can not safely change the file size here if the client is writing to it due to potential races */ @@ -491,8 +491,8 @@ int cifs_get_inode_info(struct inode **pinode, /* BB add code here - validate if device or weird share or device type? */ } - if (is_size_safe_to_change(cifsInfo)) { - /* can not safely change the file size here if the + if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) { + /* can not safely shrink the file size here if the client is writing to it due to potential races */ i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 782940b..c6220bd 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -222,7 +222,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, atomic_set(&cifsInfo->inUse, 1); } - if (is_size_safe_to_change(cifsInfo)) { + if (is_size_safe_to_change(cifsInfo, end_of_file)) { /* can not safely change the file size here if the client is writing to it due to potential races */ i_size_write(tmp_inode, end_of_file); @@ -351,10 +351,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode, tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); - if (is_size_safe_to_change(cifsInfo)) { + if (is_size_safe_to_change(cifsInfo, end_of_file)) { /* can not safely change the file size here if the client is writing to it due to potential races */ - i_size_write(tmp_inode,end_of_file); + i_size_write(tmp_inode, end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, not the real blocksize */ diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index db3b1a9..c57a1fa 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c @@ -33,8 +33,6 @@ static struct ctl_table_header *fs_table_header; -#define FS_CODA 1 /* Coda file system */ - #define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */ #define CODA_HARD 5 /* mount type "hard" or "soft" */ #define CODA_VFS 6 /* vfs statistics */ @@ -183,17 +181,57 @@ static const struct file_operations proc_cache_inv_stats_fops = { }; static ctl_table coda_table[] = { - {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, - {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec}, - {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats}, - {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats}, - {CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec}, - { 0 } + { + .ctl_name = CTL_UNNUMBERED, + .procname = "timeout", + .data = &coda_timeout, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "hard", + .data = &coda_hard, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "vfs_stats", + .data = NULL, + .maxlen = 0, + .mode = 0644, + .proc_handler = &do_reset_coda_vfs_stats + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "cache_inv_stats", + .data = NULL, + .maxlen = 0, + .mode = 0644, + .proc_handler = &do_reset_coda_cache_inv_stats + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "fake_statfs", + .data = &coda_fake_statfs, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec + }, + {} }; static ctl_table fs_table[] = { - {FS_CODA, "coda", NULL, 0, 0555, coda_table}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "coda", + .mode = 0555, + .child = coda_table + }, + {} }; @@ -233,7 +271,7 @@ void coda_sysctl_init(void) #ifdef CONFIG_SYSCTL if ( !fs_table_header ) - fs_table_header = register_sysctl_table(fs_table, 0); + fs_table_header = register_sysctl_table(fs_table); #endif } diff --git a/fs/dcache.c b/fs/dcache.c index b5f6139..d68631f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1739,41 +1739,45 @@ shouldnt_be_hashed: * @rootmnt: vfsmnt to which the root dentry belongs * @buffer: buffer to return value in * @buflen: buffer length - * @fail_deleted: what to return for deleted files * - * Convert a dentry into an ASCII path name. If the entry has been deleted, - * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise, - * the the string " (deleted)" is appended. Note that this is ambiguous. + * Convert a dentry into an ASCII path name. If the entry has been deleted + * the string " (deleted)" is appended. Note that this is ambiguous. * - * Returns the buffer or an error code. + * Returns the buffer or an error code if the path was too long. + * + * "buflen" should be positive. Caller holds the dcache_lock. */ -static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, - struct dentry *root, struct vfsmount *rootmnt, - char *buffer, int buflen, int fail_deleted) +static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, + struct dentry *root, struct vfsmount *rootmnt, + char *buffer, int buflen) { - int namelen, is_slash; - - if (buflen < 2) - return ERR_PTR(-ENAMETOOLONG); - buffer += --buflen; - *buffer = '\0'; + char * end = buffer+buflen; + char * retval; + int namelen; - spin_lock(&dcache_lock); + *--end = '\0'; + buflen--; if (!IS_ROOT(dentry) && d_unhashed(dentry)) { - if (fail_deleted) { - buffer = ERR_PTR(-ENOENT); - goto out; - } - if (buflen < 10) - goto Elong; buflen -= 10; - buffer -= 10; - memcpy(buffer, " (deleted)", 10); + end -= 10; + if (buflen < 0) + goto Elong; + memcpy(end, " (deleted)", 10); } - while (dentry != root || vfsmnt != rootmnt) { + + if (buflen < 1) + goto Elong; + /* Get '/' right */ + retval = end-1; + *retval = '/'; + + for (;;) { struct dentry * parent; + if (dentry == root && vfsmnt == rootmnt) + break; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { + /* Global root? */ spin_lock(&vfsmount_lock); if (vfsmnt->mnt_parent == vfsmnt) { spin_unlock(&vfsmount_lock); @@ -1787,60 +1791,33 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, parent = dentry->d_parent; prefetch(parent); namelen = dentry->d_name.len; - if (buflen <= namelen) - goto Elong; buflen -= namelen + 1; - buffer -= namelen; - memcpy(buffer, dentry->d_name.name, namelen); - *--buffer = '/'; + if (buflen < 0) + goto Elong; + end -= namelen; + memcpy(end, dentry->d_name.name, namelen); + *--end = '/'; + retval = end; dentry = parent; } - /* Get '/' right */ - if (*buffer != '/') - *--buffer = '/'; -out: - spin_unlock(&dcache_lock); - return buffer; + return retval; global_root: - /* - * We went past the (vfsmount, dentry) we were looking for and have - * either hit a root dentry, a lazily unmounted dentry, an - * unconnected dentry, or the file is on a pseudo filesystem. - */ namelen = dentry->d_name.len; - is_slash = (namelen == 1 && *dentry->d_name.name == '/'); - if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) { - /* - * Make sure we won't return a pathname starting with '/'. - * - * Historically, we also glue together the root dentry and - * remaining name for pseudo filesystems like pipefs, which - * have the MS_NOUSER flag set. This results in pathnames - * like "pipe:[439336]". - */ - if (*buffer == '/') { - buffer++; - buflen++; - } - if (is_slash) - goto out; - } - if (buflen < namelen) + buflen -= namelen; + if (buflen < 0) goto Elong; - buffer -= namelen; - memcpy(buffer, dentry->d_name.name, namelen); - goto out; - + retval -= namelen-1; /* hit the slash */ + memcpy(retval, dentry->d_name.name, namelen); + return retval; Elong: - buffer = ERR_PTR(-ENAMETOOLONG); - goto out; + return ERR_PTR(-ENAMETOOLONG); } /* write full pathname into buffer and return start of pathname */ -char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, - int buflen) +char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, + char *buf, int buflen) { char *res; struct vfsmount *rootmnt; @@ -1850,7 +1827,9 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, rootmnt = mntget(current->fs->rootmnt); root = dget(current->fs->root); read_unlock(¤t->fs->lock); - res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0); + spin_lock(&dcache_lock); + res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); + spin_unlock(&dcache_lock); dput(root); mntput(rootmnt); return res; @@ -1876,10 +1855,10 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, */ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) { - int error, len; + int error; struct vfsmount *pwdmnt, *rootmnt; struct dentry *pwd, *root; - char *page = (char *) __get_free_page(GFP_USER), *cwd; + char *page = (char *) __get_free_page(GFP_USER); if (!page) return -ENOMEM; @@ -1891,18 +1870,29 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) root = dget(current->fs->root); read_unlock(¤t->fs->lock); - cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1); - error = PTR_ERR(cwd); - if (IS_ERR(cwd)) - goto out; + error = -ENOENT; + /* Has the current directory has been unlinked? */ + spin_lock(&dcache_lock); + if (pwd->d_parent == pwd || !d_unhashed(pwd)) { + unsigned long len; + char * cwd; - error = -ERANGE; - len = PAGE_SIZE + page - cwd; - if (len <= size) { - error = len; - if (copy_to_user(buf, cwd, len)) - error = -EFAULT; - } + cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); + spin_unlock(&dcache_lock); + + error = PTR_ERR(cwd); + if (IS_ERR(cwd)) + goto out; + + error = -ERANGE; + len = PAGE_SIZE + page - cwd; + if (len <= size) { + error = len; + if (copy_to_user(buf, cwd, len)) + error = -EFAULT; + } + } else + spin_unlock(&dcache_lock); out: dput(pwd); @@ -1841,7 +1841,7 @@ static int __init dquot_init(void) printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); - register_sysctl_table(sys_table, 0); + register_sysctl_table(sys_table); dquot_cachep = kmem_cache_create("dquot", sizeof(struct dquot), sizeof(unsigned long) * 4, diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index b3609b7..403e3ba 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -467,6 +467,7 @@ extern struct kmem_cache *ecryptfs_header_cache_1; extern struct kmem_cache *ecryptfs_header_cache_2; extern struct kmem_cache *ecryptfs_xattr_cache; extern struct kmem_cache *ecryptfs_lower_page_cache; +extern struct kmem_cache *ecryptfs_key_record_cache; int ecryptfs_interpose(struct dentry *hidden_dentry, struct dentry *this_dentry, struct super_block *sb, diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index c209f67..b550dea 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -26,7 +26,6 @@ */ #include <linux/string.h> -#include <linux/sched.h> #include <linux/syscalls.h> #include <linux/pagemap.h> #include <linux/key.h> @@ -1639,6 +1638,8 @@ out: return rc; } +struct kmem_cache *ecryptfs_key_record_cache; + /** * ecryptfs_generate_key_packet_set * @dest: Virtual address from which to write the key record set @@ -1665,50 +1666,55 @@ ecryptfs_generate_key_packet_set(char *dest_base, &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; size_t written; - struct ecryptfs_key_record key_rec; + struct ecryptfs_key_record *key_rec; int rc = 0; (*len) = 0; + key_rec = kmem_cache_alloc(ecryptfs_key_record_cache, GFP_KERNEL); + if (!key_rec) { + rc = -ENOMEM; + goto out; + } if (mount_crypt_stat->global_auth_tok) { auth_tok = mount_crypt_stat->global_auth_tok; if (auth_tok->token_type == ECRYPTFS_PASSWORD) { rc = write_tag_3_packet((dest_base + (*len)), max, auth_tok, - crypt_stat, &key_rec, + crypt_stat, key_rec, &written); if (rc) { ecryptfs_printk(KERN_WARNING, "Error " "writing tag 3 packet\n"); - goto out; + goto out_free; } (*len) += written; /* Write auth tok signature packet */ rc = write_tag_11_packet( (dest_base + (*len)), (max - (*len)), - key_rec.sig, ECRYPTFS_SIG_SIZE, &written); + key_rec->sig, ECRYPTFS_SIG_SIZE, &written); if (rc) { ecryptfs_printk(KERN_ERR, "Error writing " "auth tok signature packet\n"); - goto out; + goto out_free; } (*len) += written; } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { rc = write_tag_1_packet(dest_base + (*len), max, auth_tok, crypt_stat,mount_crypt_stat, - &key_rec, &written); + key_rec, &written); if (rc) { ecryptfs_printk(KERN_WARNING, "Error " "writing tag 1 packet\n"); - goto out; + goto out_free; } (*len) += written; } else { ecryptfs_printk(KERN_WARNING, "Unsupported " "authentication token type\n"); rc = -EINVAL; - goto out; + goto out_free; } } else BUG(); @@ -1718,6 +1724,9 @@ ecryptfs_generate_key_packet_set(char *dest_base, ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n"); rc = -EIO; } + +out_free: + kmem_cache_free(ecryptfs_key_record_cache, key_rec); out: if (rc) (*len) = 0; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 26fe405..80044d1 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -651,6 +651,11 @@ static struct ecryptfs_cache_info { .name = "ecryptfs_lower_page_cache", .size = PAGE_CACHE_SIZE, }, + { + .cache = &ecryptfs_key_record_cache, + .name = "ecryptfs_key_record_cache", + .size = sizeof(struct ecryptfs_key_record), + }, }; static void ecryptfs_free_kmem_caches(void) diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 47d7e7b..3baf253 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -169,7 +169,8 @@ int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid) if (!new_id) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable " - "to register daemon [%d] for user\n", pid, uid); + "to register daemon [%d] for user [%d]\n", + pid, uid); goto unlock; } if (!ecryptfs_find_daemon_id(uid, &old_id)) { diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c index deeb27b..c30e149 100644 --- a/fs/ext3/hash.c +++ b/fs/ext3/hash.c @@ -11,7 +11,6 @@ #include <linux/fs.h> #include <linux/jbd.h> -#include <linux/sched.h> #include <linux/ext3_fs.h> #include <linux/cryptohash.h> diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index b73cba1..ecf8990 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -11,7 +11,6 @@ #define EXT3FS_DEBUG -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/ext3_jbd.h> diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index a679663..1555024 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -11,7 +11,6 @@ #include <linux/fs.h> #include <linux/jbd2.h> -#include <linux/sched.h> #include <linux/ext4_fs.h> #include <linux/cryptohash.h> diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 4fe49c3..ea99f6c 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -11,7 +11,6 @@ #define EXT4FS_DEBUG -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/ext4_jbd2.h> diff --git a/fs/filesystems.c b/fs/filesystems.c index e3fa77c..7a4f61a 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -12,7 +12,6 @@ #include <linux/kmod.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/sched.h> /* for 'current' */ #include <asm/uaccess.h> /* diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 113f6c9..c53a5d2 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index c93ca8f..82a1ac7 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -53,7 +53,6 @@ * but never before the maximum hash table size has been reached. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/buffer_head.h> diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index cd747c0..c1f4400 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 0c83c7f..5b83ca6 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index c4b0391..46af553 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index e30673d..cfcc39b 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 7c1a9e2..6e8a598 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index ef3092e..32caecd 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index f2495f1..d9ecfd2 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index 9187eb1..c6bac6b 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 4855e8c..1de05b6 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index c996aa7..b50180e 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 60f47bf..d85f6e0 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 14b380f..aa0dbd2 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index d0c806b..8bc182c 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index ff08465..8d9c08b 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index e5707a9..601eaa1 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -7,7 +7,6 @@ * of the GNU General Public License version 2. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index f2d7c49..ba117c4 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -8,7 +8,6 @@ * Handling of catalog records */ -#include <linux/sched.h> #include "hfsplus_fs.h" #include "hfsplus_raw.h" diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 7813700..80b5682 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -10,7 +10,6 @@ #include <linux/errno.h> #include <linux/fs.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/random.h> diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 5a282f6..1a97f92 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/pagemap.h> #include <linux/fs.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/vfs.h> #include <linux/nls.h> diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 3681d07..0c1fc6e 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -16,7 +16,6 @@ #endif #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/zlib.h> #include <linux/zutil.h> diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index cdbe2fe..9fa2e27 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -13,7 +13,6 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/fs.h> #include <linux/crc32.h> #include <linux/jffs2.h> diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 2526596..30f8884 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -14,7 +14,6 @@ */ #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/pagemap.h> diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 0b4acc1..a5c019e 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -361,7 +361,6 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * { struct nlm_host *host = req->a_host; struct rpc_clnt *clnt; - int status = -ENOLCK; dprintk("lockd: call procedure %d on %s (async)\n", (int)proc, host->h_name); @@ -373,12 +372,10 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * msg->rpc_proc = &clnt->cl_procinfo[proc]; /* bootstrap and kick off the async RPC call */ - status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); - if (status == 0) - return 0; + return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); out_err: - nlm_release_call(req); - return status; + tk_ops->rpc_release(req); + return -ENOLCK; } int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 22d4032..ad21c07 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -9,7 +9,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/in.h> #include <linux/sunrpc/clnt.h> diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 80fcacc..50cb8da 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -512,7 +512,7 @@ module_param(nsm_use_hostnames, bool, 0644); static int __init init_nlm(void) { - nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root, 0); + nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); return nlm_sysctl_table ? 0 : -ENOMEM; } diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index c7db0a5..cf51f84 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -593,9 +593,7 @@ callback: /* Call the client */ kref_get(&block->b_count); - if (nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, - &nlmsvc_grant_ops) < 0) - nlmsvc_release_block(block); + nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); } /* @@ -2688,10 +2688,11 @@ int __page_symlink(struct inode *inode, const char *symname, int len, { struct address_space *mapping = inode->i_mapping; struct page *page; - int err = -ENOMEM; + int err; char *kaddr; retry: + err = -ENOMEM; page = find_or_create_page(mapping, 0, gfp_mask); if (!page) goto fail; diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ae9f36e..2190e6c 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -394,7 +394,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, static int nfs_create_rpc_client(struct nfs_client *clp, int proto, unsigned int timeo, unsigned int retrans, - rpc_authflavor_t flavor) + rpc_authflavor_t flavor, + int flags) { struct rpc_timeout timeparms; struct rpc_clnt *clnt = NULL; @@ -407,6 +408,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, .program = &nfs_program, .version = clp->rpc_ops->version, .authflavor = flavor, + .flags = flags, }; if (!IS_ERR(clp->cl_rpcclient)) @@ -548,7 +550,7 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data * * - RFC 2623, sec 2.3.2 */ error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, - RPC_AUTH_UNIX); + RPC_AUTH_UNIX, 0); if (error < 0) goto error; nfs_mark_client_ready(clp, NFS_CS_READY); @@ -868,7 +870,8 @@ static int nfs4_init_client(struct nfs_client *clp, /* Check NFS protocol revision and initialize RPC op vector */ clp->rpc_ops = &nfs_v4_clientops; - error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour); + error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour, + RPC_CLNT_CREATE_DISCRTRY); if (error < 0) goto error; memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); @@ -1030,7 +1033,7 @@ error: * Create an NFS4 referral server record */ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, - struct nfs_fh *fh) + struct nfs_fh *mntfh) { struct nfs_client *parent_client; struct nfs_server *server, *parent_server; @@ -1069,8 +1072,13 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, BUG_ON(!server->nfs_client->rpc_ops); BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); + /* Probe the root fh to retrieve its FSID and filehandle */ + error = nfs4_path_walk(server, mntfh, data->mnt_path); + if (error < 0) + goto error; + /* probe the filesystem info for this server filesystem */ - error = nfs_probe_fsinfo(server, fh, &fattr); + error = nfs_probe_fsinfo(server, mntfh, &fattr); if (error < 0) goto error; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f03a770..92d8ec8 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -637,7 +637,7 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. */ -static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) +static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { if (IS_ROOT(dentry)) return 1; @@ -652,6 +652,12 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) dentry->d_fsdata = (void *)verf; } +static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) +{ + if (time_after(verf, (unsigned long)dentry->d_fsdata)) + nfs_set_verifier(dentry, verf); +} + /* * Whenever an NFS operation succeeds, we know that the dentry * is valid, so we update the revalidation timestamp. @@ -785,7 +791,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) goto out_bad; nfs_renew_times(dentry); - nfs_set_verifier(dentry, verifier); + nfs_refresh_verifier(dentry, verifier); out_valid: unlock_kernel(); dput(parent); @@ -1085,7 +1091,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) verifier = nfs_save_change_attribute(dir); ret = nfs4_open_revalidate(dir, dentry, openflags, nd); if (!ret) - nfs_set_verifier(dentry, verifier); + nfs_refresh_verifier(dentry, verifier); unlock_kernel(); out: dput(parent); @@ -1123,8 +1129,21 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) } name.hash = full_name_hash(name.name, name.len); dentry = d_lookup(parent, &name); - if (dentry != NULL) - return dentry; + if (dentry != NULL) { + /* Is this a positive dentry that matches the readdir info? */ + if (dentry->d_inode != NULL && + (NFS_FILEID(dentry->d_inode) == entry->ino || + d_mountpoint(dentry))) { + if (!desc->plus || entry->fh->size == 0) + return dentry; + if (nfs_compare_fh(NFS_FH(dentry->d_inode), + entry->fh) == 0) + goto out_renew; + } + /* No, so d_drop to allow one to be created */ + d_drop(dentry); + dput(dentry); + } if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR)) return NULL; /* Note: caller is already holding the dir->i_mutex! */ @@ -1149,6 +1168,10 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); return dentry; +out_renew: + nfs_renew_times(dentry); + nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir)); + return dentry; } /* @@ -1443,6 +1466,8 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) if (atomic_read(&dentry->d_count) > 1) { spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); + /* Start asynchronous writeout of the inode */ + write_inode_now(dentry->d_inode, 0); error = nfs_sillyrename(dir, dentry); unlock_kernel(); return error; @@ -1684,7 +1709,7 @@ out: if (!error) { d_move(old_dentry, new_dentry); nfs_renew_times(new_dentry); - nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir)); + nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir)); } /* new dentry created? */ diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index bd21d7f..b1c98ea 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -309,7 +309,8 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo rpc_execute(&data->task); - dfprintk(VFS, "NFS: %5u initiated direct read call (req %s/%Ld, %zu bytes @ offset %Lu)\n", + dprintk("NFS: %5u initiated direct read call " + "(req %s/%Ld, %zu bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), @@ -639,7 +640,8 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l rpc_execute(&data->task); - dfprintk(VFS, "NFS: %5u initiated direct write call (req %s/%Ld, %zu bytes @ offset %Lu)\n", + dprintk("NFS: %5u initiated direct write call " + "(req %s/%Ld, %zu bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), @@ -797,7 +799,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, const char __user *buf = iov[0].iov_base; size_t count = iov[0].iov_len; - dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", + dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, (unsigned long) count, (long long) pos); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 8391bd7..6ef268f 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -135,17 +135,15 @@ int nfs4_path_walk(struct nfs_server *server, struct nfs_fh lastfh; struct qstr name; int ret; - //int referral_count = 0; dprintk("--> nfs4_path_walk(,,%s)\n", path); fsinfo.fattr = &fattr; nfs_fattr_init(&fattr); - if (*path++ != '/') { - dprintk("nfs4_get_root: Path does not begin with a slash\n"); - return -EINVAL; - } + /* Eat leading slashes */ + while (*path == '/') + path++; /* Start by getting the root filehandle from the server */ ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); @@ -160,6 +158,7 @@ int nfs4_path_walk(struct nfs_server *server, return -ENOTDIR; } + /* FIXME: It is quite valid for the server to return a referral here */ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { printk(KERN_ERR "nfs4_get_root:" " getroot obtained referral\n"); @@ -187,6 +186,7 @@ eat_dot_dir: goto eat_dot_dir; } + /* FIXME: Why shouldn't the user be able to use ".." in the path? */ if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) ) { printk(KERN_ERR "nfs4_get_root:" @@ -212,6 +212,7 @@ eat_dot_dir: return -ENOTDIR; } + /* FIXME: Referrals are quite valid here too */ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { printk(KERN_ERR "nfs4_get_root:" " lookupfh obtained referral\n"); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d834982..af53c02 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -65,13 +65,18 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) int nfs_write_inode(struct inode *inode, int sync) { - int flags = sync ? FLUSH_SYNC : 0; int ret; - ret = nfs_commit_inode(inode, flags); - if (ret < 0) - return ret; - return 0; + if (sync) { + ret = filemap_fdatawait(inode->i_mapping); + if (ret == 0) + ret = nfs_commit_inode(inode, FLUSH_SYNC); + } else + ret = nfs_commit_inode(inode, 0); + if (ret >= 0) + return 0; + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + return ret; } void nfs_clear_inode(struct inode *inode) @@ -235,6 +240,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) if (inode->i_state & I_NEW) { struct nfs_inode *nfsi = NFS_I(inode); + unsigned long now = jiffies; /* We set i_ino for the few things that still rely on it, * such as stat(2) */ @@ -271,7 +277,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) init_special_inode(inode, inode->i_mode, fattr->rdev); nfsi->read_cache_jiffies = fattr->time_start; - nfsi->last_updated = jiffies; + nfsi->last_updated = now; + nfsi->cache_change_attribute = now; inode->i_atime = fattr->atime; inode->i_mtime = fattr->mtime; inode->i_ctime = fattr->ctime; @@ -290,7 +297,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) inode->i_blocks = fattr->du.nfs2.blocks; } nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); - nfsi->attrtimeo_timestamp = jiffies; + nfsi->attrtimeo_timestamp = now; memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); nfsi->access_cache = RB_ROOT; @@ -783,20 +790,21 @@ void nfs_end_data_update(struct inode *inode) static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) { struct nfs_inode *nfsi = NFS_I(inode); + unsigned long now = jiffies; /* If we have atomic WCC data, we may update some attributes */ if ((fattr->valid & NFS_ATTR_WCC) != 0) { if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) { memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; } if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; } if (inode->i_size == fattr->pre_size && nfsi->npages == 0) { inode->i_size = fattr->size; - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; } } } @@ -934,6 +942,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_isize, new_isize; unsigned int invalid = 0; + unsigned long now = jiffies; int data_stable; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", @@ -959,7 +968,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) * Update the read time so we don't revalidate too often. */ nfsi->read_cache_jiffies = fattr->time_start; - nfsi->last_updated = jiffies; + nfsi->last_updated = now; + + /* Fix a wraparound issue with nfsi->cache_change_attribute */ + if (time_before(now, nfsi->cache_change_attribute)) + nfsi->cache_change_attribute = now - 600*HZ; /* Are we racing with known updates of the metadata on the server? */ data_stable = nfs_verify_change_attribute(inode, fattr->time_start); @@ -985,7 +998,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; dprintk("NFS: isize change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); } @@ -996,14 +1009,14 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) dprintk("NFS: mtime change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; } /* If ctime has changed we should definitely clear access+acl caches */ if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; } memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); @@ -1032,18 +1045,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_sb->s_id, inode->i_ino); nfsi->change_attr = fattr->change_attr; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; - nfsi->cache_change_attribute = jiffies; + nfsi->cache_change_attribute = now; } /* Update attrtimeo value if we're out of the unstable period */ if (invalid & NFS_INO_INVALID_ATTR) { nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); - nfsi->attrtimeo_timestamp = jiffies; - } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { + nfsi->attrtimeo_timestamp = now; + } else if (time_after(now, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); - nfsi->attrtimeo_timestamp = jiffies; + nfsi->attrtimeo_timestamp = now; } /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) @@ -1122,7 +1135,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb) return NULL; nfsi->flags = 0UL; nfsi->cache_validity = 0UL; - nfsi->cache_change_attribute = jiffies; #ifdef CONFIG_NFS_V3_ACL nfsi->acl_access = ERR_PTR(-EAGAIN); nfsi->acl_default = ERR_PTR(-EAGAIN); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index a28f6ce..6610f2b 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -107,10 +107,6 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); /* nfs4proc.c */ #ifdef CONFIG_NFS_V4 extern struct rpc_procinfo nfs4_procedures[]; - -extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, - struct nfs4_fs_locations *fs_locations, - struct page *page); #endif /* dir.c */ diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index acd8fe9..7d0371e 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -253,29 +253,6 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, return status; } -static int nfs3_proc_read(struct nfs_read_data *rdata) -{ - int flags = rdata->flags; - struct inode * inode = rdata->inode; - struct nfs_fattr * fattr = rdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_READ], - .rpc_argp = &rdata->args, - .rpc_resp = &rdata->res, - .rpc_cred = rdata->cred, - }; - int status; - - dprintk("NFS call read %d @ %Ld\n", rdata->args.count, - (long long) rdata->args.offset); - nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); - if (status >= 0) - nfs_refresh_inode(inode, fattr); - dprintk("NFS reply read: %d\n", status); - return status; -} - /* * Create a regular file. * For now, we don't implement O_EXCL. @@ -855,7 +832,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .lookup = nfs3_proc_lookup, .access = nfs3_proc_access, .readlink = nfs3_proc_readlink, - .read = nfs3_proc_read, .create = nfs3_proc_create, .remove = nfs3_proc_remove, .unlink_setup = nfs3_proc_unlink_setup, diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index e234176..cf3a17e 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -169,7 +169,7 @@ extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); -extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, +extern int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page); extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index b872779..dd5fef2 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -16,6 +16,7 @@ #include <linux/vfs.h> #include <linux/inet.h> #include "internal.h" +#include "nfs4_fs.h" #define NFSDBG_FACILITY NFSDBG_VFS @@ -130,7 +131,6 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, }; char *page = NULL, *page2 = NULL; - char *devname; int loc, s, error; if (locations == NULL || locations->nlocations <= 0) @@ -154,12 +154,6 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, goto out; } - devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); - if (IS_ERR(devname)) { - mnt = (struct vfsmount *)devname; - goto out; - } - loc = 0; while (loc < locations->nlocations && IS_ERR(mnt)) { const struct nfs4_fs_location *location = &locations->locations[loc]; @@ -194,7 +188,11 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, addr.sin_port = htons(NFS_PORT); mountdata.addr = &addr; - mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata); + snprintf(page, PAGE_SIZE, "%s:%s", + mountdata.hostname, + mountdata.mnt_path); + + mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, &mountdata); if (!IS_ERR(mnt)) { break; } @@ -242,7 +240,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name); - err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); + err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); dput(parent); if (err != 0 || fs_locations->nlocations <= 0 || diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1daee65..f52cf5c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1140,7 +1140,6 @@ static void nfs4_close_done(struct rpc_task *task, void *data) break; case -NFS4ERR_STALE_STATEID: case -NFS4ERR_EXPIRED: - nfs4_schedule_state_recovery(server->nfs_client); break; default: if (nfs4_async_handle_error(task, server) == -EAGAIN) { @@ -1424,7 +1423,6 @@ static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fa int status = -ENOMEM; struct page *page = NULL; struct nfs4_fs_locations *locations = NULL; - struct dentry dentry = {}; page = alloc_page(GFP_KERNEL); if (page == NULL) @@ -1433,9 +1431,7 @@ static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fa if (locations == NULL) goto out; - dentry.d_name.name = name->name; - dentry.d_name.len = name->len; - status = nfs4_proc_fs_locations(dir, &dentry, locations, page); + status = nfs4_proc_fs_locations(dir, name, locations, page); if (status != 0) goto out; /* Make sure server returned a different fsid for the referral */ @@ -1737,44 +1733,6 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page, return err; } -static int _nfs4_proc_read(struct nfs_read_data *rdata) -{ - int flags = rdata->flags; - struct inode *inode = rdata->inode; - struct nfs_fattr *fattr = rdata->res.fattr; - struct nfs_server *server = NFS_SERVER(inode); - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], - .rpc_argp = &rdata->args, - .rpc_resp = &rdata->res, - .rpc_cred = rdata->cred, - }; - unsigned long timestamp = jiffies; - int status; - - dprintk("NFS call read %d @ %Ld\n", rdata->args.count, - (long long) rdata->args.offset); - - nfs_fattr_init(fattr); - status = rpc_call_sync(server->client, &msg, flags); - if (!status) - renew_lease(server, timestamp); - dprintk("NFS reply read: %d\n", status); - return status; -} - -static int nfs4_proc_read(struct nfs_read_data *rdata) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = nfs4_handle_exception(NFS_SERVER(rdata->inode), - _nfs4_proc_read(rdata), - &exception); - } while (exception.retry); - return err; -} - /* * Got race? * We will need to arrange for the VFS layer to provide an atomic open. @@ -2753,11 +2711,15 @@ static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) might_sleep(); + rwsem_acquire(&clp->cl_sem.dep_map, 0, 0, _RET_IP_); + rpc_clnt_sigmask(clnt, &oldset); res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, nfs4_wait_bit_interruptible, TASK_INTERRUPTIBLE); rpc_clnt_sigunmask(clnt, &oldset); + + rwsem_release(&clp->cl_sem.dep_map, 1, _RET_IP_); return res; } @@ -2996,7 +2958,6 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 switch (err) { case -NFS4ERR_STALE_STATEID: case -NFS4ERR_EXPIRED: - nfs4_schedule_state_recovery(server->nfs_client); case 0: return 0; } @@ -3150,12 +3111,10 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) break; case -NFS4ERR_STALE_STATEID: case -NFS4ERR_EXPIRED: - nfs4_schedule_state_recovery(calldata->server->nfs_client); break; default: - if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { + if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) rpc_restart_call(task); - } } } @@ -3585,7 +3544,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) return len; } -int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, +int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page) { struct nfs_server *server = NFS_SERVER(dir); @@ -3595,7 +3554,7 @@ int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, }; struct nfs4_fs_locations_arg args = { .dir_fh = NFS_FH(dir), - .name = &dentry->d_name, + .name = name, .page = page, .bitmask = bitmask, }; @@ -3607,7 +3566,7 @@ int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, int status; dprintk("%s: start\n", __FUNCTION__); - fs_locations->fattr.valid = 0; + nfs_fattr_init(&fs_locations->fattr); fs_locations->server = server; fs_locations->nlocations = 0; status = rpc_call_sync(server->client, &msg, 0); @@ -3646,7 +3605,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = { .lookup = nfs4_proc_lookup, .access = nfs4_proc_access, .readlink = nfs4_proc_readlink, - .read = nfs4_proc_read, .create = nfs4_proc_create, .remove = nfs4_proc_remove, .unlink_setup = nfs4_proc_unlink_setup, diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 8232985..f5f4430 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -43,7 +43,6 @@ * child task framework of the RPC layer? */ -#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/pagemap.h> diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0cf3fa3..f02d522 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -387,8 +387,10 @@ static int nfs4_stat_to_errno(int); decode_putfh_maxsz + \ op_decode_hdr_maxsz + 12) #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ encode_getattr_maxsz) #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ decode_getattr_maxsz) #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 560536a..1dcf56d 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -186,35 +186,6 @@ static int nfs_proc_readlink(struct inode *inode, struct page *page, return status; } -static int nfs_proc_read(struct nfs_read_data *rdata) -{ - int flags = rdata->flags; - struct inode * inode = rdata->inode; - struct nfs_fattr * fattr = rdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_READ], - .rpc_argp = &rdata->args, - .rpc_resp = &rdata->res, - .rpc_cred = rdata->cred, - }; - int status; - - dprintk("NFS call read %d @ %Ld\n", rdata->args.count, - (long long) rdata->args.offset); - nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); - if (status >= 0) { - nfs_refresh_inode(inode, fattr); - /* Emulate the eof flag, which isn't normally needed in NFSv2 - * as it is guaranteed to always return the file attributes - */ - if (rdata->args.offset + rdata->args.count >= fattr->size) - rdata->res.eof = 1; - } - dprintk("NFS reply read: %d\n", status); - return status; -} - static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd) @@ -666,7 +637,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { .lookup = nfs_proc_lookup, .access = NULL, /* access */ .readlink = nfs_proc_readlink, - .read = nfs_proc_read, .create = nfs_proc_create, .remove = nfs_proc_remove, .unlink_setup = nfs_proc_unlink_setup, diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a9c2652..6ab4d5a 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -5,14 +5,6 @@ * * Partial copy of Linus' read cache modifications to fs/nfs/file.c * modified for async RPC by okir@monad.swb.de - * - * We do an ugly hack here in order to return proper error codes to the - * user program when a read request failed: since generic_file_read - * only checks the return value of inode->i_op->readpage() which is always 0 - * for async RPC, we set the error bit of the page to 1 when an error occurs, - * and make nfs_readpage transmit requests synchronously when encountering this. - * This is only a small problem, though, since we now retry all operations - * within the RPC code when root squashing is suspected. */ #include <linux/time.h> @@ -122,93 +114,6 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) } } -/* - * Read a page synchronously. - */ -static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, - struct page *page) -{ - unsigned int rsize = NFS_SERVER(inode)->rsize; - unsigned int count = PAGE_CACHE_SIZE; - int result = -ENOMEM; - struct nfs_read_data *rdata; - - rdata = nfs_readdata_alloc(count); - if (!rdata) - goto out_unlock; - - memset(rdata, 0, sizeof(*rdata)); - rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); - rdata->cred = ctx->cred; - rdata->inode = inode; - INIT_LIST_HEAD(&rdata->pages); - rdata->args.fh = NFS_FH(inode); - rdata->args.context = ctx; - rdata->args.pages = &page; - rdata->args.pgbase = 0UL; - rdata->args.count = rsize; - rdata->res.fattr = &rdata->fattr; - - dprintk("NFS: nfs_readpage_sync(%p)\n", page); - - /* - * This works now because the socket layer never tries to DMA - * into this buffer directly. - */ - do { - if (count < rsize) - rdata->args.count = count; - rdata->res.count = rdata->args.count; - rdata->args.offset = page_offset(page) + rdata->args.pgbase; - - dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", - NFS_SERVER(inode)->nfs_client->cl_hostname, - inode->i_sb->s_id, - (long long)NFS_FILEID(inode), - (unsigned long long)rdata->args.pgbase, - rdata->args.count); - - lock_kernel(); - result = NFS_PROTO(inode)->read(rdata); - unlock_kernel(); - - /* - * Even if we had a partial success we can't mark the page - * cache valid. - */ - if (result < 0) { - if (result == -EISDIR) - result = -EINVAL; - goto io_error; - } - count -= result; - rdata->args.pgbase += result; - nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, result); - - /* Note: result == 0 should only happen if we're caching - * a write that extends the file and punches a hole. - */ - if (rdata->res.eof != 0 || result == 0) - break; - } while (count); - spin_lock(&inode->i_lock); - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; - spin_unlock(&inode->i_lock); - - if (rdata->res.eof || rdata->res.count == rdata->args.count) { - SetPageUptodate(page); - if (rdata->res.eof && count != 0) - memclear_highpage_flush(page, rdata->args.pgbase, count); - } - result = 0; - -io_error: - nfs_readdata_free(rdata); -out_unlock: - unlock_page(page); - return result; -} - static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, struct page *page) { @@ -278,7 +183,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, data->task.tk_cookie = (unsigned long)inode; - dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", + dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), @@ -452,7 +357,7 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) { int status; - dprintk("%s: %4d, (status %d)\n", __FUNCTION__, task->tk_pid, + dprintk("NFS: %s: %5u, (status %d)\n", __FUNCTION__, task->tk_pid, task->tk_status); status = NFS_PROTO(data->inode)->read_done(task, data); @@ -621,15 +526,9 @@ int nfs_readpage(struct file *file, struct page *page) } else ctx = get_nfs_open_context((struct nfs_open_context *) file->private_data); - if (!IS_SYNC(inode)) { - error = nfs_readpage_async(ctx, inode, page); - goto out; - } - error = nfs_readpage_sync(ctx, inode, page); - if (error < 0 && IS_SWAPFILE(inode)) - printk("Aiee.. nfs swap-in of page failed!\n"); -out: + error = nfs_readpage_async(ctx, inode, page); + put_nfs_open_context(ctx); return error; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index baa2886..bb516a2 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1045,7 +1045,7 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, nfs4_fill_super(s); } - mntroot = nfs4_get_root(s, data->fh); + mntroot = nfs4_get_root(s, &mntfh); if (IS_ERR(mntroot)) { error = PTR_ERR(mntroot); goto error_splat_super; diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 3ea50ac..fcdcafb 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c @@ -75,7 +75,7 @@ static ctl_table nfs_cb_sysctl_root[] = { int nfs_register_sysctl(void) { - nfs_callback_sysctl_table = register_sysctl_table(nfs_cb_sysctl_root, 0); + nfs_callback_sysctl_table = register_sysctl_table(nfs_cb_sysctl_root); if (nfs_callback_sysctl_table == NULL) return -ENOMEM; return 0; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 345492e..febdade 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1,47 +1,7 @@ /* * linux/fs/nfs/write.c * - * Writing file data over NFS. - * - * We do it like this: When a (user) process wishes to write data to an - * NFS file, a write request is allocated that contains the RPC task data - * plus some info on the page to be written, and added to the inode's - * write chain. If the process writes past the end of the page, an async - * RPC call to write the page is scheduled immediately; otherwise, the call - * is delayed for a few seconds. - * - * Just like readahead, no async I/O is performed if wsize < PAGE_SIZE. - * - * Write requests are kept on the inode's writeback list. Each entry in - * that list references the page (portion) to be written. When the - * cache timeout has expired, the RPC task is woken up, and tries to - * lock the page. As soon as it manages to do so, the request is moved - * from the writeback list to the writelock list. - * - * Note: we must make sure never to confuse the inode passed in the - * write_page request with the one in page->inode. As far as I understand - * it, these are different when doing a swap-out. - * - * To understand everything that goes on here and in the NFS read code, - * one should be aware that a page is locked in exactly one of the following - * cases: - * - * - A write request is in progress. - * - A user process is in generic_file_write/nfs_update_page - * - A user process is in generic_file_read - * - * Also note that because of the way pages are invalidated in - * nfs_revalidate_inode, the following assertions hold: - * - * - If a page is dirty, there will be no read requests (a page will - * not be re-read unless invalidated by nfs_revalidate_inode). - * - If the page is not uptodate, there will be no pending write - * requests, and no process will be in nfs_update_page. - * - * FIXME: Interaction with the vmscan routines is not optimal yet. - * Either vmscan must be made nfs-savvy, or we need a different page - * reclaim concept that supports something like FS-independent - * buffer_heads with a b_ops-> field. + * Write file data over NFS. * * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> */ @@ -79,7 +39,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, unsigned int, unsigned int); static void nfs_mark_request_dirty(struct nfs_page *req); static int nfs_wait_on_write_congestion(struct address_space *, int); -static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); static const struct rpc_call_ops nfs_write_partial_ops; static const struct rpc_call_ops nfs_write_full_ops; @@ -194,6 +153,13 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c i_size_write(inode, end); } +/* A writeback failed: mark the page as bad, and invalidate the page cache */ +static void nfs_set_pageerror(struct page *page) +{ + SetPageError(page); + nfs_zap_mapping(page->mapping->host, page->mapping); +} + /* We can set the PG_uptodate flag if we see that a write request * covers the full page. */ @@ -323,7 +289,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc err = 0; out: if (!wbc->for_writepages) - nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); + nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc)); return err; } @@ -360,14 +326,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) if (err < 0) goto out; nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); - if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { - err = nfs_wait_on_requests(inode, 0, 0); - if (err < 0) - goto out; - } - err = nfs_commit_inode(inode, wb_priority(wbc)); - if (err > 0) - err = 0; + err = 0; out: clear_bit(BDI_write_congested, &bdi->state); wake_up_all(&nfs_write_congestion); @@ -516,17 +475,6 @@ static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_st return res; } -static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) -{ - struct nfs_inode *nfsi = NFS_I(inode); - int ret; - - spin_lock(&nfsi->req_lock); - ret = nfs_wait_on_requests_locked(inode, idx_start, npages); - spin_unlock(&nfsi->req_lock); - return ret; -} - static void nfs_cancel_dirty_list(struct list_head *head) { struct nfs_page *req; @@ -773,7 +721,7 @@ int nfs_updatepage(struct file *file, struct page *page, dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", status, (long long)i_size_read(inode)); if (status < 0) - ClearPageUptodate(page); + nfs_set_pageerror(page); return status; } @@ -852,7 +800,8 @@ static void nfs_write_rpcsetup(struct nfs_page *req, data->task.tk_priority = flush_task_priority(how); data->task.tk_cookie = (unsigned long)inode; - dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", + dprintk("NFS: %5u initiated write call " + "(req %s/%Ld, %u bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), @@ -1034,8 +983,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) return; if (task->tk_status < 0) { - ClearPageUptodate(page); - SetPageError(page); + nfs_set_pageerror(page); req->wb_context->error = task->tk_status; dprintk(", error = %d\n", task->tk_status); } else { @@ -1092,8 +1040,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) (long long)req_offset(req)); if (task->tk_status < 0) { - ClearPageUptodate(page); - SetPageError(page); + nfs_set_pageerror(page); req->wb_context->error = task->tk_status; end_page_writeback(page); nfs_inode_remove_request(req); @@ -1134,7 +1081,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) struct nfs_writeres *resp = &data->res; int status; - dprintk("NFS: %4d nfs_writeback_done (status %d)\n", + dprintk("NFS: %5u nfs_writeback_done (status %d)\n", task->tk_pid, task->tk_status); /* @@ -1250,7 +1197,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, data->task.tk_priority = flush_task_priority(how); data->task.tk_cookie = (unsigned long)inode; - dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); + dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); } /* @@ -1291,7 +1238,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) struct nfs_write_data *data = calldata; struct nfs_page *req; - dprintk("NFS: %4d nfs_commit_done (status %d)\n", + dprintk("NFS: %5u nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); /* Call the NFS version-specific code */ @@ -1516,6 +1463,8 @@ int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) if (ret < 0) goto out; } + if (!PagePrivate(page)) + return 0; ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); if (ret >= 0) return 0; diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 49c310b..6f24768 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -16,7 +16,6 @@ #include <linux/unistd.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/stat.h> #include <linux/in.h> #include <linux/seq_file.h> @@ -190,18 +189,17 @@ static int expkey_show(struct seq_file *m, struct cache_head *h) { struct svc_expkey *ek ; + int i; if (h ==NULL) { seq_puts(m, "#domain fsidtype fsid [path]\n"); return 0; } ek = container_of(h, struct svc_expkey, h); - seq_printf(m, "%s %d 0x%08x", ek->ek_client->name, - ek->ek_fsidtype, ek->ek_fsid[0]); - if (ek->ek_fsidtype != 1) - seq_printf(m, "%08x", ek->ek_fsid[1]); - if (ek->ek_fsidtype == 2) - seq_printf(m, "%08x", ek->ek_fsid[2]); + seq_printf(m, "%s %d 0x", ek->ek_client->name, + ek->ek_fsidtype); + for (i=0; i < key_len(ek->ek_fsidtype)/4; i++) + seq_printf(m, "%08x", ek->ek_fsid[i]); if (test_bit(CACHE_VALID, &h->flags) && !test_bit(CACHE_NEGATIVE, &h->flags)) { seq_printf(m, " "); @@ -232,9 +230,8 @@ static inline void expkey_init(struct cache_head *cnew, kref_get(&item->ek_client->ref); new->ek_client = item->ek_client; new->ek_fsidtype = item->ek_fsidtype; - new->ek_fsid[0] = item->ek_fsid[0]; - new->ek_fsid[1] = item->ek_fsid[1]; - new->ek_fsid[2] = item->ek_fsid[2]; + + memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid)); } static inline void expkey_update(struct cache_head *cnew, @@ -363,7 +360,7 @@ static struct svc_export *svc_export_update(struct svc_export *new, struct svc_export *old); static struct svc_export *svc_export_lookup(struct svc_export *); -static int check_export(struct inode *inode, int flags) +static int check_export(struct inode *inode, int flags, unsigned char *uuid) { /* We currently export only dirs and regular files. @@ -376,12 +373,13 @@ static int check_export(struct inode *inode, int flags) /* There are two requirements on a filesystem to be exportable. * 1: We must be able to identify the filesystem from a number. * either a device number (so FS_REQUIRES_DEV needed) - * or an FSID number (so NFSEXP_FSID needed). + * or an FSID number (so NFSEXP_FSID or ->uuid is needed). * 2: We must be able to find an inode from a filehandle. * This means that s_export_op must be set. */ if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && - !(flags & NFSEXP_FSID)) { + !(flags & NFSEXP_FSID) && + uuid == NULL) { dprintk("exp_export: export of non-dev fs without fsid\n"); return -EINVAL; } @@ -406,10 +404,6 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) int len; int migrated, i, err; - len = qword_get(mesg, buf, PAGE_SIZE); - if (len != 5 || memcmp(buf, "fsloc", 5)) - return 0; - /* listsize */ err = get_int(mesg, &fsloc->locations_count); if (err) @@ -520,6 +514,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) exp.ex_fslocs.locations_count = 0; exp.ex_fslocs.migrated = 0; + exp.ex_uuid = NULL; + /* flags */ err = get_int(&mesg, &an_int); if (err == -ENOENT) @@ -543,12 +539,33 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) if (err) goto out; exp.ex_fsid = an_int; - err = check_export(nd.dentry->d_inode, exp.ex_flags); - if (err) goto out; + while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { + if (strcmp(buf, "fsloc") == 0) + err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); + else if (strcmp(buf, "uuid") == 0) { + /* expect a 16 byte uuid encoded as \xXXXX... */ + len = qword_get(&mesg, buf, PAGE_SIZE); + if (len != 16) + err = -EINVAL; + else { + exp.ex_uuid = + kmemdup(buf, 16, GFP_KERNEL); + if (exp.ex_uuid == NULL) + err = -ENOMEM; + } + } else + /* quietly ignore unknown words and anything + * following. Newer user-space can try to set + * new values, then see what the result was. + */ + break; + if (err) + goto out; + } - err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); - if (err) - goto out; + err = check_export(nd.dentry->d_inode, exp.ex_flags, + exp.ex_uuid); + if (err) goto out; } expp = svc_export_lookup(&exp); @@ -562,6 +579,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) else exp_put(expp); out: + nfsd4_fslocs_free(&exp.ex_fslocs); + kfree(exp.ex_uuid); kfree(exp.ex_path); if (nd.dentry) path_release(&nd); @@ -591,9 +610,19 @@ static int svc_export_show(struct seq_file *m, seq_escape(m, exp->ex_client->name, " \t\n\\"); seq_putc(m, '('); if (test_bit(CACHE_VALID, &h->flags) && - !test_bit(CACHE_NEGATIVE, &h->flags)) + !test_bit(CACHE_NEGATIVE, &h->flags)) { exp_flags(m, exp->ex_flags, exp->ex_fsid, exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); + if (exp->ex_uuid) { + int i; + seq_puts(m, ",uuid="); + for (i=0; i<16; i++) { + if ((i&3) == 0 && i) + seq_putc(m, ':'); + seq_printf(m, "%02x", exp->ex_uuid[i]); + } + } + } seq_puts(m, ")\n"); return 0; } @@ -630,6 +659,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) new->ex_anon_uid = item->ex_anon_uid; new->ex_anon_gid = item->ex_anon_gid; new->ex_fsid = item->ex_fsid; + new->ex_uuid = item->ex_uuid; + item->ex_uuid = NULL; new->ex_path = item->ex_path; item->ex_path = NULL; new->ex_fslocs.locations = item->ex_fslocs.locations; @@ -752,11 +783,11 @@ exp_get_key(svc_client *clp, dev_t dev, ino_t ino) u32 fsidv[3]; if (old_valid_dev(dev)) { - mk_fsid_v0(fsidv, dev, ino); - return exp_find_key(clp, 0, fsidv, NULL); + mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL); + return exp_find_key(clp, FSID_DEV, fsidv, NULL); } - mk_fsid_v3(fsidv, dev, ino); - return exp_find_key(clp, 3, fsidv, NULL); + mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL); + return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL); } /* @@ -767,9 +798,9 @@ exp_get_fsid_key(svc_client *clp, int fsid) { u32 fsidv[2]; - mk_fsid_v1(fsidv, fsid); + mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL); - return exp_find_key(clp, 1, fsidv, NULL); + return exp_find_key(clp, FSID_NUM, fsidv, NULL); } svc_export * @@ -883,8 +914,8 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) if ((exp->ex_flags & NFSEXP_FSID) == 0) return 0; - mk_fsid_v1(fsid, exp->ex_fsid); - return exp_set_key(clp, 1, fsid, exp); + mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL); + return exp_set_key(clp, FSID_NUM, fsid, exp); } static int exp_hash(struct auth_domain *clp, struct svc_export *exp) @@ -894,11 +925,11 @@ static int exp_hash(struct auth_domain *clp, struct svc_export *exp) dev_t dev = inode->i_sb->s_dev; if (old_valid_dev(dev)) { - mk_fsid_v0(fsid, dev, inode->i_ino); - return exp_set_key(clp, 0, fsid, exp); + mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL); + return exp_set_key(clp, FSID_DEV, fsid, exp); } - mk_fsid_v3(fsid, dev, inode->i_ino); - return exp_set_key(clp, 3, fsid, exp); + mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL); + return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp); } static void exp_unhash(struct svc_export *exp) @@ -977,7 +1008,7 @@ exp_export(struct nfsctl_export *nxp) goto finish; } - err = check_export(nd.dentry->d_inode, nxp->ex_flags); + err = check_export(nd.dentry->d_inode, nxp->ex_flags, NULL); if (err) goto finish; err = -ENOMEM; @@ -1170,9 +1201,9 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, __be32 rv; u32 fsidv[2]; - mk_fsid_v1(fsidv, 0); + mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); - exp = exp_find(clp, 1, fsidv, creq); + exp = exp_find(clp, FSID_NUM, fsidv, creq); if (IS_ERR(exp)) return nfserrno(PTR_ERR(exp)); if (exp == NULL) diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index e695660..6f67798 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -149,6 +149,27 @@ decode_sattr3(__be32 *p, struct iattr *iap) return p; } +static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) +{ + u64 f; + switch(fsid_source(fhp)) { + default: + case FSIDSOURCE_DEV: + p = xdr_encode_hyper(p, (u64)huge_encode_dev + (fhp->fh_dentry->d_inode->i_sb->s_dev)); + break; + case FSIDSOURCE_FSID: + p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); + break; + case FSIDSOURCE_UUID: + f = ((u64*)fhp->fh_export->ex_uuid)[0]; + f ^= ((u64*)fhp->fh_export->ex_uuid)[1]; + p = xdr_encode_hyper(p, f); + break; + } + return p; +} + static __be32 * encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) @@ -169,10 +190,7 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); *p++ = htonl((u32) MAJOR(stat->rdev)); *p++ = htonl((u32) MINOR(stat->rdev)); - if (is_fsid(fhp, rqstp->rq_reffh)) - p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); - else - p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev)); + p = encode_fsid(p, fhp); p = xdr_encode_hyper(p, (u64) stat->ino); p = encode_time3(p, &stat->atime); lease_get_mtime(dentry->d_inode, &time); @@ -203,10 +221,7 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); *p++ = fhp->fh_post_rdev[0]; *p++ = fhp->fh_post_rdev[1]; - if (is_fsid(fhp, rqstp->rq_reffh)) - p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); - else - p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev)); + p = encode_fsid(p, fhp); p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, &fhp->fh_post_atime); p = encode_time3(p, &fhp->fh_post_mtime); diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 5d94555..832673b 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -61,9 +61,11 @@ /* flags used to simulate posix default ACLs */ #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ - | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE) + | NFS4_ACE_DIRECTORY_INHERIT_ACE) -#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP) +#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \ + | NFS4_ACE_INHERIT_ONLY_ACE \ + | NFS4_ACE_IDENTIFIER_GROUP) #define MASK_EQUAL(mask1, mask2) \ ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) ) @@ -87,12 +89,19 @@ mask_from_posix(unsigned short perm, unsigned int flags) } static u32 -deny_mask(u32 allow_mask, unsigned int flags) +deny_mask_from_posix(unsigned short perm, u32 flags) { - u32 ret = ~allow_mask & ~NFS4_MASK_UNSUPP; - if (!(flags & NFS4_ACL_DIR)) - ret &= ~NFS4_ACE_DELETE_CHILD; - return ret; + u32 mask = 0; + + if (perm & ACL_READ) + mask |= NFS4_READ_MODE; + if (perm & ACL_WRITE) + mask |= NFS4_WRITE_MODE; + if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) + mask |= NFS4_ACE_DELETE_CHILD; + if (perm & ACL_EXECUTE) + mask |= NFS4_EXECUTE_MODE; + return mask; } /* XXX: modify functions to return NFS errors; they're only ever @@ -126,108 +135,151 @@ struct ace_container { }; static short ace2type(struct nfs4_ace *); -static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); -static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int); -int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); -static int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *); +static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, + unsigned int); +void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); struct nfs4_acl * nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, unsigned int flags) { struct nfs4_acl *acl; - int error = -EINVAL; + int size = 0; - if ((pacl != NULL && - (posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) || - (dpacl != NULL && - (posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0))) - goto out_err; - - acl = nfs4_acl_new(); - if (acl == NULL) { - error = -ENOMEM; - goto out_err; + if (pacl) { + if (posix_acl_valid(pacl) < 0) + return ERR_PTR(-EINVAL); + size += 2*pacl->a_count; } - - if (pacl != NULL) { - error = _posix_to_nfsv4_one(pacl, acl, - flags & ~NFS4_ACL_TYPE_DEFAULT); - if (error < 0) - goto out_acl; + if (dpacl) { + if (posix_acl_valid(dpacl) < 0) + return ERR_PTR(-EINVAL); + size += 2*dpacl->a_count; } - if (dpacl != NULL) { - error = _posix_to_nfsv4_one(dpacl, acl, - flags | NFS4_ACL_TYPE_DEFAULT); - if (error < 0) - goto out_acl; - } + /* Allocate for worst case: one (deny, allow) pair each: */ + acl = nfs4_acl_new(size); + if (acl == NULL) + return ERR_PTR(-ENOMEM); - return acl; + if (pacl) + _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT); -out_acl: - nfs4_acl_free(acl); -out_err: - acl = ERR_PTR(error); + if (dpacl) + _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT); return acl; } -static int -nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype, - uid_t owner, unsigned int flags) +struct posix_acl_summary { + unsigned short owner; + unsigned short users; + unsigned short group; + unsigned short groups; + unsigned short other; + unsigned short mask; +}; + +static void +summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) { - int error; - - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, - eflag, mask, whotype, owner); - if (error < 0) - return error; - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, - eflag, deny_mask(mask, flags), whotype, owner); - return error; + struct posix_acl_entry *pa, *pe; + pas->users = 0; + pas->groups = 0; + pas->mask = 07; + + pe = acl->a_entries + acl->a_count; + + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch (pa->e_tag) { + case ACL_USER_OBJ: + pas->owner = pa->e_perm; + break; + case ACL_GROUP_OBJ: + pas->group = pa->e_perm; + break; + case ACL_USER: + pas->users |= pa->e_perm; + break; + case ACL_GROUP: + pas->groups |= pa->e_perm; + break; + case ACL_OTHER: + pas->other = pa->e_perm; + break; + case ACL_MASK: + pas->mask = pa->e_perm; + break; + } + } + /* We'll only care about effective permissions: */ + pas->users &= pas->mask; + pas->group &= pas->mask; + pas->groups &= pas->mask; } /* We assume the acl has been verified with posix_acl_valid. */ -static int +static void _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, unsigned int flags) { - struct posix_acl_entry *pa, *pe, *group_owner_entry; - int error = -EINVAL; - u32 mask, mask_mask; + struct posix_acl_entry *pa, *group_owner_entry; + struct nfs4_ace *ace; + struct posix_acl_summary pas; + unsigned short deny; int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? NFS4_INHERITANCE_FLAGS : 0); BUG_ON(pacl->a_count < 3); - pe = pacl->a_entries + pacl->a_count; - pa = pe - 2; /* if mask entry exists, it's second from the last. */ - if (pa->e_tag == ACL_MASK) - mask_mask = deny_mask(mask_from_posix(pa->e_perm, flags), flags); - else - mask_mask = 0; + summarize_posix_acl(pacl, &pas); pa = pacl->a_entries; - BUG_ON(pa->e_tag != ACL_USER_OBJ); - mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); - error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags); - if (error < 0) - goto out; - pa++; + ace = acl->aces + acl->naces; - while (pa->e_tag == ACL_USER) { - mask = mask_from_posix(pa->e_perm, flags); - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, - eflag, mask_mask, NFS4_ACL_WHO_NAMED, pa->e_id); - if (error < 0) - goto out; + /* We could deny everything not granted by the owner: */ + deny = ~pas.owner; + /* + * but it is equivalent (and simpler) to deny only what is not + * granted by later entries: + */ + deny &= pas.users | pas.group | pas.groups | pas.other; + if (deny) { + ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; + ace->flag = eflag; + ace->access_mask = deny_mask_from_posix(deny, flags); + ace->whotype = NFS4_ACL_WHO_OWNER; + ace++; + acl->naces++; + } + ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; + ace->flag = eflag; + ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); + ace->whotype = NFS4_ACL_WHO_OWNER; + ace++; + acl->naces++; + pa++; - error = nfs4_acl_add_pair(acl, eflag, mask, - NFS4_ACL_WHO_NAMED, pa->e_id, flags); - if (error < 0) - goto out; + while (pa->e_tag == ACL_USER) { + deny = ~(pa->e_perm & pas.mask); + deny &= pas.groups | pas.group | pas.other; + if (deny) { + ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; + ace->flag = eflag; + ace->access_mask = deny_mask_from_posix(deny, flags); + ace->whotype = NFS4_ACL_WHO_NAMED; + ace->who = pa->e_id; + ace++; + acl->naces++; + } + ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; + ace->flag = eflag; + ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, + flags); + ace->whotype = NFS4_ACL_WHO_NAMED; + ace->who = pa->e_id; + ace++; + acl->naces++; pa++; } @@ -236,67 +288,65 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, /* allow ACEs */ - if (pacl->a_count > 3) { - BUG_ON(pa->e_tag != ACL_GROUP_OBJ); - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, - NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask, - NFS4_ACL_WHO_GROUP, 0); - if (error < 0) - goto out; - } group_owner_entry = pa; - mask = mask_from_posix(pa->e_perm, flags); - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, - NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, - NFS4_ACL_WHO_GROUP, 0); - if (error < 0) - goto out; + + ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; + ace->flag = eflag; + ace->access_mask = mask_from_posix(pas.group, flags); + ace->whotype = NFS4_ACL_WHO_GROUP; + ace++; + acl->naces++; pa++; while (pa->e_tag == ACL_GROUP) { - mask = mask_from_posix(pa->e_perm, flags); - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, - NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask, - NFS4_ACL_WHO_NAMED, pa->e_id); - if (error < 0) - goto out; - - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, - NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, - NFS4_ACL_WHO_NAMED, pa->e_id); - if (error < 0) - goto out; + ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; + ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; + ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, + flags); + ace->whotype = NFS4_ACL_WHO_NAMED; + ace->who = pa->e_id; + ace++; + acl->naces++; pa++; } /* deny ACEs */ pa = group_owner_entry; - mask = mask_from_posix(pa->e_perm, flags); - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, - NFS4_ACE_IDENTIFIER_GROUP | eflag, - deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0); - if (error < 0) - goto out; + + deny = ~pas.group & pas.other; + if (deny) { + ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; + ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; + ace->access_mask = deny_mask_from_posix(deny, flags); + ace->whotype = NFS4_ACL_WHO_GROUP; + ace++; + acl->naces++; + } pa++; + while (pa->e_tag == ACL_GROUP) { - mask = mask_from_posix(pa->e_perm, flags); - error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, - NFS4_ACE_IDENTIFIER_GROUP | eflag, - deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id); - if (error < 0) - goto out; + deny = ~(pa->e_perm & pas.mask); + deny &= pas.other; + if (deny) { + ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; + ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; + ace->access_mask = mask_from_posix(deny, flags); + ace->whotype = NFS4_ACL_WHO_NAMED; + ace->who = pa->e_id; + ace++; + acl->naces++; + } pa++; } if (pa->e_tag == ACL_MASK) pa++; - BUG_ON(pa->e_tag != ACL_OTHER); - mask = mask_from_posix(pa->e_perm, flags); - error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags); - -out: - return error; + ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; + ace->flag = eflag; + ace->access_mask = mask_from_posix(pa->e_perm, flags); + ace->whotype = NFS4_ACL_WHO_EVERYONE; + acl->naces++; } static void @@ -342,46 +392,6 @@ sort_pacl(struct posix_acl *pacl) return; } -int -nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, - struct posix_acl **dpacl, unsigned int flags) -{ - struct nfs4_acl *dacl; - int error = -ENOMEM; - - *pacl = NULL; - *dpacl = NULL; - - dacl = nfs4_acl_new(); - if (dacl == NULL) - goto out; - - error = nfs4_acl_split(acl, dacl); - if (error) - goto out_acl; - - *pacl = _nfsv4_to_posix_one(acl, flags); - if (IS_ERR(*pacl)) { - error = PTR_ERR(*pacl); - *pacl = NULL; - goto out_acl; - } - - *dpacl = _nfsv4_to_posix_one(dacl, flags); - if (IS_ERR(*dpacl)) { - error = PTR_ERR(*dpacl); - *dpacl = NULL; - } -out_acl: - if (error) { - posix_acl_release(*pacl); - *pacl = NULL; - } - nfs4_acl_free(dacl); -out: - return error; -} - /* * While processing the NFSv4 ACE, this maintains bitmasks representing * which permission bits have been allowed and which denied to a given @@ -406,6 +416,7 @@ struct posix_ace_state_array { * calculated so far: */ struct posix_acl_state { + int empty; struct posix_ace_state owner; struct posix_ace_state group; struct posix_ace_state other; @@ -421,6 +432,7 @@ init_state(struct posix_acl_state *state, int cnt) int alloc; memset(state, 0, sizeof(struct posix_acl_state)); + state->empty = 1; /* * In the worst case, each individual acl could be for a distinct * named user or group, but we don't no which, so we allocate @@ -488,6 +500,20 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) int nace; int i, error = 0; + /* + * ACLs with no ACEs are treated differently in the inheritable + * and effective cases: when there are no inheritable ACEs, we + * set a zero-length default posix acl: + */ + if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) { + pacl = posix_acl_alloc(0, GFP_KERNEL); + return pacl ? pacl : ERR_PTR(-ENOMEM); + } + /* + * When there are no effective ACEs, the following will end + * up setting a 3-element effective posix ACL with all + * permissions zero. + */ nace = 4 + state->users->n + state->groups->n; pacl = posix_acl_alloc(nace, GFP_KERNEL); if (!pacl) @@ -603,6 +629,8 @@ static void process_one_v4_ace(struct posix_acl_state *state, u32 mask = ace->access_mask; int i; + state->empty = 0; + switch (ace2type(ace)) { case ACL_USER_OBJ: if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { @@ -666,75 +694,62 @@ static void process_one_v4_ace(struct posix_acl_state *state, } } -static struct posix_acl * -_nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) +int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, + struct posix_acl **dpacl, unsigned int flags) { - struct posix_acl_state state; - struct posix_acl *pacl; + struct posix_acl_state effective_acl_state, default_acl_state; struct nfs4_ace *ace; int ret; - ret = init_state(&state, n4acl->naces); + ret = init_state(&effective_acl_state, acl->naces); if (ret) - return ERR_PTR(ret); - - list_for_each_entry(ace, &n4acl->ace_head, l_ace) - process_one_v4_ace(&state, ace); - - pacl = posix_state_to_acl(&state, flags); - - free_state(&state); - - if (!IS_ERR(pacl)) - sort_pacl(pacl); - return pacl; -} - -static int -nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) -{ - struct list_head *h, *n; - struct nfs4_ace *ace; - int error = 0; - - list_for_each_safe(h, n, &acl->ace_head) { - ace = list_entry(h, struct nfs4_ace, l_ace); - + return ret; + ret = init_state(&default_acl_state, acl->naces); + if (ret) + goto out_estate; + ret = -EINVAL; + for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) - return -EINVAL; - + goto out_dstate; if (ace->flag & ~NFS4_SUPPORTED_FLAGS) - return -EINVAL; - - switch (ace->flag & NFS4_INHERITANCE_FLAGS) { - case 0: - /* Leave this ace in the effective acl: */ + goto out_dstate; + if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { + process_one_v4_ace(&effective_acl_state, ace); continue; - case NFS4_INHERITANCE_FLAGS: - /* Add this ace to the default acl and remove it - * from the effective acl: */ - error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, - ace->access_mask, ace->whotype, ace->who); - if (error) - return error; - list_del(h); - kfree(ace); - acl->naces--; - break; - case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE: - /* Add this ace to the default, but leave it in - * the effective acl as well: */ - error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, - ace->access_mask, ace->whotype, ace->who); - if (error) - return error; - break; - default: - return -EINVAL; } + if (!(flags & NFS4_ACL_DIR)) + goto out_dstate; + /* + * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT + * is set, we're effectively turning on the other. That's OK, + * according to rfc 3530. + */ + process_one_v4_ace(&default_acl_state, ace); + + if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) + process_one_v4_ace(&effective_acl_state, ace); } - return 0; + *pacl = posix_state_to_acl(&effective_acl_state, flags); + if (IS_ERR(*pacl)) { + ret = PTR_ERR(*pacl); + goto out_dstate; + } + *dpacl = posix_state_to_acl(&default_acl_state, + flags | NFS4_ACL_TYPE_DEFAULT); + if (IS_ERR(*dpacl)) { + ret = PTR_ERR(*dpacl); + posix_acl_release(*pacl); + goto out_dstate; + } + sort_pacl(*pacl); + sort_pacl(*dpacl); + ret = 0; +out_dstate: + free_state(&default_acl_state); +out_estate: + free_state(&effective_acl_state); + return ret; } static short @@ -759,48 +774,22 @@ EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4); EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); struct nfs4_acl * -nfs4_acl_new(void) +nfs4_acl_new(int n) { struct nfs4_acl *acl; - if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL) + acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL); + if (acl == NULL) return NULL; - acl->naces = 0; - INIT_LIST_HEAD(&acl->ace_head); - return acl; } void -nfs4_acl_free(struct nfs4_acl *acl) -{ - struct list_head *h; - struct nfs4_ace *ace; - - if (!acl) - return; - - while (!list_empty(&acl->ace_head)) { - h = acl->ace_head.next; - list_del(h); - ace = list_entry(h, struct nfs4_ace, l_ace); - kfree(ace); - } - - kfree(acl); - - return; -} - -int nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, int whotype, uid_t who) { - struct nfs4_ace *ace; - - if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL) - return -ENOMEM; + struct nfs4_ace *ace = acl->aces + acl->naces; ace->type = type; ace->flag = flag; @@ -808,10 +797,7 @@ nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, ace->whotype = whotype; ace->who = who; - list_add_tail(&ace->l_ace, &acl->ace_head); acl->naces++; - - return 0; } static struct { @@ -865,7 +851,6 @@ nfs4_acl_write_who(int who, char *p) } EXPORT_SYMBOL(nfs4_acl_new); -EXPORT_SYMBOL(nfs4_acl_free); EXPORT_SYMBOL(nfs4_acl_add_ace); EXPORT_SYMBOL(nfs4_acl_get_whotype); EXPORT_SYMBOL(nfs4_acl_write_who); diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index f57655a..fb14d68 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -387,7 +387,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) .address = (struct sockaddr *)&addr, .addrsize = sizeof(addr), .timeout = &timeparms, - .servername = clp->cl_name.data, .program = program, .version = nfs_cb_version[1]->number, .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ @@ -397,6 +396,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], .rpc_argp = clp, }; + char clientname[16]; int status; if (atomic_read(&cb->cb_set)) @@ -419,6 +419,11 @@ nfsd4_probe_callback(struct nfs4_client *clp) memset(program->stats, 0, sizeof(cb->cb_stat)); program->stats->program = program; + /* Just here to make some printk's more useful: */ + snprintf(clientname, sizeof(clientname), + "%u.%u.%u.%u", NIPQUAD(addr.sin_addr)); + args.servername = clientname; + /* Create RPC client */ cb->cb_client = rpc_create(&args); if (IS_ERR(cb->cb_client)) { diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index b1902eb..e4a83d7 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -50,7 +50,6 @@ #include <linux/sunrpc/cache.h> #include <linux/nfsd_idmap.h> #include <linux/list.h> -#include <linux/sched.h> #include <linux/time.h> #include <linux/seq_file.h> #include <linux/sunrpc/svcauth.h> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 18aa944..5d090f1 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -199,24 +199,22 @@ defer_free(struct nfsd4_compoundargs *argp, static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) { - void *new = NULL; if (p == argp->tmp) { - new = kmalloc(nbytes, GFP_KERNEL); - if (!new) return NULL; - p = new; + p = kmalloc(nbytes, GFP_KERNEL); + if (!p) + return NULL; memcpy(p, argp->tmp, nbytes); } else { BUG_ON(p != argp->tmpp); argp->tmpp = NULL; } if (defer_free(argp, kfree, p)) { - kfree(new); + kfree(p); return NULL; } else return (char *)p; } - static __be32 nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) { @@ -255,7 +253,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia return status; /* - * According to spec, unsupported attributes return ERR_NOTSUPP; + * According to spec, unsupported attributes return ERR_ATTRNOTSUPP; * read-only attributes return ERR_INVAL. */ if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1)) @@ -273,42 +271,42 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia iattr->ia_valid |= ATTR_SIZE; } if (bmval[0] & FATTR4_WORD0_ACL) { - int nace, i; - struct nfs4_ace ace; + int nace; + struct nfs4_ace *ace; READ_BUF(4); len += 4; READ32(nace); - *acl = nfs4_acl_new(); + if (nace > NFS4_ACL_MAX) + return nfserr_resource; + + *acl = nfs4_acl_new(nace); if (*acl == NULL) { host_err = -ENOMEM; goto out_nfserr; } - defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl); + defer_free(argp, kfree, *acl); - for (i = 0; i < nace; i++) { + (*acl)->naces = nace; + for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { READ_BUF(16); len += 16; - READ32(ace.type); - READ32(ace.flag); - READ32(ace.access_mask); + READ32(ace->type); + READ32(ace->flag); + READ32(ace->access_mask); READ32(dummy32); READ_BUF(dummy32); len += XDR_QUADLEN(dummy32) << 2; READMEM(buf, dummy32); - ace.whotype = nfs4_acl_get_whotype(buf, dummy32); + ace->whotype = nfs4_acl_get_whotype(buf, dummy32); host_err = 0; - if (ace.whotype != NFS4_ACL_WHO_NAMED) - ace.who = 0; - else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP) + if (ace->whotype != NFS4_ACL_WHO_NAMED) + ace->who = 0; + else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) host_err = nfsd_map_name_to_gid(argp->rqstp, - buf, dummy32, &ace.who); + buf, dummy32, &ace->who); else host_err = nfsd_map_name_to_uid(argp->rqstp, - buf, dummy32, &ace.who); - if (host_err) - goto out_nfserr; - host_err = nfs4_acl_add_ace(*acl, ace.type, ace.flag, - ace.access_mask, ace.whotype, ace.who); + buf, dummy32, &ace->who); if (host_err) goto out_nfserr; } @@ -1563,14 +1561,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (exp->ex_fslocs.migrated) { WRITE64(NFS4_REFERRAL_FSID_MAJOR); WRITE64(NFS4_REFERRAL_FSID_MINOR); - } else if (is_fsid(fhp, rqstp->rq_reffh)) { + } else switch(fsid_source(fhp)) { + case FSIDSOURCE_FSID: WRITE64((u64)exp->ex_fsid); WRITE64((u64)0); - } else { + break; + case FSIDSOURCE_DEV: WRITE32(0); WRITE32(MAJOR(stat.dev)); WRITE32(0); WRITE32(MINOR(stat.dev)); + break; + case FSIDSOURCE_UUID: + WRITEMEM(exp->ex_uuid, 16); + break; } } if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { @@ -1590,7 +1594,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, } if (bmval0 & FATTR4_WORD0_ACL) { struct nfs4_ace *ace; - struct list_head *h; if (acl == NULL) { if ((buflen -= 4) < 0) @@ -1603,9 +1606,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, goto out_resource; WRITE32(acl->naces); - list_for_each(h, &acl->ace_head) { - ace = list_entry(h, struct nfs4_ace, l_ace); - + for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { if ((buflen -= 4*3) < 0) goto out_resource; WRITE32(ace->type); @@ -1815,7 +1816,7 @@ out_acl: status = nfs_ok; out: - nfs4_acl_free(acl); + kfree(acl); if (fhp == &tempfh) fh_put(&tempfh); return status; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index eedf2e3..71c686d 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -123,7 +123,7 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu return PTR_ERR(data); rv = write_op[ino](file, data, size); - if (rv>0) { + if (rv >= 0) { simple_transaction_set(file, rv); rv = size; } diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index a0b4282..c2660cb 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -9,7 +9,6 @@ * ... and again Southern-Winter 2001 to support export_operations */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/fs.h> @@ -119,9 +118,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); - /* keep this filehandle for possible reference when encoding attributes */ - rqstp->rq_reffh = fh; - if (!fhp->fh_dentry) { __u32 *datap=NULL; __u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */ @@ -146,10 +142,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) } len = key_len(fh->fh_fsid_type) / 4; if (len == 0) goto out; - if (fh->fh_fsid_type == 2) { + if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { /* deprecated, convert to type 3 */ - len = 3; - fh->fh_fsid_type = 3; + len = key_len(FSID_ENCODE_DEV)/4; + fh->fh_fsid_type = FSID_ENCODE_DEV; fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); fh->fh_fsid[1] = fh->fh_fsid[2]; } @@ -164,8 +160,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) /* assume old filehandle format */ xdev = old_decode_dev(fh->ofh_xdev); xino = u32_to_ino_t(fh->ofh_xino); - mk_fsid_v0(tfh, xdev, xino); - exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle); + mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); + exp = exp_find(rqstp->rq_client, FSID_DEV, tfh, + &rqstp->rq_chandle); } if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN @@ -212,7 +209,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) fileid_type = 2; } else fileid_type = fh->fh_fileid_type; - + if (fileid_type == 0) dentry = dget(exp->ex_dentry); else { @@ -292,7 +289,7 @@ static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, __u32 *datap, int *maxsize) { struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op; - + if (dentry == exp->ex_dentry) { *maxsize = 0; return 0; @@ -317,7 +314,8 @@ static inline void _fh_update_old(struct dentry *dentry, } __be32 -fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh) +fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, + struct svc_fh *ref_fh) { /* ref_fh is a reference file handle. * if it is non-null and for the same filesystem, then we should compose @@ -327,12 +325,13 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st * */ - u8 ref_fh_version = 0; - u8 ref_fh_fsid_type = 0; + u8 version = 1; + u8 fsid_type = 0; struct inode * inode = dentry->d_inode; struct dentry *parent = dentry->d_parent; __u32 *datap; dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev; + int root_export = (exp->ex_dentry == exp->ex_dentry->d_sb->s_root); dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", MAJOR(ex_dev), MINOR(ex_dev), @@ -340,57 +339,64 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st parent->d_name.name, dentry->d_name.name, (inode ? inode->i_ino : 0)); + /* Choose filehandle version and fsid type based on + * the reference filehandle (if it is in the same export) + * or the export options. + */ if (ref_fh && ref_fh->fh_export == exp) { - ref_fh_version = ref_fh->fh_handle.fh_version; - if (ref_fh_version == 0xca) - ref_fh_fsid_type = 0; + version = ref_fh->fh_handle.fh_version; + if (version == 0xca) + fsid_type = FSID_DEV; else - ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type; - if (ref_fh_fsid_type > 3) - ref_fh_fsid_type = 0; - - /* make sure ref_fh type works for given export */ - if (ref_fh_fsid_type == 1 && - !(exp->ex_flags & NFSEXP_FSID)) { - /* if we don't have an fsid, we cannot provide one... */ - ref_fh_fsid_type = 0; + fsid_type = ref_fh->fh_handle.fh_fsid_type; + /* We know this version/type works for this export + * so there is no need for further checks. + */ + } else if (exp->ex_uuid) { + if (fhp->fh_maxsize >= 64) { + if (root_export) + fsid_type = FSID_UUID16; + else + fsid_type = FSID_UUID16_INUM; + } else { + if (root_export) + fsid_type = FSID_UUID8; + else + fsid_type = FSID_UUID4_INUM; } } else if (exp->ex_flags & NFSEXP_FSID) - ref_fh_fsid_type = 1; - - if (!old_valid_dev(ex_dev) && ref_fh_fsid_type == 0) { + fsid_type = FSID_NUM; + else if (!old_valid_dev(ex_dev)) /* for newer device numbers, we must use a newer fsid format */ - ref_fh_version = 1; - ref_fh_fsid_type = 3; - } - if (old_valid_dev(ex_dev) && - (ref_fh_fsid_type == 2 || ref_fh_fsid_type == 3)) - /* must use type1 for smaller device numbers */ - ref_fh_fsid_type = 0; + fsid_type = FSID_ENCODE_DEV; + else + fsid_type = FSID_DEV; if (ref_fh == fhp) fh_put(ref_fh); if (fhp->fh_locked || fhp->fh_dentry) { printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n", - parent->d_name.name, dentry->d_name.name); + parent->d_name.name, dentry->d_name.name); } if (fhp->fh_maxsize < NFS_FHSIZE) printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n", - fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name); + fhp->fh_maxsize, + parent->d_name.name, dentry->d_name.name); fhp->fh_dentry = dget(dentry); /* our internal copy */ fhp->fh_export = exp; cache_get(&exp->h); - if (ref_fh_version == 0xca) { + if (version == 0xca) { /* old style filehandle please */ memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); fhp->fh_handle.fh_size = NFS_FHSIZE; fhp->fh_handle.ofh_dcookie = 0xfeebbaca; fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev); fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; - fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_dentry->d_inode->i_ino); + fhp->fh_handle.ofh_xino = + ino_t_to_u32(exp->ex_dentry->d_inode->i_ino); fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); if (inode) _fh_update_old(dentry, exp, &fhp->fh_handle); @@ -399,38 +405,12 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st fhp->fh_handle.fh_version = 1; fhp->fh_handle.fh_auth_type = 0; datap = fhp->fh_handle.fh_auth+0; - fhp->fh_handle.fh_fsid_type = ref_fh_fsid_type; - switch (ref_fh_fsid_type) { - case 0: - /* - * fsid_type 0: - * 2byte major, 2byte minor, 4byte inode - */ - mk_fsid_v0(datap, ex_dev, - exp->ex_dentry->d_inode->i_ino); - break; - case 1: - /* fsid_type 1 == 4 bytes filesystem id */ - mk_fsid_v1(datap, exp->ex_fsid); - break; - case 2: - /* - * fsid_type 2: - * 4byte major, 4byte minor, 4byte inode - */ - mk_fsid_v2(datap, ex_dev, - exp->ex_dentry->d_inode->i_ino); - break; - case 3: - /* - * fsid_type 3: - * 4byte devicenumber, 4byte inode - */ - mk_fsid_v3(datap, ex_dev, - exp->ex_dentry->d_inode->i_ino); - break; - } - len = key_len(ref_fh_fsid_type); + fhp->fh_handle.fh_fsid_type = fsid_type; + mk_fsid(fsid_type, datap, ex_dev, + exp->ex_dentry->d_inode->i_ino, + exp->ex_fsid, exp->ex_uuid); + + len = key_len(fsid_type); datap += len/4; fhp->fh_handle.fh_size = 4 + len; @@ -457,7 +437,7 @@ fh_update(struct svc_fh *fhp) { struct dentry *dentry; __u32 *datap; - + if (!fhp->fh_dentry) goto out_bad; @@ -534,3 +514,22 @@ char * SVCFH_fmt(struct svc_fh *fhp) fh->fh_base.fh_pad[5]); return buf; } + +enum fsid_source fsid_source(struct svc_fh *fhp) +{ + if (fhp->fh_handle.fh_version != 1) + return FSIDSOURCE_DEV; + switch(fhp->fh_handle.fh_fsid_type) { + case FSID_DEV: + case FSID_ENCODE_DEV: + case FSID_MAJOR_MINOR: + return FSIDSOURCE_DEV; + case FSID_NUM: + return FSIDSOURCE_FSID; + default: + if (fhp->fh_export->ex_flags & NFSEXP_FSID) + return FSIDSOURCE_FSID; + else + return FSIDSOURCE_UUID; + } +} diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 6555c50..0c24b9e 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -153,6 +153,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct dentry *dentry = fhp->fh_dentry; int type; struct timespec time; + u32 f; type = (stat->mode & S_IFMT); @@ -173,10 +174,22 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, else *p++ = htonl(0xffffffff); *p++ = htonl((u32) stat->blocks); - if (is_fsid(fhp, rqstp->rq_reffh)) - *p++ = htonl((u32) fhp->fh_export->ex_fsid); - else + switch (fsid_source(fhp)) { + default: + case FSIDSOURCE_DEV: *p++ = htonl(new_encode_dev(stat->dev)); + break; + case FSIDSOURCE_FSID: + *p++ = htonl((u32) fhp->fh_export->ex_fsid); + break; + case FSIDSOURCE_UUID: + f = ((u32*)fhp->fh_export->ex_uuid)[0]; + f ^= ((u32*)fhp->fh_export->ex_uuid)[1]; + f ^= ((u32*)fhp->fh_export->ex_uuid)[2]; + f ^= ((u32*)fhp->fh_export->ex_uuid)[3]; + *p++ = htonl(f); + break; + } *p++ = htonl((u32) stat->ino); *p++ = htonl((u32) stat->atime.tv_sec); *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8283236..7e6aa24 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -466,7 +466,10 @@ out: posix_acl_release(dpacl); return (error); out_nfserr: - error = nfserrno(host_error); + if (host_error == -EOPNOTSUPP) + error = nfserr_attrnotsupp; + else + error = nfserrno(host_error); goto out; } diff --git a/fs/ntfs/sysctl.c b/fs/ntfs/sysctl.c index 1c23138..4847fbf 100644 --- a/fs/ntfs/sysctl.c +++ b/fs/ntfs/sysctl.c @@ -33,20 +33,28 @@ #include "sysctl.h" #include "debug.h" -#define FS_NTFS 1 - /* Definition of the ntfs sysctl. */ static ctl_table ntfs_sysctls[] = { - { FS_NTFS, "ntfs-debug", /* Binary and text IDs. */ - &debug_msgs,sizeof(debug_msgs), /* Data pointer and size. */ - 0644, NULL, &proc_dointvec }, /* Mode, child, proc handler. */ - { 0 } + { + .ctl_name = CTL_UNNUMBERED, /* Binary and text IDs. */ + .procname = "ntfs-debug", + .data = &debug_msgs, /* Data pointer and size. */ + .maxlen = sizeof(debug_msgs), + .mode = 0644, /* Mode, proc handler. */ + .proc_handler = &proc_dointvec + }, + {} }; /* Define the parent directory /proc/sys/fs. */ static ctl_table sysctls_root[] = { - { CTL_FS, "fs", NULL, 0, 0555, ntfs_sysctls }, - { 0 } + { + .ctl_name = CTL_FS, + .procname = "fs", + .mode = 0555, + .child = ntfs_sysctls + }, + {} }; /* Storage for the sysctls header. */ @@ -62,17 +70,9 @@ int ntfs_sysctl(int add) { if (add) { BUG_ON(sysctls_root_table); - sysctls_root_table = register_sysctl_table(sysctls_root, 0); + sysctls_root_table = register_sysctl_table(sysctls_root); if (!sysctls_root_table) return -ENOMEM; -#ifdef CONFIG_PROC_FS - /* - * If the proc filesystem is in use and we are a module, need - * to set the owner of our proc entry to our module. In the - * non-modular case, THIS_MODULE is NULL, so this is ok. - */ - ntfs_sysctls[0].de->owner = THIS_MODULE; -#endif } else { BUG_ON(!sysctls_root_table); unregister_sysctl_table(sysctls_root_table); diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index b17333a..9f5ad0f 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -55,7 +55,7 @@ static ctl_table ocfs2_nm_table[] = { static ctl_table ocfs2_mod_table[] = { { - .ctl_name = KERN_OCFS2_NM, + .ctl_name = FS_OCFS2_NM, .procname = "nm", .data = NULL, .maxlen = 0, @@ -67,7 +67,7 @@ static ctl_table ocfs2_mod_table[] = { static ctl_table ocfs2_kern_table[] = { { - .ctl_name = KERN_OCFS2, + .ctl_name = FS_OCFS2, .procname = "ocfs2", .data = NULL, .maxlen = 0, @@ -922,7 +922,7 @@ static int __init init_o2nm(void) o2hb_init(); o2net_init(); - ocfs2_table_header = register_sysctl_table(ocfs2_root_table, 0); + ocfs2_table_header = register_sysctl_table(ocfs2_root_table); if (!ocfs2_table_header) { printk(KERN_ERR "nodemanager: unable to register sysctl\n"); ret = -ENOMEM; /* or something. */ diff --git a/fs/ocfs2/cluster/nodemanager.h b/fs/ocfs2/cluster/nodemanager.h index 8fb23ca..0705221 100644 --- a/fs/ocfs2/cluster/nodemanager.h +++ b/fs/ocfs2/cluster/nodemanager.h @@ -33,8 +33,7 @@ #include <linux/configfs.h> #include <linux/rbtree.h> -#define KERN_OCFS2 988 -#define KERN_OCFS2_NM 1 +#define FS_OCFS2_NM 1 const char *o2nm_get_hb_ctl_path(void); diff --git a/fs/proc/Makefile b/fs/proc/Makefile index f6c7762..a6b3a8f 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -8,7 +8,7 @@ proc-y := nommu.o task_nommu.o proc-$(CONFIG_MMU) := mmu.o task_mmu.o proc-y += inode.o root.o base.o generic.o array.o \ - proc_tty.o proc_misc.o + proc_tty.o proc_misc.o proc_sysctl.o proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 0cdc00d..775fb21 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -32,7 +32,7 @@ static loff_t proc_file_lseek(struct file *, loff_t, int); DEFINE_SPINLOCK(proc_subdir_lock); -int proc_match(int len, const char *name, struct proc_dir_entry *de) +static int proc_match(int len, const char *name, struct proc_dir_entry *de) { if (de->namelen != len) return 0; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index f6722be..c372eb15 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -161,6 +161,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, if (!inode) goto out_ino; + PROC_I(inode)->fd = 0; PROC_I(inode)->pde = de; if (de) { if (de->mode) { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 277dcd6..c932aa6 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -11,6 +11,8 @@ #include <linux/proc_fs.h> +extern int proc_sys_init(void); + struct vmalloc_info { unsigned long used; unsigned long largest_chunk; diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c new file mode 100644 index 0000000..20e8cbb --- /dev/null +++ b/fs/proc/proc_sysctl.c @@ -0,0 +1,479 @@ +/* + * /proc/sys support + */ + +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/security.h> +#include "internal.h" + +static struct dentry_operations proc_sys_dentry_operations; +static const struct file_operations proc_sys_file_operations; +static struct inode_operations proc_sys_inode_operations; + +static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table) +{ + /* Refresh the cached information bits in the inode */ + if (table) { + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_mode = table->mode; + if (table->proc_handler) { + inode->i_mode |= S_IFREG; + inode->i_nlink = 1; + } else { + inode->i_mode |= S_IFDIR; + inode->i_nlink = 0; /* It is too hard to figure out */ + } + } +} + +static struct inode *proc_sys_make_inode(struct inode *dir, struct ctl_table *table) +{ + struct inode *inode; + struct proc_inode *dir_ei, *ei; + int depth; + + inode = new_inode(dir->i_sb); + if (!inode) + goto out; + + /* A directory is always one deeper than it's parent */ + dir_ei = PROC_I(dir); + depth = dir_ei->fd + 1; + + ei = PROC_I(inode); + ei->fd = depth; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &proc_sys_inode_operations; + inode->i_fop = &proc_sys_file_operations; + inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */ + proc_sys_refresh_inode(inode, table); +out: + return inode; +} + +static struct dentry *proc_sys_ancestor(struct dentry *dentry, int depth) +{ + for (;;) { + struct proc_inode *ei; + + ei = PROC_I(dentry->d_inode); + if (ei->fd == depth) + break; /* found */ + + dentry = dentry->d_parent; + } + return dentry; +} + +static struct ctl_table *proc_sys_lookup_table_one(struct ctl_table *table, + struct qstr *name) +{ + int len; + for ( ; table->ctl_name || table->procname; table++) { + + if (!table->procname) + continue; + + len = strlen(table->procname); + if (len != name->len) + continue; + + if (memcmp(table->procname, name->name, len) != 0) + continue; + + /* I have a match */ + return table; + } + return NULL; +} + +static struct ctl_table *proc_sys_lookup_table(struct dentry *dentry, + struct ctl_table *table) +{ + struct dentry *ancestor; + struct proc_inode *ei; + int depth, i; + + ei = PROC_I(dentry->d_inode); + depth = ei->fd; + + if (depth == 0) + return table; + + for (i = 1; table && (i <= depth); i++) { + ancestor = proc_sys_ancestor(dentry, i); + table = proc_sys_lookup_table_one(table, &ancestor->d_name); + if (table) + table = table->child; + } + return table; + +} +static struct ctl_table *proc_sys_lookup_entry(struct dentry *dparent, + struct qstr *name, + struct ctl_table *table) +{ + table = proc_sys_lookup_table(dparent, table); + if (table) + table = proc_sys_lookup_table_one(table, name); + return table; +} + +static struct ctl_table *do_proc_sys_lookup(struct dentry *parent, + struct qstr *name, + struct ctl_table_header **ptr) +{ + struct ctl_table_header *head; + struct ctl_table *table = NULL; + + for (head = sysctl_head_next(NULL); head; + head = sysctl_head_next(head)) { + table = proc_sys_lookup_entry(parent, name, head->ctl_table); + if (table) + break; + } + *ptr = head; + return table; +} + +static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct ctl_table_header *head; + struct inode *inode; + struct dentry *err; + struct ctl_table *table; + + err = ERR_PTR(-ENOENT); + table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); + if (!table) + goto out; + + err = ERR_PTR(-ENOMEM); + inode = proc_sys_make_inode(dir, table); + if (!inode) + goto out; + + err = NULL; + dentry->d_op = &proc_sys_dentry_operations; + d_add(dentry, inode); + +out: + sysctl_head_finish(head); + return err; +} + +static ssize_t proc_sys_read(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dentry *dentry = filp->f_dentry; + struct ctl_table_header *head; + struct ctl_table *table; + ssize_t error, res; + + table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); + /* Has the sysctl entry disappeared on us? */ + error = -ENOENT; + if (!table) + goto out; + + /* Has the sysctl entry been replaced by a directory? */ + error = -EISDIR; + if (!table->proc_handler) + goto out; + + /* + * At this point we know that the sysctl was not unregistered + * and won't be until we finish. + */ + error = -EPERM; + if (sysctl_perm(table, MAY_READ)) + goto out; + + /* careful: calling conventions are nasty here */ + res = count; + error = table->proc_handler(table, 0, filp, buf, &res, ppos); + if (!error) + error = res; +out: + sysctl_head_finish(head); + + return error; +} + +static ssize_t proc_sys_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dentry *dentry = filp->f_dentry; + struct ctl_table_header *head; + struct ctl_table *table; + ssize_t error, res; + + table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); + /* Has the sysctl entry disappeared on us? */ + error = -ENOENT; + if (!table) + goto out; + + /* Has the sysctl entry been replaced by a directory? */ + error = -EISDIR; + if (!table->proc_handler) + goto out; + + /* + * At this point we know that the sysctl was not unregistered + * and won't be until we finish. + */ + error = -EPERM; + if (sysctl_perm(table, MAY_WRITE)) + goto out; + + /* careful: calling conventions are nasty here */ + res = count; + error = table->proc_handler(table, 1, filp, (char __user *)buf, + &res, ppos); + if (!error) + error = res; +out: + sysctl_head_finish(head); + + return error; +} + + +static int proc_sys_fill_cache(struct file *filp, void *dirent, + filldir_t filldir, struct ctl_table *table) +{ + struct ctl_table_header *head; + struct ctl_table *child_table = NULL; + struct dentry *child, *dir = filp->f_path.dentry; + struct inode *inode; + struct qstr qname; + ino_t ino = 0; + unsigned type = DT_UNKNOWN; + int ret; + + qname.name = table->procname; + qname.len = strlen(table->procname); + qname.hash = full_name_hash(qname.name, qname.len); + + /* Suppress duplicates. + * Only fill a directory entry if it is the value that + * an ordinary lookup of that name returns. Hide all + * others. + * + * If we ever cache this translation in the dcache + * I should do a dcache lookup first. But for now + * it is just simpler not to. + */ + ret = 0; + child_table = do_proc_sys_lookup(dir, &qname, &head); + sysctl_head_finish(head); + if (child_table != table) + return 0; + + child = d_lookup(dir, &qname); + if (!child) { + struct dentry *new; + new = d_alloc(dir, &qname); + if (new) { + inode = proc_sys_make_inode(dir->d_inode, table); + if (!inode) + child = ERR_PTR(-ENOMEM); + else { + new->d_op = &proc_sys_dentry_operations; + d_add(new, inode); + } + if (child) + dput(new); + else + child = new; + } + } + if (!child || IS_ERR(child) || !child->d_inode) + goto end_instantiate; + inode = child->d_inode; + if (inode) { + ino = inode->i_ino; + type = inode->i_mode >> 12; + } + dput(child); +end_instantiate: + if (!ino) + ino= find_inode_number(dir, &qname); + if (!ino) + ino = 1; + return filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); +} + +static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + struct ctl_table_header *head = NULL; + struct ctl_table *table; + unsigned long pos; + int ret; + + ret = -ENOTDIR; + if (!S_ISDIR(inode->i_mode)) + goto out; + + ret = 0; + /* Avoid a switch here: arm builds fail with missing __cmpdi2 */ + if (filp->f_pos == 0) { + if (filldir(dirent, ".", 1, filp->f_pos, + inode->i_ino, DT_DIR) < 0) + goto out; + filp->f_pos++; + } + if (filp->f_pos == 1) { + if (filldir(dirent, "..", 2, filp->f_pos, + parent_ino(dentry), DT_DIR) < 0) + goto out; + filp->f_pos++; + } + pos = 2; + + /* - Find each instance of the directory + * - Read all entries in each instance + * - Before returning an entry to user space lookup the entry + * by name and if I find a different entry don't return + * this one because it means it is a buried dup. + * For sysctl this should only happen for directory entries. + */ + for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) { + table = proc_sys_lookup_table(dentry, head->ctl_table); + + if (!table) + continue; + + for (; table->ctl_name || table->procname; table++, pos++) { + /* Can't do anything without a proc name */ + if (!table->procname) + continue; + + if (pos < filp->f_pos) + continue; + + if (proc_sys_fill_cache(filp, dirent, filldir, table) < 0) + goto out; + filp->f_pos = pos + 1; + } + } + ret = 1; +out: + sysctl_head_finish(head); + return ret; +} + +static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + /* + * sysctl entries that are not writeable, + * are _NOT_ writeable, capabilities or not. + */ + struct ctl_table_header *head; + struct ctl_table *table; + struct dentry *dentry; + int mode; + int depth; + int error; + + head = NULL; + depth = PROC_I(inode)->fd; + + /* First check the cached permissions, in case we don't have + * enough information to lookup the sysctl table entry. + */ + error = -EACCES; + mode = inode->i_mode; + + if (current->euid == 0) + mode >>= 6; + else if (in_group_p(0)) + mode >>= 3; + + if ((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask) + error = 0; + + /* If we can't get a sysctl table entry the permission + * checks on the cached mode will have to be enough. + */ + if (!nd || !depth) + goto out; + + dentry = nd->dentry; + table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); + + /* If the entry does not exist deny permission */ + error = -EACCES; + if (!table) + goto out; + + /* Use the permissions on the sysctl table entry */ + error = sysctl_perm(table, mask); +out: + sysctl_head_finish(head); + return error; +} + +static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error; + + if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) + return -EPERM; + + error = inode_change_ok(inode, attr); + if (!error) { + error = security_inode_setattr(dentry, attr); + if (!error) + error = inode_setattr(inode, attr); + } + + return error; +} + +/* I'm lazy and don't distinguish between files and directories, + * until access time. + */ +static const struct file_operations proc_sys_file_operations = { + .read = proc_sys_read, + .write = proc_sys_write, + .readdir = proc_sys_readdir, +}; + +static struct inode_operations proc_sys_inode_operations = { + .lookup = proc_sys_lookup, + .permission = proc_sys_permission, + .setattr = proc_sys_setattr, +}; + +static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct ctl_table_header *head; + struct ctl_table *table; + table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); + proc_sys_refresh_inode(dentry->d_inode, table); + sysctl_head_finish(head); + return !!table; +} + +static struct dentry_operations proc_sys_dentry_operations = { + .d_revalidate = proc_sys_revalidate, +}; + +static struct proc_dir_entry *proc_sys_root; + +int proc_sys_init(void) +{ + proc_sys_root = proc_mkdir("sys", NULL); + proc_sys_root->proc_iops = &proc_sys_inode_operations; + proc_sys_root->proc_fops = &proc_sys_file_operations; + proc_sys_root->nlink = 0; + return 0; +} diff --git a/fs/proc/root.c b/fs/proc/root.c index af15445..5834a744 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -23,10 +23,6 @@ struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; -#ifdef CONFIG_SYSCTL -struct proc_dir_entry *proc_sys_root; -#endif - static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { @@ -71,13 +67,6 @@ void __init proc_root_init(void) #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); #endif -#ifdef CONFIG_SYSCTL - proc_sys_root = proc_mkdir("sys", NULL); -#endif -#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) - proc_mkdir("sys/fs", NULL); - proc_mkdir("sys/fs/binfmt_misc", NULL); -#endif proc_root_fs = proc_mkdir("fs", NULL); proc_root_driver = proc_mkdir("driver", NULL); proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ @@ -90,6 +79,9 @@ void __init proc_root_init(void) proc_device_tree_init(); #endif proc_bus = proc_mkdir("bus", NULL); +#ifdef CONFIG_SYSCTL + proc_sys_init(); +#endif } static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c index e4bf345..fea20ce 100644 --- a/fs/smbfs/symlink.c +++ b/fs/smbfs/symlink.c @@ -6,7 +6,6 @@ * Please add a note about your changes to smbfs in the ChangeLog file. */ -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/fcntl.h> diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 0e97a4f..bcc4408 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -16,7 +16,6 @@ #include <linux/quotaops.h> #include <linux/buffer_head.h> #include <linux/capability.h> -#include <linux/sched.h> #include <linux/bitops.h> #include <asm/byteorder.h> diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index a6c0ca9..4890ddf 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -20,7 +20,6 @@ #include <linux/fs.h> #include <linux/ufs_fs.h> #include <linux/smp_lock.h> -#include <linux/sched.h> #include "swab.h" #include "util.h" diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c index 789a255..c6ad7c7 100644 --- a/fs/xattr_acl.c +++ b/fs/xattr_acl.c @@ -6,7 +6,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/posix_acl_xattr.h> diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 004baf6..ed2b16d 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -15,7 +15,6 @@ * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <linux/sched.h> #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/highmem.h> diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c index 5c46c35..cd6eaa4 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.c +++ b/fs/xfs/linux-2.6/xfs_sysctl.c @@ -251,7 +251,7 @@ static ctl_table xfs_root_table[] = { void xfs_sysctl_register(void) { - xfs_table_header = register_sysctl_table(xfs_root_table, 0); + xfs_table_header = register_sysctl_table(xfs_root_table); } void diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 4dc8a50..3d7ebe0 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -122,10 +122,24 @@ extern int register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, void *context); extern void unregister_hotplug_dock_device(acpi_handle handle); #else -#define is_dock_device(h) (0) -#define register_dock_notifier(nb) (-ENODEV) -#define unregister_dock_notifier(nb) do { } while(0) -#define register_hotplug_dock_device(h1, h2, c) (-ENODEV) -#define unregister_hotplug_dock_device(h) do { } while(0) +static inline int is_dock_device(acpi_handle handle) +{ + return 0; +} +static inline int register_dock_notifier(struct notifier_block *nb) +{ + return -ENODEV; +} +static inline void unregister_dock_notifier(struct notifier_block *nb) +{ +} +static inline int register_hotplug_dock_device(acpi_handle handle, + acpi_notify_handler handler, void *context) +{ + return -ENODEV; +} +static inline void unregister_hotplug_dock_device(acpi_handle handle) +{ +} #endif #endif /*__ACPI_DRIVERS_H__*/ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 781394b..2785058 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -240,12 +240,6 @@ acpi_status acpi_os_validate_address(u8 space_id, acpi_physical_address address, acpi_size length); -u8 acpi_os_readable(void *pointer, acpi_size length); - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *pointer, acpi_size length); -#endif - u64 acpi_os_get_timer(void); acpi_status acpi_os_signal(u32 function, void *info); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 7798d2a..916c010 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -79,6 +79,7 @@ struct acpi_processor_power { u32 bm_activity; int count; struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; + int timer_broadcast_on_state; }; /* Performance Management */ diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index b120ee0..1a7b07d 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -26,7 +26,9 @@ struct eth_platform_data { struct platform_device * at32_add_device_eth(unsigned int id, struct eth_platform_data *data); -struct platform_device *at32_add_device_spi(unsigned int id); +struct spi_board_info; +struct platform_device * +at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n); struct lcdc_platform_data { unsigned long fbmem_start; diff --git a/include/asm-avr32/io.h b/include/asm-avr32/io.h index eec4750..c08e810 100644 --- a/include/asm-avr32/io.h +++ b/include/asm-avr32/io.h @@ -28,13 +28,13 @@ static __inline__ void * phys_to_virt(unsigned long address) * Generic IO read/write. These perform native-endian accesses. Note * that some architectures will want to re-define __raw_{read,write}w. */ -extern void __raw_writesb(unsigned int addr, const void *data, int bytelen); -extern void __raw_writesw(unsigned int addr, const void *data, int wordlen); -extern void __raw_writesl(unsigned int addr, const void *data, int longlen); +extern void __raw_writesb(void __iomem *addr, const void *data, int bytelen); +extern void __raw_writesw(void __iomem *addr, const void *data, int wordlen); +extern void __raw_writesl(void __iomem *addr, const void *data, int longlen); -extern void __raw_readsb(unsigned int addr, void *data, int bytelen); -extern void __raw_readsw(unsigned int addr, void *data, int wordlen); -extern void __raw_readsl(unsigned int addr, void *data, int longlen); +extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen); +extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); +extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); static inline void writeb(unsigned char b, volatile void __iomem *addr) { @@ -252,6 +252,9 @@ extern void __iounmap(void __iomem *addr); #define ioremap(offset, size) \ __ioremap((offset), (size), 0) +#define ioremap_nocache(offset, size) \ + __ioremap((offset), (size), 0) + #define iounmap(addr) \ __iounmap(addr) @@ -263,6 +266,14 @@ extern void __iounmap(void __iomem *addr); #define page_to_bus page_to_phys #define bus_to_page phys_to_page +/* + * Create a virtual mapping cookie for an IO port range. There exists + * no such thing as port-based I/O on AVR32, so a regular ioremap() + * should do what we need. + */ +#define ioport_map(port, nr) ioremap(port, nr) +#define ioport_unmap(port) iounmap(port) + #define dma_cache_wback_inv(_start, _size) \ flush_dcache_region(_start, _size) #define dma_cache_inv(_start, _size) \ diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h index 56ed1f9..8f51204 100644 --- a/include/asm-avr32/unistd.h +++ b/include/asm-avr32/unistd.h @@ -120,7 +120,7 @@ #define __NR_getitimer 105 #define __NR_swapoff 106 #define __NR_sysinfo 107 -#define __NR_ipc 108 +/* 108 was __NR_ipc for a little while */ #define __NR_sendfile 109 #define __NR_setdomainname 110 #define __NR_uname 111 @@ -282,8 +282,21 @@ #define __NR_vmsplice 264 #define __NR_epoll_pwait 265 +#define __NR_msgget 266 +#define __NR_msgsnd 267 +#define __NR_msgrcv 268 +#define __NR_msgctl 269 +#define __NR_semget 270 +#define __NR_semop 271 +#define __NR_semctl 272 +#define __NR_semtimedop 273 +#define __NR_shmat 274 +#define __NR_shmget 275 +#define __NR_shmdt 276 +#define __NR_shmctl 277 + #ifdef __KERNEL__ -#define NR_syscalls 266 +#define NR_syscalls 278 #define __ARCH_WANT_IPC_PARSE_VERSION diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 9d774d0..00c2343 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -183,6 +183,19 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres #endif /* + * A facility to provide batching of the reload of page tables with the + * actual context switch code for paravirtualized guests. By convention, + * only one of the lazy modes (CPU, MMU) should be active at any given + * time, entry should never be nested, and entry and exits should always + * be paired. This is for sanity of maintaining and reasoning about the + * kernel code. + */ +#ifndef __HAVE_ARCH_ENTER_LAZY_CPU_MODE +#define arch_enter_lazy_cpu_mode() do {} while (0) +#define arch_leave_lazy_cpu_mode() do {} while (0) +#endif + +/* * When walking page tables, get the address of the next boundary, * or the end address of the range if that comes earlier. Although no * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout. diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index 5e657eb..449f3f2 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -127,6 +127,7 @@ extern int acpi_irq_balance_set(char *str); #define acpi_ioapic 0 static inline void acpi_noirq_set(void) { } static inline void acpi_disable_pci(void) { } +static inline void disable_acpi(void) { } #endif /* !CONFIG_ACPI */ diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index 41a4431..cc6b165 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -43,6 +43,8 @@ extern void generic_apic_probe(void); #define apic_write native_apic_write #define apic_write_atomic native_apic_write_atomic #define apic_read native_apic_read +#define setup_boot_clock setup_boot_APIC_clock +#define setup_secondary_clock setup_secondary_APIC_clock #endif static __inline fastcall void native_apic_write(unsigned long reg, @@ -93,9 +95,7 @@ static inline void ack_APIC_irq(void) apic_write_around(APIC_EOI, 0); } -extern void (*wait_timer_tick)(void); - -extern int get_maxlvt(void); +extern int lapic_get_maxlvt(void); extern void clear_local_APIC(void); extern void connect_bsp_APIC (void); extern void disconnect_bsp_APIC (int virt_wire_setup); @@ -111,14 +111,9 @@ extern void smp_local_timer_interrupt (void); extern void setup_boot_APIC_clock (void); extern void setup_secondary_APIC_clock (void); extern int APIC_init_uniprocessor (void); -extern void disable_APIC_timer(void); -extern void enable_APIC_timer(void); extern void enable_NMI_through_LVT0 (void * dummy); -void smp_send_timer_broadcast_ipi(void); -void switch_APIC_timer_to_ipi(void *cpumask); -void switch_ipi_to_APIC_timer(void *cpumask); #define ARCH_APICTIMER_STOPS_ON_C3 1 extern int timer_over_8254; diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h index 38f1aeb..c90c7c4 100644 --- a/include/asm-i386/bugs.h +++ b/include/asm-i386/bugs.h @@ -160,7 +160,7 @@ static void __init check_config(void) * If we configured ourselves for a TSC, we'd better have one! */ #ifdef CONFIG_X86_TSC - if (!cpu_has_tsc) + if (!cpu_has_tsc && !tsc_disable) panic("Kernel compiled for Pentium+, requires TSC feature!"); #endif diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h index f398cc4..050831f 100644 --- a/include/asm-i386/desc.h +++ b/include/asm-i386/desc.h @@ -22,7 +22,7 @@ struct Xgt_desc_struct { extern struct Xgt_desc_struct idt_descr; DECLARE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); - +extern struct Xgt_desc_struct early_gdt_descr; static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) { diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index 369035d..8d33c9b 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h @@ -90,8 +90,8 @@ typedef struct user_fxsr_struct elf_fpxregset_t; pr_reg[6] = regs->eax; \ pr_reg[7] = regs->xds; \ pr_reg[8] = regs->xes; \ - savesegment(fs,pr_reg[9]); \ - pr_reg[10] = regs->xgs; \ + pr_reg[9] = regs->xfs; \ + savesegment(gs,pr_reg[10]); \ pr_reg[11] = regs->orig_eax; \ pr_reg[12] = regs->eip; \ pr_reg[13] = regs->xcs; \ diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h index e47be9a..fc03cf9 100644 --- a/include/asm-i386/hpet.h +++ b/include/asm-i386/hpet.h @@ -90,16 +90,19 @@ #define HPET_MIN_PERIOD (100000UL) #define HPET_TICK_RATE (HZ * 100000UL) -extern unsigned long hpet_tick; /* hpet clks count per tick */ extern unsigned long hpet_address; /* hpet memory map physical address */ -extern int hpet_use_timer; +extern int is_hpet_enabled(void); +#ifdef CONFIG_X86_64 +extern unsigned long hpet_tick; /* hpet clks count per tick */ +extern int hpet_use_timer; extern int hpet_rtc_timer_init(void); extern int hpet_enable(void); -extern int hpet_reenable(void); -extern int is_hpet_enabled(void); extern int is_hpet_capable(void); extern int hpet_readl(unsigned long a); +#else +extern int hpet_enable(void); +#endif #ifdef CONFIG_HPET_EMULATE_RTC extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); @@ -110,5 +113,10 @@ extern int hpet_rtc_dropped_irq(void); extern int hpet_rtc_timer_init(void); extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); #endif /* CONFIG_HPET_EMULATE_RTC */ + +#else + +static inline int hpet_enable(void) { return 0; } + #endif /* CONFIG_HPET_TIMER */ #endif /* _I386_HPET_H */ diff --git a/include/asm-i386/i8253.h b/include/asm-i386/i8253.h index 015d8df..6cb0dd4 100644 --- a/include/asm-i386/i8253.h +++ b/include/asm-i386/i8253.h @@ -1,6 +1,21 @@ #ifndef __ASM_I8253_H__ #define __ASM_I8253_H__ +#include <linux/clockchips.h> + extern spinlock_t i8253_lock; +extern struct clock_event_device *global_clock_event; + +/** + * pit_interrupt_hook - hook into timer tick + * @regs: standard registers from interrupt + * + * Call the global clock event handler. + **/ +static inline void pit_interrupt_hook(void) +{ + global_clock_event->event_handler(global_clock_event); +} + #endif /* __ASM_I8253_H__ */ diff --git a/include/asm-i386/idle.h b/include/asm-i386/idle.h new file mode 100644 index 0000000..87ab939 --- /dev/null +++ b/include/asm-i386/idle.h @@ -0,0 +1,14 @@ +#ifndef _ASM_I386_IDLE_H +#define _ASM_I386_IDLE_H 1 + +#define IDLE_START 1 +#define IDLE_END 2 + +struct notifier_block; +void idle_notifier_register(struct notifier_block *n); +void idle_notifier_unregister(struct notifier_block *n); + +void exit_idle(void); +void enter_idle(void); + +#endif diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h index 7d606e3..56e5689 100644 --- a/include/asm-i386/mach-default/do_timer.h +++ b/include/asm-i386/mach-default/do_timer.h @@ -1,86 +1,16 @@ /* defines for inline arch setup functions */ +#include <linux/clockchips.h> -#include <asm/apic.h> #include <asm/i8259.h> +#include <asm/i8253.h> /** * do_timer_interrupt_hook - hook into timer tick - * @regs: standard registers from interrupt * - * Description: - * This hook is called immediately after the timer interrupt is ack'd. - * It's primary purpose is to allow architectures that don't possess - * individual per CPU clocks (like the CPU APICs supply) to broadcast the - * timer interrupt as a means of triggering reschedules etc. + * Call the pit clock event handler. see asm/i8253.h **/ static inline void do_timer_interrupt_hook(void) { - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode_vm(get_irq_regs())); -#endif -/* - * In the SMP case we use the local APIC timer interrupt to do the - * profiling, except when we simulate SMP mode on a uniprocessor - * system, in that case we have to call the local interrupt handler. - */ -#ifndef CONFIG_X86_LOCAL_APIC - profile_tick(CPU_PROFILING); -#else - if (!using_apic_timer) - smp_local_timer_interrupt(); -#endif -} - - -/* you can safely undefine this if you don't have the Neptune chipset */ - -#define BUGGY_NEPTUN_TIMER - -/** - * do_timer_overflow - process a detected timer overflow condition - * @count: hardware timer interrupt count on overflow - * - * Description: - * This call is invoked when the jiffies count has not incremented but - * the hardware timer interrupt has. It means that a timer tick interrupt - * came along while the previous one was pending, thus a tick was missed - **/ -static inline int do_timer_overflow(int count) -{ - int i; - - spin_lock(&i8259A_lock); - /* - * This is tricky when I/O APICs are used; - * see do_timer_interrupt(). - */ - i = inb(0x20); - spin_unlock(&i8259A_lock); - - /* assumption about timer being IRQ0 */ - if (i & 0x01) { - /* - * We cannot detect lost timer interrupts ... - * well, that's why we call them lost, don't we? :) - * [hmm, on the Pentium and Alpha we can ... sort of] - */ - count -= LATCH; - } else { -#ifdef BUGGY_NEPTUN_TIMER - /* - * for the Neptun bug we know that the 'latch' - * command doesn't latch the high and low value - * of the counter atomically. Thus we have to - * substract 256 from the counter - * ... funny, isnt it? :) - */ - - count -= 256; -#else - printk("do_slow_gettimeoffset(): hardware timer problem?\n"); -#endif - } - return count; + pit_interrupt_hook(); } diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h index 04e69c1..60f9dcc 100644 --- a/include/asm-i386/mach-voyager/do_timer.h +++ b/include/asm-i386/mach-voyager/do_timer.h @@ -1,25 +1,18 @@ /* defines for inline arch setup functions */ +#include <linux/clockchips.h> + #include <asm/voyager.h> +#include <asm/i8253.h> +/** + * do_timer_interrupt_hook - hook into timer tick + * @regs: standard registers from interrupt + * + * Call the pit clock event handler. see asm/i8253.h + **/ static inline void do_timer_interrupt_hook(void) { - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode_vm(irq_regs)); -#endif - + pit_interrupt_hook(); voyager_timer_interrupt(); } -static inline int do_timer_overflow(int count) -{ - /* can't read the ISR, just assume 1 tick - overflow */ - if(count > LATCH || count < 0) { - printk(KERN_ERR "VOYAGER PROBLEM: count is %d, latch is %d\n", count, LATCH); - count = LATCH; - } - count -= LATCH; - - return count; -} diff --git a/include/asm-i386/mce.h b/include/asm-i386/mce.h index 7cc1a973..b0a02ee 100644 --- a/include/asm-i386/mce.h +++ b/include/asm-i386/mce.h @@ -3,3 +3,5 @@ extern void mcheck_init(struct cpuinfo_x86 *c); #else #define mcheck_init(c) do {} while(0) #endif + +extern int mce_disabled; diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h index 68ff102..e6aa30f 100644 --- a/include/asm-i386/mmu_context.h +++ b/include/asm-i386/mmu_context.h @@ -63,7 +63,7 @@ static inline void switch_mm(struct mm_struct *prev, } #define deactivate_mm(tsk, mm) \ - asm("movl %0,%%fs": :"r" (0)); + asm("movl %0,%%gs": :"r" (0)); #define activate_mm(prev, next) \ switch_mm((prev),(next),NULL) diff --git a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h index 770bf6d..f213493 100644 --- a/include/asm-i386/mpspec.h +++ b/include/asm-i386/mpspec.h @@ -23,7 +23,6 @@ extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; extern int mpc_default_type; extern unsigned long mp_lapic_addr; extern int pic_mode; -extern int using_apic_timer; #ifdef CONFIG_ACPI extern void mp_register_lapic (u8 id, u8 enabled); diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h index 609a389..6db40d0 100644 --- a/include/asm-i386/msr.h +++ b/include/asm-i386/msr.h @@ -307,4 +307,7 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val) #define MSR_CORE_PERF_GLOBAL_CTRL 0x38f #define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x390 +/* Geode defined MSRs */ +#define MSR_GEODE_BUSCONT_CONF0 0x1900 + #endif /* __ASM_MSR_H */ diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h index 9f06265..6317e0a 100644 --- a/include/asm-i386/paravirt.h +++ b/include/asm-i386/paravirt.h @@ -59,90 +59,102 @@ struct paravirt_ops convention. This makes it easier to implement inline assembler replacements. */ - void (fastcall *cpuid)(unsigned int *eax, unsigned int *ebx, + void (*cpuid)(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx); - unsigned long (fastcall *get_debugreg)(int regno); - void (fastcall *set_debugreg)(int regno, unsigned long value); + unsigned long (*get_debugreg)(int regno); + void (*set_debugreg)(int regno, unsigned long value); - void (fastcall *clts)(void); + void (*clts)(void); - unsigned long (fastcall *read_cr0)(void); - void (fastcall *write_cr0)(unsigned long); + unsigned long (*read_cr0)(void); + void (*write_cr0)(unsigned long); - unsigned long (fastcall *read_cr2)(void); - void (fastcall *write_cr2)(unsigned long); + unsigned long (*read_cr2)(void); + void (*write_cr2)(unsigned long); - unsigned long (fastcall *read_cr3)(void); - void (fastcall *write_cr3)(unsigned long); + unsigned long (*read_cr3)(void); + void (*write_cr3)(unsigned long); - unsigned long (fastcall *read_cr4_safe)(void); - unsigned long (fastcall *read_cr4)(void); - void (fastcall *write_cr4)(unsigned long); + unsigned long (*read_cr4_safe)(void); + unsigned long (*read_cr4)(void); + void (*write_cr4)(unsigned long); - unsigned long (fastcall *save_fl)(void); - void (fastcall *restore_fl)(unsigned long); - void (fastcall *irq_disable)(void); - void (fastcall *irq_enable)(void); - void (fastcall *safe_halt)(void); - void (fastcall *halt)(void); - void (fastcall *wbinvd)(void); + unsigned long (*save_fl)(void); + void (*restore_fl)(unsigned long); + void (*irq_disable)(void); + void (*irq_enable)(void); + void (*safe_halt)(void); + void (*halt)(void); + void (*wbinvd)(void); /* err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ - u64 (fastcall *read_msr)(unsigned int msr, int *err); - int (fastcall *write_msr)(unsigned int msr, u64 val); - - u64 (fastcall *read_tsc)(void); - u64 (fastcall *read_pmc)(void); - - void (fastcall *load_tr_desc)(void); - void (fastcall *load_gdt)(const struct Xgt_desc_struct *); - void (fastcall *load_idt)(const struct Xgt_desc_struct *); - void (fastcall *store_gdt)(struct Xgt_desc_struct *); - void (fastcall *store_idt)(struct Xgt_desc_struct *); - void (fastcall *set_ldt)(const void *desc, unsigned entries); - unsigned long (fastcall *store_tr)(void); - void (fastcall *load_tls)(struct thread_struct *t, unsigned int cpu); - void (fastcall *write_ldt_entry)(void *dt, int entrynum, + u64 (*read_msr)(unsigned int msr, int *err); + int (*write_msr)(unsigned int msr, u64 val); + + u64 (*read_tsc)(void); + u64 (*read_pmc)(void); + + void (*load_tr_desc)(void); + void (*load_gdt)(const struct Xgt_desc_struct *); + void (*load_idt)(const struct Xgt_desc_struct *); + void (*store_gdt)(struct Xgt_desc_struct *); + void (*store_idt)(struct Xgt_desc_struct *); + void (*set_ldt)(const void *desc, unsigned entries); + unsigned long (*store_tr)(void); + void (*load_tls)(struct thread_struct *t, unsigned int cpu); + void (*write_ldt_entry)(void *dt, int entrynum, u32 low, u32 high); - void (fastcall *write_gdt_entry)(void *dt, int entrynum, + void (*write_gdt_entry)(void *dt, int entrynum, u32 low, u32 high); - void (fastcall *write_idt_entry)(void *dt, int entrynum, + void (*write_idt_entry)(void *dt, int entrynum, u32 low, u32 high); - void (fastcall *load_esp0)(struct tss_struct *tss, + void (*load_esp0)(struct tss_struct *tss, struct thread_struct *thread); - void (fastcall *set_iopl_mask)(unsigned mask); + void (*set_iopl_mask)(unsigned mask); - void (fastcall *io_delay)(void); + void (*io_delay)(void); void (*const_udelay)(unsigned long loops); #ifdef CONFIG_X86_LOCAL_APIC - void (fastcall *apic_write)(unsigned long reg, unsigned long v); - void (fastcall *apic_write_atomic)(unsigned long reg, unsigned long v); - unsigned long (fastcall *apic_read)(unsigned long reg); + void (*apic_write)(unsigned long reg, unsigned long v); + void (*apic_write_atomic)(unsigned long reg, unsigned long v); + unsigned long (*apic_read)(unsigned long reg); + void (*setup_boot_clock)(void); + void (*setup_secondary_clock)(void); #endif - void (fastcall *flush_tlb_user)(void); - void (fastcall *flush_tlb_kernel)(void); - void (fastcall *flush_tlb_single)(u32 addr); - - void (fastcall *set_pte)(pte_t *ptep, pte_t pteval); - void (fastcall *set_pte_at)(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval); - void (fastcall *set_pmd)(pmd_t *pmdp, pmd_t pmdval); - void (fastcall *pte_update)(struct mm_struct *mm, u32 addr, pte_t *ptep); - void (fastcall *pte_update_defer)(struct mm_struct *mm, u32 addr, pte_t *ptep); + void (*flush_tlb_user)(void); + void (*flush_tlb_kernel)(void); + void (*flush_tlb_single)(u32 addr); + + void (*alloc_pt)(u32 pfn); + void (*alloc_pd)(u32 pfn); + void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count); + void (*release_pt)(u32 pfn); + void (*release_pd)(u32 pfn); + + void (*set_pte)(pte_t *ptep, pte_t pteval); + void (*set_pte_at)(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval); + void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval); + void (*pte_update)(struct mm_struct *mm, u32 addr, pte_t *ptep); + void (*pte_update_defer)(struct mm_struct *mm, u32 addr, pte_t *ptep); #ifdef CONFIG_X86_PAE - void (fastcall *set_pte_atomic)(pte_t *ptep, pte_t pteval); - void (fastcall *set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); - void (fastcall *set_pud)(pud_t *pudp, pud_t pudval); - void (fastcall *pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep); - void (fastcall *pmd_clear)(pmd_t *pmdp); + void (*set_pte_atomic)(pte_t *ptep, pte_t pteval); + void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); + void (*set_pud)(pud_t *pudp, pud_t pudval); + void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep); + void (*pmd_clear)(pmd_t *pmdp); #endif + void (*set_lazy_mode)(int mode); + /* These two are jmp to, not actually called. */ - void (fastcall *irq_enable_sysexit)(void); - void (fastcall *iret)(void); + void (*irq_enable_sysexit)(void); + void (*iret)(void); + + void (*startup_ipi_hook)(int phys_apicid, unsigned long start_eip, unsigned long start_esp); }; /* Mark a paravirt probe function. */ @@ -313,13 +325,38 @@ static inline unsigned long apic_read(unsigned long reg) { return paravirt_ops.apic_read(reg); } + +static inline void setup_boot_clock(void) +{ + paravirt_ops.setup_boot_clock(); +} + +static inline void setup_secondary_clock(void) +{ + paravirt_ops.setup_secondary_clock(); +} #endif +#ifdef CONFIG_SMP +static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip, + unsigned long start_esp) +{ + return paravirt_ops.startup_ipi_hook(phys_apicid, start_eip, start_esp); +} +#endif #define __flush_tlb() paravirt_ops.flush_tlb_user() #define __flush_tlb_global() paravirt_ops.flush_tlb_kernel() #define __flush_tlb_single(addr) paravirt_ops.flush_tlb_single(addr) +#define paravirt_alloc_pt(pfn) paravirt_ops.alloc_pt(pfn) +#define paravirt_release_pt(pfn) paravirt_ops.release_pt(pfn) + +#define paravirt_alloc_pd(pfn) paravirt_ops.alloc_pd(pfn) +#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) \ + paravirt_ops.alloc_pd_clone(pfn, clonepfn, start, count) +#define paravirt_release_pd(pfn) paravirt_ops.release_pd(pfn) + static inline void set_pte(pte_t *ptep, pte_t pteval) { paravirt_ops.set_pte(ptep, pteval); @@ -372,6 +409,19 @@ static inline void pmd_clear(pmd_t *pmdp) } #endif +/* Lazy mode for batching updates / context switch */ +#define PARAVIRT_LAZY_NONE 0 +#define PARAVIRT_LAZY_MMU 1 +#define PARAVIRT_LAZY_CPU 2 + +#define __HAVE_ARCH_ENTER_LAZY_CPU_MODE +#define arch_enter_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_CPU) +#define arch_leave_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE) + +#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE +#define arch_enter_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_MMU) +#define arch_leave_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE) + /* These all sit in the .parainstructions section to tell us what to patch. */ struct paravirt_patch { u8 *instr; /* original instructions */ diff --git a/include/asm-i386/pda.h b/include/asm-i386/pda.h index 2ba2736..b12d59a 100644 --- a/include/asm-i386/pda.h +++ b/include/asm-i386/pda.h @@ -39,19 +39,19 @@ extern struct i386_pda _proxy_pda; if (0) { T__ tmp__; tmp__ = (val); } \ switch (sizeof(_proxy_pda.field)) { \ case 1: \ - asm(op "b %1,%%gs:%c2" \ + asm(op "b %1,%%fs:%c2" \ : "+m" (_proxy_pda.field) \ :"ri" ((T__)val), \ "i"(pda_offset(field))); \ break; \ case 2: \ - asm(op "w %1,%%gs:%c2" \ + asm(op "w %1,%%fs:%c2" \ : "+m" (_proxy_pda.field) \ :"ri" ((T__)val), \ "i"(pda_offset(field))); \ break; \ case 4: \ - asm(op "l %1,%%gs:%c2" \ + asm(op "l %1,%%fs:%c2" \ : "+m" (_proxy_pda.field) \ :"ri" ((T__)val), \ "i"(pda_offset(field))); \ @@ -65,19 +65,19 @@ extern struct i386_pda _proxy_pda; typeof(_proxy_pda.field) ret__; \ switch (sizeof(_proxy_pda.field)) { \ case 1: \ - asm(op "b %%gs:%c1,%0" \ + asm(op "b %%fs:%c1,%0" \ : "=r" (ret__) \ : "i" (pda_offset(field)), \ "m" (_proxy_pda.field)); \ break; \ case 2: \ - asm(op "w %%gs:%c1,%0" \ + asm(op "w %%fs:%c1,%0" \ : "=r" (ret__) \ : "i" (pda_offset(field)), \ "m" (_proxy_pda.field)); \ break; \ case 4: \ - asm(op "l %%gs:%c1,%0" \ + asm(op "l %%fs:%c1,%0" \ : "=r" (ret__) \ : "i" (pda_offset(field)), \ "m" (_proxy_pda.field)); \ diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h index 4b1e613..c8dc2d0 100644 --- a/include/asm-i386/pgalloc.h +++ b/include/asm-i386/pgalloc.h @@ -5,13 +5,31 @@ #include <linux/threads.h> #include <linux/mm.h> /* for struct page */ -#define pmd_populate_kernel(mm, pmd, pte) \ - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#define paravirt_alloc_pt(pfn) do { } while (0) +#define paravirt_alloc_pd(pfn) do { } while (0) +#define paravirt_alloc_pd(pfn) do { } while (0) +#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0) +#define paravirt_release_pt(pfn) do { } while (0) +#define paravirt_release_pd(pfn) do { } while (0) +#endif + +#define pmd_populate_kernel(mm, pmd, pte) \ +do { \ + paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT); \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \ +} while (0) #define pmd_populate(mm, pmd, pte) \ +do { \ + paravirt_alloc_pt(page_to_pfn(pte)); \ set_pmd(pmd, __pmd(_PAGE_TABLE + \ ((unsigned long long)page_to_pfn(pte) << \ - (unsigned long long) PAGE_SHIFT))) + (unsigned long long) PAGE_SHIFT))); \ +} while (0) + /* * Allocate and free page tables. */ @@ -32,7 +50,11 @@ static inline void pte_free(struct page *pte) } -#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pte_free_tlb(tlb,pte) \ +do { \ + paravirt_release_pt(page_to_pfn(pte)); \ + tlb_remove_page((tlb),(pte)); \ +} while (0) #ifdef CONFIG_X86_PAE /* diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 359f10b..edfbe46 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -257,6 +257,14 @@ static inline void __mwait(unsigned long eax, unsigned long ecx) : :"a" (eax), "c" (ecx)); } +static inline void __sti_mwait(unsigned long eax, unsigned long ecx) +{ + /* "mwait %eax,%ecx;" */ + asm volatile( + "sti; .byte 0x0f,0x01,0xc9;" + : :"a" (eax), "c" (ecx)); +} + extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); /* from system description table in BIOS. Mostly for MCA use, but @@ -424,7 +432,7 @@ struct thread_struct { .vm86_info = NULL, \ .sysenter_cs = __KERNEL_CS, \ .io_bitmap_ptr = NULL, \ - .gs = __KERNEL_PDA, \ + .fs = __KERNEL_PDA, \ } /* @@ -442,8 +450,8 @@ struct thread_struct { } #define start_thread(regs, new_eip, new_esp) do { \ - __asm__("movl %0,%%fs": :"r" (0)); \ - regs->xgs = 0; \ + __asm__("movl %0,%%gs": :"r" (0)); \ + regs->xfs = 0; \ set_fs(USER_DS); \ regs->xds = __USER_DS; \ regs->xes = __USER_DS; \ diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h index bdbc894..6002597 100644 --- a/include/asm-i386/ptrace.h +++ b/include/asm-i386/ptrace.h @@ -16,8 +16,8 @@ struct pt_regs { long eax; int xds; int xes; - /* int xfs; */ - int xgs; + int xfs; + /* int xgs; */ long orig_eax; long eip; int xcs; @@ -49,6 +49,10 @@ static inline int user_mode_vm(struct pt_regs *regs) { return ((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= USER_RPL; } +static inline int v8086_mode(struct pt_regs *regs) +{ + return (regs->eflags & VM_MASK); +} #define instruction_pointer(regs) ((regs)->eip) #define regs_return_value(regs) ((regs)->eax) diff --git a/include/asm-i386/segment.h b/include/asm-i386/segment.h index 3c796af..065f10b 100644 --- a/include/asm-i386/segment.h +++ b/include/asm-i386/segment.h @@ -83,14 +83,8 @@ * The GDT has 32 entries */ #define GDT_ENTRIES 32 - #define GDT_SIZE (GDT_ENTRIES * 8) -/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ -#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) -/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ -#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) - /* Simple and small GDT entries for booting only */ #define GDT_ENTRY_BOOT_CS 2 @@ -134,4 +128,17 @@ #ifndef CONFIG_PARAVIRT #define get_kernel_rpl() 0 #endif +/* + * Matching rules for certain types of segments. + */ + +/* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */ +#define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8) + +/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ +#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) + +/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ +#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) + #endif diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h index 7631627..0e8077c 100644 --- a/include/asm-i386/setup.h +++ b/include/asm-i386/setup.h @@ -77,6 +77,8 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map); void __init add_memory_region(unsigned long long start, unsigned long long size, int type); +extern unsigned long init_pg_tables_end; + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 64fe624..6bf0033 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -52,6 +52,11 @@ extern void cpu_exit_clear(void); extern void cpu_uninit(void); #endif +#ifndef CONFIG_PARAVIRT +#define startup_ipi_hook(phys_apicid, start_eip, start_esp) \ +do { } while (0) +#endif + /* * This function is needed by all SMP systems. It must _always_ be valid * from the initial startup. We map APIC_BASE very early in page_setup(), diff --git a/include/asm-i386/time.h b/include/asm-i386/time.h index ea8065a..571b429 100644 --- a/include/asm-i386/time.h +++ b/include/asm-i386/time.h @@ -30,6 +30,7 @@ static inline int native_set_wallclock(unsigned long nowtime) #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> +extern unsigned long long native_sched_clock(void); #else /* !CONFIG_PARAVIRT */ #define get_wallclock() native_get_wallclock() diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h index d0ebd05..4752c3a 100644 --- a/include/asm-i386/timer.h +++ b/include/asm-i386/timer.h @@ -8,6 +8,9 @@ void setup_pit_timer(void); /* Modifiers for buggy PIT handling */ extern int pit_latch_buggy; extern int timer_ack; +extern int no_timer_check; +extern unsigned long long (*custom_sched_clock)(void); +extern int no_sync_cmos_clock; extern int recalibrate_cpu_khz(void); #endif diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h index c139331..e997891 100644 --- a/include/asm-i386/tsc.h +++ b/include/asm-i386/tsc.h @@ -1,48 +1 @@ -/* - * linux/include/asm-i386/tsc.h - * - * i386 TSC related functions - */ -#ifndef _ASM_i386_TSC_H -#define _ASM_i386_TSC_H - -#include <asm/processor.h> - -/* - * Standard way to access the cycle counter on i586+ CPUs. - * Currently only used on SMP. - * - * If you really have a SMP machine with i486 chips or older, - * compile for that, and this will just always return zero. - * That's ok, it just means that the nicer scheduling heuristics - * won't work for you. - * - * We only use the low 32 bits, and we'd simply better make sure - * that we reschedule before that wraps. Scheduling at least every - * four billion cycles just basically sounds like a good idea, - * regardless of how fast the machine is. - */ -typedef unsigned long long cycles_t; - -extern unsigned int cpu_khz; -extern unsigned int tsc_khz; - -static inline cycles_t get_cycles(void) -{ - unsigned long long ret = 0; - -#ifndef CONFIG_X86_TSC - if (!cpu_has_tsc) - return 0; -#endif - -#if defined(CONFIG_X86_GENERIC) || defined(CONFIG_X86_TSC) - rdtscll(ret); -#endif - return ret; -} - -extern void tsc_init(void); -extern void mark_tsc_unstable(void); - -#endif +#include <asm-x86_64/tsc.h> diff --git a/include/asm-i386/vmi.h b/include/asm-i386/vmi.h new file mode 100644 index 0000000..43c8933 --- /dev/null +++ b/include/asm-i386/vmi.h @@ -0,0 +1,262 @@ +/* + * VMI interface definition + * + * 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. + * + * Maintained by: Zachary Amsden zach@vmware.com + * + */ +#include <linux/types.h> + +/* + *--------------------------------------------------------------------- + * + * VMI Option ROM API + * + *--------------------------------------------------------------------- + */ +#define VMI_SIGNATURE 0x696d5663 /* "cVmi" */ + +#define PCI_VENDOR_ID_VMWARE 0x15AD +#define PCI_DEVICE_ID_VMWARE_VMI 0x0801 + +/* + * We use two version numbers for compatibility, with the major + * number signifying interface breakages, and the minor number + * interface extensions. + */ +#define VMI_API_REV_MAJOR 3 +#define VMI_API_REV_MINOR 0 + +#define VMI_CALL_CPUID 0 +#define VMI_CALL_WRMSR 1 +#define VMI_CALL_RDMSR 2 +#define VMI_CALL_SetGDT 3 +#define VMI_CALL_SetLDT 4 +#define VMI_CALL_SetIDT 5 +#define VMI_CALL_SetTR 6 +#define VMI_CALL_GetGDT 7 +#define VMI_CALL_GetLDT 8 +#define VMI_CALL_GetIDT 9 +#define VMI_CALL_GetTR 10 +#define VMI_CALL_WriteGDTEntry 11 +#define VMI_CALL_WriteLDTEntry 12 +#define VMI_CALL_WriteIDTEntry 13 +#define VMI_CALL_UpdateKernelStack 14 +#define VMI_CALL_SetCR0 15 +#define VMI_CALL_SetCR2 16 +#define VMI_CALL_SetCR3 17 +#define VMI_CALL_SetCR4 18 +#define VMI_CALL_GetCR0 19 +#define VMI_CALL_GetCR2 20 +#define VMI_CALL_GetCR3 21 +#define VMI_CALL_GetCR4 22 +#define VMI_CALL_WBINVD 23 +#define VMI_CALL_SetDR 24 +#define VMI_CALL_GetDR 25 +#define VMI_CALL_RDPMC 26 +#define VMI_CALL_RDTSC 27 +#define VMI_CALL_CLTS 28 +#define VMI_CALL_EnableInterrupts 29 +#define VMI_CALL_DisableInterrupts 30 +#define VMI_CALL_GetInterruptMask 31 +#define VMI_CALL_SetInterruptMask 32 +#define VMI_CALL_IRET 33 +#define VMI_CALL_SYSEXIT 34 +#define VMI_CALL_Halt 35 +#define VMI_CALL_Reboot 36 +#define VMI_CALL_Shutdown 37 +#define VMI_CALL_SetPxE 38 +#define VMI_CALL_SetPxELong 39 +#define VMI_CALL_UpdatePxE 40 +#define VMI_CALL_UpdatePxELong 41 +#define VMI_CALL_MachineToPhysical 42 +#define VMI_CALL_PhysicalToMachine 43 +#define VMI_CALL_AllocatePage 44 +#define VMI_CALL_ReleasePage 45 +#define VMI_CALL_InvalPage 46 +#define VMI_CALL_FlushTLB 47 +#define VMI_CALL_SetLinearMapping 48 + +#define VMI_CALL_SetIOPLMask 61 +#define VMI_CALL_SetInitialAPState 62 +#define VMI_CALL_APICWrite 63 +#define VMI_CALL_APICRead 64 +#define VMI_CALL_SetLazyMode 73 + +/* + *--------------------------------------------------------------------- + * + * MMU operation flags + * + *--------------------------------------------------------------------- + */ + +/* Flags used by VMI_{Allocate|Release}Page call */ +#define VMI_PAGE_PAE 0x10 /* Allocate PAE shadow */ +#define VMI_PAGE_CLONE 0x20 /* Clone from another shadow */ +#define VMI_PAGE_ZEROED 0x40 /* Page is pre-zeroed */ + + +/* Flags shared by Allocate|Release Page and PTE updates */ +#define VMI_PAGE_PT 0x01 +#define VMI_PAGE_PD 0x02 +#define VMI_PAGE_PDP 0x04 +#define VMI_PAGE_PML4 0x08 + +#define VMI_PAGE_NORMAL 0x00 /* for debugging */ + +/* Flags used by PTE updates */ +#define VMI_PAGE_CURRENT_AS 0x10 /* implies VMI_PAGE_VA_MASK is valid */ +#define VMI_PAGE_DEFER 0x20 /* may queue update until TLB inval */ +#define VMI_PAGE_VA_MASK 0xfffff000 + +#ifdef CONFIG_X86_PAE +#define VMI_PAGE_L1 (VMI_PAGE_PT | VMI_PAGE_PAE | VMI_PAGE_ZEROED) +#define VMI_PAGE_L2 (VMI_PAGE_PD | VMI_PAGE_PAE | VMI_PAGE_ZEROED) +#else +#define VMI_PAGE_L1 (VMI_PAGE_PT | VMI_PAGE_ZEROED) +#define VMI_PAGE_L2 (VMI_PAGE_PD | VMI_PAGE_ZEROED) +#endif + +/* Flags used by VMI_FlushTLB call */ +#define VMI_FLUSH_TLB 0x01 +#define VMI_FLUSH_GLOBAL 0x02 + +/* + *--------------------------------------------------------------------- + * + * VMI relocation definitions for ROM call get_reloc + * + *--------------------------------------------------------------------- + */ + +/* VMI Relocation types */ +#define VMI_RELOCATION_NONE 0 +#define VMI_RELOCATION_CALL_REL 1 +#define VMI_RELOCATION_JUMP_REL 2 +#define VMI_RELOCATION_NOP 3 + +#ifndef __ASSEMBLY__ +struct vmi_relocation_info { + unsigned char *eip; + unsigned char type; + unsigned char reserved[3]; +}; +#endif + + +/* + *--------------------------------------------------------------------- + * + * Generic ROM structures and definitions + * + *--------------------------------------------------------------------- + */ + +#ifndef __ASSEMBLY__ + +struct vrom_header { + u16 rom_signature; // option ROM signature + u8 rom_length; // ROM length in 512 byte chunks + u8 rom_entry[4]; // 16-bit code entry point + u8 rom_pad0; // 4-byte align pad + u32 vrom_signature; // VROM identification signature + u8 api_version_min;// Minor version of API + u8 api_version_maj;// Major version of API + u8 jump_slots; // Number of jump slots + u8 reserved1; // Reserved for expansion + u32 virtual_top; // Hypervisor virtual address start + u16 reserved2; // Reserved for expansion + u16 license_offs; // Offset to License string + u16 pci_header_offs;// Offset to PCI OPROM header + u16 pnp_header_offs;// Offset to PnP OPROM header + u32 rom_pad3; // PnP reserverd / VMI reserved + u8 reserved[96]; // Reserved for headers + char vmi_init[8]; // VMI_Init jump point + char get_reloc[8]; // VMI_GetRelocationInfo jump point +} __attribute__((packed)); + +struct pnp_header { + char sig[4]; + char rev; + char size; + short next; + short res; + long devID; + unsigned short manufacturer_offset; + unsigned short product_offset; +} __attribute__((packed)); + +struct pci_header { + char sig[4]; + short vendorID; + short deviceID; + short vpdData; + short size; + char rev; + char class; + char subclass; + char interface; + short chunks; + char rom_version_min; + char rom_version_maj; + char codetype; + char lastRom; + short reserved; +} __attribute__((packed)); + +/* Function prototypes for bootstrapping */ +extern void vmi_init(void); +extern void vmi_bringup(void); +extern void vmi_apply_boot_page_allocations(void); + +/* State needed to start an application processor in an SMP system. */ +struct vmi_ap_state { + u32 cr0; + u32 cr2; + u32 cr3; + u32 cr4; + + u64 efer; + + u32 eip; + u32 eflags; + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; + u32 esp; + u32 ebp; + u32 esi; + u32 edi; + u16 cs; + u16 ss; + u16 ds; + u16 es; + u16 fs; + u16 gs; + u16 ldtr; + + u16 gdtr_limit; + u32 gdtr_base; + u32 idtr_base; + u16 idtr_limit; +}; + +#endif diff --git a/include/asm-i386/vmi_time.h b/include/asm-i386/vmi_time.h new file mode 100644 index 0000000..c129312 --- /dev/null +++ b/include/asm-i386/vmi_time.h @@ -0,0 +1,103 @@ +/* + * VMI Time wrappers + * + * Copyright (C) 2006, 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 + * + */ + +#ifndef __VMI_TIME_H +#define __VMI_TIME_H + +/* + * Raw VMI call indices for timer functions + */ +#define VMI_CALL_GetCycleFrequency 66 +#define VMI_CALL_GetCycleCounter 67 +#define VMI_CALL_SetAlarm 68 +#define VMI_CALL_CancelAlarm 69 +#define VMI_CALL_GetWallclockTime 70 +#define VMI_CALL_WallclockUpdated 71 + +/* Cached VMI timer operations */ +extern struct vmi_timer_ops { + u64 (*get_cycle_frequency)(void); + u64 (*get_cycle_counter)(int); + u64 (*get_wallclock)(void); + int (*wallclock_updated)(void); + void (*set_alarm)(u32 flags, u64 expiry, u64 period); + void (*cancel_alarm)(u32 flags); +} vmi_timer_ops; + +/* Prototypes */ +extern void __init vmi_time_init(void); +extern unsigned long vmi_get_wallclock(void); +extern int vmi_set_wallclock(unsigned long now); +extern unsigned long long vmi_sched_clock(void); + +#ifdef CONFIG_X86_LOCAL_APIC +extern void __init vmi_timer_setup_boot_alarm(void); +extern void __init vmi_timer_setup_secondary_alarm(void); +extern void apic_vmi_timer_interrupt(void); +#endif + +#ifdef CONFIG_NO_IDLE_HZ +extern int vmi_stop_hz_timer(void); +extern void vmi_account_time_restart_hz_timer(void); +#endif + +/* + * When run under a hypervisor, a vcpu is always in one of three states: + * running, halted, or ready. The vcpu is in the 'running' state if it + * is executing. When the vcpu executes the halt interface, the vcpu + * enters the 'halted' state and remains halted until there is some work + * pending for the vcpu (e.g. an alarm expires, host I/O completes on + * behalf of virtual I/O). At this point, the vcpu enters the 'ready' + * state (waiting for the hypervisor to reschedule it). Finally, at any + * time when the vcpu is not in the 'running' state nor the 'halted' + * state, it is in the 'ready' state. + * + * Real time is advances while the vcpu is 'running', 'ready', or + * 'halted'. Stolen time is the time in which the vcpu is in the + * 'ready' state. Available time is the remaining time -- the vcpu is + * either 'running' or 'halted'. + * + * All three views of time are accessible through the VMI cycle + * counters. + */ + +/* The cycle counters. */ +#define VMI_CYCLES_REAL 0 +#define VMI_CYCLES_AVAILABLE 1 +#define VMI_CYCLES_STOLEN 2 + +/* The alarm interface 'flags' bits */ +#define VMI_ALARM_COUNTERS 2 + +#define VMI_ALARM_COUNTER_MASK 0x000000ff + +#define VMI_ALARM_WIRED_IRQ0 0x00000000 +#define VMI_ALARM_WIRED_LVTT 0x00010000 + +#define VMI_ALARM_IS_ONESHOT 0x00000000 +#define VMI_ALARM_IS_PERIODIC 0x00000100 + +#define CONFIG_VMI_ALARM_HZ 100 + +#endif diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h index ebd5887..6299b51 100644 --- a/include/asm-ia64/dma-mapping.h +++ b/include/asm-ia64/dma-mapping.h @@ -8,9 +8,20 @@ #include <asm/machvec.h> #define dma_alloc_coherent platform_dma_alloc_coherent -#define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */ +/* coherent mem. is cheap */ +static inline void * +dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) +{ + return dma_alloc_coherent(dev, size, dma_handle, flag); +} #define dma_free_coherent platform_dma_free_coherent -#define dma_free_noncoherent platform_dma_free_coherent +static inline void +dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + dma_free_coherent(dev, size, cpu_addr, dma_handle); +} #define dma_map_single platform_dma_map_single #define dma_map_sg platform_dma_map_sg #define dma_unmap_single platform_dma_unmap_single diff --git a/include/asm-ia64/libata-portmap.h b/include/asm-ia64/libata-portmap.h new file mode 100644 index 0000000..0e00c9a --- /dev/null +++ b/include/asm-ia64/libata-portmap.h @@ -0,0 +1,12 @@ +#ifndef __ASM_IA64_LIBATA_PORTMAP_H +#define __ASM_IA64_LIBATA_PORTMAP_H + +#define ATA_PRIMARY_CMD 0x1F0 +#define ATA_PRIMARY_CTL 0x3F6 +#define ATA_PRIMARY_IRQ(dev) isa_irq_to_vector(14) + +#define ATA_SECONDARY_CMD 0x170 +#define ATA_SECONDARY_CTL 0x376 +#define ATA_SECONDARY_IRQ(dev) isa_irq_to_vector(15) + +#endif diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h index c1a2409..8578869 100644 --- a/include/asm-mips/atomic.h +++ b/include/asm-mips/atomic.h @@ -69,7 +69,10 @@ static __inline__ void atomic_add(int i, atomic_t * v) "1: ll %0, %1 # atomic_add \n" " addu %0, %2 \n" " sc %0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter)); @@ -111,7 +114,10 @@ static __inline__ void atomic_sub(int i, atomic_t * v) "1: ll %0, %1 # atomic_sub \n" " subu %0, %2 \n" " sc %0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter)); @@ -155,8 +161,11 @@ static __inline__ int atomic_add_return(int i, atomic_t * v) "1: ll %1, %2 # atomic_add_return \n" " addu %0, %1, %3 \n" " sc %0, %2 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" " addu %0, %1, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) @@ -204,8 +213,11 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v) "1: ll %1, %2 # atomic_sub_return \n" " subu %0, %1, %3 \n" " sc %0, %2 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" " subu %0, %1, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) @@ -267,10 +279,13 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) " bltz %0, 1f \n" " sc %0, %2 \n" " .set noreorder \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" " subu %0, %1, %3 \n" " .set reorder \n" "1: \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) @@ -429,7 +444,10 @@ static __inline__ void atomic64_add(long i, atomic64_t * v) "1: lld %0, %1 # atomic64_add \n" " addu %0, %2 \n" " scd %0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter)); @@ -471,7 +489,10 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v) "1: lld %0, %1 # atomic64_sub \n" " subu %0, %2 \n" " scd %0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter)); @@ -515,8 +536,11 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v) "1: lld %1, %2 # atomic64_add_return \n" " addu %0, %1, %3 \n" " scd %0, %2 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" " addu %0, %1, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) @@ -564,8 +588,11 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v) "1: lld %1, %2 # atomic64_sub_return \n" " subu %0, %1, %3 \n" " scd %0, %2 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" " subu %0, %1, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) @@ -627,10 +654,13 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) " bltz %0, 1f \n" " scd %0, %2 \n" " .set noreorder \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" " dsubu %0, %1, %3 \n" " .set reorder \n" "1: \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 06445de..06c0822 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -68,7 +68,10 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) "1: " __LL "%0, %1 # set_bit \n" " or %0, %2 \n" " " __SC "%0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (*m) : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m)); @@ -116,7 +119,10 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) "1: " __LL "%0, %1 # clear_bit \n" " and %0, %2 \n" " " __SC "%0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (*m) : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m)); @@ -166,7 +172,10 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) "1: " __LL "%0, %1 # change_bit \n" " xor %0, %2 \n" " " __SC "%0, %1 \n" - " beqz %0, 1b \n" + " beqz %0, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (temp), "=m" (*m) : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m)); @@ -222,8 +231,12 @@ static inline int test_and_set_bit(unsigned long nr, "1: " __LL "%0, %1 # test_and_set_bit \n" " or %2, %0, %3 \n" " " __SC "%2, %1 \n" - " beqz %2, 1b \n" + " beqz %2, 2f \n" " and %2, %0, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " nop \n" + " .previous \n" " .set pop \n" : "=&r" (temp), "=m" (*m), "=&r" (res) : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m) @@ -290,8 +303,12 @@ static inline int test_and_clear_bit(unsigned long nr, " or %2, %0, %3 \n" " xor %2, %3 \n" " " __SC "%2, %1 \n" - " beqz %2, 1b \n" + " beqz %2, 2f \n" " and %2, %0, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " nop \n" + " .previous \n" " .set pop \n" : "=&r" (temp), "=m" (*m), "=&r" (res) : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m) @@ -356,8 +373,12 @@ static inline int test_and_change_bit(unsigned long nr, "1: " __LL "%0, %1 # test_and_change_bit \n" " xor %2, %0, %3 \n" " " __SC "\t%2, %1 \n" - " beqz %2, 1b \n" + " beqz %2, 2f \n" " and %2, %0, %3 \n" + " .subsection 2 \n" + "2: b 1b \n" + " nop \n" + " .previous \n" " .set pop \n" : "=&r" (temp), "=m" (*m), "=&r" (res) : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m) diff --git a/include/asm-mips/compat-signal.h b/include/asm-mips/compat-signal.h new file mode 100644 index 0000000..6720770 --- /dev/null +++ b/include/asm-mips/compat-signal.h @@ -0,0 +1,55 @@ +#ifndef __ASM_COMPAT_SIGNAL_H +#define __ASM_COMPAT_SIGNAL_H + +#include <linux/bug.h> +#include <linux/compat.h> +#include <linux/compiler.h> + +static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d, + const sigset_t *s) +{ + int err; + + BUG_ON(sizeof(*d) != sizeof(*s)); + BUG_ON(_NSIG_WORDS != 2); + + err = __put_user(s->sig[0], &d->sig[0]); + err |= __put_user(s->sig[0] >> 32, &d->sig[1]); + err |= __put_user(s->sig[1], &d->sig[2]); + err |= __put_user(s->sig[1] >> 32, &d->sig[3]); + + return err; +} + +static inline int __copy_conv_sigset_from_user(sigset_t *d, + const compat_sigset_t __user *s) +{ + int err; + union sigset_u { + sigset_t s; + compat_sigset_t c; + } *u = (union sigset_u *) d; + + BUG_ON(sizeof(*d) != sizeof(*s)); + BUG_ON(_NSIG_WORDS != 2); + + if (unlikely(!access_ok(VERIFY_READ, d, sizeof(*d)))) + return -EFAULT; + +#ifdef CONFIG_CPU_BIG_ENDIAN + err = __get_user(u->c.sig[1], &s->sig[0]); + err |= __get_user(u->c.sig[0], &s->sig[1]); + err |= __get_user(u->c.sig[3], &s->sig[2]); + err |= __get_user(u->c.sig[2], &s->sig[3]); +#endif +#ifdef CONFIG_CPU_LITTLE_ENDIAN + err = __get_user(u->c.sig[0], &s->sig[0]); + err |= __get_user(u->c.sig[1], &s->sig[1]); + err |= __get_user(u->c.sig[2], &s->sig[2]); + err |= __get_user(u->c.sig[3], &s->sig[3]); +#endif + + return err; +} + +#endif /* __ASM_COMPAT_SIGNAL_H */ diff --git a/include/asm-mips/dma-mapping.h b/include/asm-mips/dma-mapping.h index 236d1a4..230b3f1 100644 --- a/include/asm-mips/dma-mapping.h +++ b/include/asm-mips/dma-mapping.h @@ -68,6 +68,7 @@ extern int dma_is_consistent(struct device *dev, dma_addr_t dma_addr); extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); +#if 0 #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, @@ -75,5 +76,6 @@ extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, extern void dma_release_declared_memory(struct device *dev); extern void * dma_mark_declared_memory_occupied(struct device *dev, dma_addr_t device_addr, size_t size); +#endif #endif /* _ASM_DMA_MAPPING_H */ diff --git a/include/asm-mips/mach-generic/dma-coherence.h b/include/asm-mips/mach-generic/dma-coherence.h new file mode 100644 index 0000000..df71822 --- /dev/null +++ b/include/asm-mips/mach-generic/dma-coherence.h @@ -0,0 +1,43 @@ +/* + * 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) 2006 Ralf Baechle <ralf@linux-mips.org> + * + */ +#ifndef __ASM_MACH_GENERIC_DMA_COHERENCE_H +#define __ASM_MACH_GENERIC_DMA_COHERENCE_H + +struct device; + +static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) +{ + return virt_to_phys(addr); +} + +static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) +{ + return page_to_phys(page); +} + +static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr) +{ + return dma_addr; +} + +static void plat_unmap_dma_mem(dma_addr_t dma_addr) +{ +} + +static inline int plat_device_is_coherent(struct device *dev) +{ +#ifdef CONFIG_DMA_COHERENT + return 1; +#endif +#ifdef CONFIG_DMA_NONCOHERENT + return 0; +#endif +} + +#endif /* __ASM_MACH_GENERIC_DMA_COHERENCE_H */ diff --git a/include/asm-mips/mach-generic/kmalloc.h b/include/asm-mips/mach-generic/kmalloc.h index 410ab5f..b8e6deb 100644 --- a/include/asm-mips/mach-generic/kmalloc.h +++ b/include/asm-mips/mach-generic/kmalloc.h @@ -5,6 +5,7 @@ #ifndef CONFIG_DMA_COHERENT /* * Total overkill for most systems but need as a safe default. + * Set this one if any device in the system might do non-coherent DMA. */ #define ARCH_KMALLOC_MINALIGN 128 #endif diff --git a/include/asm-mips/mach-ip27/dma-coherence.h b/include/asm-mips/mach-ip27/dma-coherence.h new file mode 100644 index 0000000..659816e --- /dev/null +++ b/include/asm-mips/mach-ip27/dma-coherence.h @@ -0,0 +1,49 @@ +/* + * 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) 2006 Ralf Baechle <ralf@linux-mips.org> + * + */ +#ifndef __ASM_MACH_IP27_DMA_COHERENCE_H +#define __ASM_MACH_IP27_DMA_COHERENCE_H + +#include <asm/pci/bridge.h> + +#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)) + +struct device; + +static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) +{ + dma_addr_t pa = dev_to_baddr(dev, virt_to_phys(addr)); + + return pa; +} + +static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) +{ + dma_addr_t pa = dev_to_baddr(dev, page_to_phys(page)); + + return pa; +} + +static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr) +{ + return dma_addr & (0xffUL << 56); +} + +static void plat_unmap_dma_mem(dma_addr_t dma_addr) +{ +} + +static inline int plat_device_is_coherent(struct device *dev) +{ + return 1; /* IP27 non-cohernet mode is unsupported */ +} + +#endif /* __ASM_MACH_IP27_DMA_COHERENCE_H */ diff --git a/include/asm-mips/mach-ip32/dma-coherence.h b/include/asm-mips/mach-ip32/dma-coherence.h new file mode 100644 index 0000000..950be17 --- /dev/null +++ b/include/asm-mips/mach-ip32/dma-coherence.h @@ -0,0 +1,71 @@ +/* + * 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) 2006 Ralf Baechle <ralf@linux-mips.org> + * + */ +#ifndef __ASM_MACH_IP35_DMA_COHERENCE_H +#define __ASM_MACH_IP35_DMA_COHERENCE_H + +#include <asm/ip32/crime.h> + +struct device; + +/* + * 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 0x3fffffffUL + +static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) +{ + dma_addr_t pa = virt_to_phys(addr) & RAM_OFFSET_MASK; + + if (dev == NULL) + pa += CRIME_HI_MEM_BASE; + + return pa; +} + +static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) +{ + dma_addr_t pa; + + pa = page_to_phys(page) & RAM_OFFSET_MASK; + + if (dev == NULL) + pa += CRIME_HI_MEM_BASE; + + return pa; +} + +/* This is almost certainly wrong but it's what dma-ip32.c used to use */ +static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr) +{ + unsigned long addr = dma_addr & RAM_OFFSET_MASK; + + if (dma_addr >= 256*1024*1024) + addr += CRIME_HI_MEM_BASE; + + return addr; +} + +static void plat_unmap_dma_mem(dma_addr_t dma_addr) +{ +} + +static inline int plat_device_is_coherent(struct device *dev) +{ + return 0; /* IP32 is non-cohernet */ +} + +#endif /* __ASM_MACH_IP35_DMA_COHERENCE_H */ diff --git a/include/asm-mips/mach-jazz/dma-coherence.h b/include/asm-mips/mach-jazz/dma-coherence.h new file mode 100644 index 0000000..d66979a --- /dev/null +++ b/include/asm-mips/mach-jazz/dma-coherence.h @@ -0,0 +1,40 @@ +/* + * 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) 2006 Ralf Baechle <ralf@linux-mips.org> + */ +#ifndef __ASM_MACH_JAZZ_DMA_COHERENCE_H +#define __ASM_MACH_JAZZ_DMA_COHERENCE_H + +#include <asm/jazzdma.h> + +struct device; + +static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) +{ + return vdma_alloc(virt_to_phys(addr), size); +} + +static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) +{ + return vdma_alloc(page_to_phys(page), PAGE_SIZE); +} + +static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr) +{ + return vdma_log2phys(dma_addr); +} + +static void plat_unmap_dma_mem(dma_addr_t dma_addr) +{ + vdma_free(dma_addr); +} + +static inline int plat_device_is_coherent(struct device *dev) +{ + return 0; +} + +#endif /* __ASM_MACH_JAZZ_DMA_COHERENCE_H */ diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h index fc3217f..f1755d2 100644 --- a/include/asm-mips/spinlock.h +++ b/include/asm-mips/spinlock.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999, 2000, 06 by Ralf Baechle + * Copyright (C) 1999, 2000, 06 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #ifndef _ASM_SPINLOCK_H @@ -49,11 +49,18 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) __asm__ __volatile__( " .set noreorder # __raw_spin_lock \n" "1: ll %1, %2 \n" - " bnez %1, 1b \n" + " bnez %1, 2f \n" " li %1, 1 \n" " sc %1, %0 \n" - " beqz %1, 1b \n" + " beqz %1, 2f \n" " nop \n" + " .subsection 2 \n" + "2: ll %1, %2 \n" + " bnez %1, 2b \n" + " li %1, 1 \n" + " b 1b \n" + " nop \n" + " .previous \n" " .set reorder \n" : "=m" (lock->lock), "=&r" (tmp) : "m" (lock->lock) @@ -99,8 +106,12 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock) "1: ll %0, %3 \n" " ori %2, %0, 1 \n" " sc %2, %1 \n" - " beqz %2, 1b \n" + " beqz %2, 2f \n" " andi %2, %0, 1 \n" + " .subsection 2 \n" + "2: b 1b \n" + " nop \n" + " .previous \n" " .set reorder" : "=&r" (temp), "=m" (lock->lock), "=&r" (res) : "m" (lock->lock) @@ -154,11 +165,18 @@ static inline void __raw_read_lock(raw_rwlock_t *rw) __asm__ __volatile__( " .set noreorder # __raw_read_lock \n" "1: ll %1, %2 \n" - " bltz %1, 1b \n" + " bltz %1, 2f \n" " addu %1, 1 \n" " sc %1, %0 \n" " beqz %1, 1b \n" " nop \n" + " .subsection 2 \n" + "2: ll %1, %2 \n" + " bltz %1, 2b \n" + " addu %1, 1 \n" + " b 1b \n" + " nop \n" + " .previous \n" " .set reorder \n" : "=m" (rw->lock), "=&r" (tmp) : "m" (rw->lock) @@ -192,8 +210,12 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw) "1: ll %1, %2 \n" " sub %1, 1 \n" " sc %1, %0 \n" - " beqz %1, 1b \n" + " beqz %1, 2f \n" + " nop \n" + " .subsection 2 \n" + "2: b 1b \n" " nop \n" + " .previous \n" " .set reorder \n" : "=m" (rw->lock), "=&r" (tmp) : "m" (rw->lock) @@ -222,11 +244,18 @@ static inline void __raw_write_lock(raw_rwlock_t *rw) __asm__ __volatile__( " .set noreorder # __raw_write_lock \n" "1: ll %1, %2 \n" - " bnez %1, 1b \n" + " bnez %1, 2f \n" " lui %1, 0x8000 \n" " sc %1, %0 \n" - " beqz %1, 1b \n" + " beqz %1, 2f \n" + " nop \n" + " .subsection 2 \n" + "2: ll %1, %2 \n" + " bnez %1, 2b \n" + " lui %1, 0x8000 \n" + " b 1b \n" " nop \n" + " .previous \n" " .set reorder \n" : "=m" (rw->lock), "=&r" (tmp) : "m" (rw->lock) @@ -322,12 +351,15 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) " bnez %1, 2f \n" " lui %1, 0x8000 \n" " sc %1, %0 \n" - " beqz %1, 1b \n" - " nop \n" + " beqz %1, 3f \n" + " li %2, 1 \n" + "2: \n" __WEAK_ORDERING_MB - " li %2, 1 \n" + " .subsection 2 \n" + "3: b 1b \n" + " li %2, 0 \n" + " .previous \n" " .set reorder \n" - "2: \n" : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) : "m" (rw->lock) : "memory"); diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 5e1289c..597a374 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -110,7 +110,10 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) " move %2, %z4 \n" " .set mips3 \n" " sc %2, %1 \n" - " beqz %2, 1b \n" + " beqz %2, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (retval), "=m" (*m), "=&r" (dummy) : "R" (*m), "Jr" (val) @@ -155,7 +158,10 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) "1: lld %0, %3 # xchg_u64 \n" " move %2, %z4 \n" " scd %2, %1 \n" - " beqz %2, 1b \n" + " beqz %2, 2f \n" + " .subsection 2 \n" + "2: b 1b \n" + " .previous \n" " .set mips0 \n" : "=&r" (retval), "=m" (*m), "=&r" (dummy) : "R" (*m), "Jr" (val) @@ -232,8 +238,11 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old, " move $1, %z4 \n" " .set mips3 \n" " sc $1, %1 \n" - " beqz $1, 1b \n" + " beqz $1, 3f \n" "2: \n" + " .subsection 2 \n" + "3: b 1b \n" + " .previous \n" " .set pop \n" : "=&r" (retval), "=R" (*m) : "R" (*m), "Jr" (old), "Jr" (new) @@ -283,8 +292,11 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old, " bne %0, %z3, 2f \n" " move $1, %z4 \n" " scd $1, %1 \n" - " beqz $1, 1b \n" + " beqz $1, 3f \n" "2: \n" + " .subsection 2 \n" + "3: b 1b \n" + " .previous \n" " .set pop \n" : "=&r" (retval), "=R" (*m) : "R" (*m), "Jr" (old), "Jr" (new) diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index 825fcbd..3eff8d8 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -265,10 +265,14 @@ do { \ */ #define __get_user_asm_ll32(val, addr) \ { \ + union { \ + unsigned long long l; \ + __typeof__(*(addr)) t; \ + } __gu_tmp; \ + \ __asm__ __volatile__( \ "1: lw %1, (%3) \n" \ "2: lw %D1, 4(%3) \n" \ - " move %0, $0 \n" \ "3: .section .fixup,\"ax\" \n" \ "4: li %0, %4 \n" \ " move %1, $0 \n" \ @@ -279,8 +283,10 @@ do { \ " " __UA_ADDR " 1b, 4b \n" \ " " __UA_ADDR " 2b, 4b \n" \ " .previous \n" \ - : "=r" (__gu_err), "=&r" (val) \ + : "=r" (__gu_err), "=&r" (__gu_tmp.l) \ : "0" (0), "r" (addr), "i" (-EFAULT)); \ + \ + (val) = __gu_tmp.t; \ } /* diff --git a/include/asm-powerpc/cell-pmu.h b/include/asm-powerpc/cell-pmu.h index e8c2ebd..35b9577 100644 --- a/include/asm-powerpc/cell-pmu.h +++ b/include/asm-powerpc/cell-pmu.h @@ -53,6 +53,11 @@ #define CBE_PM_CTR_POLARITY 0x01000000 #define CBE_PM_CTR_COUNT_CYCLES 0x00800000 #define CBE_PM_CTR_ENABLE 0x00400000 +#define PM07_CTR_INPUT_MUX(x) (((x) & 0x3F) << 26) +#define PM07_CTR_INPUT_CONTROL(x) (((x) & 1) << 25) +#define PM07_CTR_POLARITY(x) (((x) & 1) << 24) +#define PM07_CTR_COUNT_CYCLES(x) (((x) & 1) << 23) +#define PM07_CTR_ENABLE(x) (((x) & 1) << 22) /* Macros for the pm_status register. */ #define CBE_PM_CTR_OVERFLOW_INTR(ctr) (1 << (31 - ((ctr) & 7))) @@ -89,8 +94,7 @@ extern void cbe_read_trace_buffer(u32 cpu, u64 *buf); extern void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask); extern void cbe_disable_pm_interrupts(u32 cpu); -extern u32 cbe_query_pm_interrupts(u32 cpu); -extern u32 cbe_clear_pm_interrupts(u32 cpu); +extern u32 cbe_get_and_clear_pm_interrupts(u32 cpu); extern void cbe_sync_irq(int node); /* Utility functions, macros */ @@ -103,11 +107,4 @@ extern u32 cbe_get_hw_thread_id(int cpu); #define CBE_COUNT_PROBLEM_MODE 2 #define CBE_COUNT_ALL_MODES 3 -/* Macros for the pm07_control registers. */ -#define PM07_CTR_INPUT_MUX(x) (((x) & 0x3F) << 26) -#define PM07_CTR_INPUT_CONTROL(x) (((x) & 1) << 25) -#define PM07_CTR_POLARITY(x) (((x) & 1) << 24) -#define PM07_CTR_COUNT_CYCLES(x) (((x) & 1) << 23) -#define PM07_CTR_ENABLE(x) (((x) & 1) << 22) - #endif /* __ASM_CELL_PMU_H__ */ diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h index fd242a2..a0f14ee 100644 --- a/include/asm-powerpc/floppy.h +++ b/include/asm-powerpc/floppy.h @@ -17,28 +17,115 @@ #define fd_outb(value,port) outb_p(value,port) #define fd_enable_dma() enable_dma(FLOPPY_DMA) -#define fd_disable_dma() disable_dma(FLOPPY_DMA) -#define fd_request_dma() request_dma(FLOPPY_DMA, "floppy") -#define fd_free_dma() free_dma(FLOPPY_DMA) +#define fd_disable_dma() fd_ops->_disable_dma(FLOPPY_DMA) +#define fd_free_dma() fd_ops->_free_dma(FLOPPY_DMA) #define fd_clear_dma_ff() clear_dma_ff(FLOPPY_DMA) #define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA, mode) #define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA, count) +#define fd_get_dma_residue() fd_ops->_get_dma_residue(FLOPPY_DMA) #define fd_enable_irq() enable_irq(FLOPPY_IRQ) #define fd_disable_irq() disable_irq(FLOPPY_IRQ) #define fd_cacheflush(addr,size) /* nothing */ -#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt, \ - IRQF_DISABLED, "floppy", NULL) #define fd_free_irq() free_irq(FLOPPY_IRQ, NULL); -#ifdef CONFIG_PCI - #include <linux/pci.h> #include <asm/ppc-pci.h> /* for ppc64_isabridge_dev */ -#define fd_dma_setup(addr,size,mode,io) powerpc_fd_dma_setup(addr,size,mode,io) +#define fd_dma_setup(addr,size,mode,io) fd_ops->_dma_setup(addr,size,mode,io) + +static int fd_request_dma(void); + +struct fd_dma_ops { + void (*_disable_dma)(unsigned int dmanr); + void (*_free_dma)(unsigned int dmanr); + int (*_get_dma_residue)(unsigned int dummy); + int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); +}; + +static int virtual_dma_count; +static int virtual_dma_residue; +static char *virtual_dma_addr; +static int virtual_dma_mode; +static int doing_vdma; +static struct fd_dma_ops *fd_ops; + +static irqreturn_t floppy_hardint(int irq, void *dev_id) +{ + unsigned char st; + int lcount; + char *lptr; + + if (!doing_vdma) + return floppy_interrupt(irq, dev_id); + + + st = 1; + for (lcount=virtual_dma_count, lptr=virtual_dma_addr; + lcount; lcount--, lptr++) { + st=inb(virtual_dma_port+4) & 0xa0 ; + if (st != 0xa0) + break; + if (virtual_dma_mode) + outb_p(*lptr, virtual_dma_port+5); + else + *lptr = inb_p(virtual_dma_port+5); + } + virtual_dma_count = lcount; + virtual_dma_addr = lptr; + st = inb(virtual_dma_port+4); + + if (st == 0x20) + return IRQ_HANDLED; + if (!(st & 0x20)) { + virtual_dma_residue += virtual_dma_count; + virtual_dma_count=0; + doing_vdma = 0; + floppy_interrupt(irq, dev_id); + return IRQ_HANDLED; + } + return IRQ_HANDLED; +} -static __inline__ int powerpc_fd_dma_setup(char *addr, unsigned long size, - int mode, int io) +static void vdma_disable_dma(unsigned int dummy) +{ + doing_vdma = 0; + virtual_dma_residue += virtual_dma_count; + virtual_dma_count=0; +} + +static void vdma_nop(unsigned int dummy) +{ +} + + +static int vdma_get_dma_residue(unsigned int dummy) +{ + return virtual_dma_count + virtual_dma_residue; +} + + +static int fd_request_irq(void) +{ + if (can_use_virtual_dma) + return request_irq(FLOPPY_IRQ, floppy_hardint, + IRQF_DISABLED, "floppy", NULL); + else + return request_irq(FLOPPY_IRQ, floppy_interrupt, + IRQF_DISABLED, "floppy", NULL); +} + +static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) +{ + doing_vdma = 1; + virtual_dma_port = io; + virtual_dma_mode = (mode == DMA_MODE_WRITE); + virtual_dma_addr = addr; + virtual_dma_count = size; + virtual_dma_residue = 0; + return 0; +} + +static int hard_dma_setup(char *addr, unsigned long size, int mode, int io) { static unsigned long prev_size; static dma_addr_t bus_addr = 0; @@ -46,6 +133,7 @@ static __inline__ int powerpc_fd_dma_setup(char *addr, unsigned long size, static int prev_dir; int dir; + doing_vdma = 0; dir = (mode == DMA_MODE_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE; if (bus_addr @@ -74,11 +162,32 @@ static __inline__ int powerpc_fd_dma_setup(char *addr, unsigned long size, return 0; } -#endif /* CONFIG_PCI */ +static struct fd_dma_ops real_dma_ops = +{ + ._disable_dma = disable_dma, + ._free_dma = free_dma, + ._get_dma_residue = get_dma_residue, + ._dma_setup = hard_dma_setup +}; + +static struct fd_dma_ops virt_dma_ops = +{ + ._disable_dma = vdma_disable_dma, + ._free_dma = vdma_nop, + ._get_dma_residue = vdma_get_dma_residue, + ._dma_setup = vdma_dma_setup +}; -__inline__ void virtual_dma_init(void) +static int fd_request_dma() { - /* Nothing to do on PowerPC */ + if (can_use_virtual_dma & 1) { + fd_ops = &virt_dma_ops; + return 0; + } + else { + fd_ops = &real_dma_ops; + return request_dma(FLOPPY_DMA, "floppy"); + } } static int FDC1 = 0x3f0; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index b634e16..0f9f2dd2 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -129,7 +129,6 @@ struct spu { struct spu_runqueue *rq; unsigned long long timestamp; pid_t pid; - int prio; int class_0_pending; spinlock_t register_lock; diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h index 97b4354..418e5c7 100644 --- a/include/asm-powerpc/systbl.h +++ b/include/asm-powerpc/systbl.h @@ -305,3 +305,4 @@ SYSCALL_SPU(faccessat) COMPAT_SYS_SPU(get_robust_list) COMPAT_SYS_SPU(set_robust_list) COMPAT_SYS(move_pages) +SYSCALL_SPU(getcpu) diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h index ca93bc9..1babad9 100644 --- a/include/asm-powerpc/ucc_slow.h +++ b/include/asm-powerpc/ucc_slow.h @@ -150,7 +150,7 @@ struct ucc_slow_info { int ucc_num; enum qe_clock rx_clock; enum qe_clock tx_clock; - struct ucc_slow *us_regs; + struct ucc_slow *regs; int irq; u16 uccm_mask; int data_mem_part; diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index 4cbc313..d03d855 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -46,6 +46,7 @@ extern void __init udbg_init_iseries(void); extern void __init udbg_init_rtas_panel(void); extern void __init udbg_init_rtas_console(void); extern void __init udbg_init_debug_beat(void); +extern void __init udbg_init_btext(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/include/asm-powerpc/vdso.h b/include/asm-powerpc/vdso.h index b9f9118..26fc449 100644 --- a/include/asm-powerpc/vdso.h +++ b/include/asm-powerpc/vdso.h @@ -18,16 +18,11 @@ #ifndef __ASSEMBLY__ -extern unsigned int vdso64_pages; -extern unsigned int vdso32_pages; - /* Offsets relative to thread->vdso_base */ extern unsigned long vdso64_rt_sigtramp; extern unsigned long vdso32_sigtramp; extern unsigned long vdso32_rt_sigtramp; -extern void vdso_init(void); - #else /* __ASSEMBLY__ */ #ifdef __VDSO64__ diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h index 7a64ede..92fd02d 100644 --- a/include/asm-ppc/ibm4xx.h +++ b/include/asm-ppc/ibm4xx.h @@ -109,6 +109,10 @@ void ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5, #include <platforms/4xx/ocotea.h> #endif +#if defined(CONFIG_TAISHAN) +#include <platforms/4xx/taishan.h> +#endif + #ifndef __ASSEMBLY__ #ifdef CONFIG_40x /* diff --git a/include/asm-sh/Kbuild b/include/asm-sh/Kbuild index c68e168..76a8ccf 100644 --- a/include/asm-sh/Kbuild +++ b/include/asm-sh/Kbuild @@ -1 +1,3 @@ include include/asm-generic/Kbuild.asm + +header-y += cpu-features.h diff --git a/include/asm-sh/bigsur/bigsur.h b/include/asm-sh/bigsur/bigsur.h deleted file mode 100644 index 427245f..0000000 --- a/include/asm-sh/bigsur/bigsur.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Hitachi Big Sur Eval Board support - * - * Dustin McIntire (dustin@sensoria.com) - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * Derived from Hitachi SH7751 reference manual - * - */ - -#ifndef _ASM_BIGSUR_H_ -#define _ASM_BIGSUR_H_ - -#include <asm/irq.h> -#include <asm/hd64465/hd64465.h> - -/* 7751 Internal IRQ's used by external CPLD controller */ -#define BIGSUR_IRQ_LOW 0 -#define BIGSUR_IRQ_NUM 14 /* External CPLD level 1 IRQs */ -#define BIGSUR_IRQ_HIGH (BIGSUR_IRQ_LOW + BIGSUR_IRQ_NUM) -#define BIGSUR_2NDLVL_IRQ_LOW (HD64465_IRQ_BASE+HD64465_IRQ_NUM) -#define BIGSUR_2NDLVL_IRQ_NUM 32 /* Level 2 IRQs = 4 regs * 8 bits */ -#define BIGSUR_2NDLVL_IRQ_HIGH (BIGSUR_2NDLVL_IRQ_LOW + \ - BIGSUR_2NDLVL_IRQ_NUM) - -/* PCI interrupt base number (A_INTA-A_INTD) */ -#define BIGSUR_SH7751_PCI_IRQ_BASE (BIGSUR_2NDLVL_IRQ_LOW+10) - -/* CPLD registers and external chip addresses */ -#define BIGSUR_HD64464_ADDR 0xB2000000 -#define BIGSUR_DGDR 0xB1FFFE00 -#define BIGSUR_BIDR 0xB1FFFD00 -#define BIGSUR_CSLR 0xB1FFFC00 -#define BIGSUR_SW1R 0xB1FFFB00 -#define BIGSUR_DBGR 0xB1FFFA00 -#define BIGSUR_BDTR 0xB1FFF900 -#define BIGSUR_BDRR 0xB1FFF800 -#define BIGSUR_PPR1 0xB1FFF700 -#define BIGSUR_PPR2 0xB1FFF600 -#define BIGSUR_IDE2 0xB1FFF500 -#define BIGSUR_IDE3 0xB1FFF400 -#define BIGSUR_SPCR 0xB1FFF300 -#define BIGSUR_ETHR 0xB1FE0000 -#define BIGSUR_PPDR 0xB1FDFF00 -#define BIGSUR_ICTL 0xB1FDFE00 -#define BIGSUR_ICMD 0xB1FDFD00 -#define BIGSUR_DMA0 0xB1FDFC00 -#define BIGSUR_DMA1 0xB1FDFB00 -#define BIGSUR_IRQ0 0xB1FDFA00 -#define BIGSUR_IRQ1 0xB1FDF900 -#define BIGSUR_IRQ2 0xB1FDF800 -#define BIGSUR_IRQ3 0xB1FDF700 -#define BIGSUR_IMR0 0xB1FDF600 -#define BIGSUR_IMR1 0xB1FDF500 -#define BIGSUR_IMR2 0xB1FDF400 -#define BIGSUR_IMR3 0xB1FDF300 -#define BIGSUR_IRLMR0 0xB1FDF200 -#define BIGSUR_IRLMR1 0xB1FDF100 -#define BIGSUR_V320USC_ADDR 0xB1000000 -#define BIGSUR_HD64465_ADDR 0xB0000000 -#define BIGSUR_INTERNAL_BASE 0xB0000000 - -/* SMC ethernet card parameters */ -#define BIGSUR_ETHER_IOPORT 0x220 - -/* IDE register paramters */ -#define BIGSUR_IDECMD_IOPORT 0x1f0 -#define BIGSUR_IDECTL_IOPORT 0x1f8 - -/* LED bit position in BIGSUR_CSLR */ -#define BIGSUR_LED (1<<4) - -/* PCI: default LOCAL memory window sizes (seen from PCI bus) */ -#define BIGSUR_LSR0_SIZE (64*(1<<20)) //64MB -#define BIGSUR_LSR1_SIZE (64*(1<<20)) //64MB - -#endif /* _ASM_BIGSUR_H_ */ diff --git a/include/asm-sh/bigsur/io.h b/include/asm-sh/bigsur/io.h deleted file mode 100644 index 1470ac8..0000000 --- a/include/asm-sh/bigsur/io.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * include/asm-sh/bigsur/io.h - * - * By Dustin McIntire (dustin@sensoria.com) (c)2001 - * Derived from io_hd64465.h, which bore the message: - * By Greg Banks <gbanks@pocketpenguins.com> - * (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. - */ - -#ifndef _ASM_SH_IO_BIGSUR_H -#define _ASM_SH_IO_BIGSUR_H - -#include <linux/types.h> - -extern unsigned long bigsur_isa_port2addr(unsigned long offset); -extern int bigsur_irq_demux(int irq); -/* Provision for generic secondary demux step -- used by PCMCIA code */ -extern void bigsur_register_irq_demux(int irq, - int (*demux)(int irq, void *dev), void *dev); -extern void bigsur_unregister_irq_demux(int irq); -/* Set this variable to 1 to see port traffic */ -extern int bigsur_io_debug; -/* Map a range of ports to a range of kernel virtual memory. */ -extern void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift); -extern void bigsur_port_unmap(u32 baseport, u32 nports); - -#endif /* _ASM_SH_IO_BIGSUR_H */ - diff --git a/include/asm-sh/bigsur/serial.h b/include/asm-sh/bigsur/serial.h deleted file mode 100644 index a08fa82..0000000 --- a/include/asm-sh/bigsur/serial.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * include/asm-sh/bigsur/serial.h - * - * Configuration details for Big Sur 16550 based serial ports - * i.e. HD64465, PCMCIA, etc. - */ - -#ifndef _ASM_SERIAL_BIGSUR_H -#define _ASM_SERIAL_BIGSUR_H -#include <asm/hd64465.h> - -#define BASE_BAUD (3379200 / 16) - -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) - - -#define SERIAL_PORT_DFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */ - -/* XXX: This should be moved ino irq.h */ -#define irq_cannonicalize(x) (x) - -#endif /* _ASM_SERIAL_BIGSUR_H */ diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h index a294997..5a117ec 100644 --- a/include/asm-sh/bugs.h +++ b/include/asm-sh/bugs.h @@ -19,9 +19,9 @@ static void __init check_bugs(void) extern unsigned long loops_per_jiffy; char *p = &init_utsname()->machine[2]; /* "sh" */ - cpu_data->loops_per_jiffy = loops_per_jiffy; + current_cpu_data.loops_per_jiffy = loops_per_jiffy; - switch (cpu_data->type) { + switch (current_cpu_data.type) { case CPU_SH7604 ... CPU_SH7619: *p++ = '2'; break; @@ -54,7 +54,7 @@ static void __init check_bugs(void) break; } - printk("CPU: %s\n", get_cpu_subtype()); + printk("CPU: %s\n", get_cpu_subtype(¤t_cpu_data)); #ifndef __LITTLE_ENDIAN__ /* 'eb' means 'Endian Big' */ diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h index 07f62ec..22f1263 100644 --- a/include/asm-sh/cacheflush.h +++ b/include/asm-sh/cacheflush.h @@ -30,5 +30,8 @@ extern void __flush_invalidate_region(void *start, int size); #define HAVE_ARCH_UNMAPPED_AREA +/* Page flag for lazy dcache write-back for the aliasing UP caches */ +#define PG_dcache_dirty PG_arch_1 + #endif /* __KERNEL__ */ #endif /* __ASM_SH_CACHEFLUSH_H */ diff --git a/include/asm-sh/cpu-sh3/cacheflush.h b/include/asm-sh/cpu-sh3/cacheflush.h index f70d8ef7..6fabbba 100644 --- a/include/asm-sh/cpu-sh3/cacheflush.h +++ b/include/asm-sh/cpu-sh3/cacheflush.h @@ -36,8 +36,6 @@ /* 32KB cache, 4kb PAGE sizes need to check bit 12 */ #define CACHE_ALIAS 0x00001000 -#define PG_mapped PG_arch_1 - void flush_cache_all(void); void flush_cache_mm(struct mm_struct *mm); #define flush_cache_dup_mm(mm) flush_cache_mm(mm) diff --git a/include/asm-sh/cpu-sh4/cacheflush.h b/include/asm-sh/cpu-sh4/cacheflush.h index b01a10f..b3746a9 100644 --- a/include/asm-sh/cpu-sh4/cacheflush.h +++ b/include/asm-sh/cpu-sh4/cacheflush.h @@ -17,6 +17,7 @@ * so we need them. */ void flush_cache_all(void); +void flush_dcache_all(void); void flush_cache_mm(struct mm_struct *mm); #define flush_cache_dup_mm(mm) flush_cache_mm(mm) void flush_cache_range(struct vm_area_struct *vma, unsigned long start, @@ -38,16 +39,4 @@ void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, /* Initialization of P3 area for copy_user_page */ void p3_cache_init(void); -#define PG_mapped PG_arch_1 - -#ifdef CONFIG_MMU -extern int remap_area_pages(unsigned long addr, unsigned long phys_addr, - unsigned long size, unsigned long flags); -#else /* CONFIG_MMU */ -static inline int remap_area_pages(unsigned long addr, unsigned long phys_addr, - unsigned long size, unsigned long flags) -{ - return 0; -} -#endif /* CONFIG_MMU */ #endif /* __ASM_CPU_SH4_CACHEFLUSH_H */ diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h index 3e4b3e6..c135e9c 100644 --- a/include/asm-sh/cpu-sh4/dma.h +++ b/include/asm-sh/cpu-sh4/dma.h @@ -3,6 +3,17 @@ #define DMAOR_INIT ( 0x8000 | DMAOR_DME ) +/* SH7751/7760/7780 DMA IRQ sources */ +#define DMTE0_IRQ 34 +#define DMTE1_IRQ 35 +#define DMTE2_IRQ 36 +#define DMTE3_IRQ 37 +#define DMTE4_IRQ 44 +#define DMTE5_IRQ 45 +#define DMTE6_IRQ 46 +#define DMTE7_IRQ 47 +#define DMAE_IRQ 38 + #ifdef CONFIG_CPU_SH4A #define SH_DMAC_BASE 0xfc808020 diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h index 8d0867b..d3bc781 100644 --- a/include/asm-sh/dma-mapping.h +++ b/include/asm-sh/dma-mapping.h @@ -53,6 +53,10 @@ static inline void dma_free_coherent(struct device *dev, size_t size, consistent_free(vaddr, size); } +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d, h) (1) + static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir) { diff --git a/include/asm-sh/ec3104/ec3104.h b/include/asm-sh/ec3104/ec3104.h deleted file mode 100644 index 639cfa4..0000000 --- a/include/asm-sh/ec3104/ec3104.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __ASM_EC3104_H -#define __ASM_EC3104_H - - -/* - * Most of the register set is at 0xb0ec0000 - 0xb0ecffff. - * - * as far as I've figured it out the register map is: - * 0xb0ec0000 - id string - * 0xb0ec0XXX - power management - * 0xb0ec1XXX - interrupt control - * 0xb0ec3XXX - ps2 port (touch pad on aero 8000) - * 0xb0ec6XXX - i2c - * 0xb0ec7000 - first serial port (proprietary connector on aero 8000) - * 0xb0ec8000 - second serial port - * 0xb0ec9000 - third serial port - * 0xb0eca000 - fourth serial port (keyboard controller on aero 8000) - * 0xb0eccXXX - GPIO - * 0xb0ecdXXX - GPIO - */ - -#define EC3104_BASE 0xb0ec0000 - -#define EC3104_SER4_DATA (EC3104_BASE+0xa000) -#define EC3104_SER4_IIR (EC3104_BASE+0xa008) -#define EC3104_SER4_MCR (EC3104_BASE+0xa010) -#define EC3104_SER4_LSR (EC3104_BASE+0xa014) -#define EC3104_SER4_MSR (EC3104_BASE+0xa018) - -/* - * our ISA bus. this seems to be real ISA. - */ -#define EC3104_ISA_BASE 0xa5000000 - -#define EC3104_IRQ 11 -#define EC3104_IRQBASE 64 - -#define EC3104_IRQ_SER1 EC3104_IRQBASE + 7 -#define EC3104_IRQ_SER2 EC3104_IRQBASE + 8 -#define EC3104_IRQ_SER3 EC3104_IRQBASE + 9 -#define EC3104_IRQ_SER4 EC3104_IRQBASE + 10 - -#endif /* __ASM_EC3104_H */ diff --git a/include/asm-sh/ec3104/io.h b/include/asm-sh/ec3104/io.h deleted file mode 100644 index ea5c8e6..0000000 --- a/include/asm-sh/ec3104/io.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASM_SH_IO_EC3104_H -#define _ASM_SH_IO_EC3104_H - -#include <linux/types.h> - -extern unsigned char ec3104_inb(unsigned long port); -extern unsigned short ec3104_inw(unsigned long port); -extern unsigned long ec3104_inl(unsigned long port); - -extern void ec3104_outb(unsigned char value, unsigned long port); -extern void ec3104_outw(unsigned short value, unsigned long port); -extern void ec3104_outl(unsigned long value, unsigned long port); - -extern int ec3104_irq_demux(int irq); - -#endif /* _ASM_SH_IO_EC3104_H */ diff --git a/include/asm-sh/ec3104/keyboard.h b/include/asm-sh/ec3104/keyboard.h deleted file mode 100644 index c1253a6..0000000 --- a/include/asm-sh/ec3104/keyboard.h +++ /dev/null @@ -1,15 +0,0 @@ -extern unsigned char ec3104_kbd_sysrq_xlate[]; -extern int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int ec3104_kbd_getkeycode(unsigned int scancode); -extern int ec3104_kbd_translate(unsigned char, unsigned char *, char); -extern char ec3104_kbd_unexpected_up(unsigned char); -extern void ec3104_kbd_leds(unsigned char); -extern void ec3104_kbd_init_hw(void); - -#define kbd_sysrq_xlate ec3104_kbd_sysrq_xlate -#define kbd_setkeycode ec3104_kbd_setkeycode -#define kbd_getkeycode ec3104_kbd_getkeycode -#define kbd_translate ec3104_kbd_translate -#define kbd_unexpected_up ec3104_kbd_unexpected_up -#define kbd_leds ec3104_kbd_leds -#define kbd_init_hw ec3104_kbd_init_hw diff --git a/include/asm-sh/ec3104/serial.h b/include/asm-sh/ec3104/serial.h deleted file mode 100644 index cfe4d78..0000000 --- a/include/asm-sh/ec3104/serial.h +++ /dev/null @@ -1,20 +0,0 @@ -#include <asm/ec3104.h> -/* Naturally we don't know the exact value but 115200 baud has a divisor - * of 9 and 19200 baud has a divisor of 52, so this seems like a good - * guess. */ -#define BASE_BAUD (16800000 / 16) - -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) - -/* there is a fourth serial port with the expected values as well, but - * it's got the keyboard controller behind it so we can't really use it - * (without moving the keyboard driver to userspace, which doesn't sound - * like a very good idea) */ -#define SERIAL_PORT_DFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x11C00, EC3104_IRQBASE+7, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x12000, EC3104_IRQBASE+8, STD_COM_FLAGS }, /* ttyS1 */ \ - { 0, BASE_BAUD, 0x12400, EC3104_IRQBASE+9, STD_COM_FLAGS }, /* ttyS2 */ - -/* XXX: This should be moved ino irq.h */ -#define irq_cannonicalize(x) (x) diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index bff965e..8ccf7ae 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -66,12 +66,8 @@ /* 3. OFFCHIP_NR_IRQS */ #if defined(CONFIG_HD64461) # define OFFCHIP_NR_IRQS 18 -#elif defined (CONFIG_SH_BIGSUR) /* must be before CONFIG_HD64465 */ -# define OFFCHIP_NR_IRQS 48 #elif defined(CONFIG_HD64465) # define OFFCHIP_NR_IRQS 16 -#elif defined (CONFIG_SH_EC3104) -# define OFFCHIP_NR_IRQS 16 #elif defined (CONFIG_SH_DREAMCAST) # define OFFCHIP_NR_IRQS 96 #elif defined (CONFIG_SH_TITAN) diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h index 7b26f53..0095c66 100644 --- a/include/asm-sh/kgdb.h +++ b/include/asm-sh/kgdb.h @@ -85,10 +85,10 @@ extern int setjmp(jmp_buf __jmpb); #define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__) /* Forced breakpoint */ -#define BREAKPOINT() do { \ - if (kgdb_enabled) { \ - asm volatile("trapa #0xff"); \ - } \ +#define BREAKPOINT() \ +do { \ + if (kgdb_enabled) \ + __asm__ __volatile__("trapa #0x3c"); \ } while (0) /* KGDB should be able to flush all kernel text space */ diff --git a/include/asm-sh/mmu.h b/include/asm-sh/mmu.h index cf47df7..eb0358c 100644 --- a/include/asm-sh/mmu.h +++ b/include/asm-sh/mmu.h @@ -1,25 +1,19 @@ #ifndef __MMU_H #define __MMU_H -#if !defined(CONFIG_MMU) +/* Default "unsigned long" context */ +typedef unsigned long mm_context_id_t[NR_CPUS]; typedef struct { +#ifdef CONFIG_MMU + mm_context_id_t id; + void *vdso; +#else struct vm_list_struct *vmlist; unsigned long end_brk; +#endif } mm_context_t; -#else - -/* Default "unsigned long" context */ -typedef unsigned long mm_context_id_t; - -typedef struct { - mm_context_id_t id; - void *vdso; -} mm_context_t; - -#endif /* CONFIG_MMU */ - /* * Privileged Space Mapping Buffer (PMB) definitions */ diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h index 46f04e2..3420244 100644 --- a/include/asm-sh/mmu_context.h +++ b/include/asm-sh/mmu_context.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003 - 2006 Paul Mundt * * ASID handling idea taken from MIPS implementation. */ @@ -19,11 +19,6 @@ * (b) ASID (Address Space IDentifier) */ -/* - * Cache of MMU context last used. - */ -extern unsigned long mmu_context_cache; - #define MMU_CONTEXT_ASID_MASK 0x000000ff #define MMU_CONTEXT_VERSION_MASK 0xffffff00 #define MMU_CONTEXT_FIRST_VERSION 0x00000100 @@ -32,6 +27,11 @@ extern unsigned long mmu_context_cache; /* ASID is 8-bit value, so it can't be 0x100 */ #define MMU_NO_ASID 0x100 +#define cpu_context(cpu, mm) ((mm)->context.id[cpu]) +#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & \ + MMU_CONTEXT_ASID_MASK) +#define asid_cache(cpu) (cpu_data[cpu].asid_cache) + /* * Virtual Page Number mask */ @@ -41,18 +41,17 @@ extern unsigned long mmu_context_cache; /* * Get MMU context if needed. */ -static inline void get_mmu_context(struct mm_struct *mm) +static inline void get_mmu_context(struct mm_struct *mm, unsigned int cpu) { - unsigned long mc = mmu_context_cache; + unsigned long asid = asid_cache(cpu); /* Check if we have old version of context. */ - if (((mm->context.id ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0) + if (((cpu_context(cpu, mm) ^ asid) & MMU_CONTEXT_VERSION_MASK) == 0) /* It's up to date, do nothing */ return; /* It's old, we need to get new context with new version. */ - mc = ++mmu_context_cache; - if (!(mc & MMU_CONTEXT_ASID_MASK)) { + if (!(++asid & MMU_CONTEXT_ASID_MASK)) { /* * We exhaust ASID of this version. * Flush all TLB and start new cycle. @@ -63,10 +62,11 @@ static inline void get_mmu_context(struct mm_struct *mm) * Fix version; Note that we avoid version #0 * to distingush NO_CONTEXT. */ - if (!mc) - mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; + if (!asid) + asid = MMU_CONTEXT_FIRST_VERSION; } - mm->context.id = mc; + + cpu_context(cpu, mm) = asid_cache(cpu) = asid; } /* @@ -74,9 +74,13 @@ static inline void get_mmu_context(struct mm_struct *mm) * instance. */ static inline int init_new_context(struct task_struct *tsk, - struct mm_struct *mm) + struct mm_struct *mm) { - mm->context.id = NO_CONTEXT; + int i; + + for (i = 0; i < num_online_cpus(); i++) + cpu_context(i, mm) = NO_CONTEXT; + return 0; } @@ -117,10 +121,10 @@ static inline unsigned long get_asid(void) * After we have set current->mm to a new value, this activates * the context for the new mm so we see the new mappings. */ -static inline void activate_context(struct mm_struct *mm) +static inline void activate_context(struct mm_struct *mm, unsigned int cpu) { - get_mmu_context(mm); - set_asid(mm->context.id & MMU_CONTEXT_ASID_MASK); + get_mmu_context(mm, cpu); + set_asid(cpu_asid(cpu, mm)); } /* MMU_TTB is used for optimizing the fault handling. */ @@ -138,10 +142,15 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { + unsigned int cpu = smp_processor_id(); + if (likely(prev != next)) { + cpu_set(cpu, next->cpu_vm_mask); set_TTB(next->pgd); - activate_context(next); - } + activate_context(next, cpu); + } else + if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) + activate_context(next, cpu); } #define deactivate_mm(tsk,mm) do { } while (0) @@ -159,7 +168,7 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) #define destroy_context(mm) do { } while (0) #define set_asid(asid) do { } while (0) #define get_asid() (0) -#define activate_context(mm) do { } while (0) +#define activate_context(mm,cpu) do { } while (0) #define switch_mm(prev,next,tsk) do { } while (0) #define deactivate_mm(tsk,mm) do { } while (0) #define activate_mm(prev,next) do { } while (0) @@ -174,14 +183,16 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) */ static inline void enable_mmu(void) { + unsigned int cpu = smp_processor_id(); + /* Enable MMU */ ctrl_outl(MMU_CONTROL_INIT, MMUCR); ctrl_barrier(); - if (mmu_context_cache == NO_CONTEXT) - mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; + if (asid_cache(cpu) == NO_CONTEXT) + asid_cache(cpu) = MMU_CONTEXT_FIRST_VERSION; - set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); + set_asid(asid_cache(cpu) & MMU_CONTEXT_ASID_MASK); } static inline void disable_mmu(void) diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 380fd62..ac4b467 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -13,6 +13,8 @@ [ P4 control ] 0xE0000000 */ +#ifdef __KERNEL__ + /* PAGE_SHIFT determines the page size */ #if defined(CONFIG_PAGE_SIZE_4KB) # define PAGE_SHIFT 12 @@ -51,7 +53,6 @@ #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) #endif -#ifdef __KERNEL__ #ifndef __ASSEMBLY__ extern void (*clear_page)(void *to); diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index 036ca28..9214c01 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -43,17 +43,17 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; /* PGD bits */ #define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) #define PGDIR_BITS (32 - PGDIR_SHIFT) -#define PGDIR_SIZE (1 << PGDIR_SHIFT) +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) /* Entries per level */ -#define PTRS_PER_PTE (PAGE_SIZE / 4) +#define PTRS_PER_PTE (PAGE_SIZE / (1 << PTE_MAGNITUDE)) #define PTRS_PER_PGD (PAGE_SIZE / 4) #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_ADDRESS 0 -#define PTE_PHYS_MASK 0x1ffff000 +#define PTE_PHYS_MASK (0x20000000 - PAGE_SIZE) /* * First 1MB map is used by fixed purpose. @@ -583,11 +583,6 @@ struct mm_struct; extern unsigned int kobjsize(const void *objp); #endif /* !CONFIG_MMU */ -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) -#define __HAVE_ARCH_PTEP_GET_AND_CLEAR -extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); -#endif - extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern void paging_init(void); diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index e29f2ab..3e46a7a 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h @@ -27,8 +27,6 @@ #define CCN_CVR 0xff000040 #define CCN_PRR 0xff000044 -const char *get_cpu_subtype(void); - /* * CPU type and hardware bug flags. Kept separately for each CPU. * @@ -66,6 +64,7 @@ enum cpu_type { struct sh_cpuinfo { unsigned int type; unsigned long loops_per_jiffy; + unsigned long asid_cache; struct cache_info icache; /* Primary I-cache */ struct cache_info dcache; /* Primary D-cache */ @@ -288,5 +287,8 @@ extern int vsyscall_init(void); #define vsyscall_init() do { } while (0) #endif +/* arch/sh/kernel/setup.c */ +const char *get_cpu_subtype(struct sh_cpuinfo *c); + #endif /* __KERNEL__ */ #endif /* __ASM_SH_PROCESSOR_H */ diff --git a/include/asm-sh/rts7751r2d.h b/include/asm-sh/rts7751r2d.h index 796b8fc..10565ac 100644 --- a/include/asm-sh/rts7751r2d.h +++ b/include/asm-sh/rts7751r2d.h @@ -68,6 +68,10 @@ #define IRQ_PCISLOT2 10 /* PCI Slot #2 IRQ */ #define IRQ_EXTENTION 11 /* EXTn IRQ */ +/* arch/sh/boards/renesas/rts7751r2d/irq.c */ +void init_rts7751r2d_IRQ(void); +int rts7751r2d_irq_demux(int); + #define __IO_PREFIX rts7751r2d #include <asm/io_generic.h> diff --git a/include/asm-sh/serial.h b/include/asm-sh/serial.h index 8734590..21f6d33 100644 --- a/include/asm-sh/serial.h +++ b/include/asm-sh/serial.h @@ -9,11 +9,6 @@ #include <linux/kernel.h> -#ifdef CONFIG_SH_EC3104 -#include <asm/serial-ec3104.h> -#elif defined (CONFIG_SH_BIGSUR) -#include <asm/serial-bigsur.h> -#else /* * This assumes you have a 1.8432 MHz clock for your UART. * @@ -34,12 +29,8 @@ #else -#define SERIAL_PORT_DFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS } /* ttyS1 */ +#define SERIAL_PORT_DFNS #endif -#endif #endif /* _ASM_SERIAL_H */ diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h index 879f741..279e70a 100644 --- a/include/asm-sh/thread_info.h +++ b/include/asm-sh/thread_info.h @@ -32,12 +32,20 @@ struct thread_info { #define PREEMPT_ACTIVE 0x10000000 -#ifdef CONFIG_4KSTACKS -#define THREAD_SIZE (PAGE_SIZE) +#if defined(CONFIG_4KSTACKS) +#define THREAD_SIZE_ORDER (0) +#elif defined(CONFIG_PAGE_SIZE_4KB) +#define THREAD_SIZE_ORDER (1) +#elif defined(CONFIG_PAGE_SIZE_8KB) +#define THREAD_SIZE_ORDER (1) +#elif defined(CONFIG_PAGE_SIZE_64KB) +#define THREAD_SIZE_ORDER (0) #else -#define THREAD_SIZE (PAGE_SIZE * 2) +#error "Unknown thread size" #endif -#define STACK_WARN (THREAD_SIZE / 8) + +#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) +#define STACK_WARN (THREAD_SIZE >> 3) /* * macros/functions for gaining access to the thread information structure diff --git a/include/asm-sh/tlbflush.h b/include/asm-sh/tlbflush.h index 28c073b..455fb8d 100644 --- a/include/asm-sh/tlbflush.h +++ b/include/asm-sh/tlbflush.h @@ -4,7 +4,6 @@ /* * TLB flushing: * - * - flush_tlb() flushes the current mm struct TLBs * - flush_tlb_all() flushes all processes TLBs * - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_page(vma, vmaddr) flushes one page @@ -12,20 +11,45 @@ * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables */ +extern void local_flush_tlb_all(void); +extern void local_flush_tlb_mm(struct mm_struct *mm); +extern void local_flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, + unsigned long end); +extern void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long page); +extern void local_flush_tlb_kernel_range(unsigned long start, + unsigned long end); +extern void local_flush_tlb_one(unsigned long asid, unsigned long page); + +#ifdef CONFIG_SMP -extern void flush_tlb(void); extern void flush_tlb_all(void); extern void flush_tlb_mm(struct mm_struct *mm); extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); -extern void __flush_tlb_page(unsigned long asid, unsigned long page); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void flush_tlb_one(unsigned long asid, unsigned long page); + +#else + +#define flush_tlb_all() local_flush_tlb_all() +#define flush_tlb_mm(mm) local_flush_tlb_mm(mm) +#define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page) +#define flush_tlb_one(asid, page) local_flush_tlb_one(asid, page) + +#define flush_tlb_range(vma, start, end) \ + local_flush_tlb_range(vma, start, end) + +#define flush_tlb_kernel_range(start, end) \ + local_flush_tlb_kernel_range(start, end) + +#endif /* CONFIG_SMP */ static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) -{ /* Nothing to do */ +{ + /* Nothing to do */ } - -extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); - #endif /* __ASM_SH_TLBFLUSH_H */ diff --git a/include/asm-sh/ubc.h b/include/asm-sh/ubc.h index 694f51f..ae9bbde 100644 --- a/include/asm-sh/ubc.h +++ b/include/asm-sh/ubc.h @@ -17,7 +17,7 @@ /* User Break Controller */ #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ defined(CONFIG_CPU_SUBTYPE_SH7300) -#define UBC_TYPE_SH7729 (cpu_data->type == CPU_SH7729) +#define UBC_TYPE_SH7729 (current_cpu_data.type == CPU_SH7729) #else #define UBC_TYPE_SH7729 0 #endif diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index f982073..17f527b 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -292,22 +292,22 @@ #define __NR_mq_getsetattr (__NR_mq_open+5) #define __NR_kexec_load 283 #define __NR_waitid 284 -/* #define __NR_sys_setaltroot 285 */ -#define __NR_add_key 286 -#define __NR_request_key 287 -#define __NR_keyctl 288 -#define __NR_ioprio_set 289 -#define __NR_ioprio_get 290 -#define __NR_inotify_init 291 -#define __NR_inotify_add_watch 292 -#define __NR_inotify_rm_watch 293 +#define __NR_add_key 285 +#define __NR_request_key 286 +#define __NR_keyctl 287 +#define __NR_ioprio_set 288 +#define __NR_ioprio_get 289 +#define __NR_inotify_init 290 +#define __NR_inotify_add_watch 291 +#define __NR_inotify_rm_watch 292 +/* 293 is unused */ #define __NR_migrate_pages 294 #define __NR_openat 295 #define __NR_mkdirat 296 #define __NR_mknodat 297 #define __NR_fchownat 298 #define __NR_futimesat 299 -#define __NR_newfstatat 300 +#define __NR_fstatat64 300 #define __NR_unlinkat 301 #define __NR_renameat 302 #define __NR_linkat 303 diff --git a/include/asm-sh/voyagergx.h b/include/asm-sh/voyagergx.h index 99b0807..64c936b 100644 --- a/include/asm-sh/voyagergx.h +++ b/include/asm-sh/voyagergx.h @@ -308,6 +308,9 @@ #define AC97C_READ (1 << 19) #define AC97C_WD_BIT (1 << 2) #define AC97C_INDEX_MASK 0x7f -/* -------------------------------------------------------------------- */ + +/* arch/sh/cchips/voyagergx/consistent.c */ +void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t); +int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t); #endif /* _VOYAGER_GX_REG_H */ diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h index 8da9609..d4dbbe5 100644 --- a/include/asm-x86_64/bitops.h +++ b/include/asm-x86_64/bitops.h @@ -7,7 +7,7 @@ #include <asm/alternative.h> -#if __GNUC__ < 4 || __GNUC_MINOR__ < 1 +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) /* Technically wrong, but this avoids compilation errors on some gcc versions. */ #define ADDR "=m" (*(volatile long *) addr) diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h index 49dbab0..d2af227 100644 --- a/include/asm-x86_64/dma-mapping.h +++ b/include/asm-x86_64/dma-mapping.h @@ -66,6 +66,9 @@ static inline int dma_mapping_error(dma_addr_t dma_addr) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) + extern void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp); extern void dma_free_coherent(struct device *dev, size_t size, void *vaddr, diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h index fa20867..6216fa3 100644 --- a/include/asm-x86_64/e820.h +++ b/include/asm-x86_64/e820.h @@ -46,6 +46,7 @@ extern void e820_mark_nosave_regions(void); extern void e820_print_map(char *who); extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type); extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type); +extern unsigned long e820_hole_size(unsigned long start, unsigned long end); extern void e820_setup_gap(void); extern void e820_register_active_regions(int nid, @@ -56,6 +57,7 @@ extern void finish_e820_parsing(void); extern struct e820map e820; extern unsigned ebda_addr, ebda_size; +extern unsigned long nodemap_addr, nodemap_size; #endif/*!__ASSEMBLY__*/ #endif/*__E820_HEADER*/ diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h index b390984..59a66f0 100644 --- a/include/asm-x86_64/hpet.h +++ b/include/asm-x86_64/hpet.h @@ -56,8 +56,15 @@ extern int is_hpet_enabled(void); extern int hpet_rtc_timer_init(void); extern int apic_is_clustered_box(void); +extern int hpet_arch_init(void); +extern int hpet_timer_stop_set_go(unsigned long tick); +extern int hpet_reenable(void); +extern unsigned int hpet_calibrate_tsc(void); extern int hpet_use_timer; +extern unsigned long hpet_address; +extern unsigned long hpet_period; +extern unsigned long hpet_tick; #ifdef CONFIG_HPET_EMULATE_RTC extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 179cce7..552df5f 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -91,7 +91,7 @@ extern void enable_8259A_irq(unsigned int irq); extern int i8259A_irq_pending(unsigned int irq); extern void make_8259A_irq(unsigned int irq); extern void init_8259A(int aeoi); -extern void FASTCALL(send_IPI_self(int vector)); +extern void send_IPI_self(int vector); extern void init_VISWS_APIC_irqs(void); extern void setup_IO_APIC(void); extern void disable_IO_APIC(void); diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h index f5d84bb..de2cd9a 100644 --- a/include/asm-x86_64/io.h +++ b/include/asm-x86_64/io.h @@ -100,7 +100,7 @@ __OUTS(l) #define IO_SPACE_LIMIT 0xffff -#if defined(__KERNEL__) && __x86_64__ +#if defined(__KERNEL__) && defined(__x86_64__) #include <linux/vmalloc.h> diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index 561ecbf..f4fb238 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -85,18 +85,8 @@ struct IO_APIC_route_entry { mask : 1, /* 0: enabled, 1: disabled */ __reserved_2 : 15; - union { struct { __u32 - __reserved_1 : 24, - physical_dest : 4, - __reserved_2 : 4; - } physical; - - struct { __u32 - __reserved_1 : 24, - logical_dest : 8; - } logical; - } dest; - + __u32 __reserved_3 : 24, + dest : 8; } __attribute__ ((packed)); /* diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h index 5a11146..177e92b 100644 --- a/include/asm-x86_64/mce.h +++ b/include/asm-x86_64/mce.h @@ -103,6 +103,8 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status); extern atomic_t mce_entry; +extern void do_machine_check(struct pt_regs *, long); + #endif #endif diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index c38ebdf..fb558fb 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h @@ -11,24 +11,25 @@ #include <asm/smp.h> -/* Should really switch to dynamic allocation at some point */ -#define NODEMAPSIZE 0x4fff - /* Simple perfect hash to map physical addresses to node numbers */ struct memnode { int shift; - u8 map[NODEMAPSIZE]; -} ____cacheline_aligned; + unsigned int mapsize; + u8 *map; + u8 embedded_map[64-16]; +} ____cacheline_aligned; /* total size = 64 bytes */ extern struct memnode memnode; #define memnode_shift memnode.shift #define memnodemap memnode.map +#define memnodemapsize memnode.mapsize extern struct pglist_data *node_data[]; static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) { unsigned nid; - VIRTUAL_BUG_ON((addr >> memnode_shift) >= NODEMAPSIZE); + VIRTUAL_BUG_ON(!memnodemap); + VIRTUAL_BUG_ON((addr >> memnode_shift) >= memnodemapsize); nid = memnodemap[addr >> memnode_shift]; VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]); return nid; @@ -46,5 +47,10 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) extern int pfn_valid(unsigned long pfn); #endif +#ifdef CONFIG_NUMA_EMU +#define FAKE_NODE_MIN_SIZE (64*1024*1024) +#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1ul)) +#endif + #endif #endif diff --git a/include/asm-x86_64/mutex.h b/include/asm-x86_64/mutex.h index 16396b1..6c2949a 100644 --- a/include/asm-x86_64/mutex.h +++ b/include/asm-x86_64/mutex.h @@ -21,7 +21,7 @@ do { \ unsigned long dummy; \ \ typecheck(atomic_t *, v); \ - typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ + typecheck_fn(void (*)(atomic_t *), fail_fn); \ \ __asm__ __volatile__( \ LOCK_PREFIX " decl (%%rdi) \n" \ @@ -47,7 +47,7 @@ do { \ */ static inline int __mutex_fastpath_lock_retval(atomic_t *count, - int fastcall (*fail_fn)(atomic_t *)) + int (*fail_fn)(atomic_t *)) { if (unlikely(atomic_dec_return(count) < 0)) return fail_fn(count); @@ -67,7 +67,7 @@ do { \ unsigned long dummy; \ \ typecheck(atomic_t *, v); \ - typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ + typecheck_fn(void (*)(atomic_t *), fail_fn); \ \ __asm__ __volatile__( \ LOCK_PREFIX " incl (%%rdi) \n" \ diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h index 43d4c33..4e28b60 100644 --- a/include/asm-x86_64/pgalloc.h +++ b/include/asm-x86_64/pgalloc.h @@ -18,11 +18,6 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT))); } -static inline pmd_t *get_pmd(void) -{ - return (pmd_t *)get_zeroed_page(GFP_KERNEL); -} - static inline void pmd_free(pmd_t *pmd) { BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index 59901c6..730bd60 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -359,15 +359,6 @@ static inline int pmd_large(pmd_t pte) { #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) #define mk_pte_huge(entry) (pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE) -/* physical address -> PTE */ -static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) -{ - pte_t pte; - pte_val(pte) = physpage | pgprot_val(pgprot); - pte_val(pte) &= __supported_pte_mask; - return pte; -} - /* Change flags of a PTE */ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index a6d2ff5..f54f3ab 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -45,11 +45,7 @@ extern u32 pmtmr_ioport; #else #define pmtmr_ioport 0 #endif -extern unsigned long long monotonic_base; -extern int sysctl_vsyscall; extern int nohpet; -extern unsigned long vxtime_hz; -extern void time_init_gtod(void); extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2))); @@ -91,8 +87,6 @@ extern void check_efer(void); extern int unhandled_signal(struct task_struct *tsk, int sig); -extern int unsynchronized_tsc(void); - extern void select_idle_routine(const struct cpuinfo_x86 *c); extern unsigned long table_start, table_end; diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h index b9e5320..8c6808a 100644 --- a/include/asm-x86_64/timex.h +++ b/include/asm-x86_64/timex.h @@ -12,38 +12,21 @@ #include <asm/hpet.h> #include <asm/system.h> #include <asm/processor.h> +#include <asm/tsc.h> #include <linux/compiler.h> #define CLOCK_TICK_RATE PIT_TICK_RATE /* Underlying HZ */ -typedef unsigned long long cycles_t; - -static inline cycles_t get_cycles (void) -{ - unsigned long long ret; - - rdtscll(ret); - return ret; -} - -/* Like get_cycles, but make sure the CPU is synchronized. */ -static __always_inline cycles_t get_cycles_sync(void) -{ - unsigned long long ret; - unsigned eax; - /* Don't do an additional sync on CPUs where we know - RDTSC is already synchronous. */ - alternative_io("cpuid", ASM_NOP2, X86_FEATURE_SYNC_RDTSC, - "=a" (eax), "0" (1) : "ebx","ecx","edx","memory"); - rdtscll(ret); - return ret; -} - -extern unsigned int cpu_khz; - extern int read_current_timer(unsigned long *timer_value); #define ARCH_HAS_READ_CURRENT_TIMER 1 -extern struct vxtime_data vxtime; +#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 */ +extern void mark_tsc_unstable(void); +extern void set_cyc2ns_scale(unsigned long khz); #endif diff --git a/include/asm-x86_64/tsc.h b/include/asm-x86_64/tsc.h new file mode 100644 index 0000000..9a0a368 --- /dev/null +++ b/include/asm-x86_64/tsc.h @@ -0,0 +1,66 @@ +/* + * linux/include/asm-x86_64/tsc.h + * + * x86_64 TSC related functions + */ +#ifndef _ASM_x86_64_TSC_H +#define _ASM_x86_64_TSC_H + +#include <asm/processor.h> + +/* + * Standard way to access the cycle counter. + */ +typedef unsigned long long cycles_t; + +extern unsigned int cpu_khz; +extern unsigned int tsc_khz; + +static inline cycles_t get_cycles(void) +{ + unsigned long long ret = 0; + +#ifndef CONFIG_X86_TSC + if (!cpu_has_tsc) + return 0; +#endif + +#if defined(CONFIG_X86_GENERIC) || defined(CONFIG_X86_TSC) + rdtscll(ret); +#endif + return ret; +} + +/* Like get_cycles, but make sure the CPU is synchronized. */ +static __always_inline cycles_t get_cycles_sync(void) +{ + unsigned long long ret; +#ifdef X86_FEATURE_SYNC_RDTSC + unsigned eax; + + /* + * Don't do an additional sync on CPUs where we know + * RDTSC is already synchronous: + */ + alternative_io("cpuid", ASM_NOP2, X86_FEATURE_SYNC_RDTSC, + "=a" (eax), "0" (1) : "ebx","ecx","edx","memory"); +#else + sync_core(); +#endif + rdtscll(ret); + + return ret; +} + +extern void tsc_init(void); +extern void mark_tsc_unstable(void); +extern int unsynchronized_tsc(void); + +/* + * Boot-time check whether the TSCs are synchronized across + * all CPUs/cores: + */ +extern void check_tsc_sync_source(int cpu); +extern void check_tsc_sync_target(void); + +#endif diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h index 8079e29..1981f70 100644 --- a/include/asm-x86_64/uaccess.h +++ b/include/asm-x86_64/uaccess.h @@ -367,4 +367,18 @@ __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size) return copy_user_generic((__force void *)dst, src, size); } +#define ARCH_HAS_NOCACHE_UACCESS 1 +extern long __copy_user_nocache(void *dst, const void __user *src, unsigned size, int zerorest); + +static inline int __copy_from_user_nocache(void *dst, const void __user *src, unsigned size) +{ + might_sleep(); + return __copy_user_nocache(dst, (__force void *)src, size, 1); +} + +static inline int __copy_from_user_inatomic_nocache(void *dst, const void __user *src, unsigned size) +{ + return __copy_user_nocache(dst, (__force void *)src, size, 0); +} + #endif /* __X86_64_UACCESS_H */ diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h index 05cb8dd2..82b4afe 100644 --- a/include/asm-x86_64/vsyscall.h +++ b/include/asm-x86_64/vsyscall.h @@ -16,51 +16,27 @@ enum vsyscall_num { #ifdef __KERNEL__ #include <linux/seqlock.h> -#define __section_vxtime __attribute__ ((unused, __section__ (".vxtime"), aligned(16))) #define __section_vgetcpu_mode __attribute__ ((unused, __section__ (".vgetcpu_mode"), aligned(16))) #define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16))) -#define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16))) -#define __section_sysctl_vsyscall __attribute__ ((unused, __section__ (".sysctl_vsyscall"), aligned(16))) -#define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16))) -#define __section_xtime_lock __attribute__ ((unused, __section__ (".xtime_lock"), aligned(16))) -#define VXTIME_TSC 1 -#define VXTIME_HPET 2 -#define VXTIME_PMTMR 3 +/* Definitions for CONFIG_GENERIC_TIME definitions */ +#define __section_vsyscall_gtod_data __attribute__ \ + ((unused, __section__ (".vsyscall_gtod_data"),aligned(16))) +#define __vsyscall_fn __attribute__ ((unused,__section__(".vsyscall_fn"))) #define VGETCPU_RDTSCP 1 #define VGETCPU_LSL 2 -struct vxtime_data { - long hpet_address; /* HPET base address */ - int last; - unsigned long last_tsc; - long quot; - long tsc_quot; - int mode; -}; - #define hpet_readl(a) readl((const void __iomem *)fix_to_virt(FIX_HPET_BASE) + a) #define hpet_writel(d,a) writel(d, (void __iomem *)fix_to_virt(FIX_HPET_BASE) + a) -/* vsyscall space (readonly) */ -extern struct vxtime_data __vxtime; extern int __vgetcpu_mode; -extern struct timespec __xtime; extern volatile unsigned long __jiffies; -extern struct timezone __sys_tz; -extern seqlock_t __xtime_lock; /* kernel space (writeable) */ -extern struct vxtime_data vxtime; extern int vgetcpu_mode; extern struct timezone sys_tz; -extern int sysctl_vsyscall; -extern seqlock_t xtime_lock; - -extern int sysctl_vsyscall; - -#define ARCH_HAVE_XTIME_LOCK 1 +extern struct vsyscall_gtod_data_t vsyscall_gtod_data; #endif /* __KERNEL__ */ diff --git a/include/linux/acpi_pmtmr.h b/include/linux/acpi_pmtmr.h new file mode 100644 index 0000000..1d0ef1a --- /dev/null +++ b/include/linux/acpi_pmtmr.h @@ -0,0 +1,38 @@ +#ifndef _ACPI_PMTMR_H_ +#define _ACPI_PMTMR_H_ + +#include <linux/clocksource.h> + +/* Number of PMTMR ticks expected during calibration run */ +#define PMTMR_TICKS_PER_SEC 3579545 + +/* limit it to 24 bits */ +#define ACPI_PM_MASK CLOCKSOURCE_MASK(24) + +/* Overrun value */ +#define ACPI_PM_OVRRUN (1<<24) + +#ifdef CONFIG_X86_PM_TIMER + +extern u32 acpi_pm_read_verified(void); +extern u32 pmtmr_ioport; + +static inline u32 acpi_pm_read_early(void) +{ + if (!pmtmr_ioport) + return 0; + /* mask the output to 24 bits */ + return acpi_pm_read_verified() & ACPI_PM_MASK; +} + +#else + +static inline u32 acpi_pm_read_early(void) +{ + return 0; +} + +#endif + +#endif + diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index a5c8bb5..abc521c 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -87,10 +87,15 @@ struct agp_memory { u32 physical; u8 is_bound; u8 is_flushed; + u8 vmalloc_flag; }; #define AGP_NORMAL_MEMORY 0 +#define AGP_USER_TYPES (1 << 16) +#define AGP_USER_MEMORY (AGP_USER_TYPES) +#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) + extern struct agp_bridge_data *agp_bridge; extern struct list_head agp_bridges; diff --git a/include/linux/ata.h b/include/linux/ata.h index 18e401f..272736e 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -352,7 +352,7 @@ static inline int ata_drive_40wire(const u16 *dev_id) { if (ata_id_major_version(dev_id) >= 5 && ata_id_is_sata(dev_id)) return 0; /* SATA */ - if (dev_id[93] & 0x4000) + if ((dev_id[93] & 0xE000) == 0x6000) return 0; /* 80 wire */ return 1; } diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index c1e82c5..2d956cd 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -59,6 +59,7 @@ struct linux_binfmt { int (*load_shlib)(struct file *); int (*core_dump)(long signr, struct pt_regs * regs, struct file * file); unsigned long min_coredump; /* minimal dump size */ + int hasvdso; }; extern int register_binfmt(struct linux_binfmt *); diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h new file mode 100644 index 0000000..4ea7e7b --- /dev/null +++ b/include/linux/clockchips.h @@ -0,0 +1,142 @@ +/* linux/include/linux/clockchips.h + * + * This file contains the structure definitions for clockchips. + * + * If you are not a clockchip, or the time of day code, you should + * not be including this file! + */ +#ifndef _LINUX_CLOCKCHIPS_H +#define _LINUX_CLOCKCHIPS_H + +#ifdef CONFIG_GENERIC_CLOCKEVENTS + +#include <linux/clocksource.h> +#include <linux/cpumask.h> +#include <linux/ktime.h> +#include <linux/notifier.h> + +struct clock_event_device; + +/* Clock event mode commands */ +enum clock_event_mode { + CLOCK_EVT_MODE_UNUSED = 0, + CLOCK_EVT_MODE_SHUTDOWN, + CLOCK_EVT_MODE_PERIODIC, + CLOCK_EVT_MODE_ONESHOT, +}; + +/* Clock event notification values */ +enum clock_event_nofitiers { + CLOCK_EVT_NOTIFY_ADD, + CLOCK_EVT_NOTIFY_BROADCAST_ON, + CLOCK_EVT_NOTIFY_BROADCAST_OFF, + CLOCK_EVT_NOTIFY_BROADCAST_ENTER, + CLOCK_EVT_NOTIFY_BROADCAST_EXIT, + CLOCK_EVT_NOTIFY_SUSPEND, + CLOCK_EVT_NOTIFY_RESUME, + CLOCK_EVT_NOTIFY_CPU_DEAD, +}; + +/* + * Clock event features + */ +#define CLOCK_EVT_FEAT_PERIODIC 0x000001 +#define CLOCK_EVT_FEAT_ONESHOT 0x000002 +/* + * x86(64) specific misfeatures: + * + * - Clockevent source stops in C3 State and needs broadcast support. + * - Local APIC timer is used as a dummy device. + */ +#define CLOCK_EVT_FEAT_C3STOP 0x000004 +#define CLOCK_EVT_FEAT_DUMMY 0x000008 + +/** + * struct clock_event_device - clock event device descriptor + * @name: ptr to clock event name + * @hints: usage hints + * @max_delta_ns: maximum delta value in ns + * @min_delta_ns: minimum delta value in ns + * @mult: nanosecond to cycles multiplier + * @shift: nanoseconds to cycles divisor (power of two) + * @rating: variable to rate clock event devices + * @irq: irq number (only for non cpu local devices) + * @cpumask: cpumask to indicate for which cpus this device works + * @set_next_event: set next event + * @set_mode: set mode function + * @evthandler: Assigned by the framework to be called by the low + * level handler of the event source + * @broadcast: function to broadcast events + * @list: list head for the management code + * @mode: operating mode assigned by the management code + * @next_event: local storage for the next event in oneshot mode + */ +struct clock_event_device { + const char *name; + unsigned int features; + unsigned long max_delta_ns; + unsigned long min_delta_ns; + unsigned long mult; + int shift; + int rating; + int irq; + cpumask_t cpumask; + int (*set_next_event)(unsigned long evt, + struct clock_event_device *); + void (*set_mode)(enum clock_event_mode mode, + struct clock_event_device *); + void (*event_handler)(struct clock_event_device *); + void (*broadcast)(cpumask_t mask); + struct list_head list; + enum clock_event_mode mode; + ktime_t next_event; +}; + +/* + * Calculate a multiplication factor for scaled math, which is used to convert + * nanoseconds based values to clock ticks: + * + * clock_ticks = (nanoseconds * factor) >> shift. + * + * div_sc is the rearranged equation to calculate a factor from a given clock + * ticks / nanoseconds ratio: + * + * factor = (clock_ticks << shift) / nanoseconds + */ +static inline unsigned long div_sc(unsigned long ticks, unsigned long nsec, + int shift) +{ + uint64_t tmp = ((uint64_t)ticks) << shift; + + do_div(tmp, nsec); + return (unsigned long) tmp; +} + +/* Clock event layer functions */ +extern unsigned long clockevent_delta2ns(unsigned long latch, + struct clock_event_device *evt); +extern void clockevents_register_device(struct clock_event_device *dev); + +extern void clockevents_exchange_device(struct clock_event_device *old, + struct clock_event_device *new); +extern +struct clock_event_device *clockevents_request_device(unsigned int features, + cpumask_t cpumask); +extern void clockevents_release_device(struct clock_event_device *dev); +extern void clockevents_set_mode(struct clock_event_device *dev, + enum clock_event_mode mode); +extern int clockevents_register_notifier(struct notifier_block *nb); +extern void clockevents_unregister_notifier(struct notifier_block *nb); +extern int clockevents_program_event(struct clock_event_device *dev, + ktime_t expires, ktime_t now); + +extern void clockevents_notify(unsigned long reason, void *arg); + +#else + +static inline void clockevents_resume_events(void) { } +#define clockevents_notify(reason, arg) do { } while (0) + +#endif + +#endif diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 1622d23..daa4940c 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -12,11 +12,13 @@ #include <linux/timex.h> #include <linux/time.h> #include <linux/list.h> +#include <linux/timer.h> #include <asm/div64.h> #include <asm/io.h> /* clocksource cycle base type */ typedef u64 cycle_t; +struct clocksource; /** * struct clocksource - hardware abstraction for a free running counter @@ -44,8 +46,8 @@ typedef u64 cycle_t; * subtraction of non 64 bit counters * @mult: cycle to nanosecond multiplier * @shift: cycle to nanosecond divisor (power of two) - * @update_callback: called when safe to alter clocksource values - * @is_continuous: defines if clocksource is free-running. + * @flags: flags describing special properties + * @vread: vsyscall based read * @cycle_interval: Used internally by timekeeping core, please ignore. * @xtime_interval: Used internally by timekeeping core, please ignore. */ @@ -57,15 +59,30 @@ struct clocksource { cycle_t mask; u32 mult; u32 shift; - int (*update_callback)(void); - int is_continuous; + unsigned long flags; + cycle_t (*vread)(void); /* timekeeping specific data, ignore */ cycle_t cycle_last, cycle_interval; u64 xtime_nsec, xtime_interval; s64 error; + +#ifdef CONFIG_CLOCKSOURCE_WATCHDOG + /* Watchdog related data, used by the framework */ + struct list_head wd_list; + cycle_t wd_last; +#endif }; +/* + * Clock source flags bits:: + */ +#define CLOCK_SOURCE_IS_CONTINUOUS 0x01 +#define CLOCK_SOURCE_MUST_VERIFY 0x02 + +#define CLOCK_SOURCE_WATCHDOG 0x10 +#define CLOCK_SOURCE_VALID_FOR_HRES 0x20 + /* simplify initialization of mask field */ #define CLOCKSOURCE_MASK(bits) (cycle_t)(bits<64 ? ((1ULL<<bits)-1) : -1) @@ -178,8 +195,16 @@ static inline void clocksource_calculate_interval(struct clocksource *c, /* used to install a new clocksource */ -int clocksource_register(struct clocksource*); -void clocksource_reselect(void); -struct clocksource* clocksource_get_next(void); +extern int clocksource_register(struct clocksource*); +extern struct clocksource* clocksource_get_next(void); +extern void clocksource_change_rating(struct clocksource *cs, int rating); + +#ifdef CONFIG_GENERIC_TIME_VSYSCALL +extern void update_vsyscall(struct timespec *ts, struct clocksource *c); +#else +static inline void update_vsyscall(struct timespec *ts, struct clocksource *c) +{ +} +#endif #endif /* _LINUX_CLOCKSOURCE_H */ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7f008f6..0899e2c 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -84,9 +84,6 @@ struct cpufreq_policy { unsigned int policy; /* see above */ struct cpufreq_governor *governor; /* see below */ - struct mutex lock; /* CPU ->setpolicy or ->target may - only be called once a time */ - struct work_struct update; /* if update_policy() needs to be * called, but you're in IRQ context */ @@ -172,11 +169,16 @@ extern int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation); -extern int cpufreq_driver_getavg(struct cpufreq_policy *policy); +extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy); int cpufreq_register_governor(struct cpufreq_governor *governor); void cpufreq_unregister_governor(struct cpufreq_governor *governor); +int lock_policy_rwsem_read(int cpu); +int lock_policy_rwsem_write(int cpu); +void unlock_policy_rwsem_read(int cpu); +void unlock_policy_rwsem_write(int cpu); + /********************************************************************* * CPUFREQ DRIVER INTERFACE * diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 612472a..7803014 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -106,7 +106,7 @@ static inline void account_system_vtime(struct task_struct *tsk) * always balanced, so the interrupted value of ->hardirq_context * will always be restored. */ -#define irq_enter() \ +#define __irq_enter() \ do { \ account_system_vtime(current); \ add_preempt_count(HARDIRQ_OFFSET); \ @@ -114,6 +114,11 @@ static inline void account_system_vtime(struct task_struct *tsk) } while (0) /* + * Enter irq context (on NO_HZ, update jiffies): + */ +extern void irq_enter(void); + +/* * Exit irq context without processing softirqs: */ #define __irq_exit() \ @@ -128,7 +133,7 @@ static inline void account_system_vtime(struct task_struct *tsk) */ extern void irq_exit(void); -#define nmi_enter() do { lockdep_off(); irq_enter(); } while (0) +#define nmi_enter() do { lockdep_off(); __irq_enter(); } while (0) #define nmi_exit() do { __irq_exit(); lockdep_on(); } while (0) #endif /* LINUX_HARDIRQ_H */ diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index fca9302..37f9279 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -21,22 +21,72 @@ #include <linux/list.h> #include <linux/wait.h> +struct hrtimer_clock_base; +struct hrtimer_cpu_base; + /* * Mode arguments of xxx_hrtimer functions: */ enum hrtimer_mode { - HRTIMER_ABS, /* Time value is absolute */ - HRTIMER_REL, /* Time value is relative to now */ + HRTIMER_MODE_ABS, /* Time value is absolute */ + HRTIMER_MODE_REL, /* Time value is relative to now */ }; +/* + * Return values for the callback function + */ enum hrtimer_restart { - HRTIMER_NORESTART, - HRTIMER_RESTART, + HRTIMER_NORESTART, /* Timer is not restarted */ + HRTIMER_RESTART, /* Timer must be restarted */ }; -#define HRTIMER_INACTIVE ((void *)1UL) +/* + * hrtimer callback modes: + * + * HRTIMER_CB_SOFTIRQ: Callback must run in softirq context + * HRTIMER_CB_IRQSAFE: Callback may run in hardirq context + * HRTIMER_CB_IRQSAFE_NO_RESTART: Callback may run in hardirq context and + * does not restart the timer + * HRTIMER_CB_IRQSAFE_NO_SOFTIRQ: Callback must run in softirq context + * Special mode for tick emultation + */ +enum hrtimer_cb_mode { + HRTIMER_CB_SOFTIRQ, + HRTIMER_CB_IRQSAFE, + HRTIMER_CB_IRQSAFE_NO_RESTART, + HRTIMER_CB_IRQSAFE_NO_SOFTIRQ, +}; -struct hrtimer_base; +/* + * Values to track state of the timer + * + * Possible states: + * + * 0x00 inactive + * 0x01 enqueued into rbtree + * 0x02 callback function running + * 0x04 callback pending (high resolution mode) + * + * Special case: + * 0x03 callback function running and enqueued + * (was requeued on another CPU) + * The "callback function running and enqueued" status is only possible on + * SMP. It happens for example when a posix timer expired and the callback + * queued a signal. Between dropping the lock which protects the posix timer + * and reacquiring the base lock of the hrtimer, another CPU can deliver the + * signal and rearm the timer. We have to preserve the callback running state, + * as otherwise the timer could be removed before the softirq code finishes the + * the handling of the timer. + * + * The HRTIMER_STATE_ENQUEUE bit is always or'ed to the current state to + * preserve the HRTIMER_STATE_CALLBACK bit in the above scenario. + * + * All state transitions are protected by cpu_base->lock. + */ +#define HRTIMER_STATE_INACTIVE 0x00 +#define HRTIMER_STATE_ENQUEUED 0x01 +#define HRTIMER_STATE_CALLBACK 0x02 +#define HRTIMER_STATE_PENDING 0x04 /** * struct hrtimer - the basic hrtimer structure @@ -46,14 +96,34 @@ struct hrtimer_base; * which the timer is based. * @function: timer expiry callback function * @base: pointer to the timer base (per cpu and per clock) + * @state: state information (See bit values above) + * @cb_mode: high resolution timer feature to select the callback execution + * mode + * @cb_entry: list head to enqueue an expired timer into the callback list + * @start_site: timer statistics field to store the site where the timer + * was started + * @start_comm: timer statistics field to store the name of the process which + * started the timer + * @start_pid: timer statistics field to store the pid of the task which + * started the timer * - * The hrtimer structure must be initialized by init_hrtimer_#CLOCKTYPE() + * The hrtimer structure must be initialized by hrtimer_init() */ struct hrtimer { - struct rb_node node; - ktime_t expires; - int (*function)(struct hrtimer *); - struct hrtimer_base *base; + struct rb_node node; + ktime_t expires; + enum hrtimer_restart (*function)(struct hrtimer *); + struct hrtimer_clock_base *base; + unsigned long state; +#ifdef CONFIG_HIGH_RES_TIMERS + enum hrtimer_cb_mode cb_mode; + struct list_head cb_entry; +#endif +#ifdef CONFIG_TIMER_STATS + void *start_site; + char start_comm[16]; + int start_pid; +#endif }; /** @@ -70,37 +140,114 @@ struct hrtimer_sleeper { /** * struct hrtimer_base - the timer base for a specific clock - * @index: clock type index for per_cpu support when moving a timer - * to a base on another cpu. - * @lock: lock protecting the base and associated timers + * @index: clock type index for per_cpu support when moving a + * timer to a base on another cpu. * @active: red black tree root node for the active timers * @first: pointer to the timer node which expires first * @resolution: the resolution of the clock, in nanoseconds * @get_time: function to retrieve the current time of the clock * @get_softirq_time: function to retrieve the current time from the softirq - * @curr_timer: the timer which is executing a callback right now * @softirq_time: the time when running the hrtimer queue in the softirq - * @lock_key: the lock_class_key for use with lockdep + * @cb_pending: list of timers where the callback is pending + * @offset: offset of this clock to the monotonic base + * @reprogram: function to reprogram the timer event */ -struct hrtimer_base { +struct hrtimer_clock_base { + struct hrtimer_cpu_base *cpu_base; clockid_t index; - spinlock_t lock; struct rb_root active; struct rb_node *first; ktime_t resolution; ktime_t (*get_time)(void); ktime_t (*get_softirq_time)(void); - struct hrtimer *curr_timer; ktime_t softirq_time; - struct lock_class_key lock_key; +#ifdef CONFIG_HIGH_RES_TIMERS + ktime_t offset; + int (*reprogram)(struct hrtimer *t, + struct hrtimer_clock_base *b, + ktime_t n); +#endif +}; + +#define HRTIMER_MAX_CLOCK_BASES 2 + +/* + * struct hrtimer_cpu_base - the per cpu clock bases + * @lock: lock protecting the base and associated clock bases + * and timers + * @lock_key: the lock_class_key for use with lockdep + * @clock_base: array of clock bases for this cpu + * @curr_timer: the timer which is executing a callback right now + * @expires_next: absolute time of the next event which was scheduled + * via clock_set_next_event() + * @hres_active: State of high resolution mode + * @check_clocks: Indictator, when set evaluate time source and clock + * event devices whether high resolution mode can be + * activated. + * @cb_pending: Expired timers are moved from the rbtree to this + * list in the timer interrupt. The list is processed + * in the softirq. + * @nr_events: Total number of timer interrupt events + */ +struct hrtimer_cpu_base { + spinlock_t lock; + struct lock_class_key lock_key; + struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; +#ifdef CONFIG_HIGH_RES_TIMERS + ktime_t expires_next; + int hres_active; + struct list_head cb_pending; + unsigned long nr_events; +#endif }; +#ifdef CONFIG_HIGH_RES_TIMERS +struct clock_event_device; + +extern void clock_was_set(void); +extern void hrtimer_interrupt(struct clock_event_device *dev); + +/* + * In high resolution mode the time reference must be read accurate + */ +static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) +{ + return timer->base->get_time(); +} + +/* + * The resolution of the clocks. The resolution value is returned in + * the clock_getres() system call to give application programmers an + * idea of the (in)accuracy of timers. Timer values are rounded up to + * this resolution values. + */ +# define KTIME_HIGH_RES (ktime_t) { .tv64 = 1 } +# define KTIME_MONOTONIC_RES KTIME_HIGH_RES + +#else + +# define KTIME_MONOTONIC_RES KTIME_LOW_RES + /* * clock_was_set() is a NOP for non- high-resolution systems. The * time-sorted order guarantees that a timer does not expire early and * is expired in the next softirq when the clock was advanced. */ -#define clock_was_set() do { } while (0) +static inline void clock_was_set(void) { } + +/* + * In non high resolution mode the time reference is taken from + * the base softirq time variable. + */ +static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) +{ + return timer->base->softirq_time; +} + +#endif + +extern ktime_t ktime_get(void); +extern ktime_t ktime_get_real(void); /* Exported timer functions: */ @@ -114,19 +261,33 @@ extern int hrtimer_start(struct hrtimer *timer, ktime_t tim, extern int hrtimer_cancel(struct hrtimer *timer); extern int hrtimer_try_to_cancel(struct hrtimer *timer); -#define hrtimer_restart(timer) hrtimer_start((timer), (timer)->expires, HRTIMER_ABS) +static inline int hrtimer_restart(struct hrtimer *timer) +{ + return hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); +} /* Query timers: */ extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); -#ifdef CONFIG_NO_IDLE_HZ extern ktime_t hrtimer_get_next_event(void); -#endif +/* + * A timer is active, when it is enqueued into the rbtree or the callback + * function is running. + */ static inline int hrtimer_active(const struct hrtimer *timer) { - return rb_parent(&timer->node) != &timer->node; + return timer->state != HRTIMER_STATE_INACTIVE; +} + +/* + * Helper function to check, whether the timer is on one of the queues + */ +static inline int hrtimer_is_queued(struct hrtimer *timer) +{ + return timer->state & + (HRTIMER_STATE_ENQUEUED | HRTIMER_STATE_PENDING); } /* Forward a hrtimer so it expires after now: */ @@ -149,4 +310,53 @@ extern void hrtimer_run_queues(void); /* Bootup initialization: */ extern void __init hrtimers_init(void); +#if BITS_PER_LONG < 64 +extern unsigned long ktime_divns(const ktime_t kt, s64 div); +#else /* BITS_PER_LONG < 64 */ +# define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div)) +#endif + +/* Show pending timers: */ +extern void sysrq_timer_list_show(void); + +/* + * Timer-statistics info: + */ +#ifdef CONFIG_TIMER_STATS + +extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, + void *timerf, char * comm); + +static inline void timer_stats_account_hrtimer(struct hrtimer *timer) +{ + timer_stats_update_stats(timer, timer->start_pid, timer->start_site, + timer->function, timer->start_comm); +} + +extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, + void *addr); + +static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) +{ + __timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0)); +} + +static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer) +{ + timer->start_site = NULL; +} +#else +static inline void timer_stats_account_hrtimer(struct hrtimer *timer) +{ +} + +static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) +{ +} + +static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer) +{ +} +#endif + #endif diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 6e7ec4c..9c21dc7 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -232,7 +232,6 @@ #define I2C_HW_SMBUS_PIIX4 0x040000 #define I2C_HW_SMBUS_ALI15X3 0x040001 #define I2C_HW_SMBUS_VIA2 0x040002 -#define I2C_HW_SMBUS_VOODOO3 0x040003 #define I2C_HW_SMBUS_I801 0x040004 #define I2C_HW_SMBUS_AMD756 0x040005 #define I2C_HW_SMBUS_SIS5595 0x040006 @@ -248,13 +247,11 @@ #define I2C_HW_SMBUS_OV519 0x040010 /* OV519 USB 1.1 webcam IC */ #define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */ #define I2C_HW_SMBUS_CAFE 0x040012 /* Marvell 88ALP01 "CAFE" cam */ +#define I2C_HW_SMBUS_ALI1563 0x040013 /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x050000 -/* --- IPMI pseudo-adapter */ -#define I2C_HW_IPMI 0x0b0000 - /* --- IPMB adapter */ #define I2C_HW_IPMB 0x0c0000 diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 71e50d3..9428092 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -125,7 +125,12 @@ struct i2c_driver { * it must be freed here. */ int (*detach_client)(struct i2c_client *); - + + /* driver model interfaces that don't relate to enumeration */ + void (*shutdown)(struct i2c_client *); + int (*suspend)(struct i2c_client *, pm_message_t mesg); + int (*resume)(struct i2c_client *); + /* a ioctl like command that can be used to perform specific functions * with the device. */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5a8ba0b..e5ea141 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -42,6 +42,8 @@ * IRQF_SHARED - allow sharing the irq among several devices * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur * IRQF_TIMER - Flag to mark this interrupt as timer interrupt + * IRQF_PERCPU - Interrupt is per cpu + * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing */ #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 @@ -49,6 +51,7 @@ #define IRQF_PROBE_SHARED 0x00000100 #define IRQF_TIMER 0x00000200 #define IRQF_PERCPU 0x00000400 +#define IRQF_NOBALANCING 0x00000800 /* * Migration helpers. Scheduled for removal in 1/2007 @@ -239,6 +242,9 @@ enum BLOCK_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, +#ifdef CONFIG_HIGH_RES_TIMERS + HRTIMER_SOFTIRQ, +#endif }; /* softirq mask and active fields moved to irq_cpustat_t in diff --git a/include/linux/irq.h b/include/linux/irq.h index 5504b67..1939d42 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -31,7 +31,7 @@ typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, /* * IRQ line status. * - * Bits 0-16 are reserved for the IRQF_* bits in linux/interrupt.h + * Bits 0-7 are reserved for the IRQF_* bits in linux/interrupt.h * * IRQ types */ @@ -45,28 +45,30 @@ typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, #define IRQ_TYPE_PROBE 0x00000010 /* Probing in progress */ /* Internal flags */ -#define IRQ_INPROGRESS 0x00010000 /* IRQ handler active - do not enter! */ -#define IRQ_DISABLED 0x00020000 /* IRQ disabled - do not enter! */ -#define IRQ_PENDING 0x00040000 /* IRQ pending - replay on enable */ -#define IRQ_REPLAY 0x00080000 /* IRQ has been replayed but not acked yet */ -#define IRQ_AUTODETECT 0x00100000 /* IRQ is being autodetected */ -#define IRQ_WAITING 0x00200000 /* IRQ not yet seen - for autodetection */ -#define IRQ_LEVEL 0x00400000 /* IRQ level triggered */ -#define IRQ_MASKED 0x00800000 /* IRQ masked - shouldn't be seen again */ -#define IRQ_PER_CPU 0x01000000 /* IRQ is per CPU */ +#define IRQ_INPROGRESS 0x00000100 /* IRQ handler active - do not enter! */ +#define IRQ_DISABLED 0x00000200 /* IRQ disabled - do not enter! */ +#define IRQ_PENDING 0x00000400 /* IRQ pending - replay on enable */ +#define IRQ_REPLAY 0x00000800 /* IRQ has been replayed but not acked yet */ +#define IRQ_AUTODETECT 0x00001000 /* IRQ is being autodetected */ +#define IRQ_WAITING 0x00002000 /* IRQ not yet seen - for autodetection */ +#define IRQ_LEVEL 0x00004000 /* IRQ level triggered */ +#define IRQ_MASKED 0x00008000 /* IRQ masked - shouldn't be seen again */ +#define IRQ_PER_CPU 0x00010000 /* IRQ is per CPU */ +#define IRQ_NOPROBE 0x00020000 /* IRQ is not valid for probing */ +#define IRQ_NOREQUEST 0x00040000 /* IRQ cannot be requested */ +#define IRQ_NOAUTOEN 0x00080000 /* IRQ will not be enabled on request irq */ +#define IRQ_WAKEUP 0x00100000 /* IRQ triggers system wakeup */ +#define IRQ_MOVE_PENDING 0x00200000 /* need to re-target IRQ destination */ +#define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */ + #ifdef CONFIG_IRQ_PER_CPU # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) +# define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) #else # define CHECK_IRQ_PER_CPU(var) 0 +# define IRQ_NO_BALANCING_MASK IRQ_NO_BALANCING #endif -#define IRQ_NOPROBE 0x02000000 /* IRQ is not valid for probing */ -#define IRQ_NOREQUEST 0x04000000 /* IRQ cannot be requested */ -#define IRQ_NOAUTOEN 0x08000000 /* IRQ will not be enabled on request irq */ -#define IRQ_DELAYED_DISABLE 0x10000000 /* IRQ disable (masking) happens delayed. */ -#define IRQ_WAKEUP 0x20000000 /* IRQ triggers system wakeup */ -#define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */ - struct proc_dir_entry; struct msi_desc; @@ -127,6 +129,7 @@ struct irq_chip { * * @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()] * @chip: low level interrupt hardware access + * @msi_desc: MSI descriptor * @handler_data: per-IRQ data for the irq_chip methods * @chip_data: platform-specific per-chip private data for the chip * methods, to allow shared chip implementations @@ -235,11 +238,21 @@ static inline void set_pending_irq(unsigned int irq, cpumask_t mask) #endif /* CONFIG_GENERIC_PENDING_IRQ */ +extern int irq_set_affinity(unsigned int irq, cpumask_t cpumask); +extern int irq_can_set_affinity(unsigned int irq); + #else /* CONFIG_SMP */ #define move_native_irq(x) #define move_masked_irq(x) +static inline int irq_set_affinity(unsigned int irq, cpumask_t cpumask) +{ + return -EINVAL; +} + +static inline int irq_can_set_affinity(unsigned int irq) { return 0; } + #endif /* CONFIG_SMP */ #ifdef CONFIG_IRQBALANCE @@ -261,6 +274,11 @@ static inline int select_smp_affinity(unsigned int irq) extern int no_irq_affinity; +static inline int irq_balancing_disabled(unsigned int irq) +{ + return irq_desc[irq].status & IRQ_NO_BALANCING_MASK; +} + /* Handle irq action chains: */ extern int handle_IRQ_event(unsigned int irq, struct irqaction *action); diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 0ec6e28..c080f61 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -142,13 +142,13 @@ static inline u64 get_jiffies_64(void) * * And some not so obvious. * - * Note that we don't want to return MAX_LONG, because + * Note that we don't want to return LONG_MAX, because * for various timeout reasons we often end up having * to wait "jiffies+1" in order to guarantee that we wait * at _least_ "jiffies" - so "jiffies+1" had better still * be positive. */ -#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1) +#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1) /* * We want to do realistic conversions of time so we need to use the same @@ -259,207 +259,23 @@ static inline u64 get_jiffies_64(void) #endif /* - * Convert jiffies to milliseconds and back. - * - * Avoid unnecessary multiplications/divisions in the - * two most common HZ cases: - */ -static inline unsigned int jiffies_to_msecs(const unsigned long j) -{ -#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) - return (MSEC_PER_SEC / HZ) * j; -#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) - return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); -#else - return (j * MSEC_PER_SEC) / HZ; -#endif -} - -static inline unsigned int jiffies_to_usecs(const unsigned long j) -{ -#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) - return (USEC_PER_SEC / HZ) * j; -#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) - return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC); -#else - return (j * USEC_PER_SEC) / HZ; -#endif -} - -static inline unsigned long msecs_to_jiffies(const unsigned int m) -{ - if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) - return MAX_JIFFY_OFFSET; -#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) - return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); -#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) - return m * (HZ / MSEC_PER_SEC); -#else - return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC; -#endif -} - -static inline unsigned long usecs_to_jiffies(const unsigned int u) -{ - if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) - return MAX_JIFFY_OFFSET; -#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) - return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ); -#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) - return u * (HZ / USEC_PER_SEC); -#else - return (u * HZ + USEC_PER_SEC - 1) / USEC_PER_SEC; -#endif -} - -/* - * The TICK_NSEC - 1 rounds up the value to the next resolution. Note - * that a remainder subtract here would not do the right thing as the - * resolution values don't fall on second boundries. I.e. the line: - * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. - * - * Rather, we just shift the bits off the right. - * - * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec - * value to a scaled second value. - */ -static __inline__ unsigned long -timespec_to_jiffies(const struct timespec *value) -{ - unsigned long sec = value->tv_sec; - long nsec = value->tv_nsec + TICK_NSEC - 1; - - if (sec >= MAX_SEC_IN_JIFFIES){ - sec = MAX_SEC_IN_JIFFIES; - nsec = 0; - } - return (((u64)sec * SEC_CONVERSION) + - (((u64)nsec * NSEC_CONVERSION) >> - (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; - -} - -static __inline__ void -jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) -{ - /* - * Convert jiffies to nanoseconds and separate with - * one divide. - */ - u64 nsec = (u64)jiffies * TICK_NSEC; - value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec); -} - -/* Same for "timeval" - * - * Well, almost. The problem here is that the real system resolution is - * in nanoseconds and the value being converted is in micro seconds. - * Also for some machines (those that use HZ = 1024, in-particular), - * there is a LARGE error in the tick size in microseconds. - - * The solution we use is to do the rounding AFTER we convert the - * microsecond part. Thus the USEC_ROUND, the bits to be shifted off. - * Instruction wise, this should cost only an additional add with carry - * instruction above the way it was done above. - */ -static __inline__ unsigned long -timeval_to_jiffies(const struct timeval *value) -{ - unsigned long sec = value->tv_sec; - long usec = value->tv_usec; - - if (sec >= MAX_SEC_IN_JIFFIES){ - sec = MAX_SEC_IN_JIFFIES; - usec = 0; - } - return (((u64)sec * SEC_CONVERSION) + - (((u64)usec * USEC_CONVERSION + USEC_ROUND) >> - (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; -} - -static __inline__ void -jiffies_to_timeval(const unsigned long jiffies, struct timeval *value) -{ - /* - * Convert jiffies to nanoseconds and separate with - * one divide. - */ - u64 nsec = (u64)jiffies * TICK_NSEC; - long tv_usec; - - value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tv_usec); - tv_usec /= NSEC_PER_USEC; - value->tv_usec = tv_usec; -} - -/* - * Convert jiffies/jiffies_64 to clock_t and back. + * Convert various time units to each other: */ -static inline clock_t jiffies_to_clock_t(long x) -{ -#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 - return x / (HZ / USER_HZ); -#else - u64 tmp = (u64)x * TICK_NSEC; - do_div(tmp, (NSEC_PER_SEC / USER_HZ)); - return (long)tmp; -#endif -} - -static inline unsigned long clock_t_to_jiffies(unsigned long x) -{ -#if (HZ % USER_HZ)==0 - if (x >= ~0UL / (HZ / USER_HZ)) - return ~0UL; - return x * (HZ / USER_HZ); -#else - u64 jif; - - /* Don't worry about loss of precision here .. */ - if (x >= ~0UL / HZ * USER_HZ) - return ~0UL; - - /* .. but do try to contain it here */ - jif = x * (u64) HZ; - do_div(jif, USER_HZ); - return jif; -#endif -} - -static inline u64 jiffies_64_to_clock_t(u64 x) -{ -#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 - do_div(x, HZ / USER_HZ); -#else - /* - * There are better ways that don't overflow early, - * but even this doesn't overflow in hundreds of years - * in 64 bits, so.. - */ - x *= TICK_NSEC; - do_div(x, (NSEC_PER_SEC / USER_HZ)); -#endif - return x; -} - -static inline u64 nsec_to_clock_t(u64 x) -{ -#if (NSEC_PER_SEC % USER_HZ) == 0 - do_div(x, (NSEC_PER_SEC / USER_HZ)); -#elif (USER_HZ % 512) == 0 - x *= USER_HZ/512; - do_div(x, (NSEC_PER_SEC / 512)); -#else - /* - * max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024, - * overflow after 64.99 years. - * exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ... - */ - x *= 9; - do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (USER_HZ/2)) - / USER_HZ)); -#endif - return x; -} +extern unsigned int jiffies_to_msecs(const unsigned long j); +extern unsigned int jiffies_to_usecs(const unsigned long j); +extern unsigned long msecs_to_jiffies(const unsigned int m); +extern unsigned long usecs_to_jiffies(const unsigned int u); +extern unsigned long timespec_to_jiffies(const struct timespec *value); +extern void jiffies_to_timespec(const unsigned long jiffies, + struct timespec *value); +extern unsigned long timeval_to_jiffies(const struct timeval *value); +extern void jiffies_to_timeval(const unsigned long jiffies, + struct timeval *value); +extern clock_t jiffies_to_clock_t(long x); +extern unsigned long clock_t_to_jiffies(unsigned long x); +extern u64 jiffies_64_to_clock_t(u64 x); +extern u64 nsec_to_clock_t(u64 x); + +#define TIMESTAMP_SIZE 30 #endif diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 7444a63..c68c7ac 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -261,8 +261,7 @@ static inline s64 ktime_to_ns(const ktime_t kt) * idea of the (in)accuracy of timers. Timer values are rounded up to * this resolution values. */ -#define KTIME_REALTIME_RES (ktime_t){ .tv64 = TICK_NSEC } -#define KTIME_MONOTONIC_RES (ktime_t){ .tv64 = TICK_NSEC } +#define KTIME_LOW_RES (ktime_t){ .tv64 = TICK_NSEC } /* Get the monotonic time in timespec format: */ extern void ktime_get_ts(struct timespec *ts); diff --git a/include/linux/libata.h b/include/linux/libata.h index 596e0c1..b870b20 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -172,6 +172,7 @@ enum { ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */ ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ + ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index db05182..1be5be8 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -105,12 +105,11 @@ struct nfs4_ace { uint32_t access_mask; int whotype; uid_t who; - struct list_head l_ace; }; struct nfs4_acl { uint32_t naces; - struct list_head ace_head; + struct nfs4_ace aces[0]; }; typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; diff --git a/include/linux/nfs4_acl.h b/include/linux/nfs4_acl.h index 22aff4d..409b6e0 100644 --- a/include/linux/nfs4_acl.h +++ b/include/linux/nfs4_acl.h @@ -39,9 +39,12 @@ #include <linux/posix_acl.h> -struct nfs4_acl *nfs4_acl_new(void); -void nfs4_acl_free(struct nfs4_acl *); -int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); +/* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to + * fit in a page: */ +#define NFS4_ACL_MAX 170 + +struct nfs4_acl *nfs4_acl_new(int); +void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); int nfs4_acl_get_whotype(char *, u32); int nfs4_acl_write_who(int who, char *p); int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group, diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index ed0f2ea..47aaa2c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -11,14 +11,6 @@ #include <linux/magic.h> -/* - * Enable debugging support for nfs client. - * Requires RPC_DEBUG. - */ -#ifdef RPC_DEBUG -# define NFS_DEBUG -#endif - /* Default timeout values */ #define NFS_MAX_UDP_TIMEOUT (60*HZ) #define NFS_MAX_TCP_TIMEOUT (600*HZ) @@ -567,6 +559,15 @@ extern void * nfs_root_data(void); #define NFSDBG_ALL 0xFFFF #ifdef __KERNEL__ + +/* + * Enable debugging support for nfs client. + * Requires RPC_DEBUG. + */ +#ifdef RPC_DEBUG +# define NFS_DEBUG +#endif + # undef ifdebug # ifdef NFS_DEBUG # define ifdebug(fac) if (unlikely(nfs_debug & NFSDBG_##fac)) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 30d7116..10c26ed 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -784,7 +784,6 @@ struct nfs_rpc_ops { int (*access) (struct inode *, struct nfs_access_entry *); int (*readlink)(struct inode *, struct page *, unsigned int, unsigned int); - int (*read) (struct nfs_read_data *); int (*create) (struct inode *, struct dentry *, struct iattr *, int, struct nameidata *); int (*remove) (struct inode *, struct qstr *); diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 045e38c..9f62d61 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -74,19 +74,20 @@ struct svc_export { uid_t ex_anon_uid; gid_t ex_anon_gid; int ex_fsid; + unsigned char * ex_uuid; /* 16 byte fsid */ struct nfsd4_fs_locations ex_fslocs; }; /* an "export key" (expkey) maps a filehandlefragement to an - * svc_export for a given client. There can be two per export, one - * for type 0 (dev/ino), one for type 1 (fsid) + * svc_export for a given client. There can be several per export, + * for the different fsid types. */ struct svc_expkey { struct cache_head h; struct auth_domain * ek_client; int ek_fsidtype; - u32 ek_fsid[3]; + u32 ek_fsid[6]; struct vfsmount * ek_mnt; struct dentry * ek_dentry; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 4b7c4b5..72feac5 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -254,18 +254,6 @@ void nfsd_lockd_shutdown(void); */ extern struct timeval nfssvc_boot; -static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh) -{ - if (fh->fh_export->ex_flags & NFSEXP_FSID) { - struct vfsmount *mnt = fh->fh_export->ex_mnt; - if (!old_valid_dev(mnt->mnt_sb->s_dev) || - (reffh->fh_version == 1 && reffh->fh_fsid_type == 1)) - return 1; - } - return 0; -} - - #ifdef CONFIG_NFSD_V4 /* before processing a COMPOUND operation, we have to check that there diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index d9c6c38..11e568e 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -165,38 +165,91 @@ typedef struct svc_fh { } svc_fh; -static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino) -{ - fsidv[0] = htonl((MAJOR(dev)<<16) | - MINOR(dev)); - fsidv[1] = ino_t_to_u32(ino); -} +enum nfsd_fsid { + FSID_DEV = 0, + FSID_NUM, + FSID_MAJOR_MINOR, + FSID_ENCODE_DEV, + FSID_UUID4_INUM, + FSID_UUID8, + FSID_UUID16, + FSID_UUID16_INUM, +}; -static inline void mk_fsid_v1(u32 *fsidv, u32 fsid) -{ - fsidv[0] = fsid; -} +enum fsid_source { + FSIDSOURCE_DEV, + FSIDSOURCE_FSID, + FSIDSOURCE_UUID, +}; +extern enum fsid_source fsid_source(struct svc_fh *fhp); -static inline void mk_fsid_v2(u32 *fsidv, dev_t dev, ino_t ino) -{ - fsidv[0] = htonl(MAJOR(dev)); - fsidv[1] = htonl(MINOR(dev)); - fsidv[2] = ino_t_to_u32(ino); -} -static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino) +/* This might look a little large to "inline" but in all calls except + * one, 'vers' is constant so moste of the function disappears. + */ +static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino, + u32 fsid, unsigned char *uuid) { - fsidv[0] = new_encode_dev(dev); - fsidv[1] = ino_t_to_u32(ino); + u32 *up; + switch(vers) { + case FSID_DEV: + fsidv[0] = htonl((MAJOR(dev)<<16) | + MINOR(dev)); + fsidv[1] = ino_t_to_u32(ino); + break; + case FSID_NUM: + fsidv[0] = fsid; + break; + case FSID_MAJOR_MINOR: + fsidv[0] = htonl(MAJOR(dev)); + fsidv[1] = htonl(MINOR(dev)); + fsidv[2] = ino_t_to_u32(ino); + break; + + case FSID_ENCODE_DEV: + fsidv[0] = new_encode_dev(dev); + fsidv[1] = ino_t_to_u32(ino); + break; + + case FSID_UUID4_INUM: + /* 4 byte fsid and inode number */ + up = (u32*)uuid; + fsidv[0] = ino_t_to_u32(ino); + fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3]; + break; + + case FSID_UUID8: + /* 8 byte fsid */ + up = (u32*)uuid; + fsidv[0] = up[0] ^ up[2]; + fsidv[1] = up[1] ^ up[3]; + break; + + case FSID_UUID16: + /* 16 byte fsid - NFSv3+ only */ + memcpy(fsidv, uuid, 16); + break; + + case FSID_UUID16_INUM: + /* 8 byte inode and 16 byte fsid */ + *(u64*)fsidv = (u64)ino; + memcpy(fsidv+2, uuid, 16); + break; + default: BUG(); + } } static inline int key_len(int type) { switch(type) { - case 0: return 8; - case 1: return 4; - case 2: return 12; - case 3: return 8; + case FSID_DEV: return 8; + case FSID_NUM: return 4; + case FSID_MAJOR_MINOR: return 12; + case FSID_ENCODE_DEV: return 8; + case FSID_UUID4_INUM: return 8; + case FSID_UUID8: return 8; + case FSID_UUID16: return 16; + case FSID_UUID16_INUM: return 24; default: return 0; } } diff --git a/include/linux/nmi.h b/include/linux/nmi.h index acb4ed1..29af2d5 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -17,8 +17,15 @@ #ifdef ARCH_HAS_NMI_WATCHDOG #include <asm/nmi.h> extern void touch_nmi_watchdog(void); +extern void acpi_nmi_disable(void); +extern void acpi_nmi_enable(void); #else -# define touch_nmi_watchdog() touch_softlockup_watchdog() +static inline void touch_nmi_watchdog(void) +{ + touch_softlockup_watchdog(); +} +static inline void acpi_nmi_disable(void) { } +static inline void acpi_nmi_enable(void) { } #endif #ifndef trigger_all_cpu_backtrace diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 8fb9c3e..182a96f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -369,6 +369,7 @@ #define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a #define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380 #define PCI_DEVICE_ID_ATI_IXP600_SRAID 0x4381 +#define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385 #define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c #define PCI_VENDOR_ID_VLSI 0x1004 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 2e13247..be4652a 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -113,8 +113,6 @@ extern struct vfsmount *proc_mnt; extern int proc_fill_super(struct super_block *,void *,int); extern struct inode *proc_get_inode(struct super_block *, unsigned int, struct proc_dir_entry *); -extern int proc_match(int, const char *,struct proc_dir_entry *); - /* * These are generic /proc routines that use the internal * "struct proc_dir_entry" tree to traverse the filesystem. diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index cf23813..586aaba 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -122,7 +122,7 @@ /*Digi jsm */ #define PORT_JSM 69 -#define PORT_IP3106 70 +#define PORT_PNX8XXX 70 /* Hilscher netx */ #define PORT_NETX 71 diff --git a/include/linux/serial_ip3106.h b/include/linux/serial_ip3106.h deleted file mode 100644 index f500ac6..0000000 --- a/include/linux/serial_ip3106.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Embedded Alley Solutions, source@embeddedalley.com. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_SERIAL_IP3106_H -#define _LINUX_SERIAL_IP3106_H - -#include <linux/serial_core.h> -#include <linux/device.h> - -#define IP3106_NR_PORTS 2 - -struct ip3106_port { - struct uart_port port; - struct timer_list timer; - unsigned int old_status; -}; - -/* register offsets */ -#define IP3106_LCR 0 -#define IP3106_MCR 0x004 -#define IP3106_BAUD 0x008 -#define IP3106_CFG 0x00c -#define IP3106_FIFO 0x028 -#define IP3106_ISTAT 0xfe0 -#define IP3106_IEN 0xfe4 -#define IP3106_ICLR 0xfe8 -#define IP3106_ISET 0xfec -#define IP3106_PD 0xff4 -#define IP3106_MID 0xffc - -#define IP3106_UART_LCR_TXBREAK (1<<30) -#define IP3106_UART_LCR_PAREVN 0x10000000 -#define IP3106_UART_LCR_PAREN 0x08000000 -#define IP3106_UART_LCR_2STOPB 0x04000000 -#define IP3106_UART_LCR_8BIT 0x01000000 -#define IP3106_UART_LCR_TX_RST 0x00040000 -#define IP3106_UART_LCR_RX_RST 0x00020000 -#define IP3106_UART_LCR_RX_NEXT 0x00010000 - -#define IP3106_UART_MCR_SCR 0xFF000000 -#define IP3106_UART_MCR_DCD 0x00800000 -#define IP3106_UART_MCR_CTS 0x00100000 -#define IP3106_UART_MCR_LOOP 0x00000010 -#define IP3106_UART_MCR_RTS 0x00000002 -#define IP3106_UART_MCR_DTR 0x00000001 - -#define IP3106_UART_INT_TX 0x00000080 -#define IP3106_UART_INT_EMPTY 0x00000040 -#define IP3106_UART_INT_RCVTO 0x00000020 -#define IP3106_UART_INT_RX 0x00000010 -#define IP3106_UART_INT_RXOVRN 0x00000008 -#define IP3106_UART_INT_FRERR 0x00000004 -#define IP3106_UART_INT_BREAK 0x00000002 -#define IP3106_UART_INT_PARITY 0x00000001 -#define IP3106_UART_INT_ALLRX 0x0000003F -#define IP3106_UART_INT_ALLTX 0x000000C0 - -#define IP3106_UART_FIFO_TXFIFO 0x001F0000 -#define IP3106_UART_FIFO_TXFIFO_STA (0x1f<<16) -#define IP3106_UART_FIFO_RXBRK 0x00008000 -#define IP3106_UART_FIFO_RXFE 0x00004000 -#define IP3106_UART_FIFO_RXPAR 0x00002000 -#define IP3106_UART_FIFO_RXFIFO 0x00001F00 -#define IP3106_UART_FIFO_RBRTHR 0x000000FF - -#endif diff --git a/include/linux/serial_pnx8xxx.h b/include/linux/serial_pnx8xxx.h new file mode 100644 index 0000000..de6c19c --- /dev/null +++ b/include/linux/serial_pnx8xxx.h @@ -0,0 +1,81 @@ +/* + * Embedded Alley Solutions, source@embeddedalley.com. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_SERIAL_PNX8XXX_H +#define _LINUX_SERIAL_PNX8XXX_H + +#include <linux/serial_core.h> +#include <linux/device.h> + +#define PNX8XXX_NR_PORTS 2 + +struct pnx8xxx_port { + struct uart_port port; + struct timer_list timer; + unsigned int old_status; +}; + +/* register offsets */ +#define PNX8XXX_LCR 0 +#define PNX8XXX_MCR 0x004 +#define PNX8XXX_BAUD 0x008 +#define PNX8XXX_CFG 0x00c +#define PNX8XXX_FIFO 0x028 +#define PNX8XXX_ISTAT 0xfe0 +#define PNX8XXX_IEN 0xfe4 +#define PNX8XXX_ICLR 0xfe8 +#define PNX8XXX_ISET 0xfec +#define PNX8XXX_PD 0xff4 +#define PNX8XXX_MID 0xffc + +#define PNX8XXX_UART_LCR_TXBREAK (1<<30) +#define PNX8XXX_UART_LCR_PAREVN 0x10000000 +#define PNX8XXX_UART_LCR_PAREN 0x08000000 +#define PNX8XXX_UART_LCR_2STOPB 0x04000000 +#define PNX8XXX_UART_LCR_8BIT 0x01000000 +#define PNX8XXX_UART_LCR_TX_RST 0x00040000 +#define PNX8XXX_UART_LCR_RX_RST 0x00020000 +#define PNX8XXX_UART_LCR_RX_NEXT 0x00010000 + +#define PNX8XXX_UART_MCR_SCR 0xFF000000 +#define PNX8XXX_UART_MCR_DCD 0x00800000 +#define PNX8XXX_UART_MCR_CTS 0x00100000 +#define PNX8XXX_UART_MCR_LOOP 0x00000010 +#define PNX8XXX_UART_MCR_RTS 0x00000002 +#define PNX8XXX_UART_MCR_DTR 0x00000001 + +#define PNX8XXX_UART_INT_TX 0x00000080 +#define PNX8XXX_UART_INT_EMPTY 0x00000040 +#define PNX8XXX_UART_INT_RCVTO 0x00000020 +#define PNX8XXX_UART_INT_RX 0x00000010 +#define PNX8XXX_UART_INT_RXOVRN 0x00000008 +#define PNX8XXX_UART_INT_FRERR 0x00000004 +#define PNX8XXX_UART_INT_BREAK 0x00000002 +#define PNX8XXX_UART_INT_PARITY 0x00000001 +#define PNX8XXX_UART_INT_ALLRX 0x0000003F +#define PNX8XXX_UART_INT_ALLTX 0x000000C0 + +#define PNX8XXX_UART_FIFO_TXFIFO 0x001F0000 +#define PNX8XXX_UART_FIFO_TXFIFO_STA (0x1f<<16) +#define PNX8XXX_UART_FIFO_RXBRK 0x00008000 +#define PNX8XXX_UART_FIFO_RXFE 0x00004000 +#define PNX8XXX_UART_FIFO_RXPAR 0x00002000 +#define PNX8XXX_UART_FIFO_RXFIFO 0x00001F00 +#define PNX8XXX_UART_FIFO_RBRTHR 0x000000FF + +#endif diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index a1be89d..c7a78eef2 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -40,6 +40,7 @@ struct rpc_clnt { unsigned int cl_softrtry : 1,/* soft timeouts */ cl_intr : 1,/* interruptible */ + cl_discrtry : 1,/* disconnect before retry */ cl_autobind : 1,/* use getport() */ cl_oneshot : 1,/* dispose after use */ cl_dead : 1;/* abandoned */ @@ -111,6 +112,7 @@ struct rpc_create_args { #define RPC_CLNT_CREATE_ONESHOT (1UL << 3) #define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4) #define RPC_CLNT_CREATE_NOPING (1UL << 5) +#define RPC_CLNT_CREATE_DISCRTRY (1UL << 6) struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index 60fce3c..b7c7307 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -78,7 +78,6 @@ void rpc_unregister_sysctl(void); * module currently registers its sysctl table dynamically, the sysctl path * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>. */ -#define CTL_SUNRPC 7249 /* arbitrary and hopefully unused */ enum { CTL_RPCDEBUG = 1, diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 8b6ce60..de9fc576 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -253,7 +253,7 @@ void rpc_put_task(struct rpc_task *); void rpc_exit_task(struct rpc_task *); void rpc_release_calldata(const struct rpc_call_ops *, void *); void rpc_killall_tasks(struct rpc_clnt *); -int rpc_execute(struct rpc_task *); +void rpc_execute(struct rpc_task *); void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 665412c..2c5fb38 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -53,7 +53,6 @@ struct __sysctl_args { /* For internal pattern-matching use only: */ #ifdef __KERNEL__ -#define CTL_ANY -1 /* Matches any name */ #define CTL_NONE 0 #define CTL_UNNUMBERED CTL_NONE /* sysctl without a binary number */ #endif @@ -69,7 +68,13 @@ enum CTL_DEV=7, /* Devices */ CTL_BUS=8, /* Busses */ CTL_ABI=9, /* Binary emulation */ - CTL_CPU=10 /* CPU stuff (speed scaling, etc) */ + CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ + CTL_ARLAN=254, /* arlan wireless driver */ + CTL_APPLDATA=2120, /* s390 appldata */ + CTL_S390DBF=5677, /* s390 debug */ + CTL_SUNRPC=7249, /* sunrpc debug */ + CTL_PM=9899, /* frv power management */ + CTL_FRV=9898, /* frv specific sysctls */ }; /* CTL_BUS names: */ @@ -202,6 +207,11 @@ enum VM_PANIC_ON_OOM=33, /* panic at out-of-memory */ VM_VDSO_ENABLED=34, /* map VDSO into new processes? */ VM_MIN_SLAB=35, /* Percent pages ignored by zone reclaim */ + + /* s390 vm cmm sysctls */ + VM_CMM_PAGES=1111, + VM_CMM_TIMED_PAGES=1112, + VM_CMM_TIMEOUT=1113, }; @@ -803,6 +813,7 @@ enum FS_AIO_NR=18, /* current system-wide number of aio requests */ FS_AIO_MAX_NR=19, /* system-wide maximum number of aio requests */ FS_INOTIFY=20, /* inotify submenu */ + FS_OCFS2=988, /* ocfs2 */ }; /* /proc/sys/fs/quota/ */ @@ -913,7 +924,11 @@ enum #ifdef __KERNEL__ #include <linux/list.h> -extern void sysctl_init(void); +/* For the /proc/sys support */ +struct ctl_table; +extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev); +extern void sysctl_head_finish(struct ctl_table_header *prev); +extern int sysctl_perm(struct ctl_table *table, int op); typedef struct ctl_table ctl_table; @@ -1007,9 +1022,9 @@ struct ctl_table int maxlen; mode_t mode; ctl_table *child; + ctl_table *parent; /* Automatically set */ proc_handler *proc_handler; /* Callback for text formatting */ ctl_handler *strategy; /* Callback function for all r/w */ - struct proc_dir_entry *de; /* /proc control block */ void *extra1; void *extra2; }; @@ -1024,8 +1039,8 @@ struct ctl_table_header struct completion *unregistering; }; -struct ctl_table_header * register_sysctl_table(ctl_table * table, - int insert_at_head); +struct ctl_table_header * register_sysctl_table(ctl_table * table); + void unregister_sysctl_table(struct ctl_table_header * table); #else /* __KERNEL__ */ diff --git a/include/linux/tick.h b/include/linux/tick.h new file mode 100644 index 0000000..9a7252e --- /dev/null +++ b/include/linux/tick.h @@ -0,0 +1,109 @@ +/* linux/include/linux/tick.h + * + * This file contains the structure definitions for tick related functions + * + */ +#ifndef _LINUX_TICK_H +#define _LINUX_TICK_H + +#include <linux/clockchips.h> + +#ifdef CONFIG_GENERIC_CLOCKEVENTS + +enum tick_device_mode { + TICKDEV_MODE_PERIODIC, + TICKDEV_MODE_ONESHOT, +}; + +struct tick_device { + struct clock_event_device *evtdev; + enum tick_device_mode mode; +}; + +enum tick_nohz_mode { + NOHZ_MODE_INACTIVE, + NOHZ_MODE_LOWRES, + NOHZ_MODE_HIGHRES, +}; + +/** + * struct tick_sched - sched tick emulation and no idle tick control/stats + * @sched_timer: hrtimer to schedule the periodic tick in high + * resolution mode + * @idle_tick: Store the last idle tick expiry time when the tick + * timer is modified for idle sleeps. This is necessary + * to resume the tick timer operation in the timeline + * when the CPU returns from idle + * @tick_stopped: Indicator that the idle tick has been stopped + * @idle_jiffies: jiffies at the entry to idle for idle time accounting + * @idle_calls: Total number of idle calls + * @idle_sleeps: Number of idle calls, where the sched tick was stopped + * @idle_entrytime: Time when the idle call was entered + * @idle_sleeptime: Sum of the time slept in idle with sched tick stopped + */ +struct tick_sched { + struct hrtimer sched_timer; + unsigned long check_clocks; + enum tick_nohz_mode nohz_mode; + ktime_t idle_tick; + int tick_stopped; + unsigned long idle_jiffies; + unsigned long idle_calls; + unsigned long idle_sleeps; + ktime_t idle_entrytime; + ktime_t idle_sleeptime; + unsigned long last_jiffies; + unsigned long next_jiffies; + ktime_t idle_expires; +}; + +extern void __init tick_init(void); +extern int tick_is_oneshot_available(void); +extern struct tick_device *tick_get_device(int cpu); + +# ifdef CONFIG_HIGH_RES_TIMERS +extern int tick_init_highres(void); +extern int tick_program_event(ktime_t expires, int force); +extern void tick_setup_sched_timer(void); +extern void tick_cancel_sched_timer(int cpu); +# else +static inline void tick_cancel_sched_timer(int cpu) { } +# endif /* HIGHRES */ + +# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +extern struct tick_device *tick_get_broadcast_device(void); +extern cpumask_t *tick_get_broadcast_mask(void); + +# ifdef CONFIG_TICK_ONESHOT +extern cpumask_t *tick_get_broadcast_oneshot_mask(void); +# endif + +# endif /* BROADCAST */ + +# ifdef CONFIG_TICK_ONESHOT +extern void tick_clock_notify(void); +extern int tick_check_oneshot_change(int allow_nohz); +extern struct tick_sched *tick_get_tick_sched(int cpu); +# else +static inline void tick_clock_notify(void) { } +static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } +# endif + +#else /* CONFIG_GENERIC_CLOCKEVENTS */ +static inline void tick_init(void) { } +static inline void tick_cancel_sched_timer(int cpu) { } +static inline void tick_clock_notify(void) { } +static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } +#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ + +# ifdef CONFIG_NO_HZ +extern void tick_nohz_stop_sched_tick(void); +extern void tick_nohz_restart_sched_tick(void); +extern void tick_nohz_update_jiffies(void); +# else +static inline void tick_nohz_stop_sched_tick(void) { } +static inline void tick_nohz_restart_sched_tick(void) { } +static inline void tick_nohz_update_jiffies(void) { } +# endif /* !NO_HZ */ + +#endif diff --git a/include/linux/time.h b/include/linux/time.h index 55cee17..8ea8dea 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -90,8 +90,9 @@ static inline struct timespec timespec_sub(struct timespec lhs, extern struct timespec xtime; extern struct timespec wall_to_monotonic; -extern seqlock_t xtime_lock; +extern seqlock_t xtime_lock __attribute__((weak)); +extern unsigned long read_persistent_clock(void); void timekeeping_init(void); static inline unsigned long get_seconds(void) diff --git a/include/linux/timer.h b/include/linux/timer.h index fb5edaa..719113b 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -2,6 +2,7 @@ #define _LINUX_TIMER_H #include <linux/list.h> +#include <linux/ktime.h> #include <linux/spinlock.h> #include <linux/stddef.h> @@ -15,6 +16,11 @@ struct timer_list { unsigned long data; struct tvec_t_base_s *base; +#ifdef CONFIG_TIMER_STATS + void *start_site; + char start_comm[16]; + int start_pid; +#endif }; extern struct tvec_t_base_s boot_tvec_bases; @@ -61,7 +67,65 @@ extern int del_timer(struct timer_list * timer); extern int __mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer(struct timer_list *timer, unsigned long expires); +/* + * Return when the next timer-wheel timeout occurs (in absolute jiffies), + * locks the timer base: + */ extern unsigned long next_timer_interrupt(void); +/* + * Return when the next timer-wheel timeout occurs (in absolute jiffies), + * locks the timer base and does the comparison against the given + * jiffie. + */ +extern unsigned long get_next_timer_interrupt(unsigned long now); + +/* + * Timer-statistics info: + */ +#ifdef CONFIG_TIMER_STATS + +extern void init_timer_stats(void); + +extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, + void *timerf, char * comm); + +static inline void timer_stats_account_timer(struct timer_list *timer) +{ + timer_stats_update_stats(timer, timer->start_pid, timer->start_site, + timer->function, timer->start_comm); +} + +extern void __timer_stats_timer_set_start_info(struct timer_list *timer, + void *addr); + +static inline void timer_stats_timer_set_start_info(struct timer_list *timer) +{ + __timer_stats_timer_set_start_info(timer, __builtin_return_address(0)); +} + +static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) +{ + timer->start_site = NULL; +} +#else +static inline void init_timer_stats(void) +{ +} + +static inline void timer_stats_account_timer(struct timer_list *timer) +{ +} + +static inline void timer_stats_timer_set_start_info(struct timer_list *timer) +{ +} + +static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) +{ +} +#endif + +extern void delayed_work_timer_fn(unsigned long __data); /** * add_timer - start a timer @@ -96,7 +160,7 @@ static inline void add_timer(struct timer_list *timer) extern void init_timers(void); extern void run_local_timers(void); struct hrtimer; -extern int it_real_fn(struct hrtimer *); +extern enum hrtimer_restart it_real_fn(struct hrtimer *); unsigned long __round_jiffies(unsigned long j, int cpu); unsigned long __round_jiffies_relative(unsigned long j, int cpu); diff --git a/include/linux/timex.h b/include/linux/timex.h index 9a24e50..da929db 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -286,6 +286,13 @@ static inline void time_interpolator_update(long delta_nsec) #define TICK_LENGTH_SHIFT 32 +#ifdef CONFIG_NO_HZ +#define NTP_INTERVAL_FREQ (2) +#else +#define NTP_INTERVAL_FREQ (HZ) +#endif +#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ) + /* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */ extern u64 current_tick_length(void); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 16924cb..92a1fc4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -946,14 +946,14 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm4_rcv(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); -extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); -extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); +extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); +extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi); extern int xfrm6_rcv(struct sk_buff **pskb); extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto); -extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); -extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); +extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); +extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index eb7ce96..23e45a4 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -628,7 +628,7 @@ #define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */ #define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */ -#define A_TBLSZ ` 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */ +#define A_TBLSZ 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */ #define TCBS 0x44 /* Tank cache buffer size register */ #define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ diff --git a/include/sound/version.h b/include/sound/version.h index c39b380..a9ba7ee 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by alsa/ksync script. */ #define CONFIG_SND_VERSION "1.0.14rc2" -#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)" +#define CONFIG_SND_DATE " (Wed Feb 14 07:42:13 2007 UTC)" diff --git a/init/Kconfig b/init/Kconfig index ad33c97..f977086 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -125,6 +125,12 @@ config IPC_NS environments, to use ipc namespaces to provide different ipc objects for different servers. If unsure, say N. +config SYSVIPC_SYSCTL + bool + depends on SYSVIPC + depends on SYSCTL + default y + config POSIX_MQUEUE bool "POSIX Message Queues" depends on NET && EXPERIMENTAL diff --git a/init/calibrate.c b/init/calibrate.c index d206c75..40ff3b4 100644 --- a/init/calibrate.c +++ b/init/calibrate.c @@ -4,7 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include <linux/sched.h> +#include <linux/jiffies.h> #include <linux/delay.h> #include <linux/init.h> diff --git a/init/main.c b/init/main.c index 4e9e92b..953500b 100644 --- a/init/main.c +++ b/init/main.c @@ -40,6 +40,7 @@ #include <linux/cpu.h> #include <linux/cpuset.h> #include <linux/efi.h> +#include <linux/tick.h> #include <linux/taskstats_kern.h> #include <linux/delayacct.h> #include <linux/unistd.h> @@ -86,7 +87,6 @@ extern void init_IRQ(void); extern void fork_init(unsigned long); extern void mca_init(void); extern void sbus_init(void); -extern void sysctl_init(void); extern void signals_init(void); extern void pidhash_init(void); extern void pidmap_init(void); @@ -516,6 +516,7 @@ asmlinkage void __init start_kernel(void) * enable them */ lock_kernel(); + tick_init(); boot_cpu_init(); page_address_init(); printk(KERN_NOTICE); @@ -702,8 +703,8 @@ static void __init do_basic_setup(void) usermodehelper_init(); driver_init(); -#ifdef CONFIG_SYSCTL - sysctl_init(); +#ifdef CONFIG_PROC_FS + init_irq_proc(); #endif do_initcalls(); @@ -727,7 +728,49 @@ static void run_init_process(char *init_filename) kernel_execve(init_filename, argv_init, envp_init); } -static int init(void * unused) +/* This is a non __init function. Force it to be noinline otherwise gcc + * makes it inline to init() and it becomes part of init.text section + */ +static int noinline init_post(void) +{ + free_initmem(); + unlock_kernel(); + mark_rodata_ro(); + system_state = SYSTEM_RUNNING; + numa_default_policy(); + + if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) + printk(KERN_WARNING "Warning: unable to open an initial console.\n"); + + (void) sys_dup(0); + (void) sys_dup(0); + + if (ramdisk_execute_command) { + run_init_process(ramdisk_execute_command); + printk(KERN_WARNING "Failed to execute %s\n", + ramdisk_execute_command); + } + + /* + * We try each of these until one succeeds. + * + * The Bourne shell can be used instead of init if we are + * trying to recover a really broken machine. + */ + if (execute_command) { + run_init_process(execute_command); + printk(KERN_WARNING "Failed to execute %s. Attempting " + "defaults...\n", execute_command); + } + run_init_process("/sbin/init"); + run_init_process("/etc/init"); + run_init_process("/bin/init"); + run_init_process("/bin/sh"); + + panic("No init found. Try passing init= option to kernel."); +} + +static int __init init(void * unused) { lock_kernel(); /* @@ -775,39 +818,6 @@ static int init(void * unused) * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. */ - free_initmem(); - unlock_kernel(); - mark_rodata_ro(); - system_state = SYSTEM_RUNNING; - numa_default_policy(); - - if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) - printk(KERN_WARNING "Warning: unable to open an initial console.\n"); - - (void) sys_dup(0); - (void) sys_dup(0); - - if (ramdisk_execute_command) { - run_init_process(ramdisk_execute_command); - printk(KERN_WARNING "Failed to execute %s\n", - ramdisk_execute_command); - } - - /* - * We try each of these until one succeeds. - * - * The Bourne shell can be used instead of init if we are - * trying to recover a really broken machine. - */ - if (execute_command) { - run_init_process(execute_command); - printk(KERN_WARNING "Failed to execute %s. Attempting " - "defaults...\n", execute_command); - } - run_init_process("/sbin/init"); - run_init_process("/etc/init"); - run_init_process("/bin/init"); - run_init_process("/bin/sh"); - - panic("No init found. Try passing init= option to kernel."); + init_post(); + return 0; } diff --git a/init/version.c b/init/version.c index 6c01ec1..9d17d70 100644 --- a/init/version.c +++ b/init/version.c @@ -12,7 +12,6 @@ #include <linux/utsname.h> #include <linux/utsrelease.h> #include <linux/version.h> -#include <linux/sched.h> #define version(a) Version_ ## a #define version_string(a) version(a) diff --git a/ipc/Makefile b/ipc/Makefile index 0a6d626..b93bba6 100644 --- a/ipc/Makefile +++ b/ipc/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o +obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o obj_mq-$(CONFIG_COMPAT) += compat_mq.o obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c new file mode 100644 index 0000000..a88934a --- /dev/null +++ b/ipc/ipc_sysctl.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2007 + * + * Author: Eric Biederman <ebiederm@xmision.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, version 2 of the + * License. + */ + +#include <linux/module.h> +#include <linux/ipc.h> +#include <linux/nsproxy.h> +#include <linux/sysctl.h> +#include <linux/uaccess.h> + +#ifdef CONFIG_IPC_NS +static void *get_ipc(ctl_table *table) +{ + char *which = table->data; + struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; + which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns; + return which; +} +#else +#define get_ipc(T) ((T)->data) +#endif + +#ifdef CONFIG_PROC_FS +static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table ipc_table; + memcpy(&ipc_table, table, sizeof(ipc_table)); + ipc_table.data = get_ipc(table); + + return proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos); +} + +static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, + struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table ipc_table; + memcpy(&ipc_table, table, sizeof(ipc_table)); + ipc_table.data = get_ipc(table); + + return proc_doulongvec_minmax(&ipc_table, write, filp, buffer, + lenp, ppos); +} + +#else +#define proc_ipc_doulongvec_minmax NULL +#define proc_ipc_dointvec NULL +#endif + +#ifdef CONFIG_SYSCTL_SYSCALL +/* The generic sysctl ipc data routine. */ +static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + size_t len; + void *data; + + /* Get out of I don't have a variable */ + if (!table->data || !table->maxlen) + return -ENOTDIR; + + data = get_ipc(table); + if (!data) + return -ENOTDIR; + + if (oldval && oldlenp) { + if (get_user(len, oldlenp)) + return -EFAULT; + if (len) { + if (len > table->maxlen) + len = table->maxlen; + if (copy_to_user(oldval, data, len)) + return -EFAULT; + if (put_user(len, oldlenp)) + return -EFAULT; + } + } + + if (newval && newlen) { + if (newlen > table->maxlen) + newlen = table->maxlen; + + if (copy_from_user(data, newval, newlen)) + return -EFAULT; + } + return 1; +} +#else +#define sysctl_ipc_data NULL +#endif + +static struct ctl_table ipc_kern_table[] = { + { + .ctl_name = KERN_SHMMAX, + .procname = "shmmax", + .data = &init_ipc_ns.shm_ctlmax, + .maxlen = sizeof (init_ipc_ns.shm_ctlmax), + .mode = 0644, + .proc_handler = proc_ipc_doulongvec_minmax, + .strategy = sysctl_ipc_data, + }, + { + .ctl_name = KERN_SHMALL, + .procname = "shmall", + .data = &init_ipc_ns.shm_ctlall, + .maxlen = sizeof (init_ipc_ns.shm_ctlall), + .mode = 0644, + .proc_handler = proc_ipc_doulongvec_minmax, + .strategy = sysctl_ipc_data, + }, + { + .ctl_name = KERN_SHMMNI, + .procname = "shmmni", + .data = &init_ipc_ns.shm_ctlmni, + .maxlen = sizeof (init_ipc_ns.shm_ctlmni), + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, + }, + { + .ctl_name = KERN_MSGMAX, + .procname = "msgmax", + .data = &init_ipc_ns.msg_ctlmax, + .maxlen = sizeof (init_ipc_ns.msg_ctlmax), + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, + }, + { + .ctl_name = KERN_MSGMNI, + .procname = "msgmni", + .data = &init_ipc_ns.msg_ctlmni, + .maxlen = sizeof (init_ipc_ns.msg_ctlmni), + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, + }, + { + .ctl_name = KERN_MSGMNB, + .procname = "msgmnb", + .data = &init_ipc_ns.msg_ctlmnb, + .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, + }, + { + .ctl_name = KERN_SEM, + .procname = "sem", + .data = &init_ipc_ns.sem_ctls, + .maxlen = 4*sizeof (int), + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, + }, + {} +}; + +static struct ctl_table ipc_root_table[] = { + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0555, + .child = ipc_kern_table, + }, + {} +}; + +static int __init ipc_sysctl_init(void) +{ + register_sysctl_table(ipc_root_table); + return 0; +} + +__initcall(ipc_sysctl_init); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 7a8ce610..0b5ecbe 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1255,7 +1255,7 @@ static int __init init_mqueue_fs(void) return -ENOMEM; /* ignore failues - they are not fatal */ - mq_sysctl_table = register_sysctl_table(mq_sysctl_root, 0); + mq_sysctl_table = register_sysctl_table(mq_sysctl_root); error = register_filesystem(&mqueue_fs_type); if (error) diff --git a/kernel/Makefile b/kernel/Makefile index 14f4d45..ac6b27a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_RELAY) += relay.o +obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_UTS_NS) += utsname.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o diff --git a/kernel/fork.c b/kernel/fork.c index 0b6293d..d154cc7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -858,7 +858,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts init_sigpending(&sig->shared_pending); INIT_LIST_HEAD(&sig->posix_timers); - hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_REL); + hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); sig->it_real_incr.tv64 = 0; sig->real_timer.function = it_real_fn; sig->tsk = tsk; diff --git a/kernel/futex.c b/kernel/futex.c index 5a737de..e749e7d 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1134,7 +1134,7 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, if (sec != MAX_SCHEDULE_TIMEOUT) { to = &timeout; - hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); + hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); hrtimer_init_sleeper(to, current); to->timer.expires = ktime_set(sec, nsec); } diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index f44e499..476cb0c 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1,8 +1,9 @@ /* * linux/kernel/hrtimer.c * - * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> - * Copyright(C) 2005, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> + * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006-2007 Timesys Corp., Thomas Gleixner * * High-resolution kernel timers * @@ -31,12 +32,17 @@ */ #include <linux/cpu.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/percpu.h> #include <linux/hrtimer.h> #include <linux/notifier.h> #include <linux/syscalls.h> +#include <linux/kallsyms.h> #include <linux/interrupt.h> +#include <linux/tick.h> +#include <linux/seq_file.h> +#include <linux/err.h> #include <asm/uaccess.h> @@ -45,7 +51,7 @@ * * returns the time in ktime_t format */ -static ktime_t ktime_get(void) +ktime_t ktime_get(void) { struct timespec now; @@ -59,7 +65,7 @@ static ktime_t ktime_get(void) * * returns the time in ktime_t format */ -static ktime_t ktime_get_real(void) +ktime_t ktime_get_real(void) { struct timespec now; @@ -79,21 +85,22 @@ EXPORT_SYMBOL_GPL(ktime_get_real); * This ensures that we capture erroneous accesses to these clock ids * rather than moving them into the range of valid clock id's. */ - -#define MAX_HRTIMER_BASES 2 - -static DEFINE_PER_CPU(struct hrtimer_base, hrtimer_bases[MAX_HRTIMER_BASES]) = +DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = { + + .clock_base = { - .index = CLOCK_REALTIME, - .get_time = &ktime_get_real, - .resolution = KTIME_REALTIME_RES, - }, - { - .index = CLOCK_MONOTONIC, - .get_time = &ktime_get, - .resolution = KTIME_MONOTONIC_RES, - }, + { + .index = CLOCK_REALTIME, + .get_time = &ktime_get_real, + .resolution = KTIME_LOW_RES, + }, + { + .index = CLOCK_MONOTONIC, + .get_time = &ktime_get, + .resolution = KTIME_LOW_RES, + }, + } }; /** @@ -125,20 +132,35 @@ EXPORT_SYMBOL_GPL(ktime_get_ts); * Get the coarse grained time at the softirq based on xtime and * wall_to_monotonic. */ -static void hrtimer_get_softirq_time(struct hrtimer_base *base) +static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base) { ktime_t xtim, tomono; + struct timespec xts; unsigned long seq; do { seq = read_seqbegin(&xtime_lock); - xtim = timespec_to_ktime(xtime); - tomono = timespec_to_ktime(wall_to_monotonic); - +#ifdef CONFIG_NO_HZ + getnstimeofday(&xts); +#else + xts = xtime; +#endif } while (read_seqretry(&xtime_lock, seq)); - base[CLOCK_REALTIME].softirq_time = xtim; - base[CLOCK_MONOTONIC].softirq_time = ktime_add(xtim, tomono); + xtim = timespec_to_ktime(xts); + tomono = timespec_to_ktime(wall_to_monotonic); + base->clock_base[CLOCK_REALTIME].softirq_time = xtim; + base->clock_base[CLOCK_MONOTONIC].softirq_time = + ktime_add(xtim, tomono); +} + +/* + * Helper function to check, whether the timer is running the callback + * function + */ +static inline int hrtimer_callback_running(struct hrtimer *timer) +{ + return timer->state & HRTIMER_STATE_CALLBACK; } /* @@ -147,8 +169,6 @@ static void hrtimer_get_softirq_time(struct hrtimer_base *base) */ #ifdef CONFIG_SMP -#define set_curr_timer(b, t) do { (b)->curr_timer = (t); } while (0) - /* * We are using hashed locking: holding per_cpu(hrtimer_bases)[n].lock * means that all timers which are tied to this base via timer->base are @@ -161,19 +181,20 @@ static void hrtimer_get_softirq_time(struct hrtimer_base *base) * possible to set timer->base = NULL and drop the lock: the timer remains * locked. */ -static struct hrtimer_base *lock_hrtimer_base(const struct hrtimer *timer, - unsigned long *flags) +static +struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, + unsigned long *flags) { - struct hrtimer_base *base; + struct hrtimer_clock_base *base; for (;;) { base = timer->base; if (likely(base != NULL)) { - spin_lock_irqsave(&base->lock, *flags); + spin_lock_irqsave(&base->cpu_base->lock, *flags); if (likely(base == timer->base)) return base; /* The timer has migrated to another CPU: */ - spin_unlock_irqrestore(&base->lock, *flags); + spin_unlock_irqrestore(&base->cpu_base->lock, *flags); } cpu_relax(); } @@ -182,12 +203,14 @@ static struct hrtimer_base *lock_hrtimer_base(const struct hrtimer *timer, /* * Switch the timer base to the current CPU when possible. */ -static inline struct hrtimer_base * -switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_base *base) +static inline struct hrtimer_clock_base * +switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base) { - struct hrtimer_base *new_base; + struct hrtimer_clock_base *new_base; + struct hrtimer_cpu_base *new_cpu_base; - new_base = &__get_cpu_var(hrtimer_bases)[base->index]; + new_cpu_base = &__get_cpu_var(hrtimer_bases); + new_base = &new_cpu_base->clock_base[base->index]; if (base != new_base) { /* @@ -199,13 +222,13 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_base *base) * completed. There is no conflict as we hold the lock until * the timer is enqueued. */ - if (unlikely(base->curr_timer == timer)) + if (unlikely(hrtimer_callback_running(timer))) return base; /* See the comment in lock_timer_base() */ timer->base = NULL; - spin_unlock(&base->lock); - spin_lock(&new_base->lock); + spin_unlock(&base->cpu_base->lock); + spin_lock(&new_base->cpu_base->lock); timer->base = new_base; } return new_base; @@ -213,19 +236,17 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_base *base) #else /* CONFIG_SMP */ -#define set_curr_timer(b, t) do { } while (0) - -static inline struct hrtimer_base * +static inline struct hrtimer_clock_base * lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) { - struct hrtimer_base *base = timer->base; + struct hrtimer_clock_base *base = timer->base; - spin_lock_irqsave(&base->lock, *flags); + spin_lock_irqsave(&base->cpu_base->lock, *flags); return base; } -#define switch_hrtimer_base(t, b) (b) +# define switch_hrtimer_base(t, b) (b) #endif /* !CONFIG_SMP */ @@ -256,15 +277,12 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec) return ktime_add(kt, tmp); } - -#else /* CONFIG_KTIME_SCALAR */ - # endif /* !CONFIG_KTIME_SCALAR */ /* * Divide a ktime value by a nanosecond value */ -static unsigned long ktime_divns(const ktime_t kt, s64 div) +unsigned long ktime_divns(const ktime_t kt, s64 div) { u64 dclc, inc, dns; int sft = 0; @@ -281,18 +299,311 @@ static unsigned long ktime_divns(const ktime_t kt, s64 div) return (unsigned long) dclc; } - -#else /* BITS_PER_LONG < 64 */ -# define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div)) #endif /* BITS_PER_LONG >= 64 */ +/* High resolution timer related functions */ +#ifdef CONFIG_HIGH_RES_TIMERS + +/* + * High resolution timer enabled ? + */ +static int hrtimer_hres_enabled __read_mostly = 1; + +/* + * Enable / Disable high resolution mode + */ +static int __init setup_hrtimer_hres(char *str) +{ + if (!strcmp(str, "off")) + hrtimer_hres_enabled = 0; + else if (!strcmp(str, "on")) + hrtimer_hres_enabled = 1; + else + return 0; + return 1; +} + +__setup("highres=", setup_hrtimer_hres); + +/* + * hrtimer_high_res_enabled - query, if the highres mode is enabled + */ +static inline int hrtimer_is_hres_enabled(void) +{ + return hrtimer_hres_enabled; +} + +/* + * Is the high resolution mode active ? + */ +static inline int hrtimer_hres_active(void) +{ + return __get_cpu_var(hrtimer_bases).hres_active; +} + +/* + * Reprogram the event source with checking both queues for the + * next event + * Called with interrupts disabled and base->lock held + */ +static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base) +{ + int i; + struct hrtimer_clock_base *base = cpu_base->clock_base; + ktime_t expires; + + cpu_base->expires_next.tv64 = KTIME_MAX; + + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) { + struct hrtimer *timer; + + if (!base->first) + continue; + timer = rb_entry(base->first, struct hrtimer, node); + expires = ktime_sub(timer->expires, base->offset); + if (expires.tv64 < cpu_base->expires_next.tv64) + cpu_base->expires_next = expires; + } + + if (cpu_base->expires_next.tv64 != KTIME_MAX) + tick_program_event(cpu_base->expires_next, 1); +} + +/* + * Shared reprogramming for clock_realtime and clock_monotonic + * + * When a timer is enqueued and expires earlier than the already enqueued + * timers, we have to check, whether it expires earlier than the timer for + * which the clock event device was armed. + * + * Called with interrupts disabled and base->cpu_base.lock held + */ +static int hrtimer_reprogram(struct hrtimer *timer, + struct hrtimer_clock_base *base) +{ + ktime_t *expires_next = &__get_cpu_var(hrtimer_bases).expires_next; + ktime_t expires = ktime_sub(timer->expires, base->offset); + int res; + + /* + * When the callback is running, we do not reprogram the clock event + * device. The timer callback is either running on a different CPU or + * the callback is executed in the hrtimer_interupt context. The + * reprogramming is handled either by the softirq, which called the + * callback or at the end of the hrtimer_interrupt. + */ + if (hrtimer_callback_running(timer)) + return 0; + + if (expires.tv64 >= expires_next->tv64) + return 0; + + /* + * Clockevents returns -ETIME, when the event was in the past. + */ + res = tick_program_event(expires, 0); + if (!IS_ERR_VALUE(res)) + *expires_next = expires; + return res; +} + + +/* + * Retrigger next event is called after clock was set + * + * Called with interrupts disabled via on_each_cpu() + */ +static void retrigger_next_event(void *arg) +{ + struct hrtimer_cpu_base *base; + struct timespec realtime_offset; + unsigned long seq; + + if (!hrtimer_hres_active()) + return; + + do { + seq = read_seqbegin(&xtime_lock); + set_normalized_timespec(&realtime_offset, + -wall_to_monotonic.tv_sec, + -wall_to_monotonic.tv_nsec); + } while (read_seqretry(&xtime_lock, seq)); + + base = &__get_cpu_var(hrtimer_bases); + + /* Adjust CLOCK_REALTIME offset */ + spin_lock(&base->lock); + base->clock_base[CLOCK_REALTIME].offset = + timespec_to_ktime(realtime_offset); + + hrtimer_force_reprogram(base); + spin_unlock(&base->lock); +} + +/* + * Clock realtime was set + * + * Change the offset of the realtime clock vs. the monotonic + * clock. + * + * We might have to reprogram the high resolution timer interrupt. On + * SMP we call the architecture specific code to retrigger _all_ high + * resolution timer interrupts. On UP we just disable interrupts and + * call the high resolution interrupt code. + */ +void clock_was_set(void) +{ + /* Retrigger the CPU local events everywhere */ + on_each_cpu(retrigger_next_event, NULL, 0, 1); +} + +/* + * Check, whether the timer is on the callback pending list + */ +static inline int hrtimer_cb_pending(const struct hrtimer *timer) +{ + return timer->state & HRTIMER_STATE_PENDING; +} + +/* + * Remove a timer from the callback pending list + */ +static inline void hrtimer_remove_cb_pending(struct hrtimer *timer) +{ + list_del_init(&timer->cb_entry); +} + +/* + * Initialize the high resolution related parts of cpu_base + */ +static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) +{ + base->expires_next.tv64 = KTIME_MAX; + base->hres_active = 0; + INIT_LIST_HEAD(&base->cb_pending); +} + +/* + * Initialize the high resolution related parts of a hrtimer + */ +static inline void hrtimer_init_timer_hres(struct hrtimer *timer) +{ + INIT_LIST_HEAD(&timer->cb_entry); +} + +/* + * When High resolution timers are active, try to reprogram. Note, that in case + * the state has HRTIMER_STATE_CALLBACK set, no reprogramming and no expiry + * check happens. The timer gets enqueued into the rbtree. The reprogramming + * and expiry check is done in the hrtimer_interrupt or in the softirq. + */ +static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, + struct hrtimer_clock_base *base) +{ + if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { + + /* Timer is expired, act upon the callback mode */ + switch(timer->cb_mode) { + case HRTIMER_CB_IRQSAFE_NO_RESTART: + /* + * We can call the callback from here. No restart + * happens, so no danger of recursion + */ + BUG_ON(timer->function(timer) != HRTIMER_NORESTART); + return 1; + case HRTIMER_CB_IRQSAFE_NO_SOFTIRQ: + /* + * This is solely for the sched tick emulation with + * dynamic tick support to ensure that we do not + * restart the tick right on the edge and end up with + * the tick timer in the softirq ! The calling site + * takes care of this. + */ + return 1; + case HRTIMER_CB_IRQSAFE: + case HRTIMER_CB_SOFTIRQ: + /* + * Move everything else into the softirq pending list ! + */ + list_add_tail(&timer->cb_entry, + &base->cpu_base->cb_pending); + timer->state = HRTIMER_STATE_PENDING; + raise_softirq(HRTIMER_SOFTIRQ); + return 1; + default: + BUG(); + } + } + return 0; +} + +/* + * Switch to high resolution mode + */ +static void hrtimer_switch_to_hres(void) +{ + struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); + unsigned long flags; + + if (base->hres_active) + return; + + local_irq_save(flags); + + if (tick_init_highres()) { + local_irq_restore(flags); + return; + } + base->hres_active = 1; + base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES; + base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES; + + tick_setup_sched_timer(); + + /* "Retrigger" the interrupt to get things going */ + retrigger_next_event(NULL); + local_irq_restore(flags); + printk(KERN_INFO "Switched to high resolution mode on CPU %d\n", + smp_processor_id()); +} + +#else + +static inline int hrtimer_hres_active(void) { return 0; } +static inline int hrtimer_is_hres_enabled(void) { return 0; } +static inline void hrtimer_switch_to_hres(void) { } +static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } +static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, + struct hrtimer_clock_base *base) +{ + return 0; +} +static inline int hrtimer_cb_pending(struct hrtimer *timer) { return 0; } +static inline void hrtimer_remove_cb_pending(struct hrtimer *timer) { } +static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { } +static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { } + +#endif /* CONFIG_HIGH_RES_TIMERS */ + +#ifdef CONFIG_TIMER_STATS +void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, void *addr) +{ + if (timer->start_site) + return; + + timer->start_site = addr; + memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); + timer->start_pid = current->pid; +} +#endif + /* * Counterpart to lock_timer_base above: */ static inline void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) { - spin_unlock_irqrestore(&timer->base->lock, *flags); + spin_unlock_irqrestore(&timer->base->cpu_base->lock, *flags); } /** @@ -342,7 +653,8 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) * The timer is inserted in expiry order. Insertion into the * red black tree is O(log(n)). Must hold the base lock. */ -static void enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) +static void enqueue_hrtimer(struct hrtimer *timer, + struct hrtimer_clock_base *base, int reprogram) { struct rb_node **link = &base->active.rb_node; struct rb_node *parent = NULL; @@ -368,39 +680,85 @@ static void enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) * Insert the timer to the rbtree and check whether it * replaces the first pending timer */ - rb_link_node(&timer->node, parent, link); - rb_insert_color(&timer->node, &base->active); - if (!base->first || timer->expires.tv64 < - rb_entry(base->first, struct hrtimer, node)->expires.tv64) + rb_entry(base->first, struct hrtimer, node)->expires.tv64) { + /* + * Reprogram the clock event device. When the timer is already + * expired hrtimer_enqueue_reprogram has either called the + * callback or added it to the pending list and raised the + * softirq. + * + * This is a NOP for !HIGHRES + */ + if (reprogram && hrtimer_enqueue_reprogram(timer, base)) + return; + base->first = &timer->node; + } + + rb_link_node(&timer->node, parent, link); + rb_insert_color(&timer->node, &base->active); + /* + * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the + * state of a possibly running callback. + */ + timer->state |= HRTIMER_STATE_ENQUEUED; } /* * __remove_hrtimer - internal function to remove a timer * * Caller must hold the base lock. + * + * High resolution timer mode reprograms the clock event device when the + * timer is the one which expires next. The caller can disable this by setting + * reprogram to zero. This is useful, when the context does a reprogramming + * anyway (e.g. timer interrupt) */ -static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) +static void __remove_hrtimer(struct hrtimer *timer, + struct hrtimer_clock_base *base, + unsigned long newstate, int reprogram) { - /* - * Remove the timer from the rbtree and replace the - * first entry pointer if necessary. - */ - if (base->first == &timer->node) - base->first = rb_next(&timer->node); - rb_erase(&timer->node, &base->active); - rb_set_parent(&timer->node, &timer->node); + /* High res. callback list. NOP for !HIGHRES */ + if (hrtimer_cb_pending(timer)) + hrtimer_remove_cb_pending(timer); + else { + /* + * Remove the timer from the rbtree and replace the + * first entry pointer if necessary. + */ + if (base->first == &timer->node) { + base->first = rb_next(&timer->node); + /* Reprogram the clock event device. if enabled */ + if (reprogram && hrtimer_hres_active()) + hrtimer_force_reprogram(base->cpu_base); + } + rb_erase(&timer->node, &base->active); + } + timer->state = newstate; } /* * remove hrtimer, called with base lock held */ static inline int -remove_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) +remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) { - if (hrtimer_active(timer)) { - __remove_hrtimer(timer, base); + if (hrtimer_is_queued(timer)) { + int reprogram; + + /* + * Remove the timer and force reprogramming when high + * resolution mode is active and the timer is on the current + * CPU. If we remove a timer on another CPU, reprogramming is + * skipped. The interrupt event on this CPU is fired and + * reprogramming happens in the interrupt handler. This is a + * rare case and less expensive than a smp call. + */ + timer_stats_hrtimer_clear_start_info(timer); + reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases); + __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, + reprogram); return 1; } return 0; @@ -419,7 +777,7 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) int hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) { - struct hrtimer_base *base, *new_base; + struct hrtimer_clock_base *base, *new_base; unsigned long flags; int ret; @@ -431,7 +789,7 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) /* Switch the timer base, if necessary: */ new_base = switch_hrtimer_base(timer, base); - if (mode == HRTIMER_REL) { + if (mode == HRTIMER_MODE_REL) { tim = ktime_add(tim, new_base->get_time()); /* * CONFIG_TIME_LOW_RES is a temporary way for architectures @@ -446,7 +804,9 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) } timer->expires = tim; - enqueue_hrtimer(timer, new_base); + timer_stats_hrtimer_set_start_info(timer); + + enqueue_hrtimer(timer, new_base, base == new_base); unlock_hrtimer_base(timer, &flags); @@ -466,13 +826,13 @@ EXPORT_SYMBOL_GPL(hrtimer_start); */ int hrtimer_try_to_cancel(struct hrtimer *timer) { - struct hrtimer_base *base; + struct hrtimer_clock_base *base; unsigned long flags; int ret = -1; base = lock_hrtimer_base(timer, &flags); - if (base->curr_timer != timer) + if (!hrtimer_callback_running(timer)) ret = remove_hrtimer(timer, base); unlock_hrtimer_base(timer, &flags); @@ -508,19 +868,19 @@ EXPORT_SYMBOL_GPL(hrtimer_cancel); */ ktime_t hrtimer_get_remaining(const struct hrtimer *timer) { - struct hrtimer_base *base; + struct hrtimer_clock_base *base; unsigned long flags; ktime_t rem; base = lock_hrtimer_base(timer, &flags); - rem = ktime_sub(timer->expires, timer->base->get_time()); + rem = ktime_sub(timer->expires, base->get_time()); unlock_hrtimer_base(timer, &flags); return rem; } EXPORT_SYMBOL_GPL(hrtimer_get_remaining); -#ifdef CONFIG_NO_IDLE_HZ +#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ) /** * hrtimer_get_next_event - get the time until next expiry event * @@ -529,26 +889,31 @@ EXPORT_SYMBOL_GPL(hrtimer_get_remaining); */ ktime_t hrtimer_get_next_event(void) { - struct hrtimer_base *base = __get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_clock_base *base = cpu_base->clock_base; ktime_t delta, mindelta = { .tv64 = KTIME_MAX }; unsigned long flags; int i; - for (i = 0; i < MAX_HRTIMER_BASES; i++, base++) { - struct hrtimer *timer; + spin_lock_irqsave(&cpu_base->lock, flags); - spin_lock_irqsave(&base->lock, flags); - if (!base->first) { - spin_unlock_irqrestore(&base->lock, flags); - continue; + if (!hrtimer_hres_active()) { + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) { + struct hrtimer *timer; + + if (!base->first) + continue; + + timer = rb_entry(base->first, struct hrtimer, node); + delta.tv64 = timer->expires.tv64; + delta = ktime_sub(delta, base->get_time()); + if (delta.tv64 < mindelta.tv64) + mindelta.tv64 = delta.tv64; } - timer = rb_entry(base->first, struct hrtimer, node); - delta.tv64 = timer->expires.tv64; - spin_unlock_irqrestore(&base->lock, flags); - delta = ktime_sub(delta, base->get_time()); - if (delta.tv64 < mindelta.tv64) - mindelta.tv64 = delta.tv64; } + + spin_unlock_irqrestore(&cpu_base->lock, flags); + if (mindelta.tv64 < 0) mindelta.tv64 = 0; return mindelta; @@ -564,17 +929,23 @@ ktime_t hrtimer_get_next_event(void) void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode mode) { - struct hrtimer_base *bases; + struct hrtimer_cpu_base *cpu_base; memset(timer, 0, sizeof(struct hrtimer)); - bases = __raw_get_cpu_var(hrtimer_bases); + cpu_base = &__raw_get_cpu_var(hrtimer_bases); - if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS) + if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS) clock_id = CLOCK_MONOTONIC; - timer->base = &bases[clock_id]; - rb_set_parent(&timer->node, &timer->node); + timer->base = &cpu_base->clock_base[clock_id]; + hrtimer_init_timer_hres(timer); + +#ifdef CONFIG_TIMER_STATS + timer->start_site = NULL; + timer->start_pid = -1; + memset(timer->start_comm, 0, TASK_COMM_LEN); +#endif } EXPORT_SYMBOL_GPL(hrtimer_init); @@ -588,21 +959,159 @@ EXPORT_SYMBOL_GPL(hrtimer_init); */ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) { - struct hrtimer_base *bases; + struct hrtimer_cpu_base *cpu_base; - bases = __raw_get_cpu_var(hrtimer_bases); - *tp = ktime_to_timespec(bases[which_clock].resolution); + cpu_base = &__raw_get_cpu_var(hrtimer_bases); + *tp = ktime_to_timespec(cpu_base->clock_base[which_clock].resolution); return 0; } EXPORT_SYMBOL_GPL(hrtimer_get_res); +#ifdef CONFIG_HIGH_RES_TIMERS + +/* + * High resolution timer interrupt + * Called with interrupts disabled + */ +void hrtimer_interrupt(struct clock_event_device *dev) +{ + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_clock_base *base; + ktime_t expires_next, now; + int i, raise = 0; + + BUG_ON(!cpu_base->hres_active); + cpu_base->nr_events++; + dev->next_event.tv64 = KTIME_MAX; + + retry: + now = ktime_get(); + + expires_next.tv64 = KTIME_MAX; + + base = cpu_base->clock_base; + + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { + ktime_t basenow; + struct rb_node *node; + + spin_lock(&cpu_base->lock); + + basenow = ktime_add(now, base->offset); + + while ((node = base->first)) { + struct hrtimer *timer; + + timer = rb_entry(node, struct hrtimer, node); + + if (basenow.tv64 < timer->expires.tv64) { + ktime_t expires; + + expires = ktime_sub(timer->expires, + base->offset); + if (expires.tv64 < expires_next.tv64) + expires_next = expires; + break; + } + + /* Move softirq callbacks to the pending list */ + if (timer->cb_mode == HRTIMER_CB_SOFTIRQ) { + __remove_hrtimer(timer, base, + HRTIMER_STATE_PENDING, 0); + list_add_tail(&timer->cb_entry, + &base->cpu_base->cb_pending); + raise = 1; + continue; + } + + __remove_hrtimer(timer, base, + HRTIMER_STATE_CALLBACK, 0); + timer_stats_account_hrtimer(timer); + + /* + * Note: We clear the CALLBACK bit after + * enqueue_hrtimer to avoid reprogramming of + * the event hardware. This happens at the end + * of this function anyway. + */ + if (timer->function(timer) != HRTIMER_NORESTART) { + BUG_ON(timer->state != HRTIMER_STATE_CALLBACK); + enqueue_hrtimer(timer, base, 0); + } + timer->state &= ~HRTIMER_STATE_CALLBACK; + } + spin_unlock(&cpu_base->lock); + base++; + } + + cpu_base->expires_next = expires_next; + + /* Reprogramming necessary ? */ + if (expires_next.tv64 != KTIME_MAX) { + if (tick_program_event(expires_next, 0)) + goto retry; + } + + /* Raise softirq ? */ + if (raise) + raise_softirq(HRTIMER_SOFTIRQ); +} + +static void run_hrtimer_softirq(struct softirq_action *h) +{ + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + + spin_lock_irq(&cpu_base->lock); + + while (!list_empty(&cpu_base->cb_pending)) { + enum hrtimer_restart (*fn)(struct hrtimer *); + struct hrtimer *timer; + int restart; + + timer = list_entry(cpu_base->cb_pending.next, + struct hrtimer, cb_entry); + + timer_stats_account_hrtimer(timer); + + fn = timer->function; + __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0); + spin_unlock_irq(&cpu_base->lock); + + restart = fn(timer); + + spin_lock_irq(&cpu_base->lock); + + timer->state &= ~HRTIMER_STATE_CALLBACK; + if (restart == HRTIMER_RESTART) { + BUG_ON(hrtimer_active(timer)); + /* + * Enqueue the timer, allow reprogramming of the event + * device + */ + enqueue_hrtimer(timer, timer->base, 1); + } else if (hrtimer_active(timer)) { + /* + * If the timer was rearmed on another CPU, reprogram + * the event device. + */ + if (timer->base->first == &timer->node) + hrtimer_reprogram(timer, timer->base); + } + } + spin_unlock_irq(&cpu_base->lock); +} + +#endif /* CONFIG_HIGH_RES_TIMERS */ + /* * Expire the per base hrtimer-queue: */ -static inline void run_hrtimer_queue(struct hrtimer_base *base) +static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base, + int index) { struct rb_node *node; + struct hrtimer_clock_base *base = &cpu_base->clock_base[index]; if (!base->first) return; @@ -610,53 +1119,72 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base) if (base->get_softirq_time) base->softirq_time = base->get_softirq_time(); - spin_lock_irq(&base->lock); + spin_lock_irq(&cpu_base->lock); while ((node = base->first)) { struct hrtimer *timer; - int (*fn)(struct hrtimer *); + enum hrtimer_restart (*fn)(struct hrtimer *); int restart; timer = rb_entry(node, struct hrtimer, node); if (base->softirq_time.tv64 <= timer->expires.tv64) break; + timer_stats_account_hrtimer(timer); + fn = timer->function; - set_curr_timer(base, timer); - __remove_hrtimer(timer, base); - spin_unlock_irq(&base->lock); + __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); + spin_unlock_irq(&cpu_base->lock); restart = fn(timer); - spin_lock_irq(&base->lock); + spin_lock_irq(&cpu_base->lock); + timer->state &= ~HRTIMER_STATE_CALLBACK; if (restart != HRTIMER_NORESTART) { BUG_ON(hrtimer_active(timer)); - enqueue_hrtimer(timer, base); + enqueue_hrtimer(timer, base, 0); } } - set_curr_timer(base, NULL); - spin_unlock_irq(&base->lock); + spin_unlock_irq(&cpu_base->lock); } /* * Called from timer softirq every jiffy, expire hrtimers: + * + * For HRT its the fall back code to run the softirq in the timer + * softirq context in case the hrtimer initialization failed or has + * not been done yet. */ void hrtimer_run_queues(void) { - struct hrtimer_base *base = __get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); int i; - hrtimer_get_softirq_time(base); + if (hrtimer_hres_active()) + return; + + /* + * This _is_ ugly: We have to check in the softirq context, + * whether we can switch to highres and / or nohz mode. The + * clocksource switch happens in the timer interrupt with + * xtime_lock held. Notification from there only sets the + * check bit in the tick_oneshot code, otherwise we might + * deadlock vs. xtime_lock. + */ + if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) + hrtimer_switch_to_hres(); - for (i = 0; i < MAX_HRTIMER_BASES; i++) - run_hrtimer_queue(&base[i]); + hrtimer_get_softirq_time(cpu_base); + + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) + run_hrtimer_queue(cpu_base, i); } /* * Sleep related functions: */ -static int hrtimer_wakeup(struct hrtimer *timer) +static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer) { struct hrtimer_sleeper *t = container_of(timer, struct hrtimer_sleeper, timer); @@ -673,6 +1201,9 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) { sl->timer.function = hrtimer_wakeup; sl->task = task; +#ifdef CONFIG_HIGH_RES_TIMERS + sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART; +#endif } static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) @@ -683,10 +1214,11 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod set_current_state(TASK_INTERRUPTIBLE); hrtimer_start(&t->timer, t->timer.expires, mode); - schedule(); + if (likely(t->task)) + schedule(); hrtimer_cancel(&t->timer); - mode = HRTIMER_ABS; + mode = HRTIMER_MODE_ABS; } while (t->task && !signal_pending(current)); @@ -702,10 +1234,10 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) restart->fn = do_no_restart_syscall; - hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS); + hrtimer_init(&t.timer, restart->arg0, HRTIMER_MODE_ABS); t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2; - if (do_nanosleep(&t, HRTIMER_ABS)) + if (do_nanosleep(&t, HRTIMER_MODE_ABS)) return 0; rmtp = (struct timespec __user *) restart->arg1; @@ -738,7 +1270,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, return 0; /* Absolute timers do not update the rmtp value and restart: */ - if (mode == HRTIMER_ABS) + if (mode == HRTIMER_MODE_ABS) return -ERESTARTNOHAND; if (rmtp) { @@ -771,7 +1303,7 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) if (!timespec_valid(&tu)) return -EINVAL; - return hrtimer_nanosleep(&tu, rmtp, HRTIMER_REL, CLOCK_MONOTONIC); + return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); } /* @@ -779,56 +1311,60 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) */ static void __devinit init_hrtimers_cpu(int cpu) { - struct hrtimer_base *base = per_cpu(hrtimer_bases, cpu); + struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); int i; - for (i = 0; i < MAX_HRTIMER_BASES; i++, base++) { - spin_lock_init(&base->lock); - lockdep_set_class(&base->lock, &base->lock_key); - } + spin_lock_init(&cpu_base->lock); + lockdep_set_class(&cpu_base->lock, &cpu_base->lock_key); + + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) + cpu_base->clock_base[i].cpu_base = cpu_base; + + hrtimer_init_hres(cpu_base); } #ifdef CONFIG_HOTPLUG_CPU -static void migrate_hrtimer_list(struct hrtimer_base *old_base, - struct hrtimer_base *new_base) +static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + struct hrtimer_clock_base *new_base) { struct hrtimer *timer; struct rb_node *node; while ((node = rb_first(&old_base->active))) { timer = rb_entry(node, struct hrtimer, node); - __remove_hrtimer(timer, old_base); + BUG_ON(hrtimer_callback_running(timer)); + __remove_hrtimer(timer, old_base, HRTIMER_STATE_INACTIVE, 0); timer->base = new_base; - enqueue_hrtimer(timer, new_base); + /* + * Enqueue the timer. Allow reprogramming of the event device + */ + enqueue_hrtimer(timer, new_base, 1); } } static void migrate_hrtimers(int cpu) { - struct hrtimer_base *old_base, *new_base; + struct hrtimer_cpu_base *old_base, *new_base; int i; BUG_ON(cpu_online(cpu)); - old_base = per_cpu(hrtimer_bases, cpu); - new_base = get_cpu_var(hrtimer_bases); - - local_irq_disable(); + old_base = &per_cpu(hrtimer_bases, cpu); + new_base = &get_cpu_var(hrtimer_bases); - for (i = 0; i < MAX_HRTIMER_BASES; i++) { + tick_cancel_sched_timer(cpu); - spin_lock(&new_base->lock); - spin_lock(&old_base->lock); - - BUG_ON(old_base->curr_timer); + local_irq_disable(); - migrate_hrtimer_list(old_base, new_base); + spin_lock(&new_base->lock); + spin_lock(&old_base->lock); - spin_unlock(&old_base->lock); - spin_unlock(&new_base->lock); - old_base++; - new_base++; + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { + migrate_hrtimer_list(&old_base->clock_base[i], + &new_base->clock_base[i]); } + spin_unlock(&old_base->lock); + spin_unlock(&new_base->lock); local_irq_enable(); put_cpu_var(hrtimer_bases); @@ -848,6 +1384,7 @@ static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self, #ifdef CONFIG_HOTPLUG_CPU case CPU_DEAD: + clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu); migrate_hrtimers(cpu); break; #endif @@ -868,5 +1405,8 @@ void __init hrtimers_init(void) hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); register_cpu_notifier(&hrtimers_nb); +#ifdef CONFIG_HIGH_RES_TIMERS + open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq, NULL); +#endif } diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 475e8a7..0133f4f 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -168,7 +168,7 @@ EXPORT_SYMBOL(set_irq_data); /** * set_irq_data - set irq type data for an irq * @irq: Interrupt number - * @data: Pointer to interrupt specific data + * @entry: Pointer to MSI descriptor data * * Set the hardware irq controller data for an irq */ @@ -230,10 +230,6 @@ static void default_enable(unsigned int irq) */ static void default_disable(unsigned int irq) { - struct irq_desc *desc = irq_desc + irq; - - if (!(desc->status & IRQ_DELAYED_DISABLE)) - desc->chip->mask(irq); } /* @@ -298,13 +294,18 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) if (unlikely(desc->status & IRQ_INPROGRESS)) goto out_unlock; - desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); kstat_cpu(cpu).irqs[irq]++; action = desc->action; - if (unlikely(!action || (desc->status & IRQ_DISABLED))) + if (unlikely(!action || (desc->status & IRQ_DISABLED))) { + if (desc->chip->mask) + desc->chip->mask(irq); + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + desc->status |= IRQ_PENDING; goto out_unlock; + } + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING | IRQ_PENDING); desc->status |= IRQ_INPROGRESS; spin_unlock(&desc->lock); @@ -396,11 +397,13 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) /* * If its disabled or no action available - * keep it masked and get out of here + * then mask it and get out of here: */ action = desc->action; if (unlikely(!action || (desc->status & IRQ_DISABLED))) { desc->status |= IRQ_PENDING; + if (desc->chip->mask) + desc->chip->mask(irq); goto out; } @@ -562,10 +565,8 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, /* Uninstall? */ if (handle == handle_bad_irq) { - if (desc->chip != &no_irq_chip) { - desc->chip->mask(irq); - desc->chip->ack(irq); - } + if (desc->chip != &no_irq_chip) + mask_ack_irq(desc, irq); desc->status |= IRQ_DISABLED; desc->depth = 1; } diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 7c85d69..5597c15 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -38,6 +38,46 @@ void synchronize_irq(unsigned int irq) } EXPORT_SYMBOL(synchronize_irq); +/** + * irq_can_set_affinity - Check if the affinity of a given irq can be set + * @irq: Interrupt to check + * + */ +int irq_can_set_affinity(unsigned int irq) +{ + struct irq_desc *desc = irq_desc + irq; + + if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip || + !desc->chip->set_affinity) + return 0; + + return 1; +} + +/** + * irq_set_affinity - Set the irq affinity of a given irq + * @irq: Interrupt to set affinity + * @cpumask: cpumask + * + */ +int irq_set_affinity(unsigned int irq, cpumask_t cpumask) +{ + struct irq_desc *desc = irq_desc + irq; + + if (!desc->chip->set_affinity) + return -EINVAL; + + set_balance_irq_affinity(irq, cpumask); + +#ifdef CONFIG_GENERIC_PENDING_IRQ + set_pending_irq(irq, cpumask); +#else + desc->affinity = cpumask; + desc->chip->set_affinity(irq, cpumask); +#endif + return 0; +} + #endif /** @@ -281,6 +321,10 @@ int setup_irq(unsigned int irq, struct irqaction *new) if (new->flags & IRQF_PERCPU) desc->status |= IRQ_PER_CPU; #endif + /* Exclude IRQ from balancing */ + if (new->flags & IRQF_NOBALANCING) + desc->status |= IRQ_NO_BALANCING; + if (!shared) { irq_chip_set_defaults(desc->chip); @@ -461,7 +505,7 @@ int request_irq(unsigned int irq, irq_handler_t handler, /* * Lockdep wants atomic interrupt handlers: */ - irqflags |= SA_INTERRUPT; + irqflags |= IRQF_DISABLED; #endif /* * Sanity-check: shared interrupts must pass in a real dev-ID, diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 6d3be06..2db91eb 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -16,26 +16,6 @@ static struct proc_dir_entry *root_irq_dir; #ifdef CONFIG_SMP -#ifdef CONFIG_GENERIC_PENDING_IRQ -void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val) -{ - set_balance_irq_affinity(irq, mask_val); - - /* - * Save these away for later use. Re-progam when the - * interrupt is pending - */ - set_pending_irq(irq, mask_val); -} -#else -void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val) -{ - set_balance_irq_affinity(irq, mask_val); - irq_desc[irq].affinity = mask_val; - irq_desc[irq].chip->set_affinity(irq, mask_val); -} -#endif - static int irq_affinity_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -55,7 +35,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, cpumask_t new_value, tmp; if (!irq_desc[irq].chip->set_affinity || no_irq_affinity || - CHECK_IRQ_PER_CPU(irq_desc[irq].status)) + irq_balancing_disabled(irq)) return -EIO; err = cpumask_parse_user(buffer, count, new_value); @@ -73,7 +53,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, code to set default SMP affinity. */ return select_smp_affinity(irq) ? -EINVAL : full_count; - proc_set_irq_affinity(irq, new_value); + irq_set_affinity(irq, new_value); return full_count; } diff --git a/kernel/itimer.c b/kernel/itimer.c index 204ed79..307c6a6 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -128,18 +128,13 @@ asmlinkage long sys_getitimer(int which, struct itimerval __user *value) /* * The timer is automagically restarted, when interval != 0 */ -int it_real_fn(struct hrtimer *timer) +enum hrtimer_restart it_real_fn(struct hrtimer *timer) { struct signal_struct *sig = container_of(timer, struct signal_struct, real_timer); send_group_sig_info(SIGALRM, SEND_SIG_PRIV, sig->tsk); - if (sig->it_real_incr.tv64 != 0) { - hrtimer_forward(timer, timer->base->softirq_time, - sig->it_real_incr); - return HRTIMER_RESTART; - } return HRTIMER_NORESTART; } @@ -231,11 +226,14 @@ again: spin_unlock_irq(&tsk->sighand->siglock); goto again; } - tsk->signal->it_real_incr = - timeval_to_ktime(value->it_interval); expires = timeval_to_ktime(value->it_value); - if (expires.tv64 != 0) - hrtimer_start(timer, expires, HRTIMER_REL); + if (expires.tv64 != 0) { + tsk->signal->it_real_incr = + timeval_to_ktime(value->it_interval); + hrtimer_start(timer, expires, HRTIMER_MODE_REL); + } else + tsk->signal->it_real_incr.tv64 = 0; + spin_unlock_irq(&tsk->sighand->siglock); break; case ITIMER_VIRTUAL: diff --git a/kernel/kmod.c b/kernel/kmod.c index 3a7379a..7962761 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -217,7 +217,10 @@ static int wait_for_helper(void *data) sub_info->retval = ret; } - complete(sub_info->complete); + if (sub_info->wait < 0) + kfree(sub_info); + else + complete(sub_info->complete); return 0; } @@ -239,6 +242,9 @@ static void __call_usermodehelper(struct work_struct *work) pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD); + if (wait < 0) + return; + if (pid < 0) { sub_info->retval = pid; complete(sub_info->complete); @@ -253,6 +259,9 @@ static void __call_usermodehelper(struct work_struct *work) * @envp: null-terminated environment list * @session_keyring: session keyring for process (NULL for an empty keyring) * @wait: wait for the application to finish and return status. + * when -1 don't wait at all, but you get no useful error back when + * the program couldn't be exec'ed. This makes it safe to call + * from interrupt context. * * Runs a user-space application. The application is started * asynchronously if wait is not set, and runs as a child of keventd. @@ -265,17 +274,8 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, struct key *session_keyring, int wait) { DECLARE_COMPLETION_ONSTACK(done); - struct subprocess_info sub_info = { - .work = __WORK_INITIALIZER(sub_info.work, - __call_usermodehelper), - .complete = &done, - .path = path, - .argv = argv, - .envp = envp, - .ring = session_keyring, - .wait = wait, - .retval = 0, - }; + struct subprocess_info *sub_info; + int retval; if (!khelper_wq) return -EBUSY; @@ -283,9 +283,25 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, if (path[0] == '\0') return 0; - queue_work(khelper_wq, &sub_info.work); + sub_info = kzalloc(sizeof(struct subprocess_info), GFP_ATOMIC); + if (!sub_info) + return -ENOMEM; + + INIT_WORK(&sub_info->work, __call_usermodehelper); + sub_info->complete = &done; + sub_info->path = path; + sub_info->argv = argv; + sub_info->envp = envp; + sub_info->ring = session_keyring; + sub_info->wait = wait; + + queue_work(khelper_wq, &sub_info->work); + if (wait < 0) /* task has freed sub_info */ + return 0; wait_for_completion(&done); - return sub_info.retval; + retval = sub_info->retval; + kfree(sub_info); + return retval; } EXPORT_SYMBOL(call_usermodehelper_keys); diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 88fc611..58f35e5 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -10,7 +10,6 @@ * Code for /proc/lockdep and /proc/lockdep_stats: * */ -#include <linux/sched.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c index 841539d..d17436c 100644 --- a/kernel/mutex-debug.c +++ b/kernel/mutex-debug.c @@ -13,7 +13,6 @@ * Released under the General Public License (GPL). */ #include <linux/mutex.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/poison.h> diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 7c3e1e6..657f776 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -304,7 +304,7 @@ int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp) * should be able to see it. */ struct task_struct *p; - read_lock(&tasklist_lock); + rcu_read_lock(); p = find_task_by_pid(pid); if (p) { if (CPUCLOCK_PERTHREAD(which_clock)) { @@ -312,12 +312,17 @@ int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp) error = cpu_clock_sample(which_clock, p, &rtn); } - } else if (p->tgid == pid && p->signal) { - error = cpu_clock_sample_group(which_clock, - p, &rtn); + } else { + read_lock(&tasklist_lock); + if (p->tgid == pid && p->signal) { + error = + cpu_clock_sample_group(which_clock, + p, &rtn); + } + read_unlock(&tasklist_lock); } } - read_unlock(&tasklist_lock); + rcu_read_unlock(); } if (error) diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index a1bf616..44318ca 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -145,7 +145,7 @@ static int common_timer_set(struct k_itimer *, int, struct itimerspec *, struct itimerspec *); static int common_timer_del(struct k_itimer *timer); -static int posix_timer_fn(struct hrtimer *data); +static enum hrtimer_restart posix_timer_fn(struct hrtimer *data); static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags); @@ -334,12 +334,12 @@ EXPORT_SYMBOL_GPL(posix_timer_event); * This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. */ -static int posix_timer_fn(struct hrtimer *timer) +static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) { struct k_itimer *timr; unsigned long flags; int si_private = 0; - int ret = HRTIMER_NORESTART; + enum hrtimer_restart ret = HRTIMER_NORESTART; timr = container_of(timer, struct k_itimer, it.real.timer); spin_lock_irqsave(&timr->it_lock, flags); @@ -356,7 +356,7 @@ static int posix_timer_fn(struct hrtimer *timer) if (timr->it.real.interval.tv64 != 0) { timr->it_overrun += hrtimer_forward(timer, - timer->base->softirq_time, + hrtimer_cb_get_time(timer), timr->it.real.interval); ret = HRTIMER_RESTART; ++timr->it_requeue_pending; @@ -722,7 +722,7 @@ common_timer_set(struct k_itimer *timr, int flags, if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) return 0; - mode = flags & TIMER_ABSTIME ? HRTIMER_ABS : HRTIMER_REL; + mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); timr->it.real.timer.function = posix_timer_fn; @@ -734,7 +734,7 @@ common_timer_set(struct k_itimer *timr, int flags, /* SIGEV_NONE timers are not queued ! See common_timer_get */ if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { /* Setup correct expiry time for relative timers */ - if (mode == HRTIMER_REL) + if (mode == HRTIMER_MODE_REL) timer->expires = ktime_add(timer->expires, timer->base->get_time()); return 0; @@ -950,7 +950,8 @@ static int common_nsleep(const clockid_t which_clock, int flags, struct timespec *tsave, struct timespec __user *rmtp) { return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? - HRTIMER_ABS : HRTIMER_REL, which_clock); + HRTIMER_MODE_ABS : HRTIMER_MODE_REL, + which_clock); } asmlinkage long diff --git a/kernel/resource.c b/kernel/resource.c index 2a3f886..bdb55a3 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -8,7 +8,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/init.h> diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c index 4ab17da..180978c 100644 --- a/kernel/rtmutex.c +++ b/kernel/rtmutex.c @@ -625,7 +625,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state, /* Setup the timer, when timeout != NULL */ if (unlikely(timeout)) hrtimer_start(&timeout->timer, timeout->timer.expires, - HRTIMER_ABS); + HRTIMER_MODE_ABS); for (;;) { /* Try to acquire the lock: */ diff --git a/kernel/sched.c b/kernel/sched.c index 08f86178..0dc7572 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1853,6 +1853,13 @@ context_switch(struct rq *rq, struct task_struct *prev, struct mm_struct *mm = next->mm; struct mm_struct *oldmm = prev->active_mm; + /* + * For paravirt, this is coupled with an exit in switch_to to + * combine the page table reload and the switch backend into + * one hypercall. + */ + arch_enter_lazy_cpu_mode(); + if (!mm) { next->active_mm = oldmm; atomic_inc(&oldmm->mm_count); diff --git a/kernel/signal.c b/kernel/signal.c index 8072e56..e2a7d4b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -456,26 +456,50 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) { int signr = __dequeue_signal(&tsk->pending, mask, info); - if (!signr) + if (!signr) { signr = __dequeue_signal(&tsk->signal->shared_pending, mask, info); + /* + * itimer signal ? + * + * itimers are process shared and we restart periodic + * itimers in the signal delivery path to prevent DoS + * attacks in the high resolution timer case. This is + * compliant with the old way of self restarting + * itimers, as the SIGALRM is a legacy signal and only + * queued once. Changing the restart behaviour to + * restart the timer in the signal dequeue path is + * reducing the timer noise on heavy loaded !highres + * systems too. + */ + if (unlikely(signr == SIGALRM)) { + struct hrtimer *tmr = &tsk->signal->real_timer; + + if (!hrtimer_is_queued(tmr) && + tsk->signal->it_real_incr.tv64 != 0) { + hrtimer_forward(tmr, tmr->base->get_time(), + tsk->signal->it_real_incr); + hrtimer_restart(tmr); + } + } + } recalc_sigpending_tsk(tsk); - if (signr && unlikely(sig_kernel_stop(signr))) { - /* - * Set a marker that we have dequeued a stop signal. Our - * caller might release the siglock and then the pending - * stop signal it is about to process is no longer in the - * pending bitmasks, but must still be cleared by a SIGCONT - * (and overruled by a SIGKILL). So those cases clear this - * shared flag after we've set it. Note that this flag may - * remain set after the signal we return is ignored or - * handled. That doesn't matter because its only purpose - * is to alert stop-signal processing code when another - * processor has come along and cleared the flag. - */ - if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) - tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; - } + if (signr && unlikely(sig_kernel_stop(signr))) { + /* + * Set a marker that we have dequeued a stop signal. Our + * caller might release the siglock and then the pending + * stop signal it is about to process is no longer in the + * pending bitmasks, but must still be cleared by a SIGCONT + * (and overruled by a SIGKILL). So those cases clear this + * shared flag after we've set it. Note that this flag may + * remain set after the signal we return is ignored or + * handled. That doesn't matter because its only purpose + * is to alert stop-signal processing code when another + * processor has come along and cleared the flag. + */ + if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) + tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; + } if ( signr && ((info->si_code & __SI_MASK) == __SI_TIMER) && info->si_sys_private){ diff --git a/kernel/softirq.c b/kernel/softirq.c index 918e52d..8b75008 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -17,6 +17,7 @@ #include <linux/kthread.h> #include <linux/rcupdate.h> #include <linux/smp.h> +#include <linux/tick.h> #include <asm/irq.h> /* @@ -273,6 +274,18 @@ EXPORT_SYMBOL(do_softirq); #endif +/* + * Enter an interrupt context. + */ +void irq_enter(void) +{ + __irq_enter(); +#ifdef CONFIG_NO_HZ + if (idle_cpu(smp_processor_id())) + tick_nohz_update_jiffies(); +#endif +} + #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED # define invoke_softirq() __do_softirq() #else @@ -289,6 +302,12 @@ void irq_exit(void) sub_preempt_count(IRQ_EXIT_OFFSET); if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); + +#ifdef CONFIG_NO_HZ + /* Make sure that timer wheel updates are propagated */ + if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched()) + tick_nohz_stop_sched_tick(); +#endif preempt_enable_no_resched(); } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index e0ac6cd..3ca1d5f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -90,12 +90,6 @@ extern char modprobe_path[]; #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; #endif -#ifdef CONFIG_SYSVIPC -static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos); -static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos); -#endif #ifdef __sparc__ extern char reboot_command []; @@ -135,18 +129,6 @@ static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, ctl_table *); #endif -static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos); - -static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen); - -#ifdef CONFIG_SYSVIPC -static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen); -#endif #ifdef CONFIG_PROC_SYSCTL static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, @@ -177,60 +159,6 @@ int sysctl_legacy_va_layout; #endif -static void *get_uts(ctl_table *table, int write) -{ - char *which = table->data; -#ifdef CONFIG_UTS_NS - struct uts_namespace *uts_ns = current->nsproxy->uts_ns; - which = (which - (char *)&init_uts_ns) + (char *)uts_ns; -#endif - if (!write) - down_read(&uts_sem); - else - down_write(&uts_sem); - return which; -} - -static void put_uts(ctl_table *table, int write, void *which) -{ - if (!write) - up_read(&uts_sem); - else - up_write(&uts_sem); -} - -#ifdef CONFIG_SYSVIPC -static void *get_ipc(ctl_table *table, int write) -{ - char *which = table->data; - struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; - which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns; - return which; -} -#else -#define get_ipc(T,W) ((T)->data) -#endif - -/* /proc declarations: */ - -#ifdef CONFIG_PROC_SYSCTL - -static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); -static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); -static int proc_opensys(struct inode *, struct file *); - -const struct file_operations proc_sys_file_operations = { - .open = proc_opensys, - .read = proc_readsys, - .write = proc_writesys, -}; - -extern struct proc_dir_entry *proc_sys_root; - -static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *); -static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); -#endif - /* The default sysctl tables: */ static ctl_table root_table[] = { @@ -278,51 +206,6 @@ static ctl_table root_table[] = { static ctl_table kern_table[] = { { - .ctl_name = KERN_OSTYPE, - .procname = "ostype", - .data = init_uts_ns.name.sysname, - .maxlen = sizeof(init_uts_ns.name.sysname), - .mode = 0444, - .proc_handler = &proc_do_uts_string, - .strategy = &sysctl_uts_string, - }, - { - .ctl_name = KERN_OSRELEASE, - .procname = "osrelease", - .data = init_uts_ns.name.release, - .maxlen = sizeof(init_uts_ns.name.release), - .mode = 0444, - .proc_handler = &proc_do_uts_string, - .strategy = &sysctl_uts_string, - }, - { - .ctl_name = KERN_VERSION, - .procname = "version", - .data = init_uts_ns.name.version, - .maxlen = sizeof(init_uts_ns.name.version), - .mode = 0444, - .proc_handler = &proc_do_uts_string, - .strategy = &sysctl_uts_string, - }, - { - .ctl_name = KERN_NODENAME, - .procname = "hostname", - .data = init_uts_ns.name.nodename, - .maxlen = sizeof(init_uts_ns.name.nodename), - .mode = 0644, - .proc_handler = &proc_do_uts_string, - .strategy = &sysctl_uts_string, - }, - { - .ctl_name = KERN_DOMAINNAME, - .procname = "domainname", - .data = init_uts_ns.name.domainname, - .maxlen = sizeof(init_uts_ns.name.domainname), - .mode = 0644, - .proc_handler = &proc_do_uts_string, - .strategy = &sysctl_uts_string, - }, - { .ctl_name = KERN_PANIC, .procname = "panic", .data = &panic_timeout, @@ -478,71 +361,6 @@ static ctl_table kern_table[] = { .proc_handler = &proc_dointvec, }, #endif -#ifdef CONFIG_SYSVIPC - { - .ctl_name = KERN_SHMMAX, - .procname = "shmmax", - .data = &init_ipc_ns.shm_ctlmax, - .maxlen = sizeof (init_ipc_ns.shm_ctlmax), - .mode = 0644, - .proc_handler = &proc_ipc_doulongvec_minmax, - .strategy = sysctl_ipc_data, - }, - { - .ctl_name = KERN_SHMALL, - .procname = "shmall", - .data = &init_ipc_ns.shm_ctlall, - .maxlen = sizeof (init_ipc_ns.shm_ctlall), - .mode = 0644, - .proc_handler = &proc_ipc_doulongvec_minmax, - .strategy = sysctl_ipc_data, - }, - { - .ctl_name = KERN_SHMMNI, - .procname = "shmmni", - .data = &init_ipc_ns.shm_ctlmni, - .maxlen = sizeof (init_ipc_ns.shm_ctlmni), - .mode = 0644, - .proc_handler = &proc_ipc_dointvec, - .strategy = sysctl_ipc_data, - }, - { - .ctl_name = KERN_MSGMAX, - .procname = "msgmax", - .data = &init_ipc_ns.msg_ctlmax, - .maxlen = sizeof (init_ipc_ns.msg_ctlmax), - .mode = 0644, - .proc_handler = &proc_ipc_dointvec, - .strategy = sysctl_ipc_data, - }, - { - .ctl_name = KERN_MSGMNI, - .procname = "msgmni", - .data = &init_ipc_ns.msg_ctlmni, - .maxlen = sizeof (init_ipc_ns.msg_ctlmni), - .mode = 0644, - .proc_handler = &proc_ipc_dointvec, - .strategy = sysctl_ipc_data, - }, - { - .ctl_name = KERN_MSGMNB, - .procname = "msgmnb", - .data = &init_ipc_ns.msg_ctlmnb, - .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), - .mode = 0644, - .proc_handler = &proc_ipc_dointvec, - .strategy = sysctl_ipc_data, - }, - { - .ctl_name = KERN_SEM, - .procname = "sem", - .data = &init_ipc_ns.sem_ctls, - .maxlen = 4*sizeof (int), - .mode = 0644, - .proc_handler = &proc_ipc_dointvec, - .strategy = sysctl_ipc_data, - }, -#endif #ifdef CONFIG_MAGIC_SYSRQ { .ctl_name = KERN_SYSRQ, @@ -1043,6 +861,12 @@ static ctl_table vm_table[] = { { .ctl_name = 0 } }; +#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) +static ctl_table binfmt_misc_table[] = { + { .ctl_name = 0 } +}; +#endif + static ctl_table fs_table[] = { { .ctl_name = FS_NRINODE, @@ -1166,6 +990,14 @@ static ctl_table fs_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, +#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) + { + .ctl_name = CTL_UNNUMBERED, + .procname = "binfmt_misc", + .mode = 0555, + .child = binfmt_misc_table, + }, +#endif { .ctl_name = 0 } }; @@ -1177,8 +1009,6 @@ static ctl_table dev_table[] = { { .ctl_name = 0 } }; -extern void init_irq_proc (void); - static DEFINE_SPINLOCK(sysctl_lock); /* called under sysctl_lock */ @@ -1220,19 +1050,47 @@ static void start_unregistering(struct ctl_table_header *p) list_del_init(&p->ctl_entry); } -void __init sysctl_init(void) +void sysctl_head_finish(struct ctl_table_header *head) { -#ifdef CONFIG_PROC_SYSCTL - register_proc_table(root_table, proc_sys_root, &root_table_header); - init_irq_proc(); -#endif + if (!head) + return; + spin_lock(&sysctl_lock); + unuse_table(head); + spin_unlock(&sysctl_lock); +} + +struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) +{ + struct ctl_table_header *head; + struct list_head *tmp; + spin_lock(&sysctl_lock); + if (prev) { + tmp = &prev->ctl_entry; + unuse_table(prev); + goto next; + } + tmp = &root_table_header.ctl_entry; + for (;;) { + head = list_entry(tmp, struct ctl_table_header, ctl_entry); + + if (!use_table(head)) + goto next; + spin_unlock(&sysctl_lock); + return head; + next: + tmp = tmp->next; + if (tmp == &root_table_header.ctl_entry) + break; + } + spin_unlock(&sysctl_lock); + return NULL; } #ifdef CONFIG_SYSCTL_SYSCALL int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen) { - struct list_head *tmp; + struct ctl_table_header *head; int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) @@ -1242,26 +1100,16 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol if (!oldlenp || get_user(old_len, oldlenp)) return -EFAULT; } - spin_lock(&sysctl_lock); - tmp = &root_table_header.ctl_entry; - do { - struct ctl_table_header *head = - list_entry(tmp, struct ctl_table_header, ctl_entry); - - if (!use_table(head)) - continue; - - spin_unlock(&sysctl_lock); + for (head = sysctl_head_next(NULL); head; + head = sysctl_head_next(head)) { error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table); - - spin_lock(&sysctl_lock); - unuse_table(head); - if (error != -ENOTDIR) + if (error != -ENOTDIR) { + sysctl_head_finish(head); break; - } while ((tmp = tmp->next) != &root_table_header.ctl_entry); - spin_unlock(&sysctl_lock); + } + } return error; } @@ -1282,7 +1130,7 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args) #endif /* CONFIG_SYSCTL_SYSCALL */ /* - * ctl_perm does NOT grant the superuser all rights automatically, because + * sysctl_perm does NOT grant the superuser all rights automatically, because * some sysctl variables are readonly even to root. */ @@ -1297,7 +1145,7 @@ static int test_perm(int mode, int op) return -EACCES; } -static inline int ctl_perm(ctl_table *table, int op) +int sysctl_perm(ctl_table *table, int op) { int error; error = security_sysctl(table, op); @@ -1321,19 +1169,11 @@ repeat: for ( ; table->ctl_name || table->procname; table++) { if (!table->ctl_name) continue; - if (n == table->ctl_name || table->ctl_name == CTL_ANY) { + if (n == table->ctl_name) { int error; if (table->child) { - if (ctl_perm(table, 001)) + if (sysctl_perm(table, 001)) return -EPERM; - if (table->strategy) { - error = table->strategy( - table, name, nlen, - oldval, oldlenp, - newval, newlen); - if (error) - return error; - } name++; nlen--; table = table->child; @@ -1361,7 +1201,7 @@ int do_sysctl_strategy (ctl_table *table, op |= 004; if (newval) op |= 002; - if (ctl_perm(table, op)) + if (sysctl_perm(table, op)) return -EPERM; if (table->strategy) { @@ -1400,10 +1240,26 @@ int do_sysctl_strategy (ctl_table *table, } #endif /* CONFIG_SYSCTL_SYSCALL */ +static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) +{ + for (; table->ctl_name || table->procname; table++) { + table->parent = parent; + if (table->child) + sysctl_set_parent(table, table->child); + } +} + +static __init int sysctl_init(void) +{ + sysctl_set_parent(NULL, root_table); + return 0; +} + +core_initcall(sysctl_init); + /** * register_sysctl_table - register a sysctl hierarchy * @table: the top-level table structure - * @insert_at_head: whether the entry should be inserted in front or at the end * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. An entry with a ctl_name of 0 terminates the table. @@ -1469,8 +1325,7 @@ int do_sysctl_strategy (ctl_table *table, * This routine returns %NULL on a failure to register, and a pointer * to the table header on success. */ -struct ctl_table_header *register_sysctl_table(ctl_table * table, - int insert_at_head) +struct ctl_table_header *register_sysctl_table(ctl_table * table) { struct ctl_table_header *tmp; tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); @@ -1480,15 +1335,10 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table, INIT_LIST_HEAD(&tmp->ctl_entry); tmp->used = 0; tmp->unregistering = NULL; + sysctl_set_parent(NULL, table); spin_lock(&sysctl_lock); - if (insert_at_head) - list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); - else - list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); + list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); spin_unlock(&sysctl_lock); -#ifdef CONFIG_PROC_SYSCTL - register_proc_table(table, proc_sys_root, tmp); -#endif return tmp; } @@ -1504,9 +1354,6 @@ void unregister_sysctl_table(struct ctl_table_header * header) might_sleep(); spin_lock(&sysctl_lock); start_unregistering(header); -#ifdef CONFIG_PROC_SYSCTL - unregister_proc_table(header->ctl_table, proc_sys_root); -#endif spin_unlock(&sysctl_lock); kfree(header); } @@ -1530,155 +1377,6 @@ void unregister_sysctl_table(struct ctl_table_header * table) #ifdef CONFIG_PROC_SYSCTL -/* Scan the sysctl entries in table and add them all into /proc */ -static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) -{ - struct proc_dir_entry *de; - int len; - mode_t mode; - - for (; table->ctl_name || table->procname; table++) { - /* Can't do anything without a proc name. */ - if (!table->procname) - continue; - /* Maybe we can't do anything with it... */ - if (!table->proc_handler && !table->child) { - printk(KERN_WARNING "SYSCTL: Can't register %s\n", - table->procname); - continue; - } - - len = strlen(table->procname); - mode = table->mode; - - de = NULL; - if (table->proc_handler) - mode |= S_IFREG; - else { - mode |= S_IFDIR; - for (de = root->subdir; de; de = de->next) { - if (proc_match(len, table->procname, de)) - break; - } - /* If the subdir exists already, de is non-NULL */ - } - - if (!de) { - de = create_proc_entry(table->procname, mode, root); - if (!de) - continue; - de->set = set; - de->data = (void *) table; - if (table->proc_handler) - de->proc_fops = &proc_sys_file_operations; - } - table->de = de; - if (de->mode & S_IFDIR) - register_proc_table(table->child, de, set); - } -} - -/* - * Unregister a /proc sysctl table and any subdirectories. - */ -static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) -{ - struct proc_dir_entry *de; - for (; table->ctl_name || table->procname; table++) { - if (!(de = table->de)) - continue; - if (de->mode & S_IFDIR) { - if (!table->child) { - printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); - continue; - } - unregister_proc_table(table->child, de); - - /* Don't unregister directories which still have entries.. */ - if (de->subdir) - continue; - } - - /* - * In any case, mark the entry as goner; we'll keep it - * around if it's busy, but we'll know to do nothing with - * its fields. We are under sysctl_lock here. - */ - de->data = NULL; - - /* Don't unregister proc entries that are still being used.. */ - if (atomic_read(&de->count)) - continue; - - table->de = NULL; - remove_proc_entry(table->procname, root); - } -} - -static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - int op; - struct proc_dir_entry *de = PDE(file->f_path.dentry->d_inode); - struct ctl_table *table; - size_t res; - ssize_t error = -ENOTDIR; - - spin_lock(&sysctl_lock); - if (de && de->data && use_table(de->set)) { - /* - * at that point we know that sysctl was not unregistered - * and won't be until we finish - */ - spin_unlock(&sysctl_lock); - table = (struct ctl_table *) de->data; - if (!table || !table->proc_handler) - goto out; - error = -EPERM; - op = (write ? 002 : 004); - if (ctl_perm(table, op)) - goto out; - - /* careful: calling conventions are nasty here */ - res = count; - error = (*table->proc_handler)(table, write, file, - buf, &res, ppos); - if (!error) - error = res; - out: - spin_lock(&sysctl_lock); - unuse_table(de->set); - } - spin_unlock(&sysctl_lock); - return error; -} - -static int proc_opensys(struct inode *inode, struct file *file) -{ - if (file->f_mode & FMODE_WRITE) { - /* - * sysctl entries that are not writable, - * are _NOT_ writable, capabilities or not. - */ - if (!(inode->i_mode & S_IWUSR)) - return -EPERM; - } - - return 0; -} - -static ssize_t proc_readsys(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - return do_rw_proc(0, file, buf, count, ppos); -} - -static ssize_t proc_writesys(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) -{ - return do_rw_proc(1, file, (char __user *) buf, count, ppos); -} - static int _proc_do_string(void* data, int maxlen, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -1762,21 +1460,6 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, buffer, lenp, ppos); } -/* - * Special case of dostring for the UTS structure. This has locks - * to observe. Should this be in kernel/sys.c ???? - */ - -static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int r; - void *which; - which = get_uts(table, write); - r = _proc_do_string(which, table->maxlen,write,filp,buffer,lenp, ppos); - put_uts(table, write, which); - return r; -} static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, int *valp, @@ -2362,27 +2045,6 @@ int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, do_proc_dointvec_ms_jiffies_conv, NULL); } -#ifdef CONFIG_SYSVIPC -static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - void *which; - which = get_ipc(table, write); - return __do_proc_dointvec(which, table, write, filp, buffer, - lenp, ppos, NULL, NULL); -} - -static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, - struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) -{ - void *which; - which = get_ipc(table, write); - return __do_proc_doulongvec_minmax(which, table, write, filp, buffer, - lenp, ppos, 1l, 1l); -} - -#endif - static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2413,31 +2075,6 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, return -ENOSYS; } -static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -#ifdef CONFIG_SYSVIPC -static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} -static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} -static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, - struct file *filp, void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} -#endif - int proc_dointvec(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2648,62 +2285,6 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, } -/* The generic string strategy routine: */ -static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen) -{ - struct ctl_table uts_table; - int r, write; - write = newval && newlen; - memcpy(&uts_table, table, sizeof(uts_table)); - uts_table.data = get_uts(table, write); - r = sysctl_string(&uts_table, name, nlen, - oldval, oldlenp, newval, newlen); - put_uts(table, write, uts_table.data); - return r; -} - -#ifdef CONFIG_SYSVIPC -/* The generic sysctl ipc data routine. */ -static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen) -{ - size_t len; - void *data; - - /* Get out of I don't have a variable */ - if (!table->data || !table->maxlen) - return -ENOTDIR; - - data = get_ipc(table, 1); - if (!data) - return -ENOTDIR; - - if (oldval && oldlenp) { - if (get_user(len, oldlenp)) - return -EFAULT; - if (len) { - if (len > table->maxlen) - len = table->maxlen; - if (copy_to_user(oldval, data, len)) - return -EFAULT; - if (put_user(len, oldlenp)) - return -EFAULT; - } - } - - if (newval && newlen) { - if (newlen > table->maxlen) - newlen = table->maxlen; - - if (copy_from_user(data, newval, newlen)) - return -EFAULT; - } - return 1; -} -#endif #else /* CONFIG_SYSCTL_SYSCALL */ @@ -2769,20 +2350,6 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, return -ENOSYS; } -static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen) -{ - return -ENOSYS; -} -#ifdef CONFIG_SYSVIPC -static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen) -{ - return -ENOSYS; -} -#endif #endif /* CONFIG_SYSCTL_SYSCALL */ /* diff --git a/kernel/time.c b/kernel/time.c index 0e017bff..c6c80ea5 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -470,6 +470,260 @@ struct timeval ns_to_timeval(const s64 nsec) return tv; } +/* + * Convert jiffies to milliseconds and back. + * + * Avoid unnecessary multiplications/divisions in the + * two most common HZ cases: + */ +unsigned int jiffies_to_msecs(const unsigned long j) +{ +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + return (MSEC_PER_SEC / HZ) * j; +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); +#else + return (j * MSEC_PER_SEC) / HZ; +#endif +} +EXPORT_SYMBOL(jiffies_to_msecs); + +unsigned int jiffies_to_usecs(const unsigned long j) +{ +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (USEC_PER_SEC / HZ) * j; +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC); +#else + return (j * USEC_PER_SEC) / HZ; +#endif +} +EXPORT_SYMBOL(jiffies_to_usecs); + +/* + * When we convert to jiffies then we interpret incoming values + * the following way: + * + * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET) + * + * - 'too large' values [that would result in larger than + * MAX_JIFFY_OFFSET values] mean 'infinite timeout' too. + * + * - all other values are converted to jiffies by either multiplying + * the input value by a factor or dividing it with a factor + * + * We must also be careful about 32-bit overflows. + */ +unsigned long msecs_to_jiffies(const unsigned int m) +{ + /* + * Negative value, means infinite timeout: + */ + if ((int)m < 0) + return MAX_JIFFY_OFFSET; + +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + /* + * HZ is equal to or smaller than 1000, and 1000 is a nice + * round multiple of HZ, divide with the factor between them, + * but round upwards: + */ + return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + /* + * HZ is larger than 1000, and HZ is a nice round multiple of + * 1000 - simply multiply with the factor between them. + * + * But first make sure the multiplication result cannot + * overflow: + */ + if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; + + return m * (HZ / MSEC_PER_SEC); +#else + /* + * Generic case - multiply, round and divide. But first + * check that if we are doing a net multiplication, that + * we wouldnt overflow: + */ + if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; + + return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC; +#endif +} +EXPORT_SYMBOL(msecs_to_jiffies); + +unsigned long usecs_to_jiffies(const unsigned int u) +{ + if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ); +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return u * (HZ / USEC_PER_SEC); +#else + return (u * HZ + USEC_PER_SEC - 1) / USEC_PER_SEC; +#endif +} +EXPORT_SYMBOL(usecs_to_jiffies); + +/* + * The TICK_NSEC - 1 rounds up the value to the next resolution. Note + * that a remainder subtract here would not do the right thing as the + * resolution values don't fall on second boundries. I.e. the line: + * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. + * + * Rather, we just shift the bits off the right. + * + * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec + * value to a scaled second value. + */ +unsigned long +timespec_to_jiffies(const struct timespec *value) +{ + unsigned long sec = value->tv_sec; + long nsec = value->tv_nsec + TICK_NSEC - 1; + + if (sec >= MAX_SEC_IN_JIFFIES){ + sec = MAX_SEC_IN_JIFFIES; + nsec = 0; + } + return (((u64)sec * SEC_CONVERSION) + + (((u64)nsec * NSEC_CONVERSION) >> + (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; + +} +EXPORT_SYMBOL(timespec_to_jiffies); + +void +jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) +{ + /* + * Convert jiffies to nanoseconds and separate with + * one divide. + */ + u64 nsec = (u64)jiffies * TICK_NSEC; + value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec); +} +EXPORT_SYMBOL(jiffies_to_timespec); + +/* Same for "timeval" + * + * Well, almost. The problem here is that the real system resolution is + * in nanoseconds and the value being converted is in micro seconds. + * Also for some machines (those that use HZ = 1024, in-particular), + * there is a LARGE error in the tick size in microseconds. + + * The solution we use is to do the rounding AFTER we convert the + * microsecond part. Thus the USEC_ROUND, the bits to be shifted off. + * Instruction wise, this should cost only an additional add with carry + * instruction above the way it was done above. + */ +unsigned long +timeval_to_jiffies(const struct timeval *value) +{ + unsigned long sec = value->tv_sec; + long usec = value->tv_usec; + + if (sec >= MAX_SEC_IN_JIFFIES){ + sec = MAX_SEC_IN_JIFFIES; + usec = 0; + } + return (((u64)sec * SEC_CONVERSION) + + (((u64)usec * USEC_CONVERSION + USEC_ROUND) >> + (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; +} + +void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value) +{ + /* + * Convert jiffies to nanoseconds and separate with + * one divide. + */ + u64 nsec = (u64)jiffies * TICK_NSEC; + long tv_usec; + + value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tv_usec); + tv_usec /= NSEC_PER_USEC; + value->tv_usec = tv_usec; +} + +/* + * Convert jiffies/jiffies_64 to clock_t and back. + */ +clock_t jiffies_to_clock_t(long x) +{ +#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 + return x / (HZ / USER_HZ); +#else + u64 tmp = (u64)x * TICK_NSEC; + do_div(tmp, (NSEC_PER_SEC / USER_HZ)); + return (long)tmp; +#endif +} +EXPORT_SYMBOL(jiffies_to_clock_t); + +unsigned long clock_t_to_jiffies(unsigned long x) +{ +#if (HZ % USER_HZ)==0 + if (x >= ~0UL / (HZ / USER_HZ)) + return ~0UL; + return x * (HZ / USER_HZ); +#else + u64 jif; + + /* Don't worry about loss of precision here .. */ + if (x >= ~0UL / HZ * USER_HZ) + return ~0UL; + + /* .. but do try to contain it here */ + jif = x * (u64) HZ; + do_div(jif, USER_HZ); + return jif; +#endif +} +EXPORT_SYMBOL(clock_t_to_jiffies); + +u64 jiffies_64_to_clock_t(u64 x) +{ +#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 + do_div(x, HZ / USER_HZ); +#else + /* + * There are better ways that don't overflow early, + * but even this doesn't overflow in hundreds of years + * in 64 bits, so.. + */ + x *= TICK_NSEC; + do_div(x, (NSEC_PER_SEC / USER_HZ)); +#endif + return x; +} + +EXPORT_SYMBOL(jiffies_64_to_clock_t); + +u64 nsec_to_clock_t(u64 x) +{ +#if (NSEC_PER_SEC % USER_HZ) == 0 + do_div(x, (NSEC_PER_SEC / USER_HZ)); +#elif (USER_HZ % 512) == 0 + x *= USER_HZ/512; + do_div(x, (NSEC_PER_SEC / 512)); +#else + /* + * max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024, + * overflow after 64.99 years. + * exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ... + */ + x *= 9; + do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (USER_HZ/2)) / + USER_HZ)); +#endif + return x; +} + #if (BITS_PER_LONG < 64) u64 get_jiffies_64(void) { diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig new file mode 100644 index 0000000..f663511 --- /dev/null +++ b/kernel/time/Kconfig @@ -0,0 +1,25 @@ +# +# Timer subsystem related configuration options +# +config TICK_ONESHOT + bool + default n + +config NO_HZ + bool "Tickless System (Dynamic Ticks)" + depends on GENERIC_TIME && GENERIC_CLOCKEVENTS + select TICK_ONESHOT + help + This option enables a tickless system: timer interrupts will + only trigger on an as-needed basis both when the system is + busy and when the system is idle. + +config HIGH_RES_TIMERS + bool "High Resolution Timer Support" + depends on GENERIC_TIME && GENERIC_CLOCKEVENTS + select TICK_ONESHOT + help + This option enables high resolution timer support. If your + hardware is not capable then this option only increases + the size of the kernel image. + diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 61a3907..93bccba 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1 +1,8 @@ -obj-y += ntp.o clocksource.o jiffies.o +obj-y += ntp.o clocksource.o jiffies.o timer_list.o + +obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o +obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o +obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o +obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o +obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o +obj-$(CONFIG_TIMER_STATS) += timer_stats.o diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c new file mode 100644 index 0000000..67932ea --- /dev/null +++ b/kernel/time/clockevents.c @@ -0,0 +1,345 @@ +/* + * linux/kernel/time/clockevents.c + * + * This file contains functions which manage clock event devices. + * + * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> + * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner + * + * This code is licenced under the GPL version 2. For details see + * kernel-base/COPYING. + */ + +#include <linux/clockchips.h> +#include <linux/hrtimer.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/smp.h> +#include <linux/sysdev.h> + +/* The registered clock event devices */ +static LIST_HEAD(clockevent_devices); +static LIST_HEAD(clockevents_released); + +/* Notification for clock events */ +static RAW_NOTIFIER_HEAD(clockevents_chain); + +/* Protection for the above */ +static DEFINE_SPINLOCK(clockevents_lock); + +/** + * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds + * @latch: value to convert + * @evt: pointer to clock event device descriptor + * + * Math helper, returns latch value converted to nanoseconds (bound checked) + */ +unsigned long clockevent_delta2ns(unsigned long latch, + struct clock_event_device *evt) +{ + u64 clc = ((u64) latch << evt->shift); + + do_div(clc, evt->mult); + if (clc < 1000) + clc = 1000; + if (clc > LONG_MAX) + clc = LONG_MAX; + + return (unsigned long) clc; +} + +/** + * clockevents_set_mode - set the operating mode of a clock event device + * @dev: device to modify + * @mode: new mode + * + * Must be called with interrupts disabled ! + */ +void clockevents_set_mode(struct clock_event_device *dev, + enum clock_event_mode mode) +{ + if (dev->mode != mode) { + dev->set_mode(mode, dev); + dev->mode = mode; + } +} + +/** + * clockevents_program_event - Reprogram the clock event device. + * @expires: absolute expiry time (monotonic clock) + * + * Returns 0 on success, -ETIME when the event is in the past. + */ +int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, + ktime_t now) +{ + unsigned long long clc; + int64_t delta; + + delta = ktime_to_ns(ktime_sub(expires, now)); + + if (delta <= 0) + return -ETIME; + + dev->next_event = expires; + + if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN) + return 0; + + if (delta > dev->max_delta_ns) + delta = dev->max_delta_ns; + if (delta < dev->min_delta_ns) + delta = dev->min_delta_ns; + + clc = delta * dev->mult; + clc >>= dev->shift; + + return dev->set_next_event((unsigned long) clc, dev); +} + +/** + * clockevents_register_notifier - register a clock events change listener + */ +int clockevents_register_notifier(struct notifier_block *nb) +{ + int ret; + + spin_lock(&clockevents_lock); + ret = raw_notifier_chain_register(&clockevents_chain, nb); + spin_unlock(&clockevents_lock); + + return ret; +} + +/** + * clockevents_unregister_notifier - unregister a clock events change listener + */ +void clockevents_unregister_notifier(struct notifier_block *nb) +{ + spin_lock(&clockevents_lock); + raw_notifier_chain_unregister(&clockevents_chain, nb); + spin_unlock(&clockevents_lock); +} + +/* + * Notify about a clock event change. Called with clockevents_lock + * held. + */ +static void clockevents_do_notify(unsigned long reason, void *dev) +{ + raw_notifier_call_chain(&clockevents_chain, reason, dev); +} + +/* + * Called after a notify add to make devices availble which were + * released from the notifier call. + */ +static void clockevents_notify_released(void) +{ + struct clock_event_device *dev; + + while (!list_empty(&clockevents_released)) { + dev = list_entry(clockevents_released.next, + struct clock_event_device, list); + list_del(&dev->list); + list_add(&dev->list, &clockevent_devices); + clockevents_do_notify(CLOCK_EVT_NOTIFY_ADD, dev); + } +} + +/** + * clockevents_register_device - register a clock event device + * @dev: device to register + */ +void clockevents_register_device(struct clock_event_device *dev) +{ + BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); + + spin_lock(&clockevents_lock); + + list_add(&dev->list, &clockevent_devices); + clockevents_do_notify(CLOCK_EVT_NOTIFY_ADD, dev); + clockevents_notify_released(); + + spin_unlock(&clockevents_lock); +} + +/* + * Noop handler when we shut down an event device + */ +static void clockevents_handle_noop(struct clock_event_device *dev) +{ +} + +/** + * clockevents_exchange_device - release and request clock devices + * @old: device to release (can be NULL) + * @new: device to request (can be NULL) + * + * Called from the notifier chain. clockevents_lock is held already + */ +void clockevents_exchange_device(struct clock_event_device *old, + struct clock_event_device *new) +{ + unsigned long flags; + + local_irq_save(flags); + /* + * Caller releases a clock event device. We queue it into the + * released list and do a notify add later. + */ + if (old) { + old->event_handler = clockevents_handle_noop; + clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); + list_del(&old->list); + list_add(&old->list, &clockevents_released); + } + + if (new) { + BUG_ON(new->mode != CLOCK_EVT_MODE_UNUSED); + clockevents_set_mode(new, CLOCK_EVT_MODE_SHUTDOWN); + } + local_irq_restore(flags); +} + +/** + * clockevents_request_device + */ +struct clock_event_device *clockevents_request_device(unsigned int features, + cpumask_t cpumask) +{ + struct clock_event_device *cur, *dev = NULL; + struct list_head *tmp; + + spin_lock(&clockevents_lock); + + list_for_each(tmp, &clockevent_devices) { + cur = list_entry(tmp, struct clock_event_device, list); + + if ((cur->features & features) == features && + cpus_equal(cpumask, cur->cpumask)) { + if (!dev || dev->rating < cur->rating) + dev = cur; + } + } + + clockevents_exchange_device(NULL, dev); + + spin_unlock(&clockevents_lock); + + return dev; +} + +/** + * clockevents_release_device + */ +void clockevents_release_device(struct clock_event_device *dev) +{ + spin_lock(&clockevents_lock); + + clockevents_exchange_device(dev, NULL); + clockevents_notify_released(); + + spin_unlock(&clockevents_lock); +} + +/** + * clockevents_notify - notification about relevant events + */ +void clockevents_notify(unsigned long reason, void *arg) +{ + spin_lock(&clockevents_lock); + clockevents_do_notify(reason, arg); + + switch (reason) { + case CLOCK_EVT_NOTIFY_CPU_DEAD: + /* + * Unregister the clock event devices which were + * released from the users in the notify chain. + */ + while (!list_empty(&clockevents_released)) { + struct clock_event_device *dev; + + dev = list_entry(clockevents_released.next, + struct clock_event_device, list); + list_del(&dev->list); + } + break; + default: + break; + } + spin_unlock(&clockevents_lock); +} +EXPORT_SYMBOL_GPL(clockevents_notify); + +#ifdef CONFIG_SYSFS + +/** + * clockevents_show_registered - sysfs interface for listing clockevents + * @dev: unused + * @buf: char buffer to be filled with clock events list + * + * Provides sysfs interface for listing registered clock event devices + */ +static ssize_t clockevents_show_registered(struct sys_device *dev, char *buf) +{ + struct list_head *tmp; + char *p = buf; + int cpu; + + spin_lock(&clockevents_lock); + + list_for_each(tmp, &clockevent_devices) { + struct clock_event_device *ce; + + ce = list_entry(tmp, struct clock_event_device, list); + p += sprintf(p, "%-20s F:%04x M:%d", ce->name, + ce->features, ce->mode); + p += sprintf(p, " C:"); + if (!cpus_equal(ce->cpumask, cpu_possible_map)) { + for_each_cpu_mask(cpu, ce->cpumask) + p += sprintf(p, " %d", cpu); + } else { + /* + * FIXME: Add the cpu which is handling this sucker + */ + } + p += sprintf(p, "\n"); + } + + spin_unlock(&clockevents_lock); + + return p - buf; +} + +/* + * Sysfs setup bits: + */ +static SYSDEV_ATTR(registered, 0600, + clockevents_show_registered, NULL); + +static struct sysdev_class clockevents_sysclass = { + set_kset_name("clockevents"), +}; + +static struct sys_device clockevents_sys_device = { + .id = 0, + .cls = &clockevents_sysclass, +}; + +static int __init clockevents_sysfs_init(void) +{ + int error = sysdev_class_register(&clockevents_sysclass); + + if (!error) + error = sysdev_register(&clockevents_sys_device); + if (!error) + error = sysdev_create_file( + &clockevents_sys_device, + &attr_registered); + return error; +} +device_initcall(clockevents_sysfs_init); +#endif diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index d9ef176..193a079 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -29,6 +29,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ +#include <linux/tick.h> /* XXX - Would like a better way for initializing curr_clocksource */ extern struct clocksource clocksource_jiffies; @@ -48,6 +49,7 @@ extern struct clocksource clocksource_jiffies; */ static struct clocksource *curr_clocksource = &clocksource_jiffies; static struct clocksource *next_clocksource; +static struct clocksource *clocksource_override; static LIST_HEAD(clocksource_list); static DEFINE_SPINLOCK(clocksource_lock); static char override_name[32]; @@ -62,9 +64,123 @@ static int __init clocksource_done_booting(void) finished_booting = 1; return 0; } - late_initcall(clocksource_done_booting); +#ifdef CONFIG_CLOCKSOURCE_WATCHDOG +static LIST_HEAD(watchdog_list); +static struct clocksource *watchdog; +static struct timer_list watchdog_timer; +static DEFINE_SPINLOCK(watchdog_lock); +static cycle_t watchdog_last; +/* + * Interval: 0.5sec Treshold: 0.0625s + */ +#define WATCHDOG_INTERVAL (HZ >> 1) +#define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4) + +static void clocksource_ratewd(struct clocksource *cs, int64_t delta) +{ + if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD) + return; + + printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", + cs->name, delta); + cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); + clocksource_change_rating(cs, 0); + cs->flags &= ~CLOCK_SOURCE_WATCHDOG; + list_del(&cs->wd_list); +} + +static void clocksource_watchdog(unsigned long data) +{ + struct clocksource *cs, *tmp; + cycle_t csnow, wdnow; + int64_t wd_nsec, cs_nsec; + + spin_lock(&watchdog_lock); + + wdnow = watchdog->read(); + wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask); + watchdog_last = wdnow; + + list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) { + csnow = cs->read(); + /* Initialized ? */ + if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) { + if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && + (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { + cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; + /* + * We just marked the clocksource as + * highres-capable, notify the rest of the + * system as well so that we transition + * into high-res mode: + */ + tick_clock_notify(); + } + cs->flags |= CLOCK_SOURCE_WATCHDOG; + cs->wd_last = csnow; + } else { + cs_nsec = cyc2ns(cs, (csnow - cs->wd_last) & cs->mask); + cs->wd_last = csnow; + /* Check the delta. Might remove from the list ! */ + clocksource_ratewd(cs, cs_nsec - wd_nsec); + } + } + + if (!list_empty(&watchdog_list)) { + __mod_timer(&watchdog_timer, + watchdog_timer.expires + WATCHDOG_INTERVAL); + } + spin_unlock(&watchdog_lock); +} +static void clocksource_check_watchdog(struct clocksource *cs) +{ + struct clocksource *cse; + unsigned long flags; + + spin_lock_irqsave(&watchdog_lock, flags); + if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { + int started = !list_empty(&watchdog_list); + + list_add(&cs->wd_list, &watchdog_list); + if (!started && watchdog) { + watchdog_last = watchdog->read(); + watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL; + add_timer(&watchdog_timer); + } + } else if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) { + cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; + + if (!watchdog || cs->rating > watchdog->rating) { + if (watchdog) + del_timer(&watchdog_timer); + watchdog = cs; + init_timer(&watchdog_timer); + watchdog_timer.function = clocksource_watchdog; + + /* Reset watchdog cycles */ + list_for_each_entry(cse, &watchdog_list, wd_list) + cse->flags &= ~CLOCK_SOURCE_WATCHDOG; + /* Start if list is not empty */ + if (!list_empty(&watchdog_list)) { + watchdog_last = watchdog->read(); + watchdog_timer.expires = + jiffies + WATCHDOG_INTERVAL; + add_timer(&watchdog_timer); + } + } + } + spin_unlock_irqrestore(&watchdog_lock, flags); +} +#else +static void clocksource_check_watchdog(struct clocksource *cs) +{ + if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) + cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; +} +#endif + /** * clocksource_get_next - Returns the selected clocksource * @@ -84,60 +200,54 @@ struct clocksource *clocksource_get_next(void) } /** - * select_clocksource - Finds the best registered clocksource. + * select_clocksource - Selects the best registered clocksource. * * Private function. Must hold clocksource_lock when called. * - * Looks through the list of registered clocksources, returning - * the one with the highest rating value. If there is a clocksource - * name that matches the override string, it returns that clocksource. + * Select the clocksource with the best rating, or the clocksource, + * which is selected by userspace override. */ static struct clocksource *select_clocksource(void) { - struct clocksource *best = NULL; - struct list_head *tmp; + struct clocksource *next; - list_for_each(tmp, &clocksource_list) { - struct clocksource *src; + if (list_empty(&clocksource_list)) + return NULL; - src = list_entry(tmp, struct clocksource, list); - if (!best) - best = src; - - /* check for override: */ - if (strlen(src->name) == strlen(override_name) && - !strcmp(src->name, override_name)) { - best = src; - break; - } - /* pick the highest rating: */ - if (src->rating > best->rating) - best = src; - } + if (clocksource_override) + next = clocksource_override; + else + next = list_entry(clocksource_list.next, struct clocksource, + list); + + if (next == curr_clocksource) + return NULL; - return best; + return next; } -/** - * is_registered_source - Checks if clocksource is registered - * @c: pointer to a clocksource - * - * Private helper function. Must hold clocksource_lock when called. - * - * Returns one if the clocksource is already registered, zero otherwise. +/* + * Enqueue the clocksource sorted by rating */ -static int is_registered_source(struct clocksource *c) +static int clocksource_enqueue(struct clocksource *c) { - int len = strlen(c->name); - struct list_head *tmp; + struct list_head *tmp, *entry = &clocksource_list; list_for_each(tmp, &clocksource_list) { - struct clocksource *src; - - src = list_entry(tmp, struct clocksource, list); - if (strlen(src->name) == len && !strcmp(src->name, c->name)) - return 1; + struct clocksource *cs; + + cs = list_entry(tmp, struct clocksource, list); + if (cs == c) + return -EBUSY; + /* Keep track of the place, where to insert */ + if (cs->rating >= c->rating) + entry = tmp; } + list_add(&c->list, entry); + + if (strlen(c->name) == strlen(override_name) && + !strcmp(c->name, override_name)) + clocksource_override = c; return 0; } @@ -150,42 +260,35 @@ static int is_registered_source(struct clocksource *c) */ int clocksource_register(struct clocksource *c) { - int ret = 0; unsigned long flags; + int ret; spin_lock_irqsave(&clocksource_lock, flags); - /* check if clocksource is already registered */ - if (is_registered_source(c)) { - printk("register_clocksource: Cannot register %s. " - "Already registered!", c->name); - ret = -EBUSY; - } else { - /* register it */ - list_add(&c->list, &clocksource_list); - /* scan the registered clocksources, and pick the best one */ + ret = clocksource_enqueue(c); + if (!ret) next_clocksource = select_clocksource(); - } spin_unlock_irqrestore(&clocksource_lock, flags); + if (!ret) + clocksource_check_watchdog(c); return ret; } EXPORT_SYMBOL(clocksource_register); /** - * clocksource_reselect - Rescan list for next clocksource + * clocksource_change_rating - Change the rating of a registered clocksource * - * A quick helper function to be used if a clocksource changes its - * rating. Forces the clocksource list to be re-scanned for the best - * clocksource. */ -void clocksource_reselect(void) +void clocksource_change_rating(struct clocksource *cs, int rating) { unsigned long flags; spin_lock_irqsave(&clocksource_lock, flags); + list_del(&cs->list); + cs->rating = rating; + clocksource_enqueue(cs); next_clocksource = select_clocksource(); spin_unlock_irqrestore(&clocksource_lock, flags); } -EXPORT_SYMBOL(clocksource_reselect); #ifdef CONFIG_SYSFS /** @@ -221,7 +324,11 @@ sysfs_show_current_clocksources(struct sys_device *dev, char *buf) static ssize_t sysfs_override_clocksource(struct sys_device *dev, const char *buf, size_t count) { + struct clocksource *ovr = NULL; + struct list_head *tmp; size_t ret = count; + int len; + /* strings from sysfs write are not 0 terminated! */ if (count >= sizeof(override_name)) return -EINVAL; @@ -229,17 +336,32 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, /* strip of \n: */ if (buf[count-1] == '\n') count--; - if (count < 1) - return -EINVAL; spin_lock_irq(&clocksource_lock); - /* copy the name given: */ - memcpy(override_name, buf, count); + if (count > 0) + memcpy(override_name, buf, count); override_name[count] = 0; - /* try to select it: */ - next_clocksource = select_clocksource(); + len = strlen(override_name); + if (len) { + ovr = clocksource_override; + /* try to select it: */ + list_for_each(tmp, &clocksource_list) { + struct clocksource *cs; + + cs = list_entry(tmp, struct clocksource, list); + if (strlen(cs->name) == len && + !strcmp(cs->name, override_name)) + ovr = cs; + } + } + + /* Reselect, when the override name has changed */ + if (ovr != clocksource_override) { + clocksource_override = ovr; + next_clocksource = select_clocksource(); + } spin_unlock_irq(&clocksource_lock); diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index a99b2a6..3be8da8 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -62,7 +62,6 @@ struct clocksource clocksource_jiffies = { .mask = 0xffffffff, /*32bits*/ .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */ .shift = JIFFIES_SHIFT, - .is_continuous = 0, /* tick based, not free running */ }; static int __init init_jiffies_clocksource(void) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 3afeaa3..eb12509 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -24,7 +24,7 @@ static u64 tick_length, tick_length_base; #define MAX_TICKADJ 500 /* microsecs */ #define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \ - TICK_LENGTH_SHIFT) / HZ) + TICK_LENGTH_SHIFT) / NTP_INTERVAL_FREQ) /* * phase-lock loop variables @@ -46,13 +46,17 @@ long time_adjust; static void ntp_update_frequency(void) { - tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT; - tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT; - tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC); + u64 second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) + << TICK_LENGTH_SHIFT; + second_length += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT; + second_length += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC); - do_div(tick_length_base, HZ); + tick_length_base = second_length; - tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT; + do_div(second_length, HZ); + tick_nsec = second_length >> TICK_LENGTH_SHIFT; + + do_div(tick_length_base, NTP_INTERVAL_FREQ); } /** @@ -162,7 +166,7 @@ void second_overflow(void) tick_length -= MAX_TICKADJ_SCALED; } else { tick_length += (s64)(time_adjust * NSEC_PER_USEC / - HZ) << TICK_LENGTH_SHIFT; + NTP_INTERVAL_FREQ) << TICK_LENGTH_SHIFT; time_adjust = 0; } } @@ -239,7 +243,8 @@ int do_adjtimex(struct timex *txc) result = -EINVAL; goto leave; } - time_freq = ((s64)txc->freq * NSEC_PER_USEC) >> (SHIFT_USEC - SHIFT_NSEC); + time_freq = ((s64)txc->freq * NSEC_PER_USEC) + >> (SHIFT_USEC - SHIFT_NSEC); } if (txc->modes & ADJ_MAXERROR) { @@ -309,7 +314,8 @@ int do_adjtimex(struct timex *txc) freq_adj += time_freq; freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC); - time_offset = (time_offset / HZ) << SHIFT_UPDATE; + time_offset = (time_offset / NTP_INTERVAL_FREQ) + << SHIFT_UPDATE; } /* STA_PLL */ } /* txc->modes & ADJ_OFFSET */ if (txc->modes & ADJ_TICK) @@ -324,8 +330,10 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) txc->offset = save_adjust; else - txc->offset = shift_right(time_offset, SHIFT_UPDATE) * HZ / 1000; - txc->freq = (time_freq / NSEC_PER_USEC) << (SHIFT_USEC - SHIFT_NSEC); + txc->offset = shift_right(time_offset, SHIFT_UPDATE) + * NTP_INTERVAL_FREQ / 1000; + txc->freq = (time_freq / NSEC_PER_USEC) + << (SHIFT_USEC - SHIFT_NSEC); txc->maxerror = time_maxerror; txc->esterror = time_esterror; txc->status = time_status; diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c new file mode 100644 index 0000000..12b3efe --- /dev/null +++ b/kernel/time/tick-broadcast.c @@ -0,0 +1,480 @@ +/* + * linux/kernel/time/tick-broadcast.c + * + * This file contains functions which emulate a local clock-event + * device via a broadcast event source. + * + * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> + * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner + * + * This code is licenced under the GPL version 2. For details see + * kernel-base/COPYING. + */ +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/hrtimer.h> +#include <linux/irq.h> +#include <linux/percpu.h> +#include <linux/profile.h> +#include <linux/sched.h> +#include <linux/tick.h> + +#include "tick-internal.h" + +/* + * Broadcast support for broken x86 hardware, where the local apic + * timer stops in C3 state. + */ + +struct tick_device tick_broadcast_device; +static cpumask_t tick_broadcast_mask; +static DEFINE_SPINLOCK(tick_broadcast_lock); + +/* + * Debugging: see timer_list.c + */ +struct tick_device *tick_get_broadcast_device(void) +{ + return &tick_broadcast_device; +} + +cpumask_t *tick_get_broadcast_mask(void) +{ + return &tick_broadcast_mask; +} + +/* + * Start the device in periodic mode + */ +static void tick_broadcast_start_periodic(struct clock_event_device *bc) +{ + if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN) + tick_setup_periodic(bc, 1); +} + +/* + * Check, if the device can be utilized as broadcast device: + */ +int tick_check_broadcast_device(struct clock_event_device *dev) +{ + if (tick_broadcast_device.evtdev || + (dev->features & CLOCK_EVT_FEAT_C3STOP)) + return 0; + + clockevents_exchange_device(NULL, dev); + tick_broadcast_device.evtdev = dev; + if (!cpus_empty(tick_broadcast_mask)) + tick_broadcast_start_periodic(dev); + return 1; +} + +/* + * Check, if the device is the broadcast device + */ +int tick_is_broadcast_device(struct clock_event_device *dev) +{ + return (dev && tick_broadcast_device.evtdev == dev); +} + +/* + * Check, if the device is disfunctional and a place holder, which + * needs to be handled by the broadcast device. + */ +int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + /* + * Devices might be registered with both periodic and oneshot + * mode disabled. This signals, that the device needs to be + * operated from the broadcast device and is a placeholder for + * the cpu local device. + */ + if (!tick_device_is_functional(dev)) { + dev->event_handler = tick_handle_periodic; + cpu_set(cpu, tick_broadcast_mask); + tick_broadcast_start_periodic(tick_broadcast_device.evtdev); + ret = 1; + } + + spin_unlock_irqrestore(&tick_broadcast_lock, flags); + return ret; +} + +/* + * Broadcast the event to the cpus, which are set in the mask + */ +int tick_do_broadcast(cpumask_t mask) +{ + int ret = 0, cpu = smp_processor_id(); + struct tick_device *td; + + /* + * Check, if the current cpu is in the mask + */ + if (cpu_isset(cpu, mask)) { + cpu_clear(cpu, mask); + td = &per_cpu(tick_cpu_device, cpu); + td->evtdev->event_handler(td->evtdev); + ret = 1; + } + + if (!cpus_empty(mask)) { + /* + * It might be necessary to actually check whether the devices + * have different broadcast functions. For now, just use the + * one of the first device. This works as long as we have this + * misfeature only on x86 (lapic) + */ + cpu = first_cpu(mask); + td = &per_cpu(tick_cpu_device, cpu); + td->evtdev->broadcast(mask); + ret = 1; + } + return ret; +} + +/* + * Periodic broadcast: + * - invoke the broadcast handlers + */ +static void tick_do_periodic_broadcast(void) +{ + cpumask_t mask; + + spin_lock(&tick_broadcast_lock); + + cpus_and(mask, cpu_online_map, tick_broadcast_mask); + tick_do_broadcast(mask); + + spin_unlock(&tick_broadcast_lock); +} + +/* + * Event handler for periodic broadcast ticks + */ +static void tick_handle_periodic_broadcast(struct clock_event_device *dev) +{ + dev->next_event.tv64 = KTIME_MAX; + + tick_do_periodic_broadcast(); + + /* + * The device is in periodic mode. No reprogramming necessary: + */ + if (dev->mode == CLOCK_EVT_MODE_PERIODIC) + return; + + /* + * Setup the next period for devices, which do not have + * periodic mode: + */ + for (;;) { + ktime_t next = ktime_add(dev->next_event, tick_period); + + if (!clockevents_program_event(dev, next, ktime_get())) + return; + tick_do_periodic_broadcast(); + } +} + +/* + * Powerstate information: The system enters/leaves a state, where + * affected devices might stop + */ +static void tick_do_broadcast_on_off(void *why) +{ + struct clock_event_device *bc, *dev; + struct tick_device *td; + unsigned long flags, *reason = why; + int cpu; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + cpu = smp_processor_id(); + td = &per_cpu(tick_cpu_device, cpu); + dev = td->evtdev; + bc = tick_broadcast_device.evtdev; + + /* + * Is the device in broadcast mode forever or is it not + * affected by the powerstate ? + */ + if (!dev || !tick_device_is_functional(dev) || + !(dev->features & CLOCK_EVT_FEAT_C3STOP)) + goto out; + + if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) { + if (!cpu_isset(cpu, tick_broadcast_mask)) { + cpu_set(cpu, tick_broadcast_mask); + if (td->mode == TICKDEV_MODE_PERIODIC) + clockevents_set_mode(dev, + CLOCK_EVT_MODE_SHUTDOWN); + } + } else { + if (cpu_isset(cpu, tick_broadcast_mask)) { + cpu_clear(cpu, tick_broadcast_mask); + if (td->mode == TICKDEV_MODE_PERIODIC) + tick_setup_periodic(dev, 0); + } + } + + if (cpus_empty(tick_broadcast_mask)) + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); + else { + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) + tick_broadcast_start_periodic(bc); + else + tick_broadcast_setup_oneshot(bc); + } +out: + spin_unlock_irqrestore(&tick_broadcast_lock, flags); +} + +/* + * Powerstate information: The system enters/leaves a state, where + * affected devices might stop. + */ +void tick_broadcast_on_off(unsigned long reason, int *oncpu) +{ + int cpu = get_cpu(); + + if (cpu == *oncpu) + tick_do_broadcast_on_off(&reason); + else + smp_call_function_single(*oncpu, tick_do_broadcast_on_off, + &reason, 1, 1); + put_cpu(); +} + +/* + * Set the periodic handler depending on broadcast on/off + */ +void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast) +{ + if (!broadcast) + dev->event_handler = tick_handle_periodic; + else + dev->event_handler = tick_handle_periodic_broadcast; +} + +/* + * Remove a CPU from broadcasting + */ +void tick_shutdown_broadcast(unsigned int *cpup) +{ + struct clock_event_device *bc; + unsigned long flags; + unsigned int cpu = *cpup; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + bc = tick_broadcast_device.evtdev; + cpu_clear(cpu, tick_broadcast_mask); + + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { + if (bc && cpus_empty(tick_broadcast_mask)) + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); + } + + spin_unlock_irqrestore(&tick_broadcast_lock, flags); +} + +#ifdef CONFIG_TICK_ONESHOT + +static cpumask_t tick_broadcast_oneshot_mask; + +/* + * Debugging: see timer_list.c + */ +cpumask_t *tick_get_broadcast_oneshot_mask(void) +{ + return &tick_broadcast_oneshot_mask; +} + +static int tick_broadcast_set_event(ktime_t expires, int force) +{ + struct clock_event_device *bc = tick_broadcast_device.evtdev; + ktime_t now = ktime_get(); + int res; + + for(;;) { + res = clockevents_program_event(bc, expires, now); + if (!res || !force) + return res; + now = ktime_get(); + expires = ktime_add(now, ktime_set(0, bc->min_delta_ns)); + } +} + +/* + * Reprogram the broadcast device: + * + * Called with tick_broadcast_lock held and interrupts disabled. + */ +static int tick_broadcast_reprogram(void) +{ + ktime_t expires = { .tv64 = KTIME_MAX }; + struct tick_device *td; + int cpu; + + /* + * Find the event which expires next: + */ + for (cpu = first_cpu(tick_broadcast_oneshot_mask); cpu != NR_CPUS; + cpu = next_cpu(cpu, tick_broadcast_oneshot_mask)) { + td = &per_cpu(tick_cpu_device, cpu); + if (td->evtdev->next_event.tv64 < expires.tv64) + expires = td->evtdev->next_event; + } + + if (expires.tv64 == KTIME_MAX) + return 0; + + return tick_broadcast_set_event(expires, 0); +} + +/* + * Handle oneshot mode broadcasting + */ +static void tick_handle_oneshot_broadcast(struct clock_event_device *dev) +{ + struct tick_device *td; + cpumask_t mask; + ktime_t now; + int cpu; + + spin_lock(&tick_broadcast_lock); +again: + dev->next_event.tv64 = KTIME_MAX; + mask = CPU_MASK_NONE; + now = ktime_get(); + /* Find all expired events */ + for (cpu = first_cpu(tick_broadcast_oneshot_mask); cpu != NR_CPUS; + cpu = next_cpu(cpu, tick_broadcast_oneshot_mask)) { + td = &per_cpu(tick_cpu_device, cpu); + if (td->evtdev->next_event.tv64 <= now.tv64) + cpu_set(cpu, mask); + } + + /* + * Wakeup the cpus which have an expired event. The broadcast + * device is reprogrammed in the return from idle code. + */ + if (!tick_do_broadcast(mask)) { + /* + * The global event did not expire any CPU local + * events. This happens in dyntick mode, as the + * maximum PIT delta is quite small. + */ + if (tick_broadcast_reprogram()) + goto again; + } + spin_unlock(&tick_broadcast_lock); +} + +/* + * Powerstate information: The system enters/leaves a state, where + * affected devices might stop + */ +void tick_broadcast_oneshot_control(unsigned long reason) +{ + struct clock_event_device *bc, *dev; + struct tick_device *td; + unsigned long flags; + int cpu; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + /* + * Periodic mode does not care about the enter/exit of power + * states + */ + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) + goto out; + + bc = tick_broadcast_device.evtdev; + cpu = smp_processor_id(); + td = &per_cpu(tick_cpu_device, cpu); + dev = td->evtdev; + + if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) + goto out; + + if (reason == CLOCK_EVT_NOTIFY_BROADCAST_ENTER) { + if (!cpu_isset(cpu, tick_broadcast_oneshot_mask)) { + cpu_set(cpu, tick_broadcast_oneshot_mask); + clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN); + if (dev->next_event.tv64 < bc->next_event.tv64) + tick_broadcast_set_event(dev->next_event, 1); + } + } else { + if (cpu_isset(cpu, tick_broadcast_oneshot_mask)) { + cpu_clear(cpu, tick_broadcast_oneshot_mask); + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); + if (dev->next_event.tv64 != KTIME_MAX) + tick_program_event(dev->next_event, 1); + } + } + +out: + spin_unlock_irqrestore(&tick_broadcast_lock, flags); +} + +/** + * tick_broadcast_setup_highres - setup the broadcast device for highres + */ +void tick_broadcast_setup_oneshot(struct clock_event_device *bc) +{ + if (bc->mode != CLOCK_EVT_MODE_ONESHOT) { + bc->event_handler = tick_handle_oneshot_broadcast; + clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); + bc->next_event.tv64 = KTIME_MAX; + } +} + +/* + * Select oneshot operating mode for the broadcast device + */ +void tick_broadcast_switch_to_oneshot(void) +{ + struct clock_event_device *bc; + unsigned long flags; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + tick_broadcast_device.mode = TICKDEV_MODE_ONESHOT; + bc = tick_broadcast_device.evtdev; + if (bc) + tick_broadcast_setup_oneshot(bc); + spin_unlock_irqrestore(&tick_broadcast_lock, flags); +} + + +/* + * Remove a dead CPU from broadcasting + */ +void tick_shutdown_broadcast_oneshot(unsigned int *cpup) +{ + struct clock_event_device *bc; + unsigned long flags; + unsigned int cpu = *cpup; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + bc = tick_broadcast_device.evtdev; + cpu_clear(cpu, tick_broadcast_oneshot_mask); + + if (tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT) { + if (bc && cpus_empty(tick_broadcast_oneshot_mask)) + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); + } + + spin_unlock_irqrestore(&tick_broadcast_lock, flags); +} + +#endif diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c new file mode 100644 index 0000000..4500e34 --- /dev/null +++ b/kernel/time/tick-common.c @@ -0,0 +1,346 @@ +/* + * linux/kernel/time/tick-common.c + * + * This file contains the base functions to manage periodic tick + * related events. + * + * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> + * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner + * + * This code is licenced under the GPL version 2. For details see + * kernel-base/COPYING. + */ +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/hrtimer.h> +#include <linux/irq.h> +#include <linux/percpu.h> +#include <linux/profile.h> +#include <linux/sched.h> +#include <linux/tick.h> + +#include "tick-internal.h" + +/* + * Tick devices + */ +DEFINE_PER_CPU(struct tick_device, tick_cpu_device); +/* + * Tick next event: keeps track of the tick time + */ +ktime_t tick_next_period; +ktime_t tick_period; +static int tick_do_timer_cpu = -1; +DEFINE_SPINLOCK(tick_device_lock); + +/* + * Debugging: see timer_list.c + */ +struct tick_device *tick_get_device(int cpu) +{ + return &per_cpu(tick_cpu_device, cpu); +} + +/** + * tick_is_oneshot_available - check for a oneshot capable event device + */ +int tick_is_oneshot_available(void) +{ + struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + + return dev && (dev->features & CLOCK_EVT_FEAT_ONESHOT); +} + +/* + * Periodic tick + */ +static void tick_periodic(int cpu) +{ + if (tick_do_timer_cpu == cpu) { + write_seqlock(&xtime_lock); + + /* Keep track of the next tick event */ + tick_next_period = ktime_add(tick_next_period, tick_period); + + do_timer(1); + write_sequnlock(&xtime_lock); + } + + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); +} + +/* + * Event handler for periodic ticks + */ +void tick_handle_periodic(struct clock_event_device *dev) +{ + int cpu = smp_processor_id(); + + tick_periodic(cpu); + + if (dev->mode != CLOCK_EVT_MODE_ONESHOT) + return; + /* + * Setup the next period for devices, which do not have + * periodic mode: + */ + for (;;) { + ktime_t next = ktime_add(dev->next_event, tick_period); + + if (!clockevents_program_event(dev, next, ktime_get())) + return; + tick_periodic(cpu); + } +} + +/* + * Setup the device for a periodic tick + */ +void tick_setup_periodic(struct clock_event_device *dev, int broadcast) +{ + tick_set_periodic_handler(dev, broadcast); + + /* Broadcast setup ? */ + if (!tick_device_is_functional(dev)) + return; + + if (dev->features & CLOCK_EVT_FEAT_PERIODIC) { + clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC); + } else { + unsigned long seq; + ktime_t next; + + do { + seq = read_seqbegin(&xtime_lock); + next = tick_next_period; + } while (read_seqretry(&xtime_lock, seq)); + + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); + + for (;;) { + if (!clockevents_program_event(dev, next, ktime_get())) + return; + next = ktime_add(next, tick_period); + } + } +} + +/* + * Setup the tick device + */ +static void tick_setup_device(struct tick_device *td, + struct clock_event_device *newdev, int cpu, + cpumask_t cpumask) +{ + ktime_t next_event; + void (*handler)(struct clock_event_device *) = NULL; + + /* + * First device setup ? + */ + if (!td->evtdev) { + /* + * If no cpu took the do_timer update, assign it to + * this cpu: + */ + if (tick_do_timer_cpu == -1) { + tick_do_timer_cpu = cpu; + tick_next_period = ktime_get(); + tick_period = ktime_set(0, NSEC_PER_SEC / HZ); + } + + /* + * Startup in periodic mode first. + */ + td->mode = TICKDEV_MODE_PERIODIC; + } else { + handler = td->evtdev->event_handler; + next_event = td->evtdev->next_event; + } + + td->evtdev = newdev; + + /* + * When the device is not per cpu, pin the interrupt to the + * current cpu: + */ + if (!cpus_equal(newdev->cpumask, cpumask)) + irq_set_affinity(newdev->irq, cpumask); + + /* + * When global broadcasting is active, check if the current + * device is registered as a placeholder for broadcast mode. + * This allows us to handle this x86 misfeature in a generic + * way. + */ + if (tick_device_uses_broadcast(newdev, cpu)) + return; + + if (td->mode == TICKDEV_MODE_PERIODIC) + tick_setup_periodic(newdev, 0); + else + tick_setup_oneshot(newdev, handler, next_event); +} + +/* + * Check, if the new registered device should be used. + */ +static int tick_check_new_device(struct clock_event_device *newdev) +{ + struct clock_event_device *curdev; + struct tick_device *td; + int cpu, ret = NOTIFY_OK; + unsigned long flags; + cpumask_t cpumask; + + spin_lock_irqsave(&tick_device_lock, flags); + + cpu = smp_processor_id(); + if (!cpu_isset(cpu, newdev->cpumask)) + goto out; + + td = &per_cpu(tick_cpu_device, cpu); + curdev = td->evtdev; + cpumask = cpumask_of_cpu(cpu); + + /* cpu local device ? */ + if (!cpus_equal(newdev->cpumask, cpumask)) { + + /* + * If the cpu affinity of the device interrupt can not + * be set, ignore it. + */ + if (!irq_can_set_affinity(newdev->irq)) + goto out_bc; + + /* + * If we have a cpu local device already, do not replace it + * by a non cpu local device + */ + if (curdev && cpus_equal(curdev->cpumask, cpumask)) + goto out_bc; + } + + /* + * If we have an active device, then check the rating and the oneshot + * feature. + */ + if (curdev) { + /* + * Prefer one shot capable devices ! + */ + if ((curdev->features & CLOCK_EVT_FEAT_ONESHOT) && + !(newdev->features & CLOCK_EVT_FEAT_ONESHOT)) + goto out_bc; + /* + * Check the rating + */ + if (curdev->rating >= newdev->rating) + goto out_bc; + } + + /* + * Replace the eventually existing device by the new + * device. If the current device is the broadcast device, do + * not give it back to the clockevents layer ! + */ + if (tick_is_broadcast_device(curdev)) { + clockevents_set_mode(curdev, CLOCK_EVT_MODE_SHUTDOWN); + curdev = NULL; + } + clockevents_exchange_device(curdev, newdev); + tick_setup_device(td, newdev, cpu, cpumask); + if (newdev->features & CLOCK_EVT_FEAT_ONESHOT) + tick_oneshot_notify(); + + spin_unlock_irqrestore(&tick_device_lock, flags); + return NOTIFY_STOP; + +out_bc: + /* + * Can the new device be used as a broadcast device ? + */ + if (tick_check_broadcast_device(newdev)) + ret = NOTIFY_STOP; +out: + spin_unlock_irqrestore(&tick_device_lock, flags); + + return ret; +} + +/* + * Shutdown an event device on a given cpu: + * + * This is called on a life CPU, when a CPU is dead. So we cannot + * access the hardware device itself. + * We just set the mode and remove it from the lists. + */ +static void tick_shutdown(unsigned int *cpup) +{ + struct tick_device *td = &per_cpu(tick_cpu_device, *cpup); + struct clock_event_device *dev = td->evtdev; + unsigned long flags; + + spin_lock_irqsave(&tick_device_lock, flags); + td->mode = TICKDEV_MODE_PERIODIC; + if (dev) { + /* + * Prevent that the clock events layer tries to call + * the set mode function! + */ + dev->mode = CLOCK_EVT_MODE_UNUSED; + clockevents_exchange_device(dev, NULL); + td->evtdev = NULL; + } + spin_unlock_irqrestore(&tick_device_lock, flags); +} + +/* + * Notification about clock event devices + */ +static int tick_notify(struct notifier_block *nb, unsigned long reason, + void *dev) +{ + switch (reason) { + + case CLOCK_EVT_NOTIFY_ADD: + return tick_check_new_device(dev); + + case CLOCK_EVT_NOTIFY_BROADCAST_ON: + case CLOCK_EVT_NOTIFY_BROADCAST_OFF: + tick_broadcast_on_off(reason, dev); + break; + + case CLOCK_EVT_NOTIFY_BROADCAST_ENTER: + case CLOCK_EVT_NOTIFY_BROADCAST_EXIT: + tick_broadcast_oneshot_control(reason); + break; + + case CLOCK_EVT_NOTIFY_CPU_DEAD: + tick_shutdown_broadcast_oneshot(dev); + tick_shutdown_broadcast(dev); + tick_shutdown(dev); + break; + + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block tick_notifier = { + .notifier_call = tick_notify, +}; + +/** + * tick_init - initialize the tick control + * + * Register the notifier with the clockevents framework + */ +void __init tick_init(void) +{ + clockevents_register_notifier(&tick_notifier); +} diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h new file mode 100644 index 0000000..54861a0 --- /dev/null +++ b/kernel/time/tick-internal.h @@ -0,0 +1,110 @@ +/* + * tick internal variable and functions used by low/high res code + */ +DECLARE_PER_CPU(struct tick_device, tick_cpu_device); +extern spinlock_t tick_device_lock; +extern ktime_t tick_next_period; +extern ktime_t tick_period; + +extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast); +extern void tick_handle_periodic(struct clock_event_device *dev); + +/* + * NO_HZ / high resolution timer shared code + */ +#ifdef CONFIG_TICK_ONESHOT +extern void tick_setup_oneshot(struct clock_event_device *newdev, + void (*handler)(struct clock_event_device *), + ktime_t nextevt); +extern int tick_program_event(ktime_t expires, int force); +extern void tick_oneshot_notify(void); +extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); + +# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc); +extern void tick_broadcast_oneshot_control(unsigned long reason); +extern void tick_broadcast_switch_to_oneshot(void); +extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); +# else /* BROADCAST */ +static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) +{ + BUG(); +} +static inline void tick_broadcast_oneshot_control(unsigned long reason) { } +static inline void tick_broadcast_switch_to_oneshot(void) { } +static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } +# endif /* !BROADCAST */ + +#else /* !ONESHOT */ +static inline +void tick_setup_oneshot(struct clock_event_device *newdev, + void (*handler)(struct clock_event_device *), + ktime_t nextevt) +{ + BUG(); +} +static inline int tick_program_event(ktime_t expires, int force) +{ + return 0; +} +static inline void tick_oneshot_notify(void) { } +static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) +{ + BUG(); +} +static inline void tick_broadcast_oneshot_control(unsigned long reason) { } +static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } +#endif /* !TICK_ONESHOT */ + +/* + * Broadcasting support + */ +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +extern int tick_do_broadcast(cpumask_t mask); + +extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu); +extern int tick_check_broadcast_device(struct clock_event_device *dev); +extern int tick_is_broadcast_device(struct clock_event_device *dev); +extern void tick_broadcast_on_off(unsigned long reason, int *oncpu); +extern void tick_shutdown_broadcast(unsigned int *cpup); + +extern void +tick_set_periodic_handler(struct clock_event_device *dev, int broadcast); + +#else /* !BROADCAST */ + +static inline int tick_check_broadcast_device(struct clock_event_device *dev) +{ + return 0; +} + +static inline int tick_is_broadcast_device(struct clock_event_device *dev) +{ + return 0; +} +static inline int tick_device_uses_broadcast(struct clock_event_device *dev, + int cpu) +{ + return 0; +} +static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } +static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { } +static inline void tick_shutdown_broadcast(unsigned int *cpup) { } + +/* + * Set the periodic handler in non broadcast mode + */ +static inline void tick_set_periodic_handler(struct clock_event_device *dev, + int broadcast) +{ + dev->event_handler = tick_handle_periodic; +} +#endif /* !BROADCAST */ + +/* + * Check, if the device is functional or a dummy for broadcast + */ +static inline int tick_device_is_functional(struct clock_event_device *dev) +{ + return !(dev->features & CLOCK_EVT_FEAT_DUMMY); +} diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c new file mode 100644 index 0000000..2e8b7ff --- /dev/null +++ b/kernel/time/tick-oneshot.c @@ -0,0 +1,84 @@ +/* + * linux/kernel/time/tick-oneshot.c + * + * This file contains functions which manage high resolution tick + * related events. + * + * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> + * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner + * + * This code is licenced under the GPL version 2. For details see + * kernel-base/COPYING. + */ +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/hrtimer.h> +#include <linux/irq.h> +#include <linux/percpu.h> +#include <linux/profile.h> +#include <linux/sched.h> +#include <linux/tick.h> + +#include "tick-internal.h" + +/** + * tick_program_event + */ +int tick_program_event(ktime_t expires, int force) +{ + struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + ktime_t now = ktime_get(); + + while (1) { + int ret = clockevents_program_event(dev, expires, now); + + if (!ret || !force) + return ret; + now = ktime_get(); + expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); + } +} + +/** + * tick_setup_oneshot - setup the event device for oneshot mode (hres or nohz) + */ +void tick_setup_oneshot(struct clock_event_device *newdev, + void (*handler)(struct clock_event_device *), + ktime_t next_event) +{ + newdev->event_handler = handler; + clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); + clockevents_program_event(newdev, next_event, ktime_get()); +} + +/** + * tick_switch_to_oneshot - switch to oneshot mode + */ +int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) +{ + struct tick_device *td = &__get_cpu_var(tick_cpu_device); + struct clock_event_device *dev = td->evtdev; + + if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || + !tick_device_is_functional(dev)) + return -EINVAL; + + td->mode = TICKDEV_MODE_ONESHOT; + dev->event_handler = handler; + clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); + tick_broadcast_switch_to_oneshot(); + return 0; +} + +#ifdef CONFIG_HIGH_RES_TIMERS +/** + * tick_init_highres - switch to high resolution mode + * + * Called with interrupts disabled. + */ +int tick_init_highres(void) +{ + return tick_switch_to_oneshot(hrtimer_interrupt); +} +#endif diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c new file mode 100644 index 0000000..95e41f7f --- /dev/null +++ b/kernel/time/tick-sched.c @@ -0,0 +1,563 @@ +/* + * linux/kernel/time/tick-sched.c + * + * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> + * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006-2007 Timesys Corp., Thomas Gleixner + * + * No idle tick implementation for low and high resolution timers + * + * Started by: Thomas Gleixner and Ingo Molnar + * + * For licencing details see kernel-base/COPYING + */ +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/hrtimer.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/percpu.h> +#include <linux/profile.h> +#include <linux/sched.h> +#include <linux/tick.h> + +#include "tick-internal.h" + +/* + * Per cpu nohz control structure + */ +static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched); + +/* + * The time, when the last jiffy update happened. Protected by xtime_lock. + */ +static ktime_t last_jiffies_update; + +struct tick_sched *tick_get_tick_sched(int cpu) +{ + return &per_cpu(tick_cpu_sched, cpu); +} + +/* + * Must be called with interrupts disabled ! + */ +static void tick_do_update_jiffies64(ktime_t now) +{ + unsigned long ticks = 0; + ktime_t delta; + + /* Reevalute with xtime_lock held */ + write_seqlock(&xtime_lock); + + delta = ktime_sub(now, last_jiffies_update); + if (delta.tv64 >= tick_period.tv64) { + + delta = ktime_sub(delta, tick_period); + last_jiffies_update = ktime_add(last_jiffies_update, + tick_period); + + /* Slow path for long timeouts */ + if (unlikely(delta.tv64 >= tick_period.tv64)) { + s64 incr = ktime_to_ns(tick_period); + + ticks = ktime_divns(delta, incr); + + last_jiffies_update = ktime_add_ns(last_jiffies_update, + incr * ticks); + } + do_timer(++ticks); + } + write_sequnlock(&xtime_lock); +} + +/* + * Initialize and return retrieve the jiffies update. + */ +static ktime_t tick_init_jiffy_update(void) +{ + ktime_t period; + + write_seqlock(&xtime_lock); + /* Did we start the jiffies update yet ? */ + if (last_jiffies_update.tv64 == 0) + last_jiffies_update = tick_next_period; + period = last_jiffies_update; + write_sequnlock(&xtime_lock); + return period; +} + +/* + * NOHZ - aka dynamic tick functionality + */ +#ifdef CONFIG_NO_HZ +/* + * NO HZ enabled ? + */ +static int tick_nohz_enabled __read_mostly = 1; + +/* + * Enable / Disable tickless mode + */ +static int __init setup_tick_nohz(char *str) +{ + if (!strcmp(str, "off")) + tick_nohz_enabled = 0; + else if (!strcmp(str, "on")) + tick_nohz_enabled = 1; + else + return 0; + return 1; +} + +__setup("nohz=", setup_tick_nohz); + +/** + * tick_nohz_update_jiffies - update jiffies when idle was interrupted + * + * Called from interrupt entry when the CPU was idle + * + * In case the sched_tick was stopped on this CPU, we have to check if jiffies + * must be updated. Otherwise an interrupt handler could use a stale jiffy + * value. We do this unconditionally on any cpu, as we don't know whether the + * cpu, which has the update task assigned is in a long sleep. + */ +void tick_nohz_update_jiffies(void) +{ + int cpu = smp_processor_id(); + struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + unsigned long flags; + ktime_t now; + + if (!ts->tick_stopped) + return; + + cpu_clear(cpu, nohz_cpu_mask); + now = ktime_get(); + + local_irq_save(flags); + tick_do_update_jiffies64(now); + local_irq_restore(flags); +} + +/** + * tick_nohz_stop_sched_tick - stop the idle tick from the idle task + * + * When the next event is more than a tick into the future, stop the idle tick + * Called either from the idle loop or from irq_exit() when an idle period was + * just interrupted by an interrupt which did not cause a reschedule. + */ +void tick_nohz_stop_sched_tick(void) +{ + unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags; + struct tick_sched *ts; + ktime_t last_update, expires, now, delta; + int cpu; + + local_irq_save(flags); + + cpu = smp_processor_id(); + ts = &per_cpu(tick_cpu_sched, cpu); + + if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) + goto end; + + if (need_resched()) + goto end; + + cpu = smp_processor_id(); + BUG_ON(local_softirq_pending()); + + now = ktime_get(); + /* + * When called from irq_exit we need to account the idle sleep time + * correctly. + */ + if (ts->tick_stopped) { + delta = ktime_sub(now, ts->idle_entrytime); + ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta); + } + + ts->idle_entrytime = now; + ts->idle_calls++; + + /* Read jiffies and the time when jiffies were updated last */ + do { + seq = read_seqbegin(&xtime_lock); + last_update = last_jiffies_update; + last_jiffies = jiffies; + } while (read_seqretry(&xtime_lock, seq)); + + /* Get the next timer wheel timer */ + next_jiffies = get_next_timer_interrupt(last_jiffies); + delta_jiffies = next_jiffies - last_jiffies; + + /* + * Do not stop the tick, if we are only one off + * or if the cpu is required for rcu + */ + if (!ts->tick_stopped && (delta_jiffies == 1 || rcu_needs_cpu(cpu))) + goto out; + + /* Schedule the tick, if we are at least one jiffie off */ + if ((long)delta_jiffies >= 1) { + + if (rcu_needs_cpu(cpu)) + delta_jiffies = 1; + else + cpu_set(cpu, nohz_cpu_mask); + /* + * nohz_stop_sched_tick can be called several times before + * the nohz_restart_sched_tick is called. This happens when + * interrupts arrive which do not cause a reschedule. In the + * first call we save the current tick time, so we can restart + * the scheduler tick in nohz_restart_sched_tick. + */ + if (!ts->tick_stopped) { + ts->idle_tick = ts->sched_timer.expires; + ts->tick_stopped = 1; + ts->idle_jiffies = last_jiffies; + } + /* + * calculate the expiry time for the next timer wheel + * timer + */ + expires = ktime_add_ns(last_update, tick_period.tv64 * + delta_jiffies); + ts->idle_expires = expires; + ts->idle_sleeps++; + + if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { + hrtimer_start(&ts->sched_timer, expires, + HRTIMER_MODE_ABS); + /* Check, if the timer was already in the past */ + if (hrtimer_active(&ts->sched_timer)) + goto out; + } else if(!tick_program_event(expires, 0)) + goto out; + /* + * We are past the event already. So we crossed a + * jiffie boundary. Update jiffies and raise the + * softirq. + */ + tick_do_update_jiffies64(ktime_get()); + cpu_clear(cpu, nohz_cpu_mask); + } + raise_softirq_irqoff(TIMER_SOFTIRQ); +out: + ts->next_jiffies = next_jiffies; + ts->last_jiffies = last_jiffies; +end: + local_irq_restore(flags); +} + +/** + * nohz_restart_sched_tick - restart the idle tick from the idle task + * + * Restart the idle tick when the CPU is woken up from idle + */ +void tick_nohz_restart_sched_tick(void) +{ + int cpu = smp_processor_id(); + struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + unsigned long ticks; + ktime_t now, delta; + + if (!ts->tick_stopped) + return; + + /* Update jiffies first */ + now = ktime_get(); + + local_irq_disable(); + tick_do_update_jiffies64(now); + cpu_clear(cpu, nohz_cpu_mask); + + /* Account the idle time */ + delta = ktime_sub(now, ts->idle_entrytime); + ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta); + + /* + * We stopped the tick in idle. Update process times would miss the + * time we slept as update_process_times does only a 1 tick + * accounting. Enforce that this is accounted to idle ! + */ + ticks = jiffies - ts->idle_jiffies; + /* + * We might be one off. Do not randomly account a huge number of ticks! + */ + if (ticks && ticks < LONG_MAX) { + add_preempt_count(HARDIRQ_OFFSET); + account_system_time(current, HARDIRQ_OFFSET, + jiffies_to_cputime(ticks)); + sub_preempt_count(HARDIRQ_OFFSET); + } + + /* + * Cancel the scheduled timer and restore the tick + */ + ts->tick_stopped = 0; + hrtimer_cancel(&ts->sched_timer); + ts->sched_timer.expires = ts->idle_tick; + + while (1) { + /* Forward the time to expire in the future */ + hrtimer_forward(&ts->sched_timer, now, tick_period); + + if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { + hrtimer_start(&ts->sched_timer, + ts->sched_timer.expires, + HRTIMER_MODE_ABS); + /* Check, if the timer was already in the past */ + if (hrtimer_active(&ts->sched_timer)) + break; + } else { + if (!tick_program_event(ts->sched_timer.expires, 0)) + break; + } + /* Update jiffies and reread time */ + tick_do_update_jiffies64(now); + now = ktime_get(); + } + local_irq_enable(); +} + +static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now) +{ + hrtimer_forward(&ts->sched_timer, now, tick_period); + return tick_program_event(ts->sched_timer.expires, 0); +} + +/* + * The nohz low res interrupt handler + */ +static void tick_nohz_handler(struct clock_event_device *dev) +{ + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct pt_regs *regs = get_irq_regs(); + ktime_t now = ktime_get(); + + dev->next_event.tv64 = KTIME_MAX; + + /* Check, if the jiffies need an update */ + tick_do_update_jiffies64(now); + + /* + * When we are idle and the tick is stopped, we have to touch + * the watchdog as we might not schedule for a really long + * time. This happens on complete idle SMP systems while + * waiting on the login prompt. We also increment the "start + * of idle" jiffy stamp so the idle accounting adjustment we + * do when we go busy again does not account too much ticks. + */ + if (ts->tick_stopped) { + touch_softlockup_watchdog(); + ts->idle_jiffies++; + } + + update_process_times(user_mode(regs)); + profile_tick(CPU_PROFILING); + + /* Do not restart, when we are in the idle loop */ + if (ts->tick_stopped) + return; + + while (tick_nohz_reprogram(ts, now)) { + now = ktime_get(); + tick_do_update_jiffies64(now); + } +} + +/** + * tick_nohz_switch_to_nohz - switch to nohz mode + */ +static void tick_nohz_switch_to_nohz(void) +{ + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + ktime_t next; + + if (!tick_nohz_enabled) + return; + + local_irq_disable(); + if (tick_switch_to_oneshot(tick_nohz_handler)) { + local_irq_enable(); + return; + } + + ts->nohz_mode = NOHZ_MODE_LOWRES; + + /* + * Recycle the hrtimer in ts, so we can share the + * hrtimer_forward with the highres code. + */ + hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + /* Get the next period */ + next = tick_init_jiffy_update(); + + for (;;) { + ts->sched_timer.expires = next; + if (!tick_program_event(next, 0)) + break; + next = ktime_add(next, tick_period); + } + local_irq_enable(); + + printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", + smp_processor_id()); +} + +#else + +static inline void tick_nohz_switch_to_nohz(void) { } + +#endif /* NO_HZ */ + +/* + * High resolution timer specific code + */ +#ifdef CONFIG_HIGH_RES_TIMERS +/* + * We rearm the timer until we get disabled by the idle code + * Called with interrupts disabled and timer->base->cpu_base->lock held. + */ +static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) +{ + struct tick_sched *ts = + container_of(timer, struct tick_sched, sched_timer); + struct hrtimer_cpu_base *base = timer->base->cpu_base; + struct pt_regs *regs = get_irq_regs(); + ktime_t now = ktime_get(); + + /* Check, if the jiffies need an update */ + tick_do_update_jiffies64(now); + + /* + * Do not call, when we are not in irq context and have + * no valid regs pointer + */ + if (regs) { + /* + * When we are idle and the tick is stopped, we have to touch + * the watchdog as we might not schedule for a really long + * time. This happens on complete idle SMP systems while + * waiting on the login prompt. We also increment the "start of + * idle" jiffy stamp so the idle accounting adjustment we do + * when we go busy again does not account too much ticks. + */ + if (ts->tick_stopped) { + touch_softlockup_watchdog(); + ts->idle_jiffies++; + } + /* + * update_process_times() might take tasklist_lock, hence + * drop the base lock. sched-tick hrtimers are per-CPU and + * never accessible by userspace APIs, so this is safe to do. + */ + spin_unlock(&base->lock); + update_process_times(user_mode(regs)); + profile_tick(CPU_PROFILING); + spin_lock(&base->lock); + } + + /* Do not restart, when we are in the idle loop */ + if (ts->tick_stopped) + return HRTIMER_NORESTART; + + hrtimer_forward(timer, now, tick_period); + + return HRTIMER_RESTART; +} + +/** + * tick_setup_sched_timer - setup the tick emulation timer + */ +void tick_setup_sched_timer(void) +{ + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + ktime_t now = ktime_get(); + + /* + * Emulate tick processing via per-CPU hrtimers: + */ + hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + ts->sched_timer.function = tick_sched_timer; + ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ; + + /* Get the next period */ + ts->sched_timer.expires = tick_init_jiffy_update(); + + for (;;) { + hrtimer_forward(&ts->sched_timer, now, tick_period); + hrtimer_start(&ts->sched_timer, ts->sched_timer.expires, + HRTIMER_MODE_ABS); + /* Check, if the timer was already in the past */ + if (hrtimer_active(&ts->sched_timer)) + break; + now = ktime_get(); + } + +#ifdef CONFIG_NO_HZ + if (tick_nohz_enabled) + ts->nohz_mode = NOHZ_MODE_HIGHRES; +#endif +} + +void tick_cancel_sched_timer(int cpu) +{ + struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + + if (ts->sched_timer.base) + hrtimer_cancel(&ts->sched_timer); + ts->tick_stopped = 0; + ts->nohz_mode = NOHZ_MODE_INACTIVE; +} +#endif /* HIGH_RES_TIMERS */ + +/** + * Async notification about clocksource changes + */ +void tick_clock_notify(void) +{ + int cpu; + + for_each_possible_cpu(cpu) + set_bit(0, &per_cpu(tick_cpu_sched, cpu).check_clocks); +} + +/* + * Async notification about clock event changes + */ +void tick_oneshot_notify(void) +{ + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + + set_bit(0, &ts->check_clocks); +} + +/** + * Check, if a change happened, which makes oneshot possible. + * + * Called cyclic from the hrtimer softirq (driven by the timer + * softirq) allow_nohz signals, that we can switch into low-res nohz + * mode, because high resolution timers are disabled (either compile + * or runtime). + */ +int tick_check_oneshot_change(int allow_nohz) +{ + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + + if (!test_and_clear_bit(0, &ts->check_clocks)) + return 0; + + if (ts->nohz_mode != NOHZ_MODE_INACTIVE) + return 0; + + if (!timekeeping_is_continuous() || !tick_is_oneshot_available()) + return 0; + + if (!allow_nohz) + return 1; + + tick_nohz_switch_to_nohz(); + return 0; +} diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c new file mode 100644 index 0000000..f82c635 --- /dev/null +++ b/kernel/time/timer_list.c @@ -0,0 +1,287 @@ +/* + * kernel/time/timer_list.c + * + * List pending timers + * + * Copyright(C) 2006, Red Hat, Inc., Ingo Molnar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/proc_fs.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/kallsyms.h> +#include <linux/tick.h> + +#include <asm/uaccess.h> + +typedef void (*print_fn_t)(struct seq_file *m, unsigned int *classes); + +DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases); + +/* + * This allows printing both to /proc/timer_list and + * to the console (on SysRq-Q): + */ +#define SEQ_printf(m, x...) \ + do { \ + if (m) \ + seq_printf(m, x); \ + else \ + printk(x); \ + } while (0) + +static void print_name_offset(struct seq_file *m, void *sym) +{ + unsigned long addr = (unsigned long)sym; + char namebuf[KSYM_NAME_LEN+1]; + unsigned long size, offset; + const char *sym_name; + char *modname; + + sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf); + if (sym_name) + SEQ_printf(m, "%s", sym_name); + else + SEQ_printf(m, "<%p>", sym); +} + +static void +print_timer(struct seq_file *m, struct hrtimer *timer, int idx, u64 now) +{ +#ifdef CONFIG_TIMER_STATS + char tmp[TASK_COMM_LEN + 1]; +#endif + SEQ_printf(m, " #%d: ", idx); + print_name_offset(m, timer); + SEQ_printf(m, ", "); + print_name_offset(m, timer->function); + SEQ_printf(m, ", S:%02lx", timer->state); +#ifdef CONFIG_TIMER_STATS + SEQ_printf(m, ", "); + print_name_offset(m, timer->start_site); + memcpy(tmp, timer->start_comm, TASK_COMM_LEN); + tmp[TASK_COMM_LEN] = 0; + SEQ_printf(m, ", %s/%d", tmp, timer->start_pid); +#endif + SEQ_printf(m, "\n"); + SEQ_printf(m, " # expires at %Ld nsecs [in %Ld nsecs]\n", + (unsigned long long)ktime_to_ns(timer->expires), + (unsigned long long)(ktime_to_ns(timer->expires) - now)); +} + +static void +print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, + u64 now) +{ + struct hrtimer *timer, tmp; + unsigned long next = 0, i; + struct rb_node *curr; + unsigned long flags; + +next_one: + i = 0; + spin_lock_irqsave(&base->cpu_base->lock, flags); + + curr = base->first; + /* + * Crude but we have to do this O(N*N) thing, because + * we have to unlock the base when printing: + */ + while (curr && i < next) { + curr = rb_next(curr); + i++; + } + + if (curr) { + + timer = rb_entry(curr, struct hrtimer, node); + tmp = *timer; + spin_unlock_irqrestore(&base->cpu_base->lock, flags); + + print_timer(m, &tmp, i, now); + next++; + goto next_one; + } + spin_unlock_irqrestore(&base->cpu_base->lock, flags); +} + +static void +print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) +{ + SEQ_printf(m, " .index: %d\n", + base->index); + SEQ_printf(m, " .resolution: %Ld nsecs\n", + (unsigned long long)ktime_to_ns(base->resolution)); + SEQ_printf(m, " .get_time: "); + print_name_offset(m, base->get_time); + SEQ_printf(m, "\n"); +#ifdef CONFIG_HIGH_RES_TIMERS + SEQ_printf(m, " .offset: %Ld nsecs\n", + ktime_to_ns(base->offset)); +#endif + SEQ_printf(m, "active timers:\n"); + print_active_timers(m, base, now); +} + +static void print_cpu(struct seq_file *m, int cpu, u64 now) +{ + struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); + int i; + + SEQ_printf(m, "\ncpu: %d\n", cpu); + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { + SEQ_printf(m, " clock %d:\n", i); + print_base(m, cpu_base->clock_base + i, now); + } +#define P(x) \ + SEQ_printf(m, " .%-15s: %Ld\n", #x, (u64)(cpu_base->x)) +#define P_ns(x) \ + SEQ_printf(m, " .%-15s: %Ld nsecs\n", #x, \ + (u64)(ktime_to_ns(cpu_base->x))) + +#ifdef CONFIG_HIGH_RES_TIMERS + P_ns(expires_next); + P(hres_active); + P(nr_events); +#endif +#undef P +#undef P_ns + +#ifdef CONFIG_TICK_ONESHOT +# define P(x) \ + SEQ_printf(m, " .%-15s: %Ld\n", #x, (u64)(ts->x)) +# define P_ns(x) \ + SEQ_printf(m, " .%-15s: %Ld nsecs\n", #x, \ + (u64)(ktime_to_ns(ts->x))) + { + struct tick_sched *ts = tick_get_tick_sched(cpu); + P(nohz_mode); + P_ns(idle_tick); + P(tick_stopped); + P(idle_jiffies); + P(idle_calls); + P(idle_sleeps); + P_ns(idle_entrytime); + P_ns(idle_sleeptime); + P(last_jiffies); + P(next_jiffies); + P_ns(idle_expires); + SEQ_printf(m, "jiffies: %Ld\n", (u64)jiffies); + } +#endif + +#undef P +#undef P_ns +} + +#ifdef CONFIG_GENERIC_CLOCKEVENTS +static void +print_tickdevice(struct seq_file *m, struct tick_device *td) +{ + struct clock_event_device *dev = td->evtdev; + + SEQ_printf(m, "\nTick Device: mode: %d\n", td->mode); + + SEQ_printf(m, "Clock Event Device: "); + if (!dev) { + SEQ_printf(m, "<NULL>\n"); + return; + } + SEQ_printf(m, "%s\n", dev->name); + SEQ_printf(m, " max_delta_ns: %ld\n", dev->max_delta_ns); + SEQ_printf(m, " min_delta_ns: %ld\n", dev->min_delta_ns); + SEQ_printf(m, " mult: %ld\n", dev->mult); + SEQ_printf(m, " shift: %d\n", dev->shift); + SEQ_printf(m, " mode: %d\n", dev->mode); + SEQ_printf(m, " next_event: %Ld nsecs\n", + (unsigned long long) ktime_to_ns(dev->next_event)); + + SEQ_printf(m, " set_next_event: "); + print_name_offset(m, dev->set_next_event); + SEQ_printf(m, "\n"); + + SEQ_printf(m, " set_mode: "); + print_name_offset(m, dev->set_mode); + SEQ_printf(m, "\n"); + + SEQ_printf(m, " event_handler: "); + print_name_offset(m, dev->event_handler); + SEQ_printf(m, "\n"); +} + +static void timer_list_show_tickdevices(struct seq_file *m) +{ + int cpu; + +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + print_tickdevice(m, tick_get_broadcast_device()); + SEQ_printf(m, "tick_broadcast_mask: %08lx\n", + tick_get_broadcast_mask()->bits[0]); +#ifdef CONFIG_TICK_ONESHOT + SEQ_printf(m, "tick_broadcast_oneshot_mask: %08lx\n", + tick_get_broadcast_oneshot_mask()->bits[0]); +#endif + SEQ_printf(m, "\n"); +#endif + for_each_online_cpu(cpu) + print_tickdevice(m, tick_get_device(cpu)); + SEQ_printf(m, "\n"); +} +#else +static void timer_list_show_tickdevices(struct seq_file *m) { } +#endif + +static int timer_list_show(struct seq_file *m, void *v) +{ + u64 now = ktime_to_ns(ktime_get()); + int cpu; + + SEQ_printf(m, "Timer List Version: v0.3\n"); + SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES); + SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now); + + for_each_online_cpu(cpu) + print_cpu(m, cpu, now); + + SEQ_printf(m, "\n"); + timer_list_show_tickdevices(m); + + return 0; +} + +void sysrq_timer_list_show(void) +{ + timer_list_show(NULL, NULL); +} + +static int timer_list_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, timer_list_show, NULL); +} + +static struct file_operations timer_list_fops = { + .open = timer_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init init_timer_list_procfs(void) +{ + struct proc_dir_entry *pe; + + pe = create_proc_entry("timer_list", 0644, NULL); + if (!pe) + return -ENOMEM; + + pe->proc_fops = &timer_list_fops; + + return 0; +} +__initcall(init_timer_list_procfs); diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c new file mode 100644 index 0000000..1bc4882 --- /dev/null +++ b/kernel/time/timer_stats.c @@ -0,0 +1,411 @@ +/* + * kernel/time/timer_stats.c + * + * Collect timer usage statistics. + * + * Copyright(C) 2006, Red Hat, Inc., Ingo Molnar + * Copyright(C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com> + * + * timer_stats is based on timer_top, a similar functionality which was part of + * Con Kolivas dyntick patch set. It was developed by Daniel Petrini at the + * Instituto Nokia de Tecnologia - INdT - Manaus. timer_top's design was based + * on dynamic allocation of the statistics entries and linear search based + * lookup combined with a global lock, rather than the static array, hash + * and per-CPU locking which is used by timer_stats. It was written for the + * pre hrtimer kernel code and therefore did not take hrtimers into account. + * Nevertheless it provided the base for the timer_stats implementation and + * was a helpful source of inspiration. Kudos to Daniel and the Nokia folks + * for this effort. + * + * timer_top.c is + * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus + * Written by Daniel Petrini <d.pensator@gmail.com> + * timer_top.c was released under the GNU General Public License version 2 + * + * We export the addresses and counting of timer functions being called, + * the pid and cmdline from the owner process if applicable. + * + * Start/stop data collection: + * # echo 1[0] >/proc/timer_stats + * + * Display the information collected so far: + * # cat /proc/timer_stats + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/proc_fs.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/kallsyms.h> + +#include <asm/uaccess.h> + +/* + * This is our basic unit of interest: a timer expiry event identified + * by the timer, its start/expire functions and the PID of the task that + * started the timer. We count the number of times an event happens: + */ +struct entry { + /* + * Hash list: + */ + struct entry *next; + + /* + * Hash keys: + */ + void *timer; + void *start_func; + void *expire_func; + pid_t pid; + + /* + * Number of timeout events: + */ + unsigned long count; + + /* + * We save the command-line string to preserve + * this information past task exit: + */ + char comm[TASK_COMM_LEN + 1]; + +} ____cacheline_aligned_in_smp; + +/* + * Spinlock protecting the tables - not taken during lookup: + */ +static DEFINE_SPINLOCK(table_lock); + +/* + * Per-CPU lookup locks for fast hash lookup: + */ +static DEFINE_PER_CPU(spinlock_t, lookup_lock); + +/* + * Mutex to serialize state changes with show-stats activities: + */ +static DEFINE_MUTEX(show_mutex); + +/* + * Collection status, active/inactive: + */ +static int __read_mostly active; + +/* + * Beginning/end timestamps of measurement: + */ +static ktime_t time_start, time_stop; + +/* + * tstat entry structs only get allocated while collection is + * active and never freed during that time - this simplifies + * things quite a bit. + * + * They get freed when a new collection period is started. + */ +#define MAX_ENTRIES_BITS 10 +#define MAX_ENTRIES (1UL << MAX_ENTRIES_BITS) + +static unsigned long nr_entries; +static struct entry entries[MAX_ENTRIES]; + +static atomic_t overflow_count; + +static void reset_entries(void) +{ + nr_entries = 0; + memset(entries, 0, sizeof(entries)); + atomic_set(&overflow_count, 0); +} + +static struct entry *alloc_entry(void) +{ + if (nr_entries >= MAX_ENTRIES) + return NULL; + + return entries + nr_entries++; +} + +/* + * The entries are in a hash-table, for fast lookup: + */ +#define TSTAT_HASH_BITS (MAX_ENTRIES_BITS - 1) +#define TSTAT_HASH_SIZE (1UL << TSTAT_HASH_BITS) +#define TSTAT_HASH_MASK (TSTAT_HASH_SIZE - 1) + +#define __tstat_hashfn(entry) \ + (((unsigned long)(entry)->timer ^ \ + (unsigned long)(entry)->start_func ^ \ + (unsigned long)(entry)->expire_func ^ \ + (unsigned long)(entry)->pid ) & TSTAT_HASH_MASK) + +#define tstat_hashentry(entry) (tstat_hash_table + __tstat_hashfn(entry)) + +static struct entry *tstat_hash_table[TSTAT_HASH_SIZE] __read_mostly; + +static int match_entries(struct entry *entry1, struct entry *entry2) +{ + return entry1->timer == entry2->timer && + entry1->start_func == entry2->start_func && + entry1->expire_func == entry2->expire_func && + entry1->pid == entry2->pid; +} + +/* + * Look up whether an entry matching this item is present + * in the hash already. Must be called with irqs off and the + * lookup lock held: + */ +static struct entry *tstat_lookup(struct entry *entry, char *comm) +{ + struct entry **head, *curr, *prev; + + head = tstat_hashentry(entry); + curr = *head; + + /* + * The fastpath is when the entry is already hashed, + * we do this with the lookup lock held, but with the + * table lock not held: + */ + while (curr) { + if (match_entries(curr, entry)) + return curr; + + curr = curr->next; + } + /* + * Slowpath: allocate, set up and link a new hash entry: + */ + prev = NULL; + curr = *head; + + spin_lock(&table_lock); + /* + * Make sure we have not raced with another CPU: + */ + while (curr) { + if (match_entries(curr, entry)) + goto out_unlock; + + prev = curr; + curr = curr->next; + } + + curr = alloc_entry(); + if (curr) { + *curr = *entry; + curr->count = 0; + memcpy(curr->comm, comm, TASK_COMM_LEN); + if (prev) + prev->next = curr; + else + *head = curr; + curr->next = NULL; + } + out_unlock: + spin_unlock(&table_lock); + + return curr; +} + +/** + * timer_stats_update_stats - Update the statistics for a timer. + * @timer: pointer to either a timer_list or a hrtimer + * @pid: the pid of the task which set up the timer + * @startf: pointer to the function which did the timer setup + * @timerf: pointer to the timer callback function of the timer + * @comm: name of the process which set up the timer + * + * When the timer is already registered, then the event counter is + * incremented. Otherwise the timer is registered in a free slot. + */ +void timer_stats_update_stats(void *timer, pid_t pid, void *startf, + void *timerf, char * comm) +{ + /* + * It doesnt matter which lock we take: + */ + spinlock_t *lock = &per_cpu(lookup_lock, raw_smp_processor_id()); + struct entry *entry, input; + unsigned long flags; + + input.timer = timer; + input.start_func = startf; + input.expire_func = timerf; + input.pid = pid; + + spin_lock_irqsave(lock, flags); + if (!active) + goto out_unlock; + + entry = tstat_lookup(&input, comm); + if (likely(entry)) + entry->count++; + else + atomic_inc(&overflow_count); + + out_unlock: + spin_unlock_irqrestore(lock, flags); +} + +static void print_name_offset(struct seq_file *m, unsigned long addr) +{ + char namebuf[KSYM_NAME_LEN+1]; + unsigned long size, offset; + const char *sym_name; + char *modname; + + sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf); + if (sym_name) + seq_printf(m, "%s", sym_name); + else + seq_printf(m, "<%p>", (void *)addr); +} + +static int tstats_show(struct seq_file *m, void *v) +{ + struct timespec period; + struct entry *entry; + unsigned long ms; + long events = 0; + ktime_t time; + int i; + + mutex_lock(&show_mutex); + /* + * If still active then calculate up to now: + */ + if (active) + time_stop = ktime_get(); + + time = ktime_sub(time_stop, time_start); + + period = ktime_to_timespec(time); + ms = period.tv_nsec / 1000000; + + seq_puts(m, "Timer Stats Version: v0.1\n"); + seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms); + if (atomic_read(&overflow_count)) + seq_printf(m, "Overflow: %d entries\n", + atomic_read(&overflow_count)); + + for (i = 0; i < nr_entries; i++) { + entry = entries + i; + seq_printf(m, "%4lu, %5d %-16s ", + entry->count, entry->pid, entry->comm); + + print_name_offset(m, (unsigned long)entry->start_func); + seq_puts(m, " ("); + print_name_offset(m, (unsigned long)entry->expire_func); + seq_puts(m, ")\n"); + + events += entry->count; + } + + ms += period.tv_sec * 1000; + if (!ms) + ms = 1; + + if (events && period.tv_sec) + seq_printf(m, "%ld total events, %ld.%ld events/sec\n", events, + events / period.tv_sec, events * 1000 / ms); + else + seq_printf(m, "%ld total events\n", events); + + mutex_unlock(&show_mutex); + + return 0; +} + +/* + * After a state change, make sure all concurrent lookup/update + * activities have stopped: + */ +static void sync_access(void) +{ + unsigned long flags; + int cpu; + + for_each_online_cpu(cpu) { + spin_lock_irqsave(&per_cpu(lookup_lock, cpu), flags); + /* nothing */ + spin_unlock_irqrestore(&per_cpu(lookup_lock, cpu), flags); + } +} + +static ssize_t tstats_write(struct file *file, const char __user *buf, + size_t count, loff_t *offs) +{ + char ctl[2]; + + if (count != 2 || *offs) + return -EINVAL; + + if (copy_from_user(ctl, buf, count)) + return -EFAULT; + + mutex_lock(&show_mutex); + switch (ctl[0]) { + case '0': + if (active) { + active = 0; + time_stop = ktime_get(); + sync_access(); + } + break; + case '1': + if (!active) { + reset_entries(); + time_start = ktime_get(); + active = 1; + } + break; + default: + count = -EINVAL; + } + mutex_unlock(&show_mutex); + + return count; +} + +static int tstats_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, tstats_show, NULL); +} + +static struct file_operations tstats_fops = { + .open = tstats_open, + .read = seq_read, + .write = tstats_write, + .llseek = seq_lseek, + .release = seq_release, +}; + +void __init init_timer_stats(void) +{ + int cpu; + + for_each_possible_cpu(cpu) + spin_lock_init(&per_cpu(lookup_lock, cpu)); +} + +static int __init init_tstats_procfs(void) +{ + struct proc_dir_entry *pe; + + pe = create_proc_entry("timer_stats", 0644, NULL); + if (!pe) + return -ENOMEM; + + pe->proc_fops = &tstats_fops; + + return 0; +} +__initcall(init_tstats_procfs); diff --git a/kernel/timer.c b/kernel/timer.c index 8533c37..cb1b86a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -34,6 +34,8 @@ #include <linux/cpu.h> #include <linux/syscalls.h> #include <linux/delay.h> +#include <linux/tick.h> +#include <linux/kallsyms.h> #include <asm/uaccess.h> #include <asm/unistd.h> @@ -262,6 +264,18 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer) list_add_tail(&timer->entry, vec); } +#ifdef CONFIG_TIMER_STATS +void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr) +{ + if (timer->start_site) + return; + + timer->start_site = addr; + memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); + timer->start_pid = current->pid; +} +#endif + /** * init_timer - initialize a timer. * @timer: the timer to be initialized @@ -273,11 +287,16 @@ void fastcall init_timer(struct timer_list *timer) { timer->entry.next = NULL; timer->base = __raw_get_cpu_var(tvec_bases); +#ifdef CONFIG_TIMER_STATS + timer->start_site = NULL; + timer->start_pid = -1; + memset(timer->start_comm, 0, TASK_COMM_LEN); +#endif } EXPORT_SYMBOL(init_timer); static inline void detach_timer(struct timer_list *timer, - int clear_pending) + int clear_pending) { struct list_head *entry = &timer->entry; @@ -324,6 +343,7 @@ int __mod_timer(struct timer_list *timer, unsigned long expires) unsigned long flags; int ret = 0; + timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); base = lock_timer_base(timer, &flags); @@ -374,6 +394,7 @@ void add_timer_on(struct timer_list *timer, int cpu) tvec_base_t *base = per_cpu(tvec_bases, cpu); unsigned long flags; + timer_stats_timer_set_start_info(timer); BUG_ON(timer_pending(timer) || !timer->function); spin_lock_irqsave(&base->lock, flags); timer->base = base; @@ -406,6 +427,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires) { BUG_ON(!timer->function); + timer_stats_timer_set_start_info(timer); /* * This is a common optimization triggered by the * networking code - if the timer is re-modified @@ -436,6 +458,7 @@ int del_timer(struct timer_list *timer) unsigned long flags; int ret = 0; + timer_stats_timer_clear_start_info(timer); if (timer_pending(timer)) { base = lock_timer_base(timer, &flags); if (timer_pending(timer)) { @@ -569,6 +592,8 @@ static inline void __run_timers(tvec_base_t *base) fn = timer->function; data = timer->data; + timer_stats_account_timer(timer); + set_running_timer(base, timer); detach_timer(timer, 1); spin_unlock_irq(&base->lock); @@ -591,105 +616,124 @@ static inline void __run_timers(tvec_base_t *base) spin_unlock_irq(&base->lock); } -#ifdef CONFIG_NO_IDLE_HZ +#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ) /* * Find out when the next timer event is due to happen. This * is used on S/390 to stop all activity when a cpus is idle. * This functions needs to be called disabled. */ -unsigned long next_timer_interrupt(void) +static unsigned long __next_timer_interrupt(tvec_base_t *base) { - tvec_base_t *base; - struct list_head *list; + unsigned long timer_jiffies = base->timer_jiffies; + unsigned long expires = timer_jiffies + (LONG_MAX >> 1); + int index, slot, array, found = 0; struct timer_list *nte; - unsigned long expires; - unsigned long hr_expires = MAX_JIFFY_OFFSET; - ktime_t hr_delta; tvec_t *varray[4]; - int i, j; - - hr_delta = hrtimer_get_next_event(); - if (hr_delta.tv64 != KTIME_MAX) { - struct timespec tsdelta; - tsdelta = ktime_to_timespec(hr_delta); - hr_expires = timespec_to_jiffies(&tsdelta); - if (hr_expires < 3) - return hr_expires + jiffies; - } - hr_expires += jiffies; - - base = __get_cpu_var(tvec_bases); - spin_lock(&base->lock); - expires = base->timer_jiffies + (LONG_MAX >> 1); - list = NULL; /* Look for timer events in tv1. */ - j = base->timer_jiffies & TVR_MASK; + index = slot = timer_jiffies & TVR_MASK; do { - list_for_each_entry(nte, base->tv1.vec + j, entry) { + list_for_each_entry(nte, base->tv1.vec + slot, entry) { + found = 1; expires = nte->expires; - if (j < (base->timer_jiffies & TVR_MASK)) - list = base->tv2.vec + (INDEX(0)); - goto found; + /* Look at the cascade bucket(s)? */ + if (!index || slot < index) + goto cascade; + return expires; } - j = (j + 1) & TVR_MASK; - } while (j != (base->timer_jiffies & TVR_MASK)); + slot = (slot + 1) & TVR_MASK; + } while (slot != index); + +cascade: + /* Calculate the next cascade event */ + if (index) + timer_jiffies += TVR_SIZE - index; + timer_jiffies >>= TVR_BITS; /* Check tv2-tv5. */ varray[0] = &base->tv2; varray[1] = &base->tv3; varray[2] = &base->tv4; varray[3] = &base->tv5; - for (i = 0; i < 4; i++) { - j = INDEX(i); + + for (array = 0; array < 4; array++) { + tvec_t *varp = varray[array]; + + index = slot = timer_jiffies & TVN_MASK; do { - if (list_empty(varray[i]->vec + j)) { - j = (j + 1) & TVN_MASK; - continue; - } - list_for_each_entry(nte, varray[i]->vec + j, entry) + list_for_each_entry(nte, varp->vec + slot, entry) { + found = 1; if (time_before(nte->expires, expires)) expires = nte->expires; - if (j < (INDEX(i)) && i < 3) - list = varray[i + 1]->vec + (INDEX(i + 1)); - goto found; - } while (j != (INDEX(i))); - } -found: - if (list) { - /* - * The search wrapped. We need to look at the next list - * from next tv element that would cascade into tv element - * where we found the timer element. - */ - list_for_each_entry(nte, list, entry) { - if (time_before(nte->expires, expires)) - expires = nte->expires; - } + } + /* + * Do we still search for the first timer or are + * we looking up the cascade buckets ? + */ + if (found) { + /* Look at the cascade bucket(s)? */ + if (!index || slot < index) + break; + return expires; + } + slot = (slot + 1) & TVN_MASK; + } while (slot != index); + + if (index) + timer_jiffies += TVN_SIZE - index; + timer_jiffies >>= TVN_BITS; } - spin_unlock(&base->lock); + return expires; +} - /* - * It can happen that other CPUs service timer IRQs and increment - * jiffies, but we have not yet got a local timer tick to process - * the timer wheels. In that case, the expiry time can be before - * jiffies, but since the high-resolution timer here is relative to - * jiffies, the default expression when high-resolution timers are - * not active, - * - * time_before(MAX_JIFFY_OFFSET + jiffies, expires) - * - * would falsely evaluate to true. If that is the case, just - * return jiffies so that we can immediately fire the local timer - */ - if (time_before(expires, jiffies)) - return jiffies; +/* + * Check, if the next hrtimer event is before the next timer wheel + * event: + */ +static unsigned long cmp_next_hrtimer_event(unsigned long now, + unsigned long expires) +{ + ktime_t hr_delta = hrtimer_get_next_event(); + struct timespec tsdelta; + + if (hr_delta.tv64 == KTIME_MAX) + return expires; - if (time_before(hr_expires, expires)) - return hr_expires; + if (hr_delta.tv64 <= TICK_NSEC) + return now; + tsdelta = ktime_to_timespec(hr_delta); + now += timespec_to_jiffies(&tsdelta); + if (time_before(now, expires)) + return now; return expires; } + +/** + * next_timer_interrupt - return the jiffy of the next pending timer + */ +unsigned long get_next_timer_interrupt(unsigned long now) +{ + tvec_base_t *base = __get_cpu_var(tvec_bases); + unsigned long expires; + + spin_lock(&base->lock); + expires = __next_timer_interrupt(base); + spin_unlock(&base->lock); + + if (time_before_eq(expires, now)) + return now; + + return cmp_next_hrtimer_event(now, expires); +} + +#ifdef CONFIG_NO_IDLE_HZ +unsigned long next_timer_interrupt(void) +{ + return get_next_timer_interrupt(jiffies); +} +#endif + #endif /******************************************************************/ @@ -832,32 +876,35 @@ EXPORT_SYMBOL(do_settimeofday); * * Accumulates current time interval and initializes new clocksource */ -static int change_clocksource(void) +static void change_clocksource(void) { struct clocksource *new; cycle_t now; u64 nsec; + new = clocksource_get_next(); - if (clock != new) { - now = clocksource_read(new); - nsec = __get_nsec_offset(); - timespec_add_ns(&xtime, nsec); - - clock = new; - clock->cycle_last = now; - printk(KERN_INFO "Time: %s clocksource has been installed.\n", - clock->name); - return 1; - } else if (clock->update_callback) { - return clock->update_callback(); - } - return 0; + + if (clock == new) + return; + + now = clocksource_read(new); + nsec = __get_nsec_offset(); + timespec_add_ns(&xtime, nsec); + + clock = new; + clock->cycle_last = now; + + clock->error = 0; + clock->xtime_nsec = 0; + clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH); + + tick_clock_notify(); + + printk(KERN_INFO "Time: %s clocksource has been installed.\n", + clock->name); } #else -static inline int change_clocksource(void) -{ - return 0; -} +static inline void change_clocksource(void) { } #endif /** @@ -871,33 +918,56 @@ int timekeeping_is_continuous(void) do { seq = read_seqbegin(&xtime_lock); - ret = clock->is_continuous; + ret = clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; } while (read_seqretry(&xtime_lock, seq)); return ret; } +/** + * read_persistent_clock - Return time in seconds from the persistent clock. + * + * Weak dummy function for arches that do not yet support it. + * Returns seconds from epoch using the battery backed persistent clock. + * Returns zero if unsupported. + * + * XXX - Do be sure to remove it once all arches implement it. + */ +unsigned long __attribute__((weak)) read_persistent_clock(void) +{ + return 0; +} + /* * timekeeping_init - Initializes the clocksource and common timekeeping values */ void __init timekeeping_init(void) { unsigned long flags; + unsigned long sec = read_persistent_clock(); write_seqlock_irqsave(&xtime_lock, flags); ntp_clear(); clock = clocksource_get_next(); - clocksource_calculate_interval(clock, tick_nsec); + clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH); clock->cycle_last = clocksource_read(clock); + xtime.tv_sec = sec; + xtime.tv_nsec = 0; + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); + write_sequnlock_irqrestore(&xtime_lock, flags); } - +/* flag for if timekeeping is suspended */ static int timekeeping_suspended; +/* time in seconds when suspend began */ +static unsigned long timekeeping_suspend_time; + /** * timekeeping_resume - Resumes the generic timekeeping subsystem. * @dev: unused @@ -909,13 +979,26 @@ static int timekeeping_suspended; static int timekeeping_resume(struct sys_device *dev) { unsigned long flags; + unsigned long now = read_persistent_clock(); write_seqlock_irqsave(&xtime_lock, flags); - /* restart the last cycle value */ + + if (now && (now > timekeeping_suspend_time)) { + unsigned long sleep_length = now - timekeeping_suspend_time; + + xtime.tv_sec += sleep_length; + wall_to_monotonic.tv_sec -= sleep_length; + } + /* re-base the last cycle value */ clock->cycle_last = clocksource_read(clock); clock->error = 0; timekeeping_suspended = 0; write_sequnlock_irqrestore(&xtime_lock, flags); + + touch_softlockup_watchdog(); + /* Resume hrtimers */ + clock_was_set(); + return 0; } @@ -925,6 +1008,7 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) write_seqlock_irqsave(&xtime_lock, flags); timekeeping_suspended = 1; + timekeeping_suspend_time = read_persistent_clock(); write_sequnlock_irqrestore(&xtime_lock, flags); return 0; } @@ -1089,11 +1173,8 @@ static void update_wall_time(void) clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift; /* check to see if there is a new clocksource to use */ - if (change_clocksource()) { - clock->error = 0; - clock->xtime_nsec = 0; - clocksource_calculate_interval(clock, tick_nsec); - } + change_clocksource(); + update_vsyscall(&xtime, clock); } /* @@ -1162,11 +1243,9 @@ static inline void calc_load(unsigned long ticks) * This read-write spinlock protects us from races in SMP while * playing with xtime and avenrun. */ -#ifndef ARCH_HAVE_XTIME_LOCK -__cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); +__attribute__((weak)) __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); EXPORT_SYMBOL(xtime_lock); -#endif /* * This function runs timers and the timer-tq in bottom half context. @@ -1175,7 +1254,8 @@ static void run_timer_softirq(struct softirq_action *h) { tvec_base_t *base = __get_cpu_var(tvec_bases); - hrtimer_run_queues(); + hrtimer_run_queues(); + if (time_after_eq(jiffies, base->timer_jiffies)) __run_timers(base); } @@ -1621,6 +1701,8 @@ void __init init_timers(void) int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); + init_timer_stats(); + BUG_ON(err == NOTIFY_BAD); register_cpu_notifier(&timers_nb); open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL); diff --git a/kernel/tsacct.c b/kernel/tsacct.c index baacc36..658f638 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -22,8 +22,6 @@ #include <linux/acct.h> #include <linux/jiffies.h> - -#define USEC_PER_TICK (USEC_PER_SEC/HZ) /* * fill in basic accounting fields */ diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c new file mode 100644 index 0000000..f22b9db --- /dev/null +++ b/kernel/utsname_sysctl.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2007 + * + * Author: Eric Biederman <ebiederm@xmision.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, version 2 of the + * License. + */ + +#include <linux/module.h> +#include <linux/uts.h> +#include <linux/utsname.h> +#include <linux/version.h> +#include <linux/sysctl.h> + +static void *get_uts(ctl_table *table, int write) +{ + char *which = table->data; +#ifdef CONFIG_UTS_NS + struct uts_namespace *uts_ns = current->nsproxy->uts_ns; + which = (which - (char *)&init_uts_ns) + (char *)uts_ns; +#endif + if (!write) + down_read(&uts_sem); + else + down_write(&uts_sem); + return which; +} + +static void put_uts(ctl_table *table, int write, void *which) +{ + if (!write) + up_read(&uts_sem); + else + up_write(&uts_sem); +} + +#ifdef CONFIG_PROC_FS +/* + * Special case of dostring for the UTS structure. This has locks + * to observe. Should this be in kernel/sys.c ???? + */ +static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table uts_table; + int r; + memcpy(&uts_table, table, sizeof(uts_table)); + uts_table.data = get_uts(table, write); + r = proc_dostring(&uts_table,write,filp,buffer,lenp, ppos); + put_uts(table, write, uts_table.data); + return r; +} +#else +#define proc_do_uts_string NULL +#endif + + +#ifdef CONFIG_SYSCTL_SYSCALL +/* The generic string strategy routine: */ +static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + struct ctl_table uts_table; + int r, write; + write = newval && newlen; + memcpy(&uts_table, table, sizeof(uts_table)); + uts_table.data = get_uts(table, write); + r = sysctl_string(&uts_table, name, nlen, + oldval, oldlenp, newval, newlen); + put_uts(table, write, uts_table.data); + return r; +} +#else +#define sysctl_uts_string NULL +#endif + +static struct ctl_table uts_kern_table[] = { + { + .ctl_name = KERN_OSTYPE, + .procname = "ostype", + .data = init_uts_ns.name.sysname, + .maxlen = sizeof(init_uts_ns.name.sysname), + .mode = 0444, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, + }, + { + .ctl_name = KERN_OSRELEASE, + .procname = "osrelease", + .data = init_uts_ns.name.release, + .maxlen = sizeof(init_uts_ns.name.release), + .mode = 0444, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, + }, + { + .ctl_name = KERN_VERSION, + .procname = "version", + .data = init_uts_ns.name.version, + .maxlen = sizeof(init_uts_ns.name.version), + .mode = 0444, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, + }, + { + .ctl_name = KERN_NODENAME, + .procname = "hostname", + .data = init_uts_ns.name.nodename, + .maxlen = sizeof(init_uts_ns.name.nodename), + .mode = 0644, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, + }, + { + .ctl_name = KERN_DOMAINNAME, + .procname = "domainname", + .data = init_uts_ns.name.domainname, + .maxlen = sizeof(init_uts_ns.name.domainname), + .mode = 0644, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, + }, + {} +}; + +static struct ctl_table uts_root_table[] = { + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0555, + .child = uts_kern_table, + }, + {} +}; + +static int __init utsname_sysctl_init(void) +{ + register_sysctl_table(uts_root_table); + return 0; +} + +__initcall(utsname_sysctl_init); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 020d1ff..b6fa5e6 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -218,7 +218,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work) } EXPORT_SYMBOL_GPL(queue_work); -static void delayed_work_timer_fn(unsigned long __data) +void delayed_work_timer_fn(unsigned long __data) { struct delayed_work *dwork = (struct delayed_work *)__data; struct workqueue_struct *wq = get_wq_data(&dwork->work); @@ -245,6 +245,7 @@ int fastcall queue_delayed_work(struct workqueue_struct *wq, struct timer_list *timer = &dwork->timer; struct work_struct *work = &dwork->work; + timer_stats_timer_set_start_info(timer); if (delay == 0) return queue_work(wq, work); @@ -593,8 +594,10 @@ EXPORT_SYMBOL(schedule_work); * After waiting for a given time this puts a job in the kernel-global * workqueue. */ -int fastcall schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) +int fastcall schedule_delayed_work(struct delayed_work *dwork, + unsigned long delay) { + timer_stats_timer_set_start_info(&dwork->timer); return queue_delayed_work(keventd_wq, dwork, delay); } EXPORT_SYMBOL(schedule_delayed_work); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 63f04c1..4448f91 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -134,6 +134,17 @@ config SCHEDSTATS application, you can say N to avoid the very slight overhead this adds. +config TIMER_STATS + bool "Collect kernel timers statistics" + depends on DEBUG_KERNEL && PROC_FS + help + If you say Y here, additional code will be inserted into the + timer routines to collect statistics about kernel timers being + reprogrammed. The statistics can be read from /proc/timer_stats. + The statistics collection is started by writing 1 to /proc/timer_stats, + writing 0 stops it. This feature is useful to collect information + about timer usage patterns in kernel and userspace. + config DEBUG_SLAB bool "Debug slab memory allocations" depends on DEBUG_KERNEL && SLAB diff --git a/lib/devres.c b/lib/devres.c index 2a668dd..eb38849 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -274,21 +274,21 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name) rc = pci_request_region(pdev, i, name); if (rc) - goto err_region; + goto err_inval; rc = -ENOMEM; if (!pcim_iomap(pdev, i, 0)) - goto err_iomap; + goto err_region; } return 0; - err_iomap: - pcim_iounmap(pdev, iomap[i]); err_region: pci_release_region(pdev, i); err_inval: while (--i >= 0) { + if (!(mask & (1 << i))) + continue; pcim_iounmap(pdev, iomap[i]); pci_release_region(pdev, i); } diff --git a/mm/filemap.c b/mm/filemap.c index 0041484..d1060b8 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2079,21 +2079,27 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, /* Limit the size of the copy to the caller's write size */ bytes = min(bytes, count); - /* - * Limit the size of the copy to that of the current segment, - * because fault_in_pages_readable() doesn't know how to walk - * segments. + /* We only need to worry about prefaulting when writes are from + * user-space. NFSd uses vfs_writev with several non-aligned + * segments in the vector, and limiting to one segment a time is + * a noticeable performance for re-write */ - bytes = min(bytes, cur_iov->iov_len - iov_base); - - /* - * Bring in the user page that we will copy from _first_. - * Otherwise there's a nasty deadlock on copying from the - * same page as we're writing to, without it being marked - * up-to-date. - */ - fault_in_pages_readable(buf, bytes); + if (!segment_eq(get_fs(), KERNEL_DS)) { + /* + * Limit the size of the copy to that of the current + * segment, because fault_in_pages_readable() doesn't + * know how to walk segments. + */ + bytes = min(bytes, cur_iov->iov_len - iov_base); + /* + * Bring in the user page that we will copy from + * _first_. Otherwise there's a nasty deadlock on + * copying from the same page as we're writing to, + * without it being marked up-to-date. + */ + fault_in_pages_readable(buf, bytes); + } page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); if (!page) { status = -ENOMEM; diff --git a/mm/mincore.c b/mm/mincore.c index 95c5f49..5efe0de 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -77,8 +77,16 @@ static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pag * PTE array for our address. */ nr = PTRS_PER_PTE - ((addr >> PAGE_SHIFT) & (PTRS_PER_PTE-1)); - if (nr > pages) - nr = pages; + + /* + * Don't overrun this vma + */ + nr = min(nr, (vma->vm_end - addr) >> PAGE_SHIFT); + + /* + * Don't return more than the caller asked for + */ + nr = min(nr, pages); pgd = pgd_offset(vma->vm_mm, addr); if (pgd_none_or_clear_bad(pgd)) @@ -116,10 +124,17 @@ static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pag /* migration entries are always uptodate */ present = 1; } else { +#ifdef CONFIG_SWAP pgoff = entry.val; present = mincore_page(&swapper_space, pgoff); +#else + WARN_ON(1); + present = 1; +#endif } } + + vec[i] = present; } pte_unmap_unlock(ptep-1, ptl); @@ -130,6 +145,9 @@ none_mapped: pgoff = linear_page_index(vma, addr); for (i = 0; i < nr; i++, pgoff++) vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff); + } else { + for (i = 0; i < nr; i++) + vec[i] = 0; } return nr; diff --git a/net/802/fc.c b/net/802/fc.c index d64e6a5..675d9ba 100644 --- a/net/802/fc.c +++ b/net/802/fc.c @@ -14,7 +14,6 @@ #include <asm/system.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/802/fddi.c b/net/802/fddi.c index 0b98fe2..ace6386 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -30,7 +30,6 @@ #include <asm/system.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/802/hippi.c b/net/802/hippi.c index be0da59..578f2a3 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c index 40b0af7..7df1778 100644 --- a/net/appletalk/sysctl_net_atalk.c +++ b/net/appletalk/sysctl_net_atalk.c @@ -73,7 +73,7 @@ static struct ctl_table_header *atalk_table_header; void atalk_register_sysctl(void) { - atalk_table_header = register_sysctl_table(atalk_root_table, 1); + atalk_table_header = register_sysctl_table(atalk_root_table); } void atalk_unregister_sysctl(void) diff --git a/net/atm/addr.c b/net/atm/addr.c index 3060fd0..6afa77d 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -4,7 +4,6 @@ #include <linux/atm.h> #include <linux/atmdev.h> -#include <linux/sched.h> #include <asm/uaccess.h> #include "signaling.h" diff --git a/net/atm/lec.c b/net/atm/lec.c index 9869455..3d804d6 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1437,7 +1437,6 @@ static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr, */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <asm/param.h> #include <asm/atomic.h> diff --git a/net/atm/raw.c b/net/atm/raw.c index 4df7cdd..1378f61 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -4,7 +4,6 @@ #include <linux/module.h> -#include <linux/sched.h> #include <linux/atmdev.h> #include <linux/capability.h> #include <linux/kernel.h> diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index 419e718..7e7964d 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -12,7 +12,6 @@ #include <linux/in.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index b7876782..528c874 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -11,7 +11,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c index edcaa89..e37d217 100644 --- a/net/ax25/ax25_ds_in.c +++ b/net/ax25/ax25_ds_in.c @@ -12,7 +12,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c index 4d22d44..9569dd3 100644 --- a/net/ax25/ax25_ds_subr.c +++ b/net/ax25/ax25_ds_subr.c @@ -12,7 +12,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c index aff3e65..16be0c1 100644 --- a/net/ax25/ax25_iface.c +++ b/net/ax25/ax25_iface.c @@ -12,7 +12,6 @@ #include <linux/in.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/timer.h> #include <linux/string.h> diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index e9d9429..4a6b26b 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -14,7 +14,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 8d62d86..7f818bb 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -12,7 +12,6 @@ #include <linux/in.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index f84047d..2238350 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -14,7 +14,6 @@ #include <linux/in.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c index f6ed283..a8eef88 100644 --- a/net/ax25/ax25_std_in.c +++ b/net/ax25/ax25_std_in.c @@ -19,7 +19,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c index 2b3c801..277f81b 100644 --- a/net/ax25/ax25_std_subr.c +++ b/net/ax25/ax25_std_subr.c @@ -11,7 +11,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c index e3528b1..f2f6918 100644 --- a/net/ax25/ax25_std_timer.c +++ b/net/ax25/ax25_std_timer.c @@ -14,7 +14,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c index 85c58c4..b6c577e 100644 --- a/net/ax25/ax25_subr.c +++ b/net/ax25/ax25_subr.c @@ -14,7 +14,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index 59a41b1..75c7664 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c @@ -13,7 +13,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c index d23a27f..443a836 100644 --- a/net/ax25/sysctl_net_ax25.c +++ b/net/ax25/sysctl_net_ax25.c @@ -245,7 +245,7 @@ void ax25_register_sysctl(void) ax25_dir_table[0].child = ax25_table; - ax25_table_header = register_sysctl_table(ax25_root_table, 1); + ax25_table_header = register_sysctl_table(ax25_root_table); } void ax25_unregister_sysctl(void) diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 6d7311c..10292e7 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -34,7 +34,6 @@ #include <linux/capability.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 0c5ccd9..19be786 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -26,7 +26,6 @@ #include <linux/capability.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 67ee0bd..f3403fd 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -29,7 +29,6 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 00d845e..936d3fc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -29,7 +29,6 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index dc3ecb1..f928d2b 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -30,7 +30,6 @@ #include <linux/capability.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 33bda40..8b8a6c1 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -26,7 +26,6 @@ #include <linux/capability.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f35c1a3..aff6a77 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -108,6 +108,7 @@ static void port_carrier_check(struct work_struct *work) spin_unlock_bh(&br->lock); } done: + dev_put(dev); rtnl_unlock(); } @@ -161,7 +162,8 @@ static void del_nbp(struct net_bridge_port *p) dev_set_promiscuity(dev, -1); - cancel_delayed_work(&p->carrier_check); + if (cancel_delayed_work(&p->carrier_check)) + dev_put(dev); spin_lock_bh(&br->lock); br_stp_disable_port(p); @@ -444,7 +446,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) spin_lock_bh(&br->lock); br_stp_recalculate_bridge_id(br); br_features_recompute(br); - schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); + if (schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE)) + dev_hold(dev); + spin_unlock_bh(&br->lock); dev_set_mtu(br->dev, br_min_mtu(br)); diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index a0744e6..7712d76 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -957,7 +957,7 @@ int __init br_netfilter_init(void) if (ret < 0) return ret; #ifdef CONFIG_SYSCTL - brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0); + brnf_sysctl_header = register_sysctl_table(brnf_net_table); if (brnf_sysctl_header == NULL) { printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n"); diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 8cd3e422..3311c4e3 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -56,7 +56,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v case NETDEV_CHANGE: if (br->dev->flags & IFF_UP) - schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); + if (schedule_delayed_work(&p->carrier_check, + BR_PORT_DEBOUNCE)) + dev_hold(dev); break; case NETDEV_FEAT_CHANGE: diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 5818d70..34c4979 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -16,7 +16,6 @@ */ /* used for print_string */ -#include <linux/sched.h> #include <linux/tty.h> #include <linux/kmod.h> diff --git a/net/compat.c b/net/compat.c index 9c97074..1f32866 100644 --- a/net/compat.c +++ b/net/compat.c @@ -13,7 +13,6 @@ #include <linux/kernel.h> #include <linux/fs.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/file.h> #include <linux/icmpv6.h> diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index c4e754e..56b310c 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -27,7 +27,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/core/dst.c b/net/core/dst.c index 61dd9d3..764bccb 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -12,7 +12,6 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/netdevice.h> -#include <linux/sched.h> #include <linux/skbuff.h> #include <linux/string.h> #include <linux/types.h> diff --git a/net/core/filter.c b/net/core/filter.c index 8123a31..8d185a0 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -18,7 +18,6 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/fcntl.h> #include <linux/socket.h> diff --git a/net/core/iovec.c b/net/core/iovec.c index 4fb1cb9..755c37f 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -18,7 +18,6 @@ #include <linux/errno.h> #include <linux/module.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/slab.h> diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 512eed9..3183142 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/socket.h> -#include <linux/sched.h> #include <linux/netdevice.h> #include <linux/proc_fs.h> #ifdef CONFIG_SYSCTL @@ -2708,7 +2707,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, t->neigh_proto_dir[0].child = t->neigh_neigh_dir; t->neigh_root_dir[0].child = t->neigh_proto_dir; - t->sysctl_header = register_sysctl_table(t->neigh_root_dir, 0); + t->sysctl_header = register_sysctl_table(t->neigh_root_dir); if (!t->sysctl_header) { err = -ENOBUFS; goto free_procname; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index ee5a787..6055074 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -21,7 +21,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3d56468..f89ff15 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -41,7 +41,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/in.h> diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index fdcfca3..1260aab 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -127,7 +127,7 @@ static struct ctl_table_header *dccp_table_header; int __init dccp_sysctl_init(void) { - dccp_table_header = register_sysctl_table(dccp_root_table, 1); + dccp_table_header = register_sysctl_table(dccp_root_table); return dccp_table_header != NULL ? 0 : -ENOMEM; } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 2b2c7fe..060d725 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -261,7 +261,6 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms * for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) { long offset = (long)t->dn_dev_vars[i].data; t->dn_dev_vars[i].data = ((char *)parms) + offset; - t->dn_dev_vars[i].de = NULL; } if (dev) { @@ -273,16 +272,12 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms * } t->dn_dev_dev[0].child = t->dn_dev_vars; - t->dn_dev_dev[0].de = NULL; t->dn_dev_conf_dir[0].child = t->dn_dev_dev; - t->dn_dev_conf_dir[0].de = NULL; t->dn_dev_proto_dir[0].child = t->dn_dev_conf_dir; - t->dn_dev_proto_dir[0].de = NULL; t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir; - t->dn_dev_root_dir[0].de = NULL; t->dn_dev_vars[0].extra1 = (void *)dev; - t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir, 0); + t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir); if (t->sysctl_header == NULL) kfree(t); else diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 0f244e8..9d20904 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -50,7 +50,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index 23d5ca8..2d2cda8 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -43,7 +43,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index a6c067b..52e40d7 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -491,7 +491,7 @@ static ctl_table dn_root_table[] = { void dn_register_sysctl(void) { - dn_table_header = register_sysctl_table(dn_root_table, 1); + dn_table_header = register_sysctl_table(dn_root_table); } void dn_unregister_sysctl(void) diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index f2ce414..bc12e36 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -13,7 +13,6 @@ #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 766a0b5..7391f55 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -40,7 +40,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 0ffd2d2..1a3488a 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -78,7 +78,6 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/capability.h> #include <linux/socket.h> #include <linux/sockios.h> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ba5e7f4..8a0ec10 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -35,7 +35,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> @@ -1577,7 +1576,6 @@ static void devinet_sysctl_register(struct in_device *in_dev, return; for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; - t->devinet_vars[i].de = NULL; } if (dev) { @@ -1599,15 +1597,11 @@ static void devinet_sysctl_register(struct in_device *in_dev, t->devinet_dev[0].procname = dev_name; t->devinet_dev[0].child = t->devinet_vars; - t->devinet_dev[0].de = NULL; t->devinet_conf_dir[0].child = t->devinet_dev; - t->devinet_conf_dir[0].de = NULL; t->devinet_proto_dir[0].child = t->devinet_conf_dir; - t->devinet_proto_dir[0].de = NULL; t->devinet_root_dir[0].child = t->devinet_proto_dir; - t->devinet_root_dir[0].de = NULL; - t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0); + t->sysctl_header = register_sysctl_table(t->devinet_root_dir); if (!t->sysctl_header) goto free_procname; @@ -1641,7 +1635,7 @@ void __init devinet_init(void) rtnetlink_links[PF_INET] = inet_rtnetlink_table; #ifdef CONFIG_SYSCTL devinet_sysctl.sysctl_header = - register_sysctl_table(devinet_sysctl.devinet_root_dir, 0); + register_sysctl_table(devinet_sysctl.devinet_root_dir); devinet_sysctl_register(NULL, &ipv4_devconf_dflt); #endif } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 64f31e6..1fba643 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -22,7 +22,6 @@ #include <linux/capability.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/socket.h> diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index b21bb28..a4949f9 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -20,7 +20,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/socket.h> diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index c33dca0..72b3036 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -57,7 +57,6 @@ #include <asm/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/socket.h> diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 711eb6d..db3ef96 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/random.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/time.h> #include <linux/kernel.h> diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index c3ea0cd..369e721 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -23,7 +23,6 @@ #include <linux/types.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/icmp.h> diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f12c0d6..9151da6 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -13,7 +13,6 @@ #include <linux/capability.h> #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <asm/uaccess.h> #include <linux/skbuff.h> diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index bb0bb8f..d096332 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -49,7 +49,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/errno.h> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index e120686..23048d9 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/icmp.h> diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 475bcd1..3ec5ce0 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -96,7 +96,6 @@ #include <linux/capability.h> #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <asm/uaccess.h> #include <linux/skbuff.h> @@ -871,7 +870,7 @@ static int __init ipip_init(void) printk(banner); - if (xfrm4_tunnel_register(&ipip_handler)) { + if (xfrm4_tunnel_register(&ipip_handler, AF_INET)) { printk(KERN_INFO "ipip init: can't register tunnel\n"); return -EAGAIN; } @@ -893,7 +892,7 @@ static int __init ipip_init(void) err2: free_netdev(ipip_fb_tunnel_dev); err1: - xfrm4_tunnel_deregister(&ipip_handler); + xfrm4_tunnel_deregister(&ipip_handler, AF_INET); goto out; } @@ -913,7 +912,7 @@ static void __exit ipip_destroy_tunnels(void) static void __exit ipip_fini(void) { - if (xfrm4_tunnel_deregister(&ipip_handler)) + if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) printk(KERN_INFO "ipip close: can't deregister tunnel\n"); rtnl_lock(); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e6d11ab..601e3df 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -31,7 +31,6 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/capability.h> #include <linux/errno.h> #include <linux/timer.h> diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index 8b08d9c..b3050a6 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -2359,7 +2359,7 @@ int ip_vs_control_init(void) proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops); proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops); - sysctl_header = register_sysctl_table(vs_root_table, 0); + sysctl_header = register_sysctl_table(vs_root_table); /* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */ for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c index 76fd1fb..c801273 100644 --- a/net/ipv4/ipvs/ip_vs_lblc.c +++ b/net/ipv4/ipvs/ip_vs_lblc.c @@ -583,7 +583,7 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler = static int __init ip_vs_lblc_init(void) { INIT_LIST_HEAD(&ip_vs_lblc_scheduler.n_list); - sysctl_header = register_sysctl_table(lblc_root_table, 0); + sysctl_header = register_sysctl_table(lblc_root_table); return register_ip_vs_scheduler(&ip_vs_lblc_scheduler); } diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c index bf1e7f2..23f9b9e 100644 --- a/net/ipv4/ipvs/ip_vs_lblcr.c +++ b/net/ipv4/ipvs/ip_vs_lblcr.c @@ -841,7 +841,7 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler = static int __init ip_vs_lblcr_init(void) { INIT_LIST_HEAD(&ip_vs_lblcr_scheduler.n_list); - sysctl_header = register_sysctl_table(lblcr_root_table, 0); + sysctl_header = register_sysctl_table(lblcr_root_table); #ifdef CONFIG_IP_VS_LBLCR_DEBUG proc_net_create("ip_vs_lblcr", 0, ip_vs_lblcr_getinfo); #endif diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c index 8bc42b7..1602304 100644 --- a/net/ipv4/ipvs/ip_vs_sched.c +++ b/net/ipv4/ipvs/ip_vs_sched.c @@ -20,7 +20,6 @@ */ #include <linux/module.h> -#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <asm/string.h> diff --git a/net/ipv4/multipath_drr.c b/net/ipv4/multipath_drr.c index cb8fce4..574c735 100644 --- a/net/ipv4/multipath_drr.c +++ b/net/ipv4/multipath_drr.c @@ -15,7 +15,6 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/mm.h> diff --git a/net/ipv4/multipath_random.c b/net/ipv4/multipath_random.c index 047e861..57f481498 100644 --- a/net/ipv4/multipath_random.c +++ b/net/ipv4/multipath_random.c @@ -15,7 +15,6 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/mm.h> diff --git a/net/ipv4/multipath_rr.c b/net/ipv4/multipath_rr.c index 896246d..0ad2252 100644 --- a/net/ipv4/multipath_rr.c +++ b/net/ipv4/multipath_rr.c @@ -15,7 +15,6 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/mm.h> diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c index 7e22f15..2bdbb92 100644 --- a/net/ipv4/multipath_wrandom.c +++ b/net/ipv4/multipath_wrandom.c @@ -15,7 +15,6 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/mm.h> diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c index 36f2b5e..88af82e 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c @@ -7,7 +7,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index ec71abe..ad70c81 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c @@ -7,7 +7,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/in.h> diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c index 9d5b917..e694299 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c @@ -14,7 +14,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/netfilter.h> @@ -623,7 +622,7 @@ static int __init ip_conntrack_proto_sctp_init(void) } #ifdef CONFIG_SYSCTL - ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table); if (ip_ct_sysctl_header == NULL) { ret = -ENOMEM; printk("ip_conntrack_proto_sctp: can't register to sysctl.\n"); diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index fa35b49f..170d625 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -20,7 +20,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/module.h> diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index a99a7c7..14c30c6 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -7,7 +7,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/in.h> diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index c7c1ec6..56b2f75 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -848,7 +848,7 @@ static int __init ip_conntrack_standalone_init(void) goto cleanup_proc_stat; } #ifdef CONFIG_SYSCTL - ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table); if (ip_ct_sysctl_header == NULL) { printk("ip_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 68bf19f..a14798a 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -693,7 +693,7 @@ static int __init ip_queue_init(void) } register_netdevice_notifier(&ipq_dev_notifier); - ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0); + ipq_sysctl_header = register_sysctl_table(ipq_root_table); status = nf_register_queue_handler(PF_INET, &nfqh); if (status < 0) { diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index a9eb363..80f739e 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -80,6 +80,10 @@ static void send_reset(struct sk_buff *oldskb, int hook) nskb->mark = 0; skb_init_secmark(nskb); + skb_shinfo(nskb)->gso_size = 0; + skb_shinfo(nskb)->gso_segs = 0; + skb_shinfo(nskb)->gso_type = 0; + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); /* Swap source and dest */ diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index e5aa4d8..88cfa6a 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -12,7 +12,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/in.h> diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c index 6cd6340..da70fef 100644 --- a/net/ipv4/protocol.c +++ b/net/ipv4/protocol.c @@ -30,7 +30,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/socket.h> #include <linux/in.h> diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9b5e564..37e0d4d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -70,7 +70,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/bootmem.h> #include <linux/string.h> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cebe9aa..dc15113 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -481,7 +481,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, /* RFC1323: The window in SYN & SYN/ACK segments * is never scaled. */ - th->window = htons(tp->rcv_wnd); + th->window = htons(min(tp->rcv_wnd, 65535U)); } else { th->window = htons(tcp_select_window(sk)); } @@ -2160,7 +2160,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, } /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ - th->window = htons(req->rcv_wnd); + th->window = htons(min(req->rcv_wnd, 65535U)); TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 8d30c48..a794a8c 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -14,9 +14,10 @@ #include <net/xfrm.h> static struct xfrm_tunnel *tunnel4_handlers; +static struct xfrm_tunnel *tunnel64_handlers; static DEFINE_MUTEX(tunnel4_mutex); -int xfrm4_tunnel_register(struct xfrm_tunnel *handler) +int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) { struct xfrm_tunnel **pprev; int ret = -EEXIST; @@ -24,7 +25,8 @@ int xfrm4_tunnel_register(struct xfrm_tunnel *handler) mutex_lock(&tunnel4_mutex); - for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; + *pprev; pprev = &(*pprev)->next) { if ((*pprev)->priority > priority) break; if ((*pprev)->priority == priority) @@ -44,14 +46,15 @@ err: EXPORT_SYMBOL(xfrm4_tunnel_register); -int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) +int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) { struct xfrm_tunnel **pprev; int ret = -ENOENT; mutex_lock(&tunnel4_mutex); - for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; + *pprev; pprev = &(*pprev)->next) { if (*pprev == handler) { *pprev = handler->next; ret = 0; @@ -86,6 +89,26 @@ drop: return 0; } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static int tunnel64_rcv(struct sk_buff *skb) +{ + struct xfrm_tunnel *handler; + + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto drop; + + for (handler = tunnel64_handlers; handler; handler = handler->next) + if (!handler->handler(skb)) + return 0; + + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + +drop: + kfree_skb(skb); + return 0; +} +#endif + static void tunnel4_err(struct sk_buff *skb, u32 info) { struct xfrm_tunnel *handler; @@ -101,17 +124,36 @@ static struct net_protocol tunnel4_protocol = { .no_policy = 1, }; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static struct net_protocol tunnel64_protocol = { + .handler = tunnel64_rcv, + .err_handler = tunnel4_err, + .no_policy = 1, +}; +#endif + static int __init tunnel4_init(void) { if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { printk(KERN_ERR "tunnel4 init: can't add protocol\n"); return -EAGAIN; } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { + printk(KERN_ERR "tunnel64 init: can't add protocol\n"); + inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); + return -EAGAIN; + } +#endif return 0; } static void __exit tunnel4_fini(void) { +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) + printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); +#endif if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); } diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 289146b..78e80de 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -27,6 +27,7 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 { switch (nexthdr) { case IPPROTO_IPIP: + case IPPROTO_IPV6: *spi = skb->nh.iph->saddr; *seq = 0; return 0; @@ -70,7 +71,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol, AF_INET); + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, + iph->protocol != IPPROTO_IPV6 ? iph->protocol : IPPROTO_IPIP, AF_INET); if (x == NULL) goto drop; diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index e54c549..e1cab33 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -95,6 +95,7 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) switch(iph->protocol){ case IPPROTO_IPIP: + break; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) case IPPROTO_IPV6: break; diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 1be6762..3eef064 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -64,24 +64,45 @@ static struct xfrm_tunnel xfrm_tunnel_handler = { .priority = 2, }; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static struct xfrm_tunnel xfrm64_tunnel_handler = { + .handler = xfrm4_rcv, + .err_handler = xfrm_tunnel_err, + .priority = 2, +}; +#endif + static int __init ipip_init(void) { if (xfrm_register_type(&ipip_type, AF_INET) < 0) { printk(KERN_INFO "ipip init: can't add xfrm type\n"); return -EAGAIN; } - if (xfrm4_tunnel_register(&xfrm_tunnel_handler)) { - printk(KERN_INFO "ipip init: can't add xfrm handler\n"); + + if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) { + printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET\n"); + xfrm_unregister_type(&ipip_type, AF_INET); + return -EAGAIN; + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) { + printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET6\n"); + xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET); xfrm_unregister_type(&ipip_type, AF_INET); return -EAGAIN; } +#endif return 0; } static void __exit ipip_fini(void) { - if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler)) - printk(KERN_INFO "ipip close: can't remove xfrm handler\n"); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6)) + printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET6\n"); +#endif + if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET)) + printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET\n"); if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) printk(KERN_INFO "ipip close: can't remove xfrm type\n"); } diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index deb4101..79682ef 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -156,6 +156,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION config IPV6_SIT tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" depends on IPV6 + select INET_TUNNEL default y ---help--- Tunneling means encapsulating data of one protocol type within diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ea0755b..569a37d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -44,7 +44,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> @@ -3999,7 +3998,6 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf return; for (i=0; t->addrconf_vars[i].data; i++) { t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; - t->addrconf_vars[i].de = NULL; t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */ } if (dev) { @@ -4022,15 +4020,11 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf t->addrconf_dev[0].procname = dev_name; t->addrconf_dev[0].child = t->addrconf_vars; - t->addrconf_dev[0].de = NULL; t->addrconf_conf_dir[0].child = t->addrconf_dev; - t->addrconf_conf_dir[0].de = NULL; t->addrconf_proto_dir[0].child = t->addrconf_conf_dir; - t->addrconf_proto_dir[0].de = NULL; t->addrconf_root_dir[0].child = t->addrconf_proto_dir; - t->addrconf_root_dir[0].de = NULL; - t->sysctl_header = register_sysctl_table(t->addrconf_root_dir, 0); + t->sysctl_header = register_sysctl_table(t->addrconf_root_dir); if (t->sysctl_header == NULL) goto free_procname; else @@ -4115,7 +4109,7 @@ int __init addrconf_init(void) rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; #ifdef CONFIG_SYSCTL addrconf_sysctl.sysctl_header = - register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0); + register_sysctl_table(addrconf_sysctl.addrconf_root_dir); addrconf_sysctl_register(NULL, &ipv6_devconf_dflt); #endif diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a006d24..3585d8f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -28,7 +28,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 6fb2e9d..e5ef5979 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -21,7 +21,6 @@ #include <linux/string.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 5f54dec..3b4e8dc 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -17,7 +17,6 @@ #include <linux/errno.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/socket.h> #include <linux/sockios.h> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 08313ef..28e0c65 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -27,7 +27,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/netdevice.h> #include <linux/in6.h> diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 9377fea..edfe98b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -37,7 +37,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/sockios.h> #include <linux/net.h> #include <linux/skbuff.h> diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 30b16da..ae6b0e7 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -172,7 +172,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, const struct in6_addr *saddr = &np->daddr; const int dif = sk->sk_bound_dev_if; const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); - const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, + const unsigned int hash = inet6_ehashfn(daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); struct sock *sk2; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 4fdded0..11bfc7c 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -25,7 +25,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/netdevice.h> #include <linux/in6.h> diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 367b748..662edb8 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1128,7 +1128,7 @@ static int __init ip6_tunnel_init(void) { int err; - if (xfrm6_tunnel_register(&ip6ip6_handler)) { + if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { printk(KERN_ERR "ip6ip6 init: can't register tunnel\n"); return -EAGAIN; } @@ -1147,7 +1147,7 @@ static int __init ip6_tunnel_init(void) } return 0; fail: - xfrm6_tunnel_deregister(&ip6ip6_handler); + xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); return err; } @@ -1171,7 +1171,7 @@ static void __exit ip6ip6_destroy_tunnels(void) static void __exit ip6_tunnel_cleanup(void) { - if (xfrm6_tunnel_deregister(&ip6ip6_handler)) + if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n"); rtnl_lock(); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 3f1e779..286c867 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -31,7 +31,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 58847d3..fdb30a5 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -683,7 +683,7 @@ static int __init ip6_queue_init(void) } register_netdevice_notifier(&ipq_dev_notifier); - ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0); + ipq_sysctl_header = register_sysctl_table(ipq_root_table); status = nf_register_queue_handler(PF_INET6, &nfqh); if (status < 0) { diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 19bdb7c..21f19cc 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -17,7 +17,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/module.h> #include <linux/netfilter.h> diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index c82257d..fa3fb50 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -17,7 +17,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include <linux/sched.h> #include <linux/socket.h> #include <linux/net.h> #include <linux/ipv6.h> diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index ad0410c..ef43bd5 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -27,7 +27,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 1f8f627..306d5d8 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -24,7 +24,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4d3cf30..08d6ed3 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -24,7 +24,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> @@ -216,7 +215,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) } -static void ipip6_err(struct sk_buff *skb, u32 info) +static int ipip6_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -228,21 +227,22 @@ static void ipip6_err(struct sk_buff *skb, u32 info) int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; + int err; switch (type) { default: case ICMP_PARAMETERPROB: - return; + return 0; case ICMP_DEST_UNREACH: switch (code) { case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ - return; + return 0; case ICMP_FRAG_NEEDED: /* Soft state for pmtu is maintained by IP core. */ - return; + return 0; default: /* All others are translated to HOST_UNREACH. rfc2003 contains "deep thoughts" about NET_UNREACH, @@ -253,14 +253,18 @@ static void ipip6_err(struct sk_buff *skb, u32 info) break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) - return; + return 0; break; } + err = -ENOENT; + read_lock(&ipip6_lock); t = ipip6_tunnel_lookup(iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; + + err = 0; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) goto out; @@ -271,7 +275,7 @@ static void ipip6_err(struct sk_buff *skb, u32 info) t->err_time = jiffies; out: read_unlock(&ipip6_lock); - return; + return err; #else struct iphdr *iph = (struct iphdr*)dp; int hlen = iph->ihl<<2; @@ -332,7 +336,7 @@ out: /* Prepare fake skb to feed it to icmpv6_send */ skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) - return; + return 0; dst_release(skb2->dst); skb2->dst = NULL; skb_pull(skb2, skb->data - (u8*)iph6); @@ -355,7 +359,7 @@ out: } } kfree_skb(skb2); - return; + return 0; #endif } @@ -791,9 +795,10 @@ static int __init ipip6_fb_tunnel_init(struct net_device *dev) return 0; } -static struct net_protocol sit_protocol = { +static struct xfrm_tunnel sit_handler = { .handler = ipip6_rcv, .err_handler = ipip6_err, + .priority = 1, }; static void __exit sit_destroy_tunnels(void) @@ -812,7 +817,7 @@ static void __exit sit_destroy_tunnels(void) static void __exit sit_cleanup(void) { - inet_del_protocol(&sit_protocol, IPPROTO_IPV6); + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); rtnl_lock(); sit_destroy_tunnels(); @@ -826,7 +831,7 @@ static int __init sit_init(void) printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); - if (inet_add_protocol(&sit_protocol, IPPROTO_IPV6) < 0) { + if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) { printk(KERN_INFO "sit init: Can't add protocol\n"); return -EAGAIN; } @@ -848,7 +853,7 @@ static int __init sit_init(void) err2: free_netdev(ipip6_fb_tunnel_dev); err1: - inet_del_protocol(&sit_protocol, IPPROTO_IPV6); + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); goto out; } diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 25e8e77..3fb4427 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -107,7 +107,7 @@ static ctl_table ipv6_root_table[] = { void ipv6_sysctl_register(void) { - ipv6_sysctl_header = register_sysctl_table(ipv6_root_table, 0); + ipv6_sysctl_header = register_sysctl_table(ipv6_root_table); } void ipv6_sysctl_unregister(void) diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 918d07d..23e2809 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -30,9 +30,10 @@ #include <net/xfrm.h> static struct xfrm6_tunnel *tunnel6_handlers; +static struct xfrm6_tunnel *tunnel46_handlers; static DEFINE_MUTEX(tunnel6_mutex); -int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) +int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) { struct xfrm6_tunnel **pprev; int ret = -EEXIST; @@ -40,7 +41,8 @@ int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) mutex_lock(&tunnel6_mutex); - for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; + *pprev; pprev = &(*pprev)->next) { if ((*pprev)->priority > priority) break; if ((*pprev)->priority == priority) @@ -60,14 +62,15 @@ err: EXPORT_SYMBOL(xfrm6_tunnel_register); -int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) +int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) { struct xfrm6_tunnel **pprev; int ret = -ENOENT; mutex_lock(&tunnel6_mutex); - for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; + *pprev; pprev = &(*pprev)->next) { if (*pprev == handler) { *pprev = handler->next; ret = 0; @@ -103,6 +106,25 @@ drop: return 0; } +static int tunnel46_rcv(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct xfrm6_tunnel *handler; + + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + + for (handler = tunnel46_handlers; handler; handler = handler->next) + if (!handler->handler(skb)) + return 0; + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); + +drop: + kfree_skb(skb); + return 0; +} + static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { @@ -119,17 +141,30 @@ static struct inet6_protocol tunnel6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; +static struct inet6_protocol tunnel46_protocol = { + .handler = tunnel46_rcv, + .err_handler = tunnel6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + static int __init tunnel6_init(void) { if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) { printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); return -EAGAIN; } + if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) { + printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); + inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6); + return -EAGAIN; + } return 0; } static void __exit tunnel6_fini(void) { + if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP)) + printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6)) printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ccf2f4d..0ad4719 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -27,7 +27,6 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> -#include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/netdevice.h> diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 2525014..31f651f 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -40,7 +40,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, + nexthdr != IPPROTO_IPIP ? nexthdr : IPPROTO_IPV6, AF_INET6); if (x == NULL) goto drop; spin_lock(&x->lock); diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index fb02287..ee4b84a 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -339,17 +339,29 @@ static struct xfrm6_tunnel xfrm6_tunnel_handler = { .priority = 2, }; +static struct xfrm6_tunnel xfrm46_tunnel_handler = { + .handler = xfrm6_tunnel_rcv, + .err_handler = xfrm6_tunnel_err, + .priority = 2, +}; + static int __init xfrm6_tunnel_init(void) { if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) return -EAGAIN; - if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { + if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) { + xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); + return -EAGAIN; + } + if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) { + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); return -EAGAIN; } if (xfrm6_tunnel_spi_init() < 0) { - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); + xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); return -EAGAIN; } @@ -359,7 +371,8 @@ static int __init xfrm6_tunnel_init(void) static void __exit xfrm6_tunnel_fini(void) { xfrm6_tunnel_spi_fini(); - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); + xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); } diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c index 85ae35f..0cf5264 100644 --- a/net/ipx/sysctl_net_ipx.c +++ b/net/ipx/sysctl_net_ipx.c @@ -52,7 +52,7 @@ static struct ctl_table_header *ipx_table_header; void ipx_register_sysctl(void) { - ipx_table_header = register_sysctl_table(ipx_root_table, 1); + ipx_table_header = register_sysctl_table(ipx_root_table); } void ipx_unregister_sysctl(void) diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c index ec40715..4749f8f 100644 --- a/net/irda/ircomm/ircomm_core.c +++ b/net/irda/ircomm/ircomm_core.c @@ -30,7 +30,6 @@ ********************************************************************/ #include <linux/module.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c index 23d0468..8ba4e59 100644 --- a/net/irda/ircomm/ircomm_event.c +++ b/net/irda/ircomm/ircomm_event.c @@ -28,7 +28,6 @@ * ********************************************************************/ -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/init.h> diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 22bd752..55860ee 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c @@ -30,7 +30,6 @@ * ********************************************************************/ -#include <linux/sched.h> #include <linux/init.h> #include <net/irda/irda.h> diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c index fbac13e..01d7c9c 100644 --- a/net/irda/ircomm/ircomm_param.c +++ b/net/irda/ircomm/ircomm_param.c @@ -28,7 +28,6 @@ * ********************************************************************/ -#include <linux/sched.h> #include <linux/workqueue.h> #include <linux/interrupt.h> diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c index bb06eba..712eafd 100644 --- a/net/irda/ircomm/ircomm_ttp.c +++ b/net/irda/ircomm/ircomm_ttp.c @@ -29,7 +29,6 @@ * ********************************************************************/ -#include <linux/sched.h> #include <linux/init.h> #include <net/irda/irda.h> diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index 8d7ba93..824309d 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -29,7 +29,6 @@ * ********************************************************************/ -#include <linux/sched.h> #include <linux/init.h> #include <net/irda/irda.h> diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index a5174e6..6030947 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -30,7 +30,6 @@ #include <linux/init.h> #include <linux/fs.h> -#include <linux/sched.h> #include <linux/termios.h> #include <linux/tty.h> #include <linux/serial.h> diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c index bb53ba0..2e968e7 100644 --- a/net/irda/irsysctl.c +++ b/net/irda/irsysctl.c @@ -274,7 +274,7 @@ static struct ctl_table_header *irda_table_header; */ int __init irda_sysctl_register(void) { - irda_table_header = register_sysctl_table(irda_root_table, 0); + irda_table_header = register_sysctl_table(irda_root_table); if (!irda_table_header) return -ENOMEM; diff --git a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c index b0f8713..6762e7c 100644 --- a/net/lapb/lapb_in.c +++ b/net/lapb/lapb_in.c @@ -20,7 +20,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c index 981beb5..339cc5f 100644 --- a/net/lapb/lapb_out.c +++ b/net/lapb/lapb_out.c @@ -19,7 +19,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c index b8739cf..b827f47 100644 --- a/net/lapb/lapb_subr.c +++ b/net/lapb/lapb_subr.c @@ -18,7 +18,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c index d047a3e..46992d0 100644 --- a/net/llc/sysctl_net_llc.c +++ b/net/llc/sysctl_net_llc.c @@ -116,7 +116,7 @@ static struct ctl_table_header *llc_table_header; int __init llc_sysctl_init(void) { - llc_table_header = register_sysctl_table(llc_root_table, 1); + llc_table_header = register_sysctl_table(llc_root_table); return llc_table_header ? 0 : -ENOMEM; } diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 6990253..7c06993 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -12,7 +12,7 @@ */ #include <linux/types.h> -#include <linux/sched.h> +#include <linux/jiffies.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <net/netfilter/nf_conntrack_l4proto.h> diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 0133afa..3c80558 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -19,7 +19,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/module.h> diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index aff65aa..069b85c 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -25,7 +25,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/netfilter.h> #include <linux/module.h> diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index e49cd25..d0a1cee 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -12,7 +12,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/module.h> #include <linux/netfilter.h> diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index a0bba48..b858636 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -445,7 +445,7 @@ static int __init nf_conntrack_standalone_init(void) proc_stat->owner = THIS_MODULE; #endif #ifdef CONFIG_SYSCTL - nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); + nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table); if (nf_ct_sysctl_header == NULL) { printk("nf_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; diff --git a/net/netfilter/nf_sysctl.c b/net/netfilter/nf_sysctl.c index 06ddddb..ee34589 100644 --- a/net/netfilter/nf_sysctl.c +++ b/net/netfilter/nf_sysctl.c @@ -56,7 +56,7 @@ nf_register_sysctl_table(struct ctl_table *path, struct ctl_table *table) path = path_dup(path, table); if (path == NULL) return NULL; - header = register_sysctl_table(path, 0); + header = register_sysctl_table(path); if (header == NULL) path_free(path, table); return header; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index f42bb13..11d504d 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -19,7 +19,6 @@ #include <linux/socket.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index 4700d52..9a97ed6 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/types.h> diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c index a7d88b5..5560acb 100644 --- a/net/netrom/nr_in.c +++ b/net/netrom/nr_in.c @@ -12,7 +12,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c index 7939ded..0cbfb61 100644 --- a/net/netrom/nr_out.c +++ b/net/netrom/nr_out.c @@ -12,7 +12,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index c2fbac9..8e6bd4e 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -13,7 +13,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c index cfab572..07b694d 100644 --- a/net/netrom/nr_subr.c +++ b/net/netrom/nr_subr.c @@ -11,7 +11,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c index e4b27d7..2ea68da 100644 --- a/net/netrom/sysctl_net_netrom.c +++ b/net/netrom/sysctl_net_netrom.c @@ -192,7 +192,7 @@ static ctl_table nr_root_table[] = { void __init nr_register_sysctl(void) { - nr_table_header = register_sysctl_table(nr_root_table, 1); + nr_table_header = register_sysctl_table(nr_root_table); } void nr_unregister_sysctl(void) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 15ff7b1..bf26990 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -50,7 +50,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/capability.h> #include <linux/fcntl.h> diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 50824d3..8d88795 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/types.h> diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c index 8348d33..4ee0879 100644 --- a/net/rose/rose_in.c +++ b/net/rose/rose_in.c @@ -16,7 +16,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c index 2965ffc..69820f9 100644 --- a/net/rose/rose_out.c +++ b/net/rose/rose_out.c @@ -11,7 +11,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 1ddf7f5..a1233e1 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -12,7 +12,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 36a7794..b05108f 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c @@ -11,7 +11,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c index 27a452b..455b055 100644 --- a/net/rose/sysctl_net_rose.c +++ b/net/rose/sysctl_net_rose.c @@ -160,7 +160,7 @@ static ctl_table rose_root_table[] = { void __init rose_register_sysctl(void) { - rose_table_header = register_sysctl_table(rose_root_table, 1); + rose_table_header = register_sysctl_table(rose_root_table); } void rose_unregister_sysctl(void) diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c index 0755ae0..8842907 100644 --- a/net/rxrpc/sysctl.c +++ b/net/rxrpc/sysctl.c @@ -97,7 +97,7 @@ static ctl_table rxrpc_dir_sysctl_table[] = { int rxrpc_sysctl_init(void) { #ifdef CONFIG_SYSCTL - rxrpc_sysctl = register_sysctl_table(rxrpc_dir_sysctl_table, 0); + rxrpc_sysctl = register_sysctl_table(rxrpc_dir_sysctl_table); if (!rxrpc_sysctl) return -ENOMEM; #endif /* CONFIG_SYSCTL */ diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c index ff5f4f3..8e57be2 100644 --- a/net/rxrpc/transport.c +++ b/net/rxrpc/transport.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#include <linux/sched.h> #include <linux/slab.h> #include <linux/module.h> #include <rxrpc/transport.h> diff --git a/net/sched/act_api.c b/net/sched/act_api.c index dd0868d..cb21617 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -16,7 +16,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 60095d8..87d0faf 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -15,7 +15,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 0fdabfa..47f0b13 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -16,7 +16,6 @@ #include <asm/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 4838972..68f26cb 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -17,7 +17,6 @@ #include <asm/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 53aa96c..3d6a2fc 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -14,7 +14,6 @@ #include <asm/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 6ffe35d..10a5a5c 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -16,7 +16,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index f41f4ee..5c6ffdb 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index ea13c2c..fad08e5 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/errno.h> diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 2ce3ce5..5dbb9d4 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -24,7 +24,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index d3aea73..e85df07 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -15,7 +15,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/cls_rsvp.c b/net/sched/cls_rsvp.c index ad26137..1d4a1fb 100644 --- a/net/sched/cls_rsvp.c +++ b/net/sched/cls_rsvp.c @@ -15,7 +15,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/cls_rsvp6.c b/net/sched/cls_rsvp6.c index fde51f7..a2979d8 100644 --- a/net/sched/cls_rsvp6.c +++ b/net/sched/cls_rsvp6.c @@ -15,7 +15,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index a232671..0bcb169 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -36,7 +36,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/em_nbyte.c b/net/sched/em_nbyte.c index 42103b2..b4b36ef 100644 --- a/net/sched/em_nbyte.c +++ b/net/sched/em_nbyte.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/skbuff.h> #include <linux/tc_ematch/tc_em_nbyte.h> diff --git a/net/sched/em_text.c b/net/sched/em_text.c index 8ad894b..e8f4616 100644 --- a/net/sched/em_text.c +++ b/net/sched/em_text.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/skbuff.h> #include <linux/textsearch.h> diff --git a/net/sched/ematch.c b/net/sched/ematch.c index d3ad36b..959c306 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -84,7 +84,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> #include <linux/interrupt.h> diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 4158127..ecc988a 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -18,7 +18,6 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 48830ca..76c92e7 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -16,7 +16,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 135087d..396deb7 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -71,8 +71,6 @@ #include <asm/system.h> #include <asm/div64.h> -#define HFSC_DEBUG 1 - /* * kernel internal service curve representation: * coordinates are given by 64 bit unsigned integers. @@ -211,17 +209,6 @@ do { \ } while (0) #endif -#if HFSC_DEBUG -#define ASSERT(cond) \ -do { \ - if (unlikely(!(cond))) \ - printk("assertion %s failed at %s:%i (%s)\n", \ - #cond, __FILE__, __LINE__, __FUNCTION__); \ -} while (0) -#else -#define ASSERT(cond) -#endif /* HFSC_DEBUG */ - #define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ @@ -1492,7 +1479,7 @@ hfsc_schedule_watchdog(struct Qdisc *sch, u64 cur_time) if (next_time == 0 || next_time > q->root.cl_cfmin) next_time = q->root.cl_cfmin; } - ASSERT(next_time != 0); + WARN_ON(next_time == 0); delay = next_time - cur_time; delay = PSCHED_US2JIFFIE(delay); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 1f098d8..97cbb9a 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -33,7 +33,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 9f957ca..de889f2 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -17,7 +17,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 6a66037..587123c 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -14,7 +14,6 @@ #include <linux/bitops.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> diff --git a/net/sctp/associola.c b/net/sctp/associola.c index fca6f75..fa82b73 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -52,7 +52,6 @@ #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/in.h> diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 80294cb..fdb287a 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -43,7 +43,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/in.h> #include <net/sock.h> #include <net/ipv6.h> diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 286a8db..1404a9e 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -50,7 +50,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/in.h> #include <linux/random.h> /* get_random_bytes() */ diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 01b27fb..63fe109 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -53,7 +53,6 @@ #include <linux/socket.h> #include <linux/sockios.h> #include <linux/net.h> -#include <linux/sched.h> #include <linux/in.h> #include <linux/in6.h> #include <linux/netdevice.h> diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 633cd17..e2c679b 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -254,7 +254,7 @@ static struct ctl_table_header * sctp_sysctl_header; /* Sysctl registration. */ void sctp_sysctl_register(void) { - sctp_sysctl_header = register_sysctl_table(sctp_root_table, 0); + sctp_sysctl_header = register_sysctl_table(sctp_root_table); } /* Sysctl deregistration. */ diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 76f7eac..9527f2b 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -181,7 +181,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) struct rpc_cred *cred; int i; - dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); + dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); for (i = 0; i < RPC_CREDCACHE_NR; i++) { hlist_for_each_safe(pos, next, &cache->hashtable[i]) { cred = hlist_entry(pos, struct rpc_cred, cr_hash); @@ -267,7 +267,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) }; struct rpc_cred *ret; - dprintk("RPC: looking up %s cred\n", + dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); get_group_info(acred.group_info); ret = auth->au_ops->lookup_cred(auth, &acred, flags); @@ -287,7 +287,7 @@ rpcauth_bindcred(struct rpc_task *task) struct rpc_cred *ret; int flags = 0; - dprintk("RPC: %4d looking up %s cred\n", + dprintk("RPC: %5u looking up %s cred\n", task->tk_pid, task->tk_auth->au_ops->au_name); get_group_info(acred.group_info); if (task->tk_flags & RPC_TASK_ROOTCREDS) @@ -304,8 +304,9 @@ rpcauth_bindcred(struct rpc_task *task) void rpcauth_holdcred(struct rpc_task *task) { - dprintk("RPC: %4d holding %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred); + dprintk("RPC: %5u holding %s cred %p\n", + task->tk_pid, task->tk_auth->au_ops->au_name, + task->tk_msg.rpc_cred); if (task->tk_msg.rpc_cred) get_rpccred(task->tk_msg.rpc_cred); } @@ -324,7 +325,7 @@ rpcauth_unbindcred(struct rpc_task *task) { struct rpc_cred *cred = task->tk_msg.rpc_cred; - dprintk("RPC: %4d releasing %s cred %p\n", + dprintk("RPC: %5u releasing %s cred %p\n", task->tk_pid, task->tk_auth->au_ops->au_name, cred); put_rpccred(cred); @@ -336,7 +337,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; - dprintk("RPC: %4d marshaling %s cred %p\n", + dprintk("RPC: %5u marshaling %s cred %p\n", task->tk_pid, task->tk_auth->au_ops->au_name, cred); return cred->cr_ops->crmarshal(task, p); @@ -347,7 +348,7 @@ rpcauth_checkverf(struct rpc_task *task, __be32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; - dprintk("RPC: %4d validating %s cred %p\n", + dprintk("RPC: %5u validating %s cred %p\n", task->tk_pid, task->tk_auth->au_ops->au_name, cred); return cred->cr_ops->crvalidate(task, p); @@ -359,7 +360,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, { struct rpc_cred *cred = task->tk_msg.rpc_cred; - dprintk("RPC: %4d using %s cred %p to wrap rpc data\n", + dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", task->tk_pid, cred->cr_ops->cr_name, cred); if (cred->cr_ops->crwrap_req) return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); @@ -373,7 +374,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, { struct rpc_cred *cred = task->tk_msg.rpc_cred; - dprintk("RPC: %4d using %s cred %p to unwrap rpc data\n", + dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", task->tk_pid, cred->cr_ops->cr_name, cred); if (cred->cr_ops->crunwrap_resp) return cred->cr_ops->crunwrap_resp(task, decode, rqstp, @@ -388,7 +389,7 @@ rpcauth_refreshcred(struct rpc_task *task) struct rpc_cred *cred = task->tk_msg.rpc_cred; int err; - dprintk("RPC: %4d refreshing %s cred %p\n", + dprintk("RPC: %5u refreshing %s cred %p\n", task->tk_pid, task->tk_auth->au_ops->au_name, cred); err = cred->cr_ops->crrefresh(task); @@ -400,7 +401,7 @@ rpcauth_refreshcred(struct rpc_task *task) void rpcauth_invalcred(struct rpc_task *task) { - dprintk("RPC: %4d invalidating %s cred %p\n", + dprintk("RPC: %5u invalidating %s cred %p\n", task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred); spin_lock(&rpc_credcache_lock); if (task->tk_msg.rpc_cred) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 718fb94..4e4ccc5 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -241,7 +241,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct } return q; err: - dprintk("RPC: gss_fill_context returning %ld\n", -PTR_ERR(p)); + dprintk("RPC: gss_fill_context returning %ld\n", -PTR_ERR(p)); return p; } @@ -276,10 +276,10 @@ __gss_find_upcall(struct gss_auth *gss_auth, uid_t uid) if (pos->uid != uid) continue; atomic_inc(&pos->count); - dprintk("RPC: gss_find_upcall found msg %p\n", pos); + dprintk("RPC: gss_find_upcall found msg %p\n", pos); return pos; } - dprintk("RPC: gss_find_upcall found nothing\n"); + dprintk("RPC: gss_find_upcall found nothing\n"); return NULL; } @@ -393,7 +393,8 @@ gss_refresh_upcall(struct rpc_task *task) struct gss_upcall_msg *gss_msg; int err = 0; - dprintk("RPC: %4u gss_refresh_upcall for uid %u\n", task->tk_pid, cred->cr_uid); + dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, + cred->cr_uid); gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); if (IS_ERR(gss_msg)) { err = PTR_ERR(gss_msg); @@ -413,8 +414,8 @@ gss_refresh_upcall(struct rpc_task *task) spin_unlock(&gss_auth->lock); gss_release_msg(gss_msg); out: - dprintk("RPC: %4u gss_refresh_upcall for uid %u result %d\n", task->tk_pid, - cred->cr_uid, err); + dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", + task->tk_pid, cred->cr_uid, err); return err; } @@ -426,7 +427,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) DEFINE_WAIT(wait); int err = 0; - dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); + dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); if (IS_ERR(gss_msg)) { err = PTR_ERR(gss_msg); @@ -454,7 +455,8 @@ out_intr: finish_wait(&gss_msg->waitqueue, &wait); gss_release_msg(gss_msg); out: - dprintk("RPC: gss_create_upcall for uid %u result %d\n", cred->cr_uid, err); + dprintk("RPC: gss_create_upcall for uid %u result %d\n", + cred->cr_uid, err); return err; } @@ -546,14 +548,14 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) } gss_put_ctx(ctx); kfree(buf); - dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); + dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); return mlen; err_put_ctx: gss_put_ctx(ctx); err: kfree(buf); out: - dprintk("RPC: gss_pipe_downcall returning %d\n", err); + dprintk("RPC: gss_pipe_downcall returning %d\n", err); return err; } @@ -591,7 +593,7 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) static unsigned long ratelimit; if (msg->errno < 0) { - dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n", + dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n", gss_msg); atomic_inc(&gss_msg->count); gss_unhash_msg(gss_msg); @@ -618,7 +620,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) struct rpc_auth * auth; int err = -ENOMEM; /* XXX? */ - dprintk("RPC: creating GSS authenticator for client %p\n",clnt); + dprintk("RPC: creating GSS authenticator for client %p\n", clnt); if (!try_module_get(THIS_MODULE)) return ERR_PTR(err); @@ -670,8 +672,8 @@ gss_destroy(struct rpc_auth *auth) { struct gss_auth *gss_auth; - dprintk("RPC: destroying GSS authenticator %p flavor %d\n", - auth, auth->au_flavor); + dprintk("RPC: destroying GSS authenticator %p flavor %d\n", + auth, auth->au_flavor); gss_auth = container_of(auth, struct gss_auth, rpc_auth); rpc_unlink(gss_auth->dentry); @@ -689,7 +691,7 @@ gss_destroy(struct rpc_auth *auth) static void gss_destroy_ctx(struct gss_cl_ctx *ctx) { - dprintk("RPC: gss_destroy_ctx\n"); + dprintk("RPC: gss_destroy_ctx\n"); if (ctx->gc_gss_ctx) gss_delete_sec_context(&ctx->gc_gss_ctx); @@ -703,7 +705,7 @@ gss_destroy_cred(struct rpc_cred *rc) { struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base); - dprintk("RPC: gss_destroy_cred \n"); + dprintk("RPC: gss_destroy_cred \n"); if (cred->gc_ctx) gss_put_ctx(cred->gc_ctx); @@ -726,7 +728,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) struct gss_cred *cred = NULL; int err = -ENOMEM; - dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", + dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", acred->uid, auth->au_flavor); if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL))) @@ -745,7 +747,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) return &cred->gc_base; out_err: - dprintk("RPC: gss_create_cred failed with error %d\n", err); + dprintk("RPC: gss_create_cred failed with error %d\n", err); return ERR_PTR(err); } @@ -799,7 +801,7 @@ gss_marshal(struct rpc_task *task, __be32 *p) struct kvec iov; struct xdr_buf verf_buf; - dprintk("RPC: %4u gss_marshal\n", task->tk_pid); + dprintk("RPC: %5u gss_marshal\n", task->tk_pid); *p++ = htonl(RPC_AUTH_GSS); cred_len = p++; @@ -865,7 +867,7 @@ gss_validate(struct rpc_task *task, __be32 *p) u32 flav,len; u32 maj_stat; - dprintk("RPC: %4u gss_validate\n", task->tk_pid); + dprintk("RPC: %5u gss_validate\n", task->tk_pid); flav = ntohl(*p++); if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE) @@ -888,12 +890,12 @@ gss_validate(struct rpc_task *task, __be32 *p) * calculate the length of the verifier: */ task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2; gss_put_ctx(ctx); - dprintk("RPC: %4u GSS gss_validate: gss_verify_mic succeeded.\n", + dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n", task->tk_pid); return p + XDR_QUADLEN(len); out_bad: gss_put_ctx(ctx); - dprintk("RPC: %4u gss_validate failed.\n", task->tk_pid); + dprintk("RPC: %5u gss_validate failed.\n", task->tk_pid); return NULL; } @@ -1063,7 +1065,7 @@ gss_wrap_req(struct rpc_task *task, struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); int status = -EIO; - dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid); + dprintk("RPC: %5u gss_wrap_req\n", task->tk_pid); if (ctx->gc_proc != RPC_GSS_PROC_DATA) { /* The spec seems a little ambiguous here, but I think that not * wrapping context destruction requests makes the most sense. @@ -1086,7 +1088,7 @@ gss_wrap_req(struct rpc_task *task, } out: gss_put_ctx(ctx); - dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status); + dprintk("RPC: %5u gss_wrap_req returning %d\n", task->tk_pid, status); return status; } @@ -1192,7 +1194,7 @@ out_decode: status = decode(rqstp, p, obj); out: gss_put_ctx(ctx); - dprintk("RPC: %4u gss_unwrap_resp returning %d\n", task->tk_pid, + dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid, status); return status; } diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 0a9948d..f441aa0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -66,8 +66,8 @@ krb5_encrypt( goto out; if (crypto_blkcipher_ivsize(tfm) > 16) { - dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n", - crypto_blkcipher_ivsize(tfm)); + dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n", + crypto_blkcipher_ivsize(tfm)); goto out; } @@ -79,7 +79,7 @@ krb5_encrypt( ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, length); out: - dprintk("RPC: krb5_encrypt returns %d\n",ret); + dprintk("RPC: krb5_encrypt returns %d\n", ret); return ret; } @@ -102,7 +102,7 @@ krb5_decrypt( goto out; if (crypto_blkcipher_ivsize(tfm) > 16) { - dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n", + dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n", crypto_blkcipher_ivsize(tfm)); goto out; } @@ -114,7 +114,7 @@ krb5_decrypt( ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, length); out: - dprintk("RPC: gss_k5decrypt returns %d\n",ret); + dprintk("RPC: gss_k5decrypt returns %d\n",ret); return ret; } diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 05d4bee..7b19432 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -175,7 +175,8 @@ gss_import_sec_context_kerberos(const void *p, } ctx_id->internal_ctx_id = ctx; - dprintk("RPC: Successfully imported new context.\n"); + + dprintk("RPC: Successfully imported new context.\n"); return 0; out_err_free_key2: diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index d0bb506..a0d9faa 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -83,7 +83,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, s32 now; u32 seq_send; - dprintk("RPC: gss_krb5_seal\n"); + dprintk("RPC: gss_krb5_seal\n"); now = get_seconds(); diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c index 3e315a6..43f3421 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c +++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c @@ -70,7 +70,7 @@ krb5_get_seq_num(struct crypto_blkcipher *key, s32 code; unsigned char plain[8]; - dprintk("RPC: krb5_get_seq_num:\n"); + dprintk("RPC: krb5_get_seq_num:\n"); if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) return code; diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 87f8977..e30a993 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -86,7 +86,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, unsigned char *ptr = (unsigned char *)read_token->data; int bodysize; - dprintk("RPC: krb5_read_token\n"); + dprintk("RPC: krb5_read_token\n"); if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, read_token->len)) diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index fe25b3d..42b3220 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -129,7 +129,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, struct page **tmp_pages; u32 seq_send; - dprintk("RPC: gss_wrap_kerberos\n"); + dprintk("RPC: gss_wrap_kerberos\n"); now = get_seconds(); @@ -215,7 +215,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) int data_len; int blocksize; - dprintk("RPC: gss_unwrap_kerberos\n"); + dprintk("RPC: gss_unwrap_kerberos\n"); ptr = (u8 *)buf->head[0].iov_base + offset; if (g_verify_token_header(&kctx->mech_used, &bodysize, &ptr, diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 3423890..2687251 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -113,7 +113,7 @@ gss_mech_register(struct gss_api_mech *gm) spin_lock(®istered_mechs_lock); list_add(&gm->gm_list, ®istered_mechs); spin_unlock(®istered_mechs_lock); - dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); + dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); return 0; } @@ -125,7 +125,7 @@ gss_mech_unregister(struct gss_api_mech *gm) spin_lock(®istered_mechs_lock); list_del(&gm->gm_list); spin_unlock(®istered_mechs_lock); - dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); + dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); gss_mech_free(gm); } @@ -298,7 +298,7 @@ gss_unwrap(struct gss_ctx *ctx_id, u32 gss_delete_sec_context(struct gss_ctx **context_handle) { - dprintk("RPC: gss_delete_sec_context deleting %p\n", + dprintk("RPC: gss_delete_sec_context deleting %p\n", *context_handle); if (!*context_handle) diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index 8ef3f1c..7e15aa6 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -97,7 +97,8 @@ gss_import_sec_context_spkm3(const void *p, size_t len, if (IS_ERR(p)) goto out_err_free_ctx; if (version != 1) { - dprintk("RPC: unknown spkm3 token format: obsolete nfs-utils?\n"); + dprintk("RPC: unknown spkm3 token format: " + "obsolete nfs-utils?\n"); goto out_err_free_ctx; } @@ -138,7 +139,7 @@ gss_import_sec_context_spkm3(const void *p, size_t len, ctx_id->internal_ctx_id = ctx; - dprintk("Successfully imported new spkm context.\n"); + dprintk("RPC: Successfully imported new spkm context.\n"); return 0; out_err_free_intg_key: @@ -183,7 +184,7 @@ gss_verify_mic_spkm3(struct gss_ctx *ctx, maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK); - dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat); + dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat); return maj_stat; } @@ -197,7 +198,7 @@ gss_get_mic_spkm3(struct gss_ctx *ctx, err = spkm3_make_token(sctx, message_buffer, message_token, SPKM_MIC_TOK); - dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err); + dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err); return err; } diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c index b179d58..104cbf4 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_seal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c @@ -75,20 +75,21 @@ spkm3_make_token(struct spkm3_ctx *ctx, now = jiffies; if (ctx->ctx_id.len != 16) { - dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n", + dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n", ctx->ctx_id.len); goto out_err; } if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { - dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm." - "only support hmac-md5 I-ALG.\n"); + dprintk("RPC: gss_spkm3_seal: unsupported I-ALG " + "algorithm. only support hmac-md5 I-ALG.\n"); goto out_err; } else checksum_type = CKSUMTYPE_HMAC_MD5; if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) { - dprintk("RPC: gss_spkm3_seal: unsupported C-ALG algorithm\n"); + dprintk("RPC: gss_spkm3_seal: unsupported C-ALG " + "algorithm\n"); goto out_err; } @@ -113,7 +114,8 @@ spkm3_make_token(struct spkm3_ctx *ctx, spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit); } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */ - dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n"); + dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK " + "not supported\n"); goto out_err; } @@ -153,7 +155,7 @@ make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header, cksumname = "md5"; break; default: - dprintk("RPC: spkm3_make_checksum:" + dprintk("RPC: spkm3_make_checksum:" " unsupported checksum %d", cksumtype); return GSS_S_FAILURE; } diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c index 8400b62..6cdd241a 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_token.c +++ b/net/sunrpc/auth_gss/gss_spkm3_token.c @@ -209,7 +209,7 @@ spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **ck /* spkm3 innercontext token preamble */ if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) { - dprintk("RPC: BAD SPKM ictoken preamble\n"); + dprintk("RPC: BAD SPKM ictoken preamble\n"); goto out; } @@ -217,25 +217,25 @@ spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **ck /* token type */ if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) { - dprintk("RPC: BAD asn1 SPKM3 token type\n"); + dprintk("RPC: BAD asn1 SPKM3 token type\n"); goto out; } /* only support SPKM_MIC_TOK */ if((ptr[6] != 0x01) || (ptr[7] != 0x01)) { - dprintk("RPC: ERROR unsupported SPKM3 token \n"); + dprintk("RPC: ERROR unsupported SPKM3 token \n"); goto out; } /* contextid */ if (ptr[8] != 0x03) { - dprintk("RPC: BAD SPKM3 asn1 context-id type\n"); + dprintk("RPC: BAD SPKM3 asn1 context-id type\n"); goto out; } ctxelen = ptr[9]; if (ctxelen > 17) { /* length includes asn1 zbit octet */ - dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen); + dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen); goto out; } @@ -251,7 +251,9 @@ spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **ck */ if (*mic_hdrlen != 6 + ctxelen) { - dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq\n", *mic_hdrlen); + dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only " + "support default int-alg (should be absent) " + "and do not support snd-seq\n", *mic_hdrlen); goto out; } /* checksum */ diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c index 35a1b34..cc21ee8 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c @@ -72,7 +72,7 @@ spkm3_read_token(struct spkm3_ctx *ctx, /* decode the token */ if (toktype != SPKM_MIC_TOK) { - dprintk("RPC: BAD SPKM3 token type: %d\n", toktype); + dprintk("RPC: BAD SPKM3 token type: %d\n", toktype); goto out; } @@ -80,7 +80,7 @@ spkm3_read_token(struct spkm3_ctx *ctx, goto out; if (*cksum++ != 0x03) { - dprintk("RPC: spkm3_read_token BAD checksum type\n"); + dprintk("RPC: spkm3_read_token BAD checksum type\n"); goto out; } md5elen = *cksum++; @@ -97,7 +97,8 @@ spkm3_read_token(struct spkm3_ctx *ctx, */ ret = GSS_S_DEFECTIVE_TOKEN; if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) { - dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm\n"); + dprintk("RPC: gss_spkm3_seal: unsupported I-ALG " + "algorithm\n"); goto out; } @@ -113,7 +114,7 @@ spkm3_read_token(struct spkm3_ctx *ctx, ret = GSS_S_BAD_SIG; code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len); if (code) { - dprintk("RPC: bad MIC checksum\n"); + dprintk("RPC: bad MIC checksum\n"); goto out; } diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 8fde38e..db298b5 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -669,14 +669,14 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, } if (gc->gc_seq > MAXSEQ) { - dprintk("RPC: svcauth_gss: discarding request with large sequence number %d\n", - gc->gc_seq); + dprintk("RPC: svcauth_gss: discarding request with " + "large sequence number %d\n", gc->gc_seq); *authp = rpcsec_gsserr_ctxproblem; return SVC_DENIED; } if (!gss_check_seq_num(rsci, gc->gc_seq)) { - dprintk("RPC: svcauth_gss: discarding request with old sequence number %d\n", - gc->gc_seq); + dprintk("RPC: svcauth_gss: discarding request with " + "old sequence number %d\n", gc->gc_seq); return SVC_DROP; } return SVC_OK; @@ -958,7 +958,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) __be32 *reject_stat = resv->iov_base + resv->iov_len; int ret; - dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len); + dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n", + argv->iov_len); *authp = rpc_autherr_badcred; if (!svcdata) diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 3be257d..3df9fcc 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/utsname.h> #include <linux/sunrpc/clnt.h> -#include <linux/sched.h> #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index f7f990c..4e7733a 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -39,7 +39,8 @@ static struct rpc_credops unix_credops; static struct rpc_auth * unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) { - dprintk("RPC: creating UNIX authenticator for client %p\n", clnt); + dprintk("RPC: creating UNIX authenticator for client %p\n", + clnt); if (atomic_inc_return(&unix_auth.au_count) == 0) unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1); return &unix_auth; @@ -48,7 +49,7 @@ unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) static void unx_destroy(struct rpc_auth *auth) { - dprintk("RPC: destroying UNIX authenticator %p\n", auth); + dprintk("RPC: destroying UNIX authenticator %p\n", auth); rpcauth_free_credcache(auth); } @@ -67,8 +68,8 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) struct unx_cred *cred; int i; - dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", - acred->uid, acred->gid); + dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", + acred->uid, acred->gid); if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL))) return ERR_PTR(-ENOMEM); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 8612044..f02f24a 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -215,7 +215,8 @@ int cache_check(struct cache_detail *detail, if (rv == -EAGAIN) rv = -ENOENT; } else if (rv == -EAGAIN || age > refresh_age/2) { - dprintk("Want update, refage=%ld, age=%ld\n", refresh_age, age); + dprintk("RPC: Want update, refage=%ld, age=%ld\n", + refresh_age, age); if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { switch (cache_make_upcall(detail, h)) { case -EINVAL: diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index c95a617..6d7221f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -42,6 +42,10 @@ # define RPCDBG_FACILITY RPCDBG_CALL #endif +#define dprint_status(t) \ + dprintk("RPC: %5u %s (status %d)\n", t->tk_pid, \ + __FUNCTION__, t->tk_status) + static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); @@ -106,8 +110,8 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s int err; int len; - dprintk("RPC: creating %s client for %s (xprt %p)\n", - program->name, servname, xprt); + dprintk("RPC: creating %s client for %s (xprt %p)\n", + program->name, servname, xprt); err = -EINVAL; if (!xprt) @@ -220,7 +224,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) xprt->resvport = 0; dprintk("RPC: creating %s client for %s (xprt %p)\n", - args->program->name, args->servername, xprt); + args->program->name, args->servername, xprt); clnt = rpc_new_client(xprt, args->servername, args->program, args->version, args->authflavor); @@ -245,6 +249,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) clnt->cl_autobind = 1; if (args->flags & RPC_CLNT_CREATE_ONESHOT) clnt->cl_oneshot = 1; + if (args->flags & RPC_CLNT_CREATE_DISCRTRY) + clnt->cl_discrtry = 1; return clnt; } @@ -288,7 +294,7 @@ out_no_path: out_no_stats: kfree(new); out_no_clnt: - dprintk("RPC: %s returned error %d\n", __FUNCTION__, err); + dprintk("RPC: %s: returned error %d\n", __FUNCTION__, err); return ERR_PTR(err); } @@ -301,7 +307,7 @@ out_no_clnt: int rpc_shutdown_client(struct rpc_clnt *clnt) { - dprintk("RPC: shutting down %s client for %s, tasks=%d\n", + dprintk("RPC: shutting down %s client for %s, tasks=%d\n", clnt->cl_protname, clnt->cl_server, atomic_read(&clnt->cl_users)); @@ -336,7 +342,7 @@ rpc_destroy_client(struct rpc_clnt *clnt) return 1; BUG_ON(atomic_read(&clnt->cl_users) != 0); - dprintk("RPC: destroying %s client for %s\n", + dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); if (clnt->cl_auth) { rpcauth_destroy(clnt->cl_auth); @@ -366,8 +372,8 @@ out_free: void rpc_release_client(struct rpc_clnt *clnt) { - dprintk("RPC: rpc_release_client(%p, %d)\n", - clnt, atomic_read(&clnt->cl_users)); + dprintk("RPC: rpc_release_client(%p, %d)\n", + clnt, atomic_read(&clnt->cl_users)); if (!atomic_dec_and_test(&clnt->cl_users)) return; @@ -486,17 +492,13 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ rpc_task_sigmask(task, &oldset); - rpc_call_setup(task, msg, 0); - /* Set up the call info struct and execute the task */ + rpc_call_setup(task, msg, 0); + if (task->tk_status == 0) { + atomic_inc(&task->tk_count); + rpc_execute(task); + } status = task->tk_status; - if (status != 0) - goto out; - atomic_inc(&task->tk_count); - status = rpc_execute(task); - if (status == 0) - status = task->tk_status; -out: rpc_put_task(task); rpc_restore_sigmask(&oldset); return status; @@ -658,9 +660,10 @@ call_start(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - dprintk("RPC: %4d call_start %s%d proc %d (%s)\n", task->tk_pid, - clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc->p_proc, - (RPC_IS_ASYNC(task) ? "async" : "sync")); + dprintk("RPC: %5u call_start %s%d proc %d (%s)\n", task->tk_pid, + clnt->cl_protname, clnt->cl_vers, + task->tk_msg.rpc_proc->p_proc, + (RPC_IS_ASYNC(task) ? "async" : "sync")); /* Increment call count */ task->tk_msg.rpc_proc->p_count++; @@ -674,7 +677,7 @@ call_start(struct rpc_task *task) static void call_reserve(struct rpc_task *task) { - dprintk("RPC: %4d call_reserve\n", task->tk_pid); + dprint_status(task); if (!rpcauth_uptodatecred(task)) { task->tk_action = call_refresh; @@ -694,8 +697,7 @@ call_reserveresult(struct rpc_task *task) { int status = task->tk_status; - dprintk("RPC: %4d call_reserveresult (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); /* * After a call to xprt_reserve(), we must have either @@ -749,8 +751,8 @@ call_allocate(struct rpc_task *task) struct rpc_xprt *xprt = task->tk_xprt; unsigned int bufsiz; - dprintk("RPC: %4d call_allocate (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); + task->tk_action = call_bind; if (req->rq_buffer) return; @@ -761,7 +763,8 @@ call_allocate(struct rpc_task *task) if (xprt->ops->buf_alloc(task, bufsiz << 1) != NULL) return; - printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); + + dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid); if (RPC_IS_ASYNC(task) || !signalled()) { xprt_release(task); @@ -798,8 +801,7 @@ call_encode(struct rpc_task *task) kxdrproc_t encode; __be32 *p; - dprintk("RPC: %4d call_encode (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); /* Default buffer setup */ bufsiz = req->rq_bufsize >> 1; @@ -845,8 +847,7 @@ call_bind(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - dprintk("RPC: %4d call_bind (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); task->tk_action = call_connect; if (!xprt_bound(xprt)) { @@ -865,8 +866,7 @@ call_bind_status(struct rpc_task *task) int status = -EACCES; if (task->tk_status >= 0) { - dprintk("RPC: %4d call_bind_status (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); task->tk_status = 0; task->tk_action = call_connect; return; @@ -874,24 +874,24 @@ call_bind_status(struct rpc_task *task) switch (task->tk_status) { case -EACCES: - dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", - task->tk_pid); + dprintk("RPC: %5u remote rpcbind: RPC program/version " + "unavailable\n", task->tk_pid); rpc_delay(task, 3*HZ); goto retry_timeout; case -ETIMEDOUT: - dprintk("RPC: %4d rpcbind request timed out\n", + dprintk("RPC: %5u rpcbind request timed out\n", task->tk_pid); goto retry_timeout; case -EPFNOSUPPORT: - dprintk("RPC: %4d remote rpcbind service unavailable\n", + dprintk("RPC: %5u remote rpcbind service unavailable\n", task->tk_pid); break; case -EPROTONOSUPPORT: - dprintk("RPC: %4d remote rpcbind version 2 unavailable\n", + dprintk("RPC: %5u remote rpcbind version 2 unavailable\n", task->tk_pid); break; default: - dprintk("RPC: %4d unrecognized rpcbind error (%d)\n", + dprintk("RPC: %5u unrecognized rpcbind error (%d)\n", task->tk_pid, -task->tk_status); status = -EIO; } @@ -911,7 +911,7 @@ call_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - dprintk("RPC: %4d call_connect xprt %p %s connected\n", + dprintk("RPC: %5u call_connect xprt %p %s connected\n", task->tk_pid, xprt, (xprt_connected(xprt) ? "is" : "is not")); @@ -933,8 +933,7 @@ call_connect_status(struct rpc_task *task) struct rpc_clnt *clnt = task->tk_client; int status = task->tk_status; - dprintk("RPC: %5u call_connect_status (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); task->tk_status = 0; if (status >= 0) { @@ -966,8 +965,7 @@ call_connect_status(struct rpc_task *task) static void call_transmit(struct rpc_task *task) { - dprintk("RPC: %4d call_transmit (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); task->tk_action = call_status; if (task->tk_status < 0) @@ -1028,8 +1026,7 @@ call_status(struct rpc_task *task) if (req->rq_received > 0 && !req->rq_bytes_sent) task->tk_status = req->rq_received; - dprintk("RPC: %4d call_status (status %d)\n", - task->tk_pid, task->tk_status); + dprint_status(task); status = task->tk_status; if (status >= 0) { @@ -1080,11 +1077,11 @@ call_timeout(struct rpc_task *task) struct rpc_clnt *clnt = task->tk_client; if (xprt_adjust_timeout(task->tk_rqstp) == 0) { - dprintk("RPC: %4d call_timeout (minor)\n", task->tk_pid); + dprintk("RPC: %5u call_timeout (minor)\n", task->tk_pid); goto retry; } - dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid); + dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid); task->tk_timeouts++; if (RPC_IS_SOFT(task)) { @@ -1118,8 +1115,8 @@ call_decode(struct rpc_task *task) kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode; __be32 *p; - dprintk("RPC: %4d call_decode (status %d)\n", - task->tk_pid, task->tk_status); + dprintk("RPC: %5u call_decode (status %d)\n", + task->tk_pid, task->tk_status); if (task->tk_flags & RPC_CALL_MAJORSEEN) { printk(KERN_NOTICE "%s: server %s OK\n", @@ -1133,8 +1130,8 @@ call_decode(struct rpc_task *task) clnt->cl_stats->rpcretrans++; goto out_retry; } - dprintk("%s: too small RPC reply size (%d bytes)\n", - clnt->cl_protname, task->tk_status); + dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", + clnt->cl_protname, task->tk_status); task->tk_action = call_timeout; goto out_retry; } @@ -1166,8 +1163,8 @@ call_decode(struct rpc_task *task) task->tk_msg.rpc_resp); unlock_kernel(); } - dprintk("RPC: %4d call_decode result %d\n", task->tk_pid, - task->tk_status); + dprintk("RPC: %5u call_decode result %d\n", task->tk_pid, + task->tk_status); return; out_retry: req->rq_received = req->rq_private_buf.len = 0; @@ -1180,7 +1177,7 @@ out_retry: static void call_refresh(struct rpc_task *task) { - dprintk("RPC: %4d call_refresh\n", task->tk_pid); + dprint_status(task); xprt_release(task); /* Must do to obtain new XID */ task->tk_action = call_refreshresult; @@ -1196,8 +1193,8 @@ static void call_refreshresult(struct rpc_task *task) { int status = task->tk_status; - dprintk("RPC: %4d call_refreshresult (status %d)\n", - task->tk_pid, task->tk_status); + + dprint_status(task); task->tk_status = 0; task->tk_action = call_reserve; @@ -1275,11 +1272,15 @@ call_verify(struct rpc_task *task) case RPC_AUTH_ERROR: break; case RPC_MISMATCH: - dprintk("%s: RPC call version mismatch!\n", __FUNCTION__); + dprintk("RPC: %5u %s: RPC call version " + "mismatch!\n", + task->tk_pid, __FUNCTION__); error = -EPROTONOSUPPORT; goto out_err; default: - dprintk("%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); + dprintk("RPC: %5u %s: RPC call rejected, " + "unknown error: %x\n", + task->tk_pid, __FUNCTION__, n); goto out_eio; } if (--len < 0) @@ -1292,8 +1293,8 @@ call_verify(struct rpc_task *task) if (!task->tk_cred_retry) break; task->tk_cred_retry--; - dprintk("RPC: %4d call_verify: retry stale creds\n", - task->tk_pid); + dprintk("RPC: %5u %s: retry stale creds\n", + task->tk_pid, __FUNCTION__); rpcauth_invalcred(task); task->tk_action = call_refresh; goto out_retry; @@ -1303,8 +1304,8 @@ call_verify(struct rpc_task *task) if (!task->tk_garb_retry) break; task->tk_garb_retry--; - dprintk("RPC: %4d call_verify: retry garbled creds\n", - task->tk_pid); + dprintk("RPC: %5u %s: retry garbled creds\n", + task->tk_pid, __FUNCTION__); task->tk_action = call_bind; goto out_retry; case RPC_AUTH_TOOWEAK: @@ -1315,8 +1316,8 @@ call_verify(struct rpc_task *task) printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n); error = -EIO; } - dprintk("RPC: %4d call_verify: call rejected %d\n", - task->tk_pid, n); + dprintk("RPC: %5u %s: call rejected %d\n", + task->tk_pid, __FUNCTION__, n); goto out_err; } if (!(p = rpcauth_checkverf(task, p))) { @@ -1330,20 +1331,24 @@ call_verify(struct rpc_task *task) case RPC_SUCCESS: return p; case RPC_PROG_UNAVAIL: - dprintk("RPC: call_verify: program %u is unsupported by server %s\n", + dprintk("RPC: %5u %s: program %u is unsupported by server %s\n", + task->tk_pid, __FUNCTION__, (unsigned int)task->tk_client->cl_prog, task->tk_client->cl_server); error = -EPFNOSUPPORT; goto out_err; case RPC_PROG_MISMATCH: - dprintk("RPC: call_verify: program %u, version %u unsupported by server %s\n", + dprintk("RPC: %5u %s: program %u, version %u unsupported by " + "server %s\n", task->tk_pid, __FUNCTION__, (unsigned int)task->tk_client->cl_prog, (unsigned int)task->tk_client->cl_vers, task->tk_client->cl_server); error = -EPROTONOSUPPORT; goto out_err; case RPC_PROC_UNAVAIL: - dprintk("RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", + dprintk("RPC: %5u %s: proc %p unsupported by program %u, " + "version %u on server %s\n", + task->tk_pid, __FUNCTION__, task->tk_msg.rpc_proc, task->tk_client->cl_prog, task->tk_client->cl_vers, @@ -1351,7 +1356,8 @@ call_verify(struct rpc_task *task) error = -EOPNOTSUPP; goto out_err; case RPC_GARBAGE_ARGS: - dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__); + dprintk("RPC: %5u %s: server saw garbage\n", + task->tk_pid, __FUNCTION__); break; /* retry */ default: printk(KERN_WARNING "call_verify: server accept status: %x\n", n); @@ -1362,7 +1368,8 @@ out_garbage: task->tk_client->cl_stats->rpcgarbage++; if (task->tk_garb_retry) { task->tk_garb_retry--; - dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); + dprintk("RPC: %5u %s: retrying\n", + task->tk_pid, __FUNCTION__); task->tk_action = call_bind; out_retry: return ERR_PTR(-EAGAIN); diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index f4e1357..d9f7653 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -62,7 +62,10 @@ static inline void pmap_map_free(struct portmap_args *map) static void pmap_map_release(void *data) { - pmap_map_free(data); + struct portmap_args *map = data; + + xprt_put(map->pm_xprt); + pmap_map_free(map); } static const struct rpc_call_ops pmap_getport_ops = { @@ -94,7 +97,7 @@ void rpc_getport(struct rpc_task *task) struct rpc_task *child; int status; - dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n", + dprintk("RPC: %5u rpc_getport(%s, %u, %u, %d)\n", task->tk_pid, clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); @@ -133,7 +136,7 @@ void rpc_getport(struct rpc_task *task) status = -EIO; child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); if (IS_ERR(child)) - goto bailout; + goto bailout_nofree; rpc_put_task(child); task->tk_xprt->stat.bind_count++; @@ -175,7 +178,7 @@ int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int pr char hostname[32]; int status; - dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n", + dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n", NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); @@ -218,11 +221,10 @@ static void pmap_getport_done(struct rpc_task *child, void *data) status = 0; } - dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n", + dprintk("RPC: %5u pmap_getport_done(status %d, port %u)\n", child->tk_pid, status, map->pm_port); pmap_wake_portmap_waiters(xprt, status); - xprt_put(xprt); } /** @@ -255,13 +257,14 @@ int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) struct rpc_clnt *pmap_clnt; int error = 0; - dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n", + dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n", prog, vers, prot, port); pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1); if (IS_ERR(pmap_clnt)) { error = PTR_ERR(pmap_clnt); - dprintk("RPC: couldn't create pmap client. Error = %d\n", error); + dprintk("RPC: couldn't create pmap client. Error = %d\n", + error); return error; } @@ -272,7 +275,7 @@ int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) "RPC: failed to contact portmap (errno %d).\n", error); } - dprintk("RPC: registration status %d/%d\n", error, *okay); + dprintk("RPC: registration status %d/%d\n", error, *okay); /* Client deleted automatically because cl_oneshot == 1 */ return error; @@ -303,8 +306,9 @@ static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, */ static int xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct portmap_args *map) { - dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n", - map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port); + dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n", + map->pm_prog, map->pm_vers, + map->pm_prot, map->pm_port); *p++ = htonl(map->pm_prog); *p++ = htonl(map->pm_vers); *p++ = htonl(map->pm_prot); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index e1fad77..9b9ea50 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -589,7 +589,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) { struct inode *inode; - inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR); + inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) goto out_err; inode->i_ino = iunique(dir->i_sb, 100); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 54a6b92..6d87320 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(rpc_sched_lock); static inline void __rpc_disable_timer(struct rpc_task *task) { - dprintk("RPC: %4d disabling timer\n", task->tk_pid); + dprintk("RPC: %5u disabling timer\n", task->tk_pid); task->tk_timeout_fn = NULL; task->tk_timeout = 0; } @@ -93,7 +93,7 @@ static void rpc_run_timer(struct rpc_task *task) callback = task->tk_timeout_fn; task->tk_timeout_fn = NULL; if (callback && RPC_IS_QUEUED(task)) { - dprintk("RPC: %4d running timer\n", task->tk_pid); + dprintk("RPC: %5u running timer\n", task->tk_pid); callback(task); } smp_mb__before_clear_bit(); @@ -110,7 +110,7 @@ __rpc_add_timer(struct rpc_task *task, rpc_action timer) if (!task->tk_timeout) return; - dprintk("RPC: %4d setting alarm for %lu ms\n", + dprintk("RPC: %5u setting alarm for %lu ms\n", task->tk_pid, task->tk_timeout * 1000 / HZ); if (timer) @@ -132,7 +132,7 @@ rpc_delete_timer(struct rpc_task *task) return; if (test_and_clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate)) { del_singleshot_timer_sync(&task->tk_timer); - dprintk("RPC: %4d deleting timer\n", task->tk_pid); + dprintk("RPC: %5u deleting timer\n", task->tk_pid); } } @@ -179,8 +179,8 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task * queue->qlen++; rpc_set_queued(task); - dprintk("RPC: %4d added to queue %p \"%s\"\n", - task->tk_pid, queue, rpc_qname(queue)); + dprintk("RPC: %5u added to queue %p \"%s\"\n", + task->tk_pid, queue, rpc_qname(queue)); } /* @@ -212,8 +212,8 @@ static void __rpc_remove_wait_queue(struct rpc_task *task) else list_del(&task->u.tk_wait.list); queue->qlen--; - dprintk("RPC: %4d removed from queue %p \"%s\"\n", - task->tk_pid, queue, rpc_qname(queue)); + dprintk("RPC: %5u removed from queue %p \"%s\"\n", + task->tk_pid, queue, rpc_qname(queue)); } static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) @@ -344,8 +344,8 @@ static void rpc_make_runnable(struct rpc_task *task) static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, rpc_action action, rpc_action timer) { - dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid, - rpc_qname(q), jiffies); + dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", + task->tk_pid, rpc_qname(q), jiffies); if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) { printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n"); @@ -381,7 +381,8 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, */ static void __rpc_do_wake_up_task(struct rpc_task *task) { - dprintk("RPC: %4d __rpc_wake_up_task (now %ld)\n", task->tk_pid, jiffies); + dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n", + task->tk_pid, jiffies); #ifdef RPC_DEBUG BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); @@ -397,7 +398,7 @@ static void __rpc_do_wake_up_task(struct rpc_task *task) rpc_make_runnable(task); - dprintk("RPC: __rpc_wake_up_task done\n"); + dprintk("RPC: __rpc_wake_up_task done\n"); } /* @@ -418,7 +419,7 @@ static void __rpc_wake_up_task(struct rpc_task *task) static void __rpc_default_timer(struct rpc_task *task) { - dprintk("RPC: %d timeout (default timer)\n", task->tk_pid); + dprintk("RPC: %5u timeout (default timer)\n", task->tk_pid); task->tk_status = -ETIMEDOUT; rpc_wake_up_task(task); } @@ -502,7 +503,8 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) { struct rpc_task *task = NULL; - dprintk("RPC: wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue)); + dprintk("RPC: wake_up_next(%p \"%s\")\n", + queue, rpc_qname(queue)); rcu_read_lock_bh(); spin_lock(&queue->lock); if (RPC_IS_PRIORITY(queue)) @@ -625,12 +627,12 @@ void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) /* * This is the RPC `scheduler' (or rather, the finite state machine). */ -static int __rpc_execute(struct rpc_task *task) +static void __rpc_execute(struct rpc_task *task) { int status = 0; - dprintk("RPC: %4d rpc_execute flgs %x\n", - task->tk_pid, task->tk_flags); + dprintk("RPC: %5u __rpc_execute flags=0x%x\n", + task->tk_pid, task->tk_flags); BUG_ON(RPC_IS_QUEUED(task)); @@ -679,14 +681,14 @@ static int __rpc_execute(struct rpc_task *task) if (RPC_IS_ASYNC(task)) { /* Careful! we may have raced... */ if (RPC_IS_QUEUED(task)) - return 0; + return; if (rpc_test_and_set_running(task)) - return 0; + return; continue; } /* sync task: sleep here */ - dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); + dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid); /* Note: Caller should be using rpc_clnt_sigmask() */ status = out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_QUEUED, rpc_wait_bit_interruptible, @@ -698,19 +700,19 @@ static int __rpc_execute(struct rpc_task *task) * clean up after sleeping on some queue, we don't * break the loop here, but go around once more. */ - dprintk("RPC: %4d got signal\n", task->tk_pid); + dprintk("RPC: %5u got signal\n", task->tk_pid); task->tk_flags |= RPC_TASK_KILLED; rpc_exit(task, -ERESTARTSYS); rpc_wake_up_task(task); } rpc_set_running(task); - dprintk("RPC: %4d sync task resuming\n", task->tk_pid); + dprintk("RPC: %5u sync task resuming\n", task->tk_pid); } - dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status); + dprintk("RPC: %5u return %d, status %d\n", task->tk_pid, status, + task->tk_status); /* Release all resources associated with the task */ rpc_release_task(task); - return status; } /* @@ -722,12 +724,11 @@ static int __rpc_execute(struct rpc_task *task) * released. In particular note that tk_release() will have * been called, so your task memory may have been freed. */ -int -rpc_execute(struct rpc_task *task) +void rpc_execute(struct rpc_task *task) { rpc_set_active(task); rpc_set_running(task); - return __rpc_execute(task); + __rpc_execute(task); } static void rpc_async_schedule(struct work_struct *work) @@ -826,7 +827,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons /* starting timestamp */ task->tk_start = jiffies; - dprintk("RPC: %4d new task procpid %d\n", task->tk_pid, + dprintk("RPC: new task initialized, procpid %u\n", current->pid); } @@ -839,7 +840,7 @@ rpc_alloc_task(void) static void rpc_free_task(struct rcu_head *rcu) { struct rpc_task *task = container_of(rcu, struct rpc_task, u.tk_rcu); - dprintk("RPC: %4d freeing task\n", task->tk_pid); + dprintk("RPC: %5u freeing task\n", task->tk_pid); mempool_free(task, rpc_task_mempool); } @@ -858,7 +859,7 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc rpc_init_task(task, clnt, flags, tk_ops, calldata); - dprintk("RPC: %4d allocated task\n", task->tk_pid); + dprintk("RPC: allocated task %p\n", task); task->tk_flags |= RPC_TASK_DYNAMIC; out: return task; @@ -902,7 +903,7 @@ static void rpc_release_task(struct rpc_task *task) #ifdef RPC_DEBUG BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); #endif - dprintk("RPC: %4d release task\n", task->tk_pid); + dprintk("RPC: %5u release task\n", task->tk_pid); /* Remove from global task list */ spin_lock(&rpc_sched_lock); @@ -955,7 +956,7 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) struct rpc_task *rovr; struct list_head *le; - dprintk("RPC: killing all tasks for client %p\n", clnt); + dprintk("RPC: killing all tasks for client %p\n", clnt); /* * Spin lock all_tasks to prevent changes... @@ -984,7 +985,8 @@ static void rpciod_killall(void) rpc_killall_tasks(NULL); flush_workqueue(rpciod_workqueue); if (!list_empty(&all_tasks)) { - dprintk("rpciod_killall: waiting for tasks to exit\n"); + dprintk("RPC: rpciod_killall: waiting for tasks " + "to exit\n"); yield(); } } @@ -1004,7 +1006,7 @@ rpciod_up(void) int error = 0; mutex_lock(&rpciod_mutex); - dprintk("rpciod_up: users %d\n", rpciod_users); + dprintk("RPC: rpciod_up: users %u\n", rpciod_users); rpciod_users++; if (rpciod_workqueue) goto out; @@ -1012,7 +1014,7 @@ rpciod_up(void) * If there's no pid, we should be the first user. */ if (rpciod_users > 1) - printk(KERN_WARNING "rpciod_up: no workqueue, %d users??\n", rpciod_users); + printk(KERN_WARNING "rpciod_up: no workqueue, %u users??\n", rpciod_users); /* * Create the rpciod thread and wait for it to start. */ @@ -1034,7 +1036,7 @@ void rpciod_down(void) { mutex_lock(&rpciod_mutex); - dprintk("rpciod_down sema %d\n", rpciod_users); + dprintk("RPC: rpciod_down sema %u\n", rpciod_users); if (rpciod_users) { if (--rpciod_users) goto out; @@ -1042,7 +1044,7 @@ rpciod_down(void) printk(KERN_WARNING "rpciod_down: no users??\n"); if (!rpciod_workqueue) { - dprintk("rpciod_down: Nothing to do!\n"); + dprintk("RPC: rpciod_down: Nothing to do!\n"); goto out; } rpciod_killall(); @@ -1072,7 +1074,7 @@ void rpc_show_tasks(void) if (RPC_IS_QUEUED(t)) rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); - printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", + printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", t->tk_pid, (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), t->tk_flags, t->tk_status, diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 044d948..74ba7d4 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -16,7 +16,6 @@ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/sunrpc/clnt.h> @@ -226,7 +225,7 @@ do_register(const char *name, void *data, const struct file_operations *fops) struct proc_dir_entry *ent; rpc_proc_init(); - dprintk("RPC: registering /proc/net/rpc/%s\n", name); + dprintk("RPC: registering /proc/net/rpc/%s\n", name); ent = create_proc_entry(name, 0, proc_net_rpc); if (ent) { @@ -263,7 +262,7 @@ svc_proc_unregister(const char *name) void rpc_proc_init(void) { - dprintk("RPC: registering /proc/net/rpc\n"); + dprintk("RPC: registering /proc/net/rpc\n"); if (!proc_net_rpc) { struct proc_dir_entry *ent; ent = proc_mkdir("rpc", proc_net); @@ -277,7 +276,7 @@ rpc_proc_init(void) void rpc_proc_exit(void) { - dprintk("RPC: unregistering /proc/net/rpc\n"); + dprintk("RPC: unregistering /proc/net/rpc\n"); if (proc_net_rpc) { proc_net_rpc = NULL; remove_proc_entry("net/rpc", NULL); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index d85fdde..43ecf62 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/uio.h> #include <linux/unistd.h> #include <linux/init.h> @@ -137,7 +136,7 @@ EXPORT_SYMBOL(nlm_debug); extern int register_rpc_pipefs(void); extern void unregister_rpc_pipefs(void); -extern struct cache_detail ip_map_cache; +extern struct cache_detail ip_map_cache, unix_gid_cache; extern int init_socket_xprt(void); extern void cleanup_socket_xprt(void); @@ -157,6 +156,7 @@ init_sunrpc(void) rpc_proc_init(); #endif cache_register(&ip_map_cache); + cache_register(&unix_gid_cache); init_socket_xprt(); out: return err; @@ -170,6 +170,8 @@ cleanup_sunrpc(void) rpc_destroy_mempool(); if (cache_unregister(&ip_map_cache)) printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); + if (cache_unregister(&unix_gid_cache)) + printk(KERN_ERR "sunrpc: failed to unregister unix_gid cache\n"); #ifdef RPC_DEBUG rpc_unregister_sysctl(); #endif diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index b00511d..4ab1374 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -317,7 +317,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, for (i = 0; i < serv->sv_nrpools; i++) { struct svc_pool *pool = &serv->sv_pools[i]; - dprintk("initialising pool %u for %s\n", + dprintk("svc: initialising pool %u for %s\n", i, serv->sv_name); pool->sp_id = i; @@ -368,7 +368,7 @@ svc_destroy(struct svc_serv *serv) { struct svc_sock *svsk; - dprintk("RPC: svc_destroy(%s, %d)\n", + dprintk("svc: svc_destroy(%s, %d)\n", serv->sv_program->pg_name, serv->sv_nrthreads); @@ -654,7 +654,7 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) if (progp->pg_vers[i] == NULL) continue; - dprintk("RPC: svc_register(%s, %s, %d, %d)%s\n", + dprintk("svc: svc_register(%s, %s, %d, %d)%s\n", progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port, diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 811a24c..f5c3808 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -10,7 +10,6 @@ */ #include <linux/types.h> -#include <linux/sched.h> #include <linux/module.h> #include <linux/sunrpc/types.h> #include <linux/sunrpc/xdr.h> diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 4b775db..9bae409 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -418,6 +418,214 @@ svcauth_unix_info_release(void *info) cache_put(&ipm->h, &ip_map_cache); } +/**************************************************************************** + * auth.unix.gid cache + * simple cache to map a UID to a list of GIDs + * because AUTH_UNIX aka AUTH_SYS has a max of 16 + */ +#define GID_HASHBITS 8 +#define GID_HASHMAX (1<<GID_HASHBITS) +#define GID_HASHMASK (GID_HASHMAX - 1) + +struct unix_gid { + struct cache_head h; + uid_t uid; + struct group_info *gi; +}; +static struct cache_head *gid_table[GID_HASHMAX]; + +static void unix_gid_put(struct kref *kref) +{ + struct cache_head *item = container_of(kref, struct cache_head, ref); + struct unix_gid *ug = container_of(item, struct unix_gid, h); + if (test_bit(CACHE_VALID, &item->flags) && + !test_bit(CACHE_NEGATIVE, &item->flags)) + put_group_info(ug->gi); + kfree(ug); +} + +static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew) +{ + struct unix_gid *orig = container_of(corig, struct unix_gid, h); + struct unix_gid *new = container_of(cnew, struct unix_gid, h); + return orig->uid == new->uid; +} +static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem) +{ + struct unix_gid *new = container_of(cnew, struct unix_gid, h); + struct unix_gid *item = container_of(citem, struct unix_gid, h); + new->uid = item->uid; +} +static void unix_gid_update(struct cache_head *cnew, struct cache_head *citem) +{ + struct unix_gid *new = container_of(cnew, struct unix_gid, h); + struct unix_gid *item = container_of(citem, struct unix_gid, h); + + get_group_info(item->gi); + new->gi = item->gi; +} +static struct cache_head *unix_gid_alloc(void) +{ + struct unix_gid *g = kmalloc(sizeof(*g), GFP_KERNEL); + if (g) + return &g->h; + else + return NULL; +} + +static void unix_gid_request(struct cache_detail *cd, + struct cache_head *h, + char **bpp, int *blen) +{ + char tuid[20]; + struct unix_gid *ug = container_of(h, struct unix_gid, h); + + snprintf(tuid, 20, "%u", ug->uid); + qword_add(bpp, blen, tuid); + (*bpp)[-1] = '\n'; +} + +static struct unix_gid *unix_gid_lookup(uid_t uid); +extern struct cache_detail unix_gid_cache; + +static int unix_gid_parse(struct cache_detail *cd, + char *mesg, int mlen) +{ + /* uid expiry Ngid gid0 gid1 ... gidN-1 */ + int uid; + int gids; + int rv; + int i; + int err; + time_t expiry; + struct unix_gid ug, *ugp; + + if (mlen <= 0 || mesg[mlen-1] != '\n') + return -EINVAL; + mesg[mlen-1] = 0; + + rv = get_int(&mesg, &uid); + if (rv) + return -EINVAL; + ug.uid = uid; + + expiry = get_expiry(&mesg); + if (expiry == 0) + return -EINVAL; + + rv = get_int(&mesg, &gids); + if (rv || gids < 0 || gids > 8192) + return -EINVAL; + + ug.gi = groups_alloc(gids); + if (!ug.gi) + return -ENOMEM; + + for (i = 0 ; i < gids ; i++) { + int gid; + rv = get_int(&mesg, &gid); + err = -EINVAL; + if (rv) + goto out; + GROUP_AT(ug.gi, i) = gid; + } + + ugp = unix_gid_lookup(uid); + if (ugp) { + struct cache_head *ch; + ug.h.flags = 0; + ug.h.expiry_time = expiry; + ch = sunrpc_cache_update(&unix_gid_cache, + &ug.h, &ugp->h, + hash_long(uid, GID_HASHBITS)); + if (!ch) + err = -ENOMEM; + else { + err = 0; + cache_put(ch, &unix_gid_cache); + } + } else + err = -ENOMEM; + out: + if (ug.gi) + put_group_info(ug.gi); + return err; +} + +static int unix_gid_show(struct seq_file *m, + struct cache_detail *cd, + struct cache_head *h) +{ + struct unix_gid *ug; + int i; + int glen; + + if (h == NULL) { + seq_puts(m, "#uid cnt: gids...\n"); + return 0; + } + ug = container_of(h, struct unix_gid, h); + if (test_bit(CACHE_VALID, &h->flags) && + !test_bit(CACHE_NEGATIVE, &h->flags)) + glen = ug->gi->ngroups; + else + glen = 0; + + seq_printf(m, "%d %d:", ug->uid, glen); + for (i = 0; i < glen; i++) + seq_printf(m, " %d", GROUP_AT(ug->gi, i)); + seq_printf(m, "\n"); + return 0; +} + +struct cache_detail unix_gid_cache = { + .owner = THIS_MODULE, + .hash_size = GID_HASHMAX, + .hash_table = gid_table, + .name = "auth.unix.gid", + .cache_put = unix_gid_put, + .cache_request = unix_gid_request, + .cache_parse = unix_gid_parse, + .cache_show = unix_gid_show, + .match = unix_gid_match, + .init = unix_gid_init, + .update = unix_gid_update, + .alloc = unix_gid_alloc, +}; + +static struct unix_gid *unix_gid_lookup(uid_t uid) +{ + struct unix_gid ug; + struct cache_head *ch; + + ug.uid = uid; + ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h, + hash_long(uid, GID_HASHBITS)); + if (ch) + return container_of(ch, struct unix_gid, h); + else + return NULL; +} + +static int unix_gid_find(uid_t uid, struct group_info **gip, + struct svc_rqst *rqstp) +{ + struct unix_gid *ug = unix_gid_lookup(uid); + if (!ug) + return -EAGAIN; + switch (cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle)) { + case -ENOENT: + *gip = NULL; + return 0; + case 0: + *gip = ug->gi; + get_group_info(*gip); + return 0; + default: + return -EAGAIN; + } +} + static int svcauth_unix_set_client(struct svc_rqst *rqstp) { @@ -543,12 +751,19 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) slen = svc_getnl(argv); /* gids length */ if (slen > 16 || (len -= (slen + 2)*4) < 0) goto badcred; - cred->cr_group_info = groups_alloc(slen); - if (cred->cr_group_info == NULL) + if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp) + == -EAGAIN) return SVC_DROP; - for (i = 0; i < slen; i++) - GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); - + if (cred->cr_group_info == NULL) { + cred->cr_group_info = groups_alloc(slen); + if (cred->cr_group_info == NULL) + return SVC_DROP; + for (i = 0; i < slen; i++) + GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); + } else { + for (i = 0; i < slen ; i++) + svc_getnl(argv); + } if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { *authp = rpc_autherr_badverf; return SVC_DENIED; diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index 47d8df2..738db32 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -35,14 +35,8 @@ static ctl_table sunrpc_table[]; void rpc_register_sysctl(void) { - if (!sunrpc_table_header) { - sunrpc_table_header = register_sysctl_table(sunrpc_table, 1); -#ifdef CONFIG_PROC_FS - if (sunrpc_table[0].de) - sunrpc_table[0].de->owner = THIS_MODULE; -#endif - } - + if (!sunrpc_table_header) + sunrpc_table_header = register_sysctl_table(sunrpc_table); } void diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e7c71a1..ee6ffa0 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -108,7 +108,7 @@ int xprt_reserve_xprt(struct rpc_task *task) return 1; out_sleep: - dprintk("RPC: %4d failed to lock transport %p\n", + dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); task->tk_timeout = 0; task->tk_status = -EAGAIN; @@ -158,7 +158,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task) } xprt_clear_locked(xprt); out_sleep: - dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt); + dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); task->tk_timeout = 0; task->tk_status = -EAGAIN; if (req && req->rq_ntrans) @@ -281,7 +281,7 @@ __xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task) if (req->rq_cong) return 1; - dprintk("RPC: %4d xprt_cwnd_limited cong = %ld cwnd = %ld\n", + dprintk("RPC: %5u xprt_cwnd_limited cong = %lu cwnd = %lu\n", task->tk_pid, xprt->cong, xprt->cwnd); if (RPCXPRT_CONGESTED(xprt)) return 0; @@ -340,7 +340,7 @@ void xprt_adjust_cwnd(struct rpc_task *task, int result) if (cwnd < RPC_CWNDSCALE) cwnd = RPC_CWNDSCALE; } - dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n", + dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n", xprt->cong, xprt->cwnd, cwnd); xprt->cwnd = cwnd; __xprt_put_cong(xprt, req); @@ -387,8 +387,8 @@ void xprt_write_space(struct rpc_xprt *xprt) spin_lock_bh(&xprt->transport_lock); if (xprt->snd_task) { - dprintk("RPC: write space: waking waiting task on xprt %p\n", - xprt); + dprintk("RPC: write space: waking waiting task on " + "xprt %p\n", xprt); rpc_wake_up_task(xprt->snd_task); } spin_unlock_bh(&xprt->transport_lock); @@ -494,7 +494,7 @@ static void xprt_autoclose(struct work_struct *work) */ void xprt_disconnect(struct rpc_xprt *xprt) { - dprintk("RPC: disconnected transport %p\n", xprt); + dprintk("RPC: disconnected transport %p\n", xprt); spin_lock_bh(&xprt->transport_lock); xprt_clear_connected(xprt); xprt_wake_pending_tasks(xprt, -ENOTCONN); @@ -530,7 +530,7 @@ void xprt_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, + dprintk("RPC: %5u xprt_connect xprt %p %s connected\n", task->tk_pid, xprt, (xprt_connected(xprt) ? "is" : "is not")); if (!xprt_bound(xprt)) { @@ -560,7 +560,7 @@ static void xprt_connect_status(struct rpc_task *task) if (task->tk_status >= 0) { xprt->stat.connect_count++; xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start; - dprintk("RPC: %4d xprt_connect_status: connection established\n", + dprintk("RPC: %5u xprt_connect_status: connection established\n", task->tk_pid); return; } @@ -568,20 +568,22 @@ static void xprt_connect_status(struct rpc_task *task) switch (task->tk_status) { case -ECONNREFUSED: case -ECONNRESET: - dprintk("RPC: %4d xprt_connect_status: server %s refused connection\n", - task->tk_pid, task->tk_client->cl_server); + dprintk("RPC: %5u xprt_connect_status: server %s refused " + "connection\n", task->tk_pid, + task->tk_client->cl_server); break; case -ENOTCONN: - dprintk("RPC: %4d xprt_connect_status: connection broken\n", + dprintk("RPC: %5u xprt_connect_status: connection broken\n", task->tk_pid); break; case -ETIMEDOUT: - dprintk("RPC: %4d xprt_connect_status: connect attempt timed out\n", - task->tk_pid); + dprintk("RPC: %5u xprt_connect_status: connect attempt timed " + "out\n", task->tk_pid); break; default: - dprintk("RPC: %4d xprt_connect_status: error %d connecting to server %s\n", - task->tk_pid, -task->tk_status, task->tk_client->cl_server); + dprintk("RPC: %5u xprt_connect_status: error %d connecting to " + "server %s\n", task->tk_pid, -task->tk_status, + task->tk_client->cl_server); xprt_release_write(xprt, task); task->tk_status = -EIO; } @@ -602,6 +604,9 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) if (entry->rq_xid == xid) return entry; } + + dprintk("RPC: xprt_lookup_rqst did not find xid %08x\n", + ntohl(xid)); xprt->stat.bad_xids++; return NULL; } @@ -654,7 +659,7 @@ static void xprt_timer(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - dprintk("RPC: %4d xprt_timer\n", task->tk_pid); + dprintk("RPC: %5u xprt_timer\n", task->tk_pid); spin_lock(&xprt->transport_lock); if (!req->rq_received) { @@ -678,7 +683,7 @@ int xprt_prepare_transmit(struct rpc_task *task) struct rpc_xprt *xprt = req->rq_xprt; int err = 0; - dprintk("RPC: %4d xprt_prepare_transmit\n", task->tk_pid); + dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); spin_lock_bh(&xprt->transport_lock); if (req->rq_received && !req->rq_bytes_sent) { @@ -716,7 +721,7 @@ void xprt_transmit(struct rpc_task *task) struct rpc_xprt *xprt = req->rq_xprt; int status; - dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); + dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); if (!req->rq_received) { if (list_empty(&req->rq_list)) { @@ -730,13 +735,23 @@ void xprt_transmit(struct rpc_task *task) xprt_reset_majortimeo(req); /* Turn off autodisconnect */ del_singleshot_timer_sync(&xprt->timer); + } else { + /* If all request bytes have been sent, + * then we must be retransmitting this one */ + if (!req->rq_bytes_sent) { + if (task->tk_client->cl_discrtry) { + xprt_disconnect(xprt); + task->tk_status = -ENOTCONN; + return; + } + } } } else if (!req->rq_bytes_sent) return; status = xprt->ops->send_request(task); if (status == 0) { - dprintk("RPC: %4d xmit complete\n", task->tk_pid); + dprintk("RPC: %5u xmit complete\n", task->tk_pid); spin_lock_bh(&xprt->transport_lock); xprt->ops->set_retrans_timeout(task); @@ -777,7 +792,7 @@ static inline void do_xprt_reserve(struct rpc_task *task) xprt_request_init(task, xprt); return; } - dprintk("RPC: waiting for request slot\n"); + dprintk("RPC: waiting for request slot\n"); task->tk_status = -EAGAIN; task->tk_timeout = 0; rpc_sleep_on(&xprt->backlog, task, NULL, NULL); @@ -822,7 +837,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) req->rq_xid = xprt_alloc_xid(xprt); req->rq_release_snd_buf = NULL; xprt_reset_majortimeo(req); - dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, + dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid, req, ntohl(req->rq_xid)); } @@ -856,7 +871,7 @@ void xprt_release(struct rpc_task *task) req->rq_release_snd_buf(req); memset(req, 0, sizeof(*req)); /* mark unused */ - dprintk("RPC: %4d release request %p\n", task->tk_pid, req); + dprintk("RPC: %5u release request %p\n", task->tk_pid, req); spin_lock(&xprt->reserve_lock); list_add(&req->rq_list, &xprt->free); @@ -906,7 +921,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si return ERR_PTR(-EIO); } if (IS_ERR(xprt)) { - dprintk("RPC: xprt_create_transport: failed, %ld\n", + dprintk("RPC: xprt_create_transport: failed, %ld\n", -PTR_ERR(xprt)); return xprt; } @@ -936,7 +951,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si xprt_init_xid(xprt); - dprintk("RPC: created transport %p with %u slots\n", xprt, + dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); return xprt; @@ -951,7 +966,7 @@ static void xprt_destroy(struct kref *kref) { struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref); - dprintk("RPC: destroying transport %p\n", xprt); + dprintk("RPC: destroying transport %p\n", xprt); xprt->shutdown = 1; del_timer_sync(&xprt->timer); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 49cabff..a5a3202 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -18,7 +18,6 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/capability.h> -#include <linux/sched.h> #include <linux/pagemap.h> #include <linux/errno.h> #include <linux/socket.h> @@ -192,7 +191,7 @@ static void xs_pktdump(char *msg, u32 *packet, unsigned int count) u8 *buf = (u8 *) packet; int j; - dprintk("RPC: %s\n", msg); + dprintk("RPC: %s\n", msg); for (j = 0; j < count && j < 128; j += 4) { if (!(j & 31)) { if (j) @@ -418,7 +417,7 @@ static void xs_nospace(struct rpc_task *task) struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - dprintk("RPC: %4d xmit incomplete (%u left of %u)\n", + dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", task->tk_pid, req->rq_slen - req->rq_bytes_sent, req->rq_slen); @@ -467,7 +466,7 @@ static int xs_udp_send_request(struct rpc_task *task) xprt->addrlen, xdr, req->rq_bytes_sent); - dprintk("RPC: xs_udp_send_request(%u) = %d\n", + dprintk("RPC: xs_udp_send_request(%u) = %d\n", xdr->len - req->rq_bytes_sent, status); if (likely(status >= (int) req->rq_slen)) @@ -488,7 +487,7 @@ static int xs_udp_send_request(struct rpc_task *task) xs_nospace(task); break; default: - dprintk("RPC: sendmsg returned unrecognized error %d\n", + dprintk("RPC: sendmsg returned unrecognized error %d\n", -status); break; } @@ -539,7 +538,7 @@ static int xs_tcp_send_request(struct rpc_task *task) status = xs_sendpages(transport->sock, NULL, 0, xdr, req->rq_bytes_sent); - dprintk("RPC: xs_tcp_send_request(%u) = %d\n", + dprintk("RPC: xs_tcp_send_request(%u) = %d\n", xdr->len - req->rq_bytes_sent, status); if (unlikely(status < 0)) @@ -570,7 +569,7 @@ static int xs_tcp_send_request(struct rpc_task *task) status = -ENOTCONN; break; default: - dprintk("RPC: sendmsg returned unrecognized error %d\n", + dprintk("RPC: sendmsg returned unrecognized error %d\n", -status); xprt_disconnect(xprt); break; @@ -622,7 +621,7 @@ static void xs_close(struct rpc_xprt *xprt) if (!sk) goto clear_close_wait; - dprintk("RPC: xs_close xprt %p\n", xprt); + dprintk("RPC: xs_close xprt %p\n", xprt); write_lock_bh(&sk->sk_callback_lock); transport->inet = NULL; @@ -652,7 +651,7 @@ static void xs_destroy(struct rpc_xprt *xprt) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - dprintk("RPC: xs_destroy xprt %p\n", xprt); + dprintk("RPC: xs_destroy xprt %p\n", xprt); cancel_delayed_work(&transport->connect_worker); flush_scheduled_work(); @@ -686,7 +685,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) __be32 *xp; read_lock(&sk->sk_callback_lock); - dprintk("RPC: xs_udp_data_ready...\n"); + dprintk("RPC: xs_udp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) goto out; @@ -698,7 +697,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) repsize = skb->len - sizeof(struct udphdr); if (repsize < 4) { - dprintk("RPC: impossible RPC reply size %d!\n", repsize); + dprintk("RPC: impossible RPC reply size %d!\n", repsize); goto dropit; } @@ -762,11 +761,11 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea /* Sanity check of the record length */ if (unlikely(transport->tcp_reclen < 4)) { - dprintk("RPC: invalid TCP record fragment length\n"); + dprintk("RPC: invalid TCP record fragment length\n"); xprt_disconnect(xprt); return; } - dprintk("RPC: reading TCP record fragment of length %d\n", + dprintk("RPC: reading TCP record fragment of length %d\n", transport->tcp_reclen); } @@ -789,7 +788,7 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r char *p; len = sizeof(transport->tcp_xid) - transport->tcp_offset; - dprintk("RPC: reading XID (%Zu bytes)\n", len); + dprintk("RPC: reading XID (%Zu bytes)\n", len); p = ((char *) &transport->tcp_xid) + transport->tcp_offset; used = xdr_skb_read_bits(desc, p, len); transport->tcp_offset += used; @@ -798,7 +797,7 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r transport->tcp_flags &= ~TCP_RCV_COPY_XID; transport->tcp_flags |= TCP_RCV_COPY_DATA; transport->tcp_copied = 4; - dprintk("RPC: reading reply for XID %08x\n", + dprintk("RPC: reading reply for XID %08x\n", ntohl(transport->tcp_xid)); xs_tcp_check_fraghdr(transport); } @@ -816,7 +815,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea req = xprt_lookup_rqst(xprt, transport->tcp_xid); if (!req) { transport->tcp_flags &= ~TCP_RCV_COPY_DATA; - dprintk("RPC: XID %08x request not found!\n", + dprintk("RPC: XID %08x request not found!\n", ntohl(transport->tcp_xid)); spin_unlock(&xprt->transport_lock); return; @@ -853,19 +852,20 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea * be discarded. */ transport->tcp_flags &= ~TCP_RCV_COPY_DATA; - dprintk("RPC: XID %08x truncated request\n", + dprintk("RPC: XID %08x truncated request\n", ntohl(transport->tcp_xid)); - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", - xprt, transport->tcp_copied, transport->tcp_offset, - transport->tcp_reclen); + dprintk("RPC: xprt = %p, tcp_copied = %lu, " + "tcp_offset = %u, tcp_reclen = %u\n", + xprt, transport->tcp_copied, + transport->tcp_offset, transport->tcp_reclen); goto out; } - dprintk("RPC: XID %08x read %Zd bytes\n", + dprintk("RPC: XID %08x read %Zd bytes\n", ntohl(transport->tcp_xid), r); - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", - xprt, transport->tcp_copied, transport->tcp_offset, - transport->tcp_reclen); + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, " + "tcp_reclen = %u\n", xprt, transport->tcp_copied, + transport->tcp_offset, transport->tcp_reclen); if (transport->tcp_copied == req->rq_private_buf.buflen) transport->tcp_flags &= ~TCP_RCV_COPY_DATA; @@ -891,7 +891,7 @@ static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_s desc->count -= len; desc->offset += len; transport->tcp_offset += len; - dprintk("RPC: discarded %Zu bytes\n", len); + dprintk("RPC: discarded %Zu bytes\n", len); xs_tcp_check_fraghdr(transport); } @@ -905,7 +905,7 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns .count = len, }; - dprintk("RPC: xs_tcp_data_recv started\n"); + dprintk("RPC: xs_tcp_data_recv started\n"); do { /* Read in a new fragment marker if necessary */ /* Can we ever really expect to get completely empty fragments? */ @@ -926,7 +926,7 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns /* Skip over any trailing bytes on short reads */ xs_tcp_read_discard(transport, &desc); } while (desc.count); - dprintk("RPC: xs_tcp_data_recv done\n"); + dprintk("RPC: xs_tcp_data_recv done\n"); return len - desc.count; } @@ -941,8 +941,9 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes) struct rpc_xprt *xprt; read_descriptor_t rd_desc; + dprintk("RPC: xs_tcp_data_ready...\n"); + read_lock(&sk->sk_callback_lock); - dprintk("RPC: xs_tcp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) goto out; if (xprt->shutdown) @@ -968,11 +969,11 @@ static void xs_tcp_state_change(struct sock *sk) read_lock(&sk->sk_callback_lock); if (!(xprt = xprt_from_sock(sk))) goto out; - dprintk("RPC: xs_tcp_state_change client %p...\n", xprt); - dprintk("RPC: state %x conn %d dead %d zapped %d\n", - sk->sk_state, xprt_connected(xprt), - sock_flag(sk, SOCK_DEAD), - sock_flag(sk, SOCK_ZAPPED)); + dprintk("RPC: xs_tcp_state_change client %p...\n", xprt); + dprintk("RPC: state %x conn %d dead %d zapped %d\n", + sk->sk_state, xprt_connected(xprt), + sock_flag(sk, SOCK_DEAD), + sock_flag(sk, SOCK_ZAPPED)); switch (sk->sk_state) { case TCP_ESTABLISHED: @@ -1140,7 +1141,7 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) { struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr; - dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); + dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); sap->sin_port = htons(port); } @@ -1159,7 +1160,7 @@ static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock) sizeof(myaddr)); if (err == 0) { transport->port = port; - dprintk("RPC: xs_bindresvport bound to port %u\n", + dprintk("RPC: xs_bindresvport bound to port %u\n", port); return 0; } @@ -1169,7 +1170,7 @@ static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock) port--; } while (err == -EADDRINUSE && port != transport->port); - dprintk("RPC: can't bind to reserved port (%d).\n", -err); + dprintk("RPC: can't bind to reserved port (%d).\n", -err); return err; } @@ -1223,7 +1224,7 @@ static void xs_udp_connect_worker(struct work_struct *work) xs_close(xprt); if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { - dprintk("RPC: can't create UDP transport socket (%d).\n", -err); + dprintk("RPC: can't create UDP transport socket (%d).\n", -err); goto out; } xs_reclassify_socket(sock); @@ -1233,7 +1234,7 @@ static void xs_udp_connect_worker(struct work_struct *work) goto out; } - dprintk("RPC: worker connecting xprt %p to address: %s\n", + dprintk("RPC: worker connecting xprt %p to address: %s\n", xprt, xprt->address_strings[RPC_DISPLAY_ALL]); if (!transport->inet) { @@ -1275,7 +1276,7 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct sockaddr any; - dprintk("RPC: disconnecting xprt %p to reuse port\n", xprt); + dprintk("RPC: disconnecting xprt %p to reuse port\n", xprt); /* * Disconnect the transport socket by doing a connect operation @@ -1285,7 +1286,7 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) any.sa_family = AF_UNSPEC; result = kernel_connect(transport->sock, &any, sizeof(any), 0); if (result) - dprintk("RPC: AF_UNSPEC connect return code %d\n", + dprintk("RPC: AF_UNSPEC connect return code %d\n", result); } @@ -1309,7 +1310,8 @@ static void xs_tcp_connect_worker(struct work_struct *work) if (!sock) { /* start from scratch */ if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { - dprintk("RPC: can't create TCP transport socket (%d).\n", -err); + dprintk("RPC: can't create TCP transport " + "socket (%d).\n", -err); goto out; } xs_reclassify_socket(sock); @@ -1322,7 +1324,7 @@ static void xs_tcp_connect_worker(struct work_struct *work) /* "close" the socket, preserving the local port */ xs_tcp_reuse_connection(xprt); - dprintk("RPC: worker connecting xprt %p to address: %s\n", + dprintk("RPC: worker connecting xprt %p to address: %s\n", xprt, xprt->address_strings[RPC_DISPLAY_ALL]); if (!transport->inet) { @@ -1359,8 +1361,9 @@ static void xs_tcp_connect_worker(struct work_struct *work) xprt->stat.connect_start = jiffies; status = kernel_connect(sock, (struct sockaddr *) &xprt->addr, xprt->addrlen, O_NONBLOCK); - dprintk("RPC: %p connect status %d connected %d sock state %d\n", - xprt, -status, xprt_connected(xprt), sock->sk->sk_state); + dprintk("RPC: %p connect status %d connected %d sock state %d\n", + xprt, -status, xprt_connected(xprt), + sock->sk->sk_state); if (status < 0) { switch (status) { case -EINPROGRESS: @@ -1404,7 +1407,8 @@ static void xs_connect(struct rpc_task *task) return; if (transport->sock != NULL) { - dprintk("RPC: xs_connect delayed xprt %p for %lu seconds\n", + dprintk("RPC: xs_connect delayed xprt %p for %lu " + "seconds\n", xprt, xprt->reestablish_timeout / HZ); schedule_delayed_work(&transport->connect_worker, xprt->reestablish_timeout); @@ -1412,7 +1416,7 @@ static void xs_connect(struct rpc_task *task) if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { - dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); + dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); schedule_delayed_work(&transport->connect_worker, 0); /* flush_scheduled_work can sleep... */ @@ -1507,13 +1511,14 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns struct sock_xprt *new; if (addrlen > sizeof(xprt->addr)) { - dprintk("RPC: xs_setup_xprt: address too large\n"); + dprintk("RPC: xs_setup_xprt: address too large\n"); return ERR_PTR(-EBADF); } new = kzalloc(sizeof(*new), GFP_KERNEL); if (new == NULL) { - dprintk("RPC: xs_setup_xprt: couldn't allocate rpc_xprt\n"); + dprintk("RPC: xs_setup_xprt: couldn't allocate " + "rpc_xprt\n"); return ERR_PTR(-ENOMEM); } xprt = &new->xprt; @@ -1522,7 +1527,8 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns xprt->slot = kcalloc(xprt->max_reqs, sizeof(struct rpc_rqst), GFP_KERNEL); if (xprt->slot == NULL) { kfree(xprt); - dprintk("RPC: xs_setup_xprt: couldn't allocate slot table\n"); + dprintk("RPC: xs_setup_xprt: couldn't allocate slot " + "table\n"); return ERR_PTR(-ENOMEM); } @@ -1572,7 +1578,7 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_ xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); xs_format_peer_addresses(xprt); - dprintk("RPC: set up transport to address %s\n", + dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); return xprt; @@ -1616,7 +1622,7 @@ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_ xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); xs_format_peer_addresses(xprt); - dprintk("RPC: set up transport to address %s\n", + dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); return xprt; @@ -1629,13 +1635,8 @@ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_ int init_socket_xprt(void) { #ifdef RPC_DEBUG - if (!sunrpc_table_header) { - sunrpc_table_header = register_sysctl_table(sunrpc_table, 1); -#ifdef CONFIG_PROC_FS - if (sunrpc_table[0].de) - sunrpc_table[0].de->owner = THIS_MODULE; -#endif - } + if (!sunrpc_table_header) + sunrpc_table_header = register_sysctl_table(sunrpc_table); #endif return 0; diff --git a/net/unix/garbage.c b/net/unix/garbage.c index f8bcf5d..f20b7ea 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -65,7 +65,6 @@ */ #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/socket.h> #include <linux/un.h> diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index 690ffa5..eb0bd57 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -50,7 +50,7 @@ static struct ctl_table_header * unix_sysctl_header; void unix_sysctl_register(void) { - unix_sysctl_header = register_sysctl_table(unix_root_table, 0); + unix_sysctl_header = register_sysctl_table(unix_root_table); } void unix_sysctl_unregister(void) diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c index 5f63106..a59b77f 100644 --- a/net/x25/sysctl_net_x25.c +++ b/net/x25/sysctl_net_x25.c @@ -106,7 +106,7 @@ static struct ctl_table x25_root_table[] = { void __init x25_register_sysctl(void) { - x25_table_header = register_sysctl_table(x25_root_table, 1); + x25_table_header = register_sysctl_table(x25_root_table); } void x25_unregister_sysctl(void) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index c394b41..946b715 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1550,7 +1550,7 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short family) { if (xfrm_state_kern(x)) - return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, family); + return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family); return x->id.proto == tmpl->id.proto && (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && (x->props.reqid == tmpl->reqid || !tmpl->reqid) && diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index c0ae0a7..512c2f5 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -89,6 +89,7 @@ void ConfigItem::okRename(int col) { Parent::okRename(col); sym_set_string_value(menu->sym, text(dataColIdx).latin1()); + listView()->updateList(this); } #endif @@ -605,6 +606,8 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu) visible = menu_is_visible(child); if (showAll || visible) { + if (!child->sym && !child->list && !child->prompt) + continue; if (!item || item->menu != child) item = new ConfigItem(parent, last, child, visible); else @@ -1247,6 +1250,7 @@ void ConfigSearchWindow::search(void) free(result); list->list->clear(); + info->clear(); result = sym_re_search(editField->text().latin1()); if (!result) @@ -1316,7 +1320,7 @@ ConfigMainWindow::ConfigMainWindow(void) conf_changed(); QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this); connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); - QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this); + QAction *searchAction = new QAction("Find", "&Find", CTRL+Key_F, this); connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this); connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); @@ -1373,10 +1377,13 @@ ConfigMainWindow::ConfigMainWindow(void) saveAction->addTo(config); saveAsAction->addTo(config); config->insertSeparator(); - searchAction->addTo(config); - config->insertSeparator(); quitAction->addTo(config); + // create edit menu + QPopupMenu* editMenu = new QPopupMenu(this); + menu->insertItem("&Edit", editMenu); + searchAction->addTo(editMenu); + // create options menu QPopupMenu* optionMenu = new QPopupMenu(this); menu->insertItem("&Option", optionMenu); @@ -1467,7 +1474,10 @@ void ConfigMainWindow::searchConfig(void) void ConfigMainWindow::changeMenu(struct menu *menu) { configList->setRootMenu(menu); - backAction->setEnabled(TRUE); + if (configList->rootEntry->parent == &rootmenu) + backAction->setEnabled(FALSE); + else + backAction->setEnabled(TRUE); } void ConfigMainWindow::setMenuLink(struct menu *menu) diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index d7b8a38..82d0af4 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -58,7 +58,7 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/" echo \#define LINUX_COMPILE_DOMAIN fi - echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\" + echo \#define LINUX_COMPILER \"`LC_ALL=C LANG=C $CC -v 2>&1 | tail -n 1`\" ) > .tmpcompile # Only replace the real compile.h if the new one is different, diff --git a/scripts/mkuboot.sh b/scripts/mkuboot.sh index 52a17ab..4b06c5e 100755 --- a/scripts/mkuboot.sh +++ b/scripts/mkuboot.sh @@ -4,12 +4,15 @@ # Build U-Boot image when `mkimage' tool is available. # -MKIMAGE=$(type -path mkimage) +MKIMAGE=$(type -path ${CROSS_COMPILE}mkimage) if [ -z "${MKIMAGE}" ]; then - # Doesn't exist - echo '"mkimage" command not found - U-Boot images will not be built' >&2 - exit 0; + MKIMAGE=$(type -path mkimage) + if [ -z "${MKIMAGE}" ]; then + # Doesn't exist + echo '"mkimage" command not found - U-Boot images will not be built' >&2 + exit 0; + fi fi # Call "mkimage" to create U-Boot image diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 2aa4762..569e684 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -641,12 +641,20 @@ static int secref_whitelist(const char *modname, const char *tosec, if (f1 && f2) return 1; - /* Whitelist all references from .pci_fixup section if vmlinux */ + /* Whitelist all references from .pci_fixup section if vmlinux + * Whitelist all refereces from .text.head to .init.data if vmlinux + * Whitelist all refereces from .text.head to .init.text if vmlinux + */ if (is_vmlinux(modname)) { if ((strcmp(fromsec, ".pci_fixup") == 0) && (strcmp(tosec, ".init.text") == 0)) return 1; + if ((strcmp(fromsec, ".text.head") == 0) && + ((strcmp(tosec, ".init.data") == 0) || + (strcmp(tosec, ".init.text") == 0))) + return 1; + /* Check for pattern 3 */ for (s = pat3refsym; *s; s++) if (strcmp(refsymname, *s) == 0) diff --git a/security/keys/compat.c b/security/keys/compat.c index bcdb285..e10ec99 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#include <linux/sched.h> #include <linux/syscalls.h> #include <linux/keyctl.h> #include <linux/compat.h> diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 5bbfdeb..7c687d5 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/seq_file.h> #include <linux/err.h> diff --git a/security/security.c b/security/security.c index ee4e070..fc8601b 100644 --- a/security/security.c +++ b/security/security.c @@ -15,7 +15,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/security.h> #define SECURITY_FRAMEWORK_VERSION "1.0.0" diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 35eb8de..b1ac22d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1077,6 +1077,9 @@ static int inode_has_perm(struct task_struct *tsk, struct inode_security_struct *isec; struct avc_audit_data ad; + if (unlikely (IS_PRIVATE (inode))) + return 0; + tsec = tsk->security; isec = inode->i_security; @@ -1423,6 +1426,47 @@ static int selinux_capable(struct task_struct *tsk, int cap) return task_has_capability(tsk,cap); } +static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) +{ + int buflen, rc; + char *buffer, *path, *end; + + rc = -ENOMEM; + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + goto out; + + buflen = PAGE_SIZE; + end = buffer+buflen; + *--end = '\0'; + buflen--; + path = end-1; + *path = '/'; + while (table) { + const char *name = table->procname; + size_t namelen = strlen(name); + buflen -= namelen + 1; + if (buflen < 0) + goto out_free; + end -= namelen; + memcpy(end, name, namelen); + *--end = '/'; + path = end; + table = table->parent; + } + buflen -= 4; + if (buflen < 0) + goto out_free; + end -= 4; + memcpy(end, "/sys", 4); + path = end; + rc = security_genfs_sid("proc", path, tclass, sid); +out_free: + free_page((unsigned long)buffer); +out: + return rc; +} + static int selinux_sysctl(ctl_table *table, int op) { int error = 0; @@ -1437,8 +1481,8 @@ static int selinux_sysctl(ctl_table *table, int op) tsec = current->security; - rc = selinux_proc_get_sid(table->de, (op == 001) ? - SECCLASS_DIR : SECCLASS_FILE, &tsid); + rc = selinux_sysctl_get_sid(table, (op == 0001) ? + SECCLASS_DIR : SECCLASS_FILE, &tsid); if (rc) { /* Default to the well-defined sysctl SID. */ tsid = SECINITSID_SYSCTL; diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 871c33b..d78f9ff 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -7,7 +7,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/errno.h> -#include <linux/sched.h> #include "flask.h" #include "security.h" #include "sidtab.h" diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index dede954..28db4be 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -305,7 +305,7 @@ static int pxa2xx_ac97_resume(struct platform_device *dev) #define pxa2xx_ac97_resume NULL #endif -static int pxa2xx_ac97_probe(struct platform_device *dev) +static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) { struct snd_card *card; struct snd_ac97_bus *ac97_bus; @@ -369,7 +369,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev) return ret; } -static int pxa2xx_ac97_remove(struct platform_device *dev) +static int __devexit pxa2xx_ac97_remove(struct platform_device *dev) { struct snd_card *card = platform_get_drvdata(dev); @@ -386,7 +386,7 @@ static int pxa2xx_ac97_remove(struct platform_device *dev) static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_probe, - .remove = pxa2xx_ac97_remove, + .remove = __devexit_p(pxa2xx_ac97_remove), .suspend = pxa2xx_ac97_suspend, .resume = pxa2xx_ac97_resume, .driver = { diff --git a/sound/core/misc.c b/sound/core/misc.c index 6db86a7..f78cd00 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -21,7 +21,6 @@ #include <sound/driver.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/time.h> #include <linux/ioport.h> #include <sound/core.h> diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c index b09babf..f80fab8 100644 --- a/sound/core/seq/instr/ainstr_fm.c +++ b/sound/core/seq/instr/ainstr_fm.c @@ -20,7 +20,6 @@ #include <sound/driver.h> #include <linux/init.h> -#include <linux/sched.h> #include <sound/core.h> #include <sound/ainstr_fm.h> #include <sound/initval.h> diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c index 3c31038..c640e1cf 100644 --- a/sound/core/seq/instr/ainstr_gf1.c +++ b/sound/core/seq/instr/ainstr_gf1.c @@ -20,7 +20,6 @@ #include <sound/driver.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/ainstr_gf1.h> diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c index 7f8df19..5367bae 100644 --- a/sound/core/seq/instr/ainstr_iw.c +++ b/sound/core/seq/instr/ainstr_iw.c @@ -20,7 +20,6 @@ #include <sound/driver.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/ainstr_iw.h> diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c index 6d6ffec..ac717be 100644 --- a/sound/core/seq/instr/ainstr_simple.c +++ b/sound/core/seq/instr/ainstr_simple.c @@ -20,7 +20,6 @@ #include <sound/driver.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/ainstr_simple.h> diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 972f934..061a7c6 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -38,7 +38,6 @@ #include <sound/driver.h> #include <linux/init.h> #include <linux/wait.h> -#include <linux/sched.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/rawmidi.h> diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 8339bad..a0f28f5 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -423,7 +423,8 @@ static struct snd_pcm_ops snd_card_dummy_capture_ops = { .pointer = snd_card_dummy_pcm_pointer, }; -static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int substreams) +static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, + int substreams) { struct snd_pcm *pcm; int err; @@ -562,7 +563,7 @@ DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) }; -static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) +static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) { struct snd_card *card = dummy->card; unsigned int idx; @@ -579,7 +580,7 @@ static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) return 0; } -static int __init snd_dummy_probe(struct platform_device *devptr) +static int __devinit snd_dummy_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_dummy *dummy; @@ -617,7 +618,7 @@ static int __init snd_dummy_probe(struct platform_device *devptr) return err; } -static int snd_dummy_remove(struct platform_device *devptr) +static int __devexit snd_dummy_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -648,7 +649,7 @@ static int snd_dummy_resume(struct platform_device *pdev) static struct platform_driver snd_dummy_driver = { .probe = snd_dummy_probe, - .remove = snd_dummy_remove, + .remove = __devexit_p(snd_dummy_remove), #ifdef CONFIG_PM .suspend = snd_dummy_suspend, .resume = snd_dummy_resume, diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index a9ff391..40eb026 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -583,7 +583,7 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id) /* * get ISA resources */ -static int __init snd_mtpav_get_ISA(struct mtpav * mcard) +static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard) { if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) { snd_printk("MTVAP port 0x%lx is busy\n", port); @@ -619,7 +619,7 @@ static struct snd_rawmidi_ops snd_mtpav_input = { * get RAWMIDI resources */ -static void __init snd_mtpav_set_name(struct mtpav *chip, +static void __devinit snd_mtpav_set_name(struct mtpav *chip, struct snd_rawmidi_substream *substream) { if (substream->number >= 0 && substream->number < chip->num_ports) @@ -634,7 +634,7 @@ static void __init snd_mtpav_set_name(struct mtpav *chip, strcpy(substream->name, "MTP broadcast"); } -static int __init snd_mtpav_get_RAWMIDI(struct mtpav *mcard) +static int __devinit snd_mtpav_get_RAWMIDI(struct mtpav *mcard) { int rval; struct snd_rawmidi *rawmidi; @@ -691,7 +691,7 @@ static void snd_mtpav_free(struct snd_card *card) /* */ -static int __init snd_mtpav_probe(struct platform_device *dev) +static int __devinit snd_mtpav_probe(struct platform_device *dev) { struct snd_card *card; int err; @@ -745,7 +745,7 @@ static int __init snd_mtpav_probe(struct platform_device *dev) return err; } -static int snd_mtpav_remove(struct platform_device *devptr) +static int __devexit snd_mtpav_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -756,7 +756,7 @@ static int snd_mtpav_remove(struct platform_device *devptr) static struct platform_driver snd_mtpav_driver = { .probe = snd_mtpav_probe, - .remove = snd_mtpav_remove, + .remove = __devexit_p(snd_mtpav_remove), .driver = { .name = SND_MTPAV_DRIVER }, diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 5327c6f..6c9f4c9 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -1026,7 +1026,7 @@ __err: return err; } -static int snd_mts64_remove(struct platform_device *pdev) +static int __devexit snd_mts64_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); @@ -1039,7 +1039,7 @@ static int snd_mts64_remove(struct platform_device *pdev) static struct platform_driver snd_mts64_driver = { .probe = snd_mts64_probe, - .remove = snd_mts64_remove, + .remove = __devexit_p(snd_mts64_remove), .driver = { .name = PLATFORM_DRIVER } @@ -1048,7 +1048,7 @@ static struct platform_driver snd_mts64_driver = { /********************************************************************* * module init stuff *********************************************************************/ -static void snd_mts64_unregister_all(void) +static void __init_or_module snd_mts64_unregister_all(void) { int i; diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 6c48772..b2d0ba4 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -811,7 +811,7 @@ __err: return err; } -static int snd_portman_remove(struct platform_device *pdev) +static int __devexit snd_portman_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); @@ -824,7 +824,7 @@ static int snd_portman_remove(struct platform_device *pdev) static struct platform_driver snd_portman_driver = { .probe = snd_portman_probe, - .remove = snd_portman_remove, + .remove = __devexit_p(snd_portman_remove), .driver = { .name = PLATFORM_DRIVER } @@ -833,7 +833,7 @@ static struct platform_driver snd_portman_driver = { /********************************************************************* * module init stuff *********************************************************************/ -static void snd_portman_unregister_all(void) +static void __init_or_module snd_portman_unregister_all(void) { int i; diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 3a86a58..838a427 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -327,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data) * return 0 if found * return negative error if not found */ -static int __init snd_uart16550_detect(struct snd_uart16550 *uart) +static int __devinit snd_uart16550_detect(struct snd_uart16550 *uart) { unsigned long io_base = uart->base; int ok; @@ -781,7 +781,7 @@ static int snd_uart16550_dev_free(struct snd_device *device) return snd_uart16550_free(uart); } -static int __init snd_uart16550_create(struct snd_card *card, +static int __devinit snd_uart16550_create(struct snd_card *card, unsigned long iobase, int irq, unsigned int speed, @@ -860,7 +860,7 @@ static int __init snd_uart16550_create(struct snd_card *card, return 0; } -static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream) +static void __devinit snd_uart16550_substreams(struct snd_rawmidi_str *stream) { struct snd_rawmidi_substream *substream; @@ -869,7 +869,7 @@ static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream) } } -static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, +static int __devinit snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi) { @@ -896,7 +896,7 @@ static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, return 0; } -static int __init snd_serial_probe(struct platform_device *devptr) +static int __devinit snd_serial_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_uart16550 *uart; @@ -981,7 +981,7 @@ static int __init snd_serial_probe(struct platform_device *devptr) return err; } -static int snd_serial_remove(struct platform_device *devptr) +static int __devexit snd_serial_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -992,7 +992,7 @@ static int snd_serial_remove(struct platform_device *devptr) static struct platform_driver snd_serial_driver = { .probe = snd_serial_probe, - .remove = snd_serial_remove, + .remove = __devexit_p( snd_serial_remove), .driver = { .name = SND_SERIAL_DRIVER }, diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 59171f8..46f3d34 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -44,7 +44,6 @@ #include <sound/driver.h> #include <linux/init.h> #include <linux/wait.h> -#include <linux/sched.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/moduleparam.h> @@ -85,7 +84,7 @@ struct snd_card_virmidi { static struct platform_device *devices[SNDRV_CARDS]; -static int __init snd_virmidi_probe(struct platform_device *devptr) +static int __devinit snd_virmidi_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_card_virmidi *vmidi; @@ -129,7 +128,7 @@ static int __init snd_virmidi_probe(struct platform_device *devptr) return err; } -static int snd_virmidi_remove(struct platform_device *devptr) +static int __devexit snd_virmidi_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -140,7 +139,7 @@ static int snd_virmidi_remove(struct platform_device *devptr) static struct platform_driver snd_virmidi_driver = { .probe = snd_virmidi_probe, - .remove = snd_virmidi_remove, + .remove = __devexit_p(snd_virmidi_remove), .driver = { .name = SND_VIRMIDI_DRIVER }, diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index 99908e4..74e501d 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -65,7 +65,7 @@ MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 3 static struct platform_device *devices[SNDRV_CARDS]; -static int __init snd_ad1848_probe(struct platform_device *pdev) +static int __devinit snd_ad1848_probe(struct platform_device *pdev) { int dev = pdev->id; struct snd_card *card; diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index d1f6dfc..c09a800 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -574,7 +574,7 @@ static int __devinit snd_cmi8330_nonpnp_probe(struct platform_device *pdev) return 0; } -static int snd_cmi8330_nonpnp_remove(struct platform_device *devptr) +static int __devexit snd_cmi8330_nonpnp_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -597,7 +597,7 @@ static int snd_cmi8330_nonpnp_resume(struct platform_device *dev) static struct platform_driver snd_cmi8330_driver = { .probe = snd_cmi8330_nonpnp_probe, - .remove = snd_cmi8330_nonpnp_remove, + .remove = __devexit_p(snd_cmi8330_nonpnp_remove), #ifdef CONFIG_PM .suspend = snd_cmi8330_nonpnp_suspend, .resume = snd_cmi8330_nonpnp_resume, diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c index c20a4b1..ce57d52 100644 --- a/sound/isa/dt019x.c +++ b/sound/isa/dt019x.c @@ -23,7 +23,6 @@ #include <sound/driver.h> #include <linux/init.h> -#include <linux/sched.h> #include <linux/wait.h> #include <linux/pnp.h> #include <linux/moduleparam.h> diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 7f29f56..65f97ff 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -73,7 +73,7 @@ static struct platform_device *devices[SNDRV_CARDS]; #define PFX "es1688: " -static int __init snd_es1688_probe(struct platform_device *pdev) +static int __devinit snd_es1688_probe(struct platform_device *pdev) { int dev = pdev->id; static int possible_irqs[] = {5, 9, 10, 7, -1}; @@ -171,7 +171,7 @@ static int __init snd_es1688_probe(struct platform_device *pdev) return err; } -static int snd_es1688_remove(struct platform_device *devptr) +static int __devexit snd_es1688_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -182,7 +182,7 @@ static int snd_es1688_remove(struct platform_device *devptr) static struct platform_driver snd_es1688_driver = { .probe = snd_es1688_probe, - .remove = snd_es1688_remove, + .remove = __devexit_p(snd_es1688_remove), /* FIXME: suspend/resume */ .driver = { .name = ES1688_DRIVER diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index 37057a3..0395e2e 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -76,7 +76,7 @@ static struct platform_device *devices[SNDRV_CARDS]; #define PFX "gusclassic: " -static int __init snd_gusclassic_detect(struct snd_gus_card * gus) +static int __devinit snd_gusclassic_detect(struct snd_gus_card * gus) { unsigned char d; @@ -95,7 +95,7 @@ static int __init snd_gusclassic_detect(struct snd_gus_card * gus) return 0; } -static void __init snd_gusclassic_init(int dev, struct snd_gus_card * gus) +static void __devinit snd_gusclassic_init(int dev, struct snd_gus_card * gus) { gus->equal_irq = 0; gus->codec_flag = 0; @@ -103,7 +103,7 @@ static void __init snd_gusclassic_init(int dev, struct snd_gus_card * gus) gus->joystick_dac = joystick_dac[dev]; } -static int __init snd_gusclassic_probe(struct platform_device *pdev) +static int __devinit snd_gusclassic_probe(struct platform_device *pdev) { int dev = pdev->id; static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, 4, -1}; @@ -211,7 +211,7 @@ static int __init snd_gusclassic_probe(struct platform_device *pdev) return err; } -static int snd_gusclassic_remove(struct platform_device *devptr) +static int __devexit snd_gusclassic_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -222,7 +222,7 @@ static int snd_gusclassic_remove(struct platform_device *devptr) static struct platform_driver snd_gusclassic_driver = { .probe = snd_gusclassic_probe, - .remove = snd_gusclassic_remove, + .remove = __devexit_p(snd_gusclassic_remove), /* FIXME: suspend/resume */ .driver = { .name = GUSCLASSIC_DRIVER diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 532c56e..4f55fc3 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -92,7 +92,7 @@ static struct platform_device *devices[SNDRV_CARDS]; #define PFX "gusextreme: " -static int __init snd_gusextreme_detect(int dev, +static int __devinit snd_gusextreme_detect(int dev, struct snd_card *card, struct snd_gus_card * gus, struct snd_es1688 *es1688) @@ -142,12 +142,12 @@ static int __init snd_gusextreme_detect(int dev, return 0; } -static void __init snd_gusextreme_init(int dev, struct snd_gus_card * gus) +static void __devinit snd_gusextreme_init(int dev, struct snd_gus_card * gus) { gus->joystick_dac = joystick_dac[dev]; } -static int __init snd_gusextreme_mixer(struct snd_es1688 *chip) +static int __devinit snd_gusextreme_mixer(struct snd_es1688 *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -169,7 +169,7 @@ static int __init snd_gusextreme_mixer(struct snd_es1688 *chip) return 0; } -static int __init snd_gusextreme_probe(struct platform_device *pdev) +static int __devinit snd_gusextreme_probe(struct platform_device *pdev) { int dev = pdev->id; static int possible_ess_irqs[] = {5, 9, 10, 7, -1}; @@ -321,7 +321,7 @@ static int __init snd_gusextreme_probe(struct platform_device *pdev) return err; } -static int snd_gusextreme_remove(struct platform_device *devptr) +static int __devexit snd_gusextreme_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -332,7 +332,7 @@ static int snd_gusextreme_remove(struct platform_device *devptr) static struct platform_driver snd_gusextreme_driver = { .probe = snd_gusextreme_probe, - .remove = snd_gusextreme_remove, + .remove = __devexit_p(snd_gusextreme_remove), /* FIXME: suspend/resume */ .driver = { .name = GUSEXTREME_DRIVER diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index c1c69e3..d1ad90c 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -85,7 +85,7 @@ struct snd_gusmax { #define PFX "gusmax: " -static int __init snd_gusmax_detect(struct snd_gus_card * gus) +static int __devinit snd_gusmax_detect(struct snd_gus_card * gus) { unsigned char d; @@ -127,7 +127,8 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static void __init snd_gusmax_init(int dev, struct snd_card *card, struct snd_gus_card * gus) +static void __devinit snd_gusmax_init(int dev, struct snd_card *card, + struct snd_gus_card * gus) { gus->equal_irq = 1; gus->codec_flag = 1; @@ -145,7 +146,7 @@ static void __init snd_gusmax_init(int dev, struct snd_card *card, struct snd_gu #define CS4231_PRIVATE( left, right, shift, mute ) \ ((left << 24)|(right << 16)|(shift<<8)|mute) -static int __init snd_gusmax_mixer(struct snd_cs4231 *chip) +static int __devinit snd_gusmax_mixer(struct snd_cs4231 *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -204,7 +205,7 @@ static void snd_gusmax_free(struct snd_card *card) free_irq(maxcard->irq, (void *)maxcard); } -static int __init snd_gusmax_probe(struct platform_device *pdev) +static int __devinit snd_gusmax_probe(struct platform_device *pdev) { int dev = pdev->id; static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1}; @@ -348,7 +349,7 @@ static int __init snd_gusmax_probe(struct platform_device *pdev) return err; } -static int snd_gusmax_remove(struct platform_device *devptr) +static int __devexit snd_gusmax_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -359,7 +360,7 @@ static int snd_gusmax_remove(struct platform_device *devptr) static struct platform_driver snd_gusmax_driver = { .probe = snd_gusmax_probe, - .remove = snd_gusmax_remove, + .remove = __devexit_p(snd_gusmax_remove), /* FIXME: suspend/resume */ .driver = { .name = GUSMAX_DRIVER diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 1e30713..f3db686 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -919,7 +919,7 @@ static int __devinit snd_opl3sa2_nonpnp_probe(struct platform_device *pdev) return 0; } -static int snd_opl3sa2_nonpnp_remove(struct platform_device *devptr) +static int __devexit snd_opl3sa2_nonpnp_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -942,7 +942,7 @@ static int snd_opl3sa2_nonpnp_resume(struct platform_device *dev) static struct platform_driver snd_opl3sa2_nonpnp_driver = { .probe = snd_opl3sa2_nonpnp_probe, - .remove = snd_opl3sa2_nonpnp_remove, + .remove = __devexit( snd_opl3sa2_nonpnp_remove), #ifdef CONFIG_PM .suspend = snd_opl3sa2_nonpnp_suspend, .resume = snd_opl3sa2_nonpnp_resume, diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 268ebd3..be1e83e 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -83,7 +83,7 @@ static void snd_sb8_free(struct snd_card *card) release_and_free_resource(acard->fm_res); } -static int __init snd_sb8_probe(struct platform_device *pdev) +static int __devinit snd_sb8_probe(struct platform_device *pdev) { int dev = pdev->id; struct snd_sb *chip; @@ -193,7 +193,7 @@ static int __init snd_sb8_probe(struct platform_device *pdev) return err; } -static int snd_sb8_remove(struct platform_device *pdev) +static int __devexit snd_sb8_remove(struct platform_device *pdev) { snd_card_free(platform_get_drvdata(pdev)); platform_set_drvdata(pdev, NULL); @@ -230,7 +230,7 @@ static int snd_sb8_resume(struct platform_device *dev) static struct platform_driver snd_sb8_driver = { .probe = snd_sb8_probe, - .remove = snd_sb8_remove, + .remove = __devexit_p(snd_sb8_remove), #ifdef CONFIG_PM .suspend = snd_sb8_suspend, .resume = snd_sb8_resume, diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index 602db49..fef56ca 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c @@ -744,11 +744,10 @@ static int ac97_check_modem(struct ac97_codec *codec) struct ac97_codec *ac97_alloc_codec(void) { - struct ac97_codec *codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL); + struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL); if(!codec) return NULL; - memset(codec, 0, sizeof(*codec)); spin_lock_init(&codec->lock); INIT_LIST_HEAD(&codec->list); return codec; diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c index f072432..c0730a35 100644 --- a/sound/oss/ad1889.c +++ b/sound/oss/ad1889.c @@ -230,9 +230,8 @@ static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci) struct dmabuf *dmabuf; int i; - if ((dev = kmalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL) + if ((dev = kzalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL) return NULL; - memset(dev, 0, sizeof(ad1889_dev_t)); spin_lock_init(&dev->lock); dev->pci = pci; diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c index f845528..f813ae9 100644 --- a/sound/oss/btaudio.c +++ b/sound/oss/btaudio.c @@ -915,12 +915,11 @@ static int __devinit btaudio_probe(struct pci_dev *pci_dev, return -EBUSY; } - bta = kmalloc(sizeof(*bta),GFP_ATOMIC); + bta = kzalloc(sizeof(*bta),GFP_ATOMIC); if (!bta) { rc = -ENOMEM; goto fail0; } - memset(bta,0,sizeof(*bta)); bta->pci = pci_dev; bta->irq = pci_dev->irq; diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c index 147c8a9..2a1f0d9 100644 --- a/sound/oss/cs46xx.c +++ b/sound/oss/cs46xx.c @@ -3048,10 +3048,9 @@ static int cs_open(struct inode *inode, struct file *file) CS_DBGOUT(CS_WAVE_READ, 2, printk("cs46xx: cs_open() FMODE_READ\n") ); if (card->states[0] == NULL) { state = card->states[0] = - kmalloc(sizeof(struct cs_state), GFP_KERNEL); + kzalloc(sizeof(struct cs_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; - memset(state, 0, sizeof(struct cs_state)); mutex_init(&state->sem); dmabuf = &state->dmabuf; dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); @@ -3114,10 +3113,9 @@ static int cs_open(struct inode *inode, struct file *file) CS_DBGOUT(CS_OPEN, 2, printk("cs46xx: cs_open() FMODE_WRITE\n") ); if (card->states[1] == NULL) { state = card->states[1] = - kmalloc(sizeof(struct cs_state), GFP_KERNEL); + kzalloc(sizeof(struct cs_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; - memset(state, 0, sizeof(struct cs_state)); mutex_init(&state->sem); dmabuf = &state->dmabuf; dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); @@ -5075,11 +5073,10 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev, pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor); pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card); - if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) { + if ((card = kzalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "cs46xx: out of memory\n"); return -ENOMEM; } - memset(card, 0, sizeof(*card)); card->ba0_addr = RSRCADDRESS(pci_dev, 0); card->ba1_addr = RSRCADDRESS(pci_dev, 1); card->pci_dev = pci_dev; diff --git a/sound/oss/dmasound/dac3550a.c b/sound/oss/dmasound/dac3550a.c index 7360d89..0f0d03a 100644 --- a/sound/oss/dmasound/dac3550a.c +++ b/sound/oss/dmasound/dac3550a.c @@ -163,10 +163,9 @@ static int daca_detect_client(struct i2c_adapter *adapter, int address) struct i2c_client *new_client; int rc = -ENODEV; - new_client = kmalloc(sizeof(*new_client), GFP_KERNEL); + new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); if (!new_client) return -ENOMEM; - memset(new_client, 0, sizeof(*new_client)); new_client->addr = address; new_client->adapter = adapter; diff --git a/sound/oss/dmasound/tas3001c.c b/sound/oss/dmasound/tas3001c.c index 2f21a3c..4b7dbdd 100644 --- a/sound/oss/dmasound/tas3001c.c +++ b/sound/oss/dmasound/tas3001c.c @@ -807,10 +807,9 @@ tas3001c_init(struct i2c_client *client) size_t sz = sizeof(*self) + (TAS3001C_REG_MAX*sizeof(tas_shadow_t)); int i, j; - self = kmalloc(sz, GFP_KERNEL); + self = kzalloc(sz, GFP_KERNEL); if (!self) return -ENOMEM; - memset(self, 0, sz); self->super.client = client; self->super.shadow = (tas_shadow_t *)(self+1); diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c index af34fb3..678bf0f 100644 --- a/sound/oss/dmasound/tas3004.c +++ b/sound/oss/dmasound/tas3004.c @@ -1092,10 +1092,9 @@ tas3004_init(struct i2c_client *client) char mcr2 = 0; int i, j; - self = kmalloc(sz, GFP_KERNEL); + self = kzalloc(sz, GFP_KERNEL); if (!self) return -ENOMEM; - memset(self, 0, sz); self->super.client = client; self->super.shadow = (tas_shadow_t *)(self+1); diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c index 882ae98..665e85b 100644 --- a/sound/oss/dmasound/tas_common.c +++ b/sound/oss/dmasound/tas_common.c @@ -135,10 +135,9 @@ tas_detect_client(struct i2c_adapter *adapter, int address) return -ENODEV; } - new_client = kmalloc(sizeof(*new_client), GFP_KERNEL); + new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); if (!new_client) return -ENOMEM; - memset(new_client, 0, sizeof(*new_client)); new_client->addr = address; new_client->adapter = adapter; diff --git a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c index 6c59df7..16ac025 100644 --- a/sound/oss/emu10k1/main.c +++ b/sound/oss/emu10k1/main.c @@ -455,15 +455,13 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card) { int ret; - card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL); + card->mpuout = kzalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL); if (card->mpuout == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); ret = -ENOMEM; goto err_out1; } - memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout)); - card->mpuout->intr = 1; card->mpuout->status = FLAGS_AVAILABLE; card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT; @@ -472,15 +470,13 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card) spin_lock_init(&card->mpuout->lock); - card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL); + card->mpuin = kzalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL); if (card->mpuin == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n"); ret = -ENOMEM; goto err_out2; } - memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin)); - card->mpuin->status = FLAGS_AVAILABLE; tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin); @@ -1280,11 +1276,10 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev pci_set_master(pci_dev); - if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { + if ((card = kzalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "emu10k1: out of memory\n"); return -ENOMEM; } - memset(card, 0, sizeof(struct emu10k1_card)); card->iobase = pci_resource_start(pci_dev, 0); card->length = pci_resource_len(pci_dev, 0); diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index e1fbcca..974dd73 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -2871,11 +2871,10 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); return i; } - if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { + if (!(s = kzalloc(sizeof(struct es1371_state), GFP_KERNEL))) { printk(KERN_WARNING PFX "out of memory\n"); return -ENOMEM; } - memset(s, 0, sizeof(struct es1371_state)); s->codec = ac97_alloc_codec(); if(s->codec == NULL) diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c index 80a4277..a94b9df 100644 --- a/sound/oss/hal2.c +++ b/sound/oss/hal2.c @@ -1435,10 +1435,9 @@ static int hal2_init_card(struct hal2_card **phal2, struct hpc3_regs *hpc3) int ret = 0; struct hal2_card *hal2; - hal2 = kmalloc(sizeof(struct hal2_card), GFP_KERNEL); + hal2 = kzalloc(sizeof(struct hal2_card), GFP_KERNEL); if (!hal2) return -ENOMEM; - memset(hal2, 0, sizeof(struct hal2_card)); hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0]; hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1]; diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index c3c8a72..f5e31f1 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -2580,10 +2580,9 @@ static int i810_open(struct inode *inode, struct file *file) for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) { if (card->states[i] == NULL) { state = card->states[i] = (struct i810_state *) - kmalloc(sizeof(struct i810_state), GFP_KERNEL); + kzalloc(sizeof(struct i810_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; - memset(state, 0, sizeof(struct i810_state)); dmabuf = &state->dmabuf; goto found_virt; } @@ -3205,10 +3204,9 @@ static void __devinit i810_configure_clocking (void) */ if(card != NULL) { state = card->states[0] = (struct i810_state *) - kmalloc(sizeof(struct i810_state), GFP_KERNEL); + kzalloc(sizeof(struct i810_state), GFP_KERNEL); if (state == NULL) return; - memset(state, 0, sizeof(struct i810_state)); dmabuf = &state->dmabuf; dmabuf->write_channel = card->alloc_pcm_channel(card); @@ -3273,11 +3271,10 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device return -ENODEV; } - if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { + if ((card = kzalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "i810_audio: out of memory\n"); return -ENOMEM; } - memset(card, 0, sizeof(*card)); card->initializing = 1; card->pci_dev = pci_dev; diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 12e7b30..dfe670f 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c @@ -139,13 +139,12 @@ static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id printk(KERN_INFO "kahlua: XpressAudio on IRQ %d, DMA %d, %d\n", irq, dma8, dma16); - hw_config = kmalloc(sizeof(struct address_info), GFP_KERNEL); + hw_config = kzalloc(sizeof(struct address_info), GFP_KERNEL); if(hw_config == NULL) { printk(KERN_ERR "kahlua: out of memory.\n"); return 1; } - memset(hw_config, 0, sizeof(*hw_config)); pci_set_drvdata(pdev, hw_config); diff --git a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c index d459bdb..27b4ba3 100644 --- a/sound/oss/nec_vrc5477.c +++ b/sound/oss/nec_vrc5477.c @@ -1860,11 +1860,10 @@ static int __devinit vrc5477_ac97_probe(struct pci_dev *pcidev, if (pcidev->irq == 0) return -1; - if (!(s = kmalloc(sizeof(struct vrc5477_ac97_state), GFP_KERNEL))) { + if (!(s = kzalloc(sizeof(struct vrc5477_ac97_state), GFP_KERNEL))) { printk(KERN_ERR PFX "alloc of device struct failed\n"); return -1; } - memset(s, 0, sizeof(struct vrc5477_ac97_state)); init_waitqueue_head(&s->dma_adc.wait); init_waitqueue_head(&s->dma_dac.wait); diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 2e8cfa5..fc273e5 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -166,7 +166,7 @@ int opl3_detect(int ioaddr, int *osp) return 0; } - devc = kmalloc(sizeof(*devc), GFP_KERNEL); + devc = kzalloc(sizeof(*devc), GFP_KERNEL); if (devc == NULL) { @@ -175,7 +175,6 @@ int opl3_detect(int ioaddr, int *osp) return 0; } - memset(devc, 0, sizeof(*devc)); strcpy(devc->fm_info.name, "OPL2"); if (!request_region(ioaddr, 4, devc->fm_info.name)) { diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c index 8666291..27acd6f 100644 --- a/sound/oss/sb_card.c +++ b/sound/oss/sb_card.c @@ -137,11 +137,10 @@ static int __init sb_init_legacy(void) { struct sb_module_options sbmo = {0}; - if((legacy = kmalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { + if((legacy = kzalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { printk(KERN_ERR "sb: Error: Could not allocate memory\n"); return -ENOMEM; } - memset(legacy, 0, sizeof(struct sb_card_config)); legacy->conf.io_base = io; legacy->conf.irq = irq; @@ -247,11 +246,10 @@ static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device return -EBUSY; } - if((scc = kmalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { + if((scc = kzalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { printk(KERN_ERR "sb: Error: Could not allocate memory\n"); return -ENOMEM; } - memset(scc, 0, sizeof(struct sb_card_config)); printk(KERN_INFO "sb: PnP: Found Card Named = \"%s\", Card PnP id = " \ "%s, Device PnP id = %s\n", card->card->name, card_id->id, diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index 9f7e5f5..016b918 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -616,25 +616,23 @@ static int init_serdma(serdma_t *dma) /* Descriptors */ dma->ringsz = DMA_DESCR; - dma->descrtab = kmalloc(dma->ringsz * sizeof(serdma_descr_t), GFP_KERNEL); + dma->descrtab = kzalloc(dma->ringsz * sizeof(serdma_descr_t), GFP_KERNEL); if (!dma->descrtab) { - printk(KERN_ERR "cs4297a: kmalloc descrtab failed\n"); + printk(KERN_ERR "cs4297a: kzalloc descrtab failed\n"); return -1; } - memset(dma->descrtab, 0, dma->ringsz * sizeof(serdma_descr_t)); dma->descrtab_end = dma->descrtab + dma->ringsz; /* XXX bloddy mess, use proper DMA API here ... */ dma->descrtab_phys = CPHYSADDR((long)dma->descrtab); dma->descr_add = dma->descr_rem = dma->descrtab; /* Frame buffer area */ - dma->dma_buf = kmalloc(DMA_BUF_SIZE, GFP_KERNEL); + dma->dma_buf = kzalloc(DMA_BUF_SIZE, GFP_KERNEL); if (!dma->dma_buf) { - printk(KERN_ERR "cs4297a: kmalloc dma_buf failed\n"); + printk(KERN_ERR "cs4297a: kzalloc dma_buf failed\n"); kfree(dma->descrtab); return -1; } - memset(dma->dma_buf, 0, DMA_BUF_SIZE); dma->dma_buf_phys = CPHYSADDR((long)dma->dma_buf); /* Samples buffer area */ @@ -2619,12 +2617,11 @@ static int __init cs4297a_init(void) udelay(100); #endif - if (!(s = kmalloc(sizeof(struct cs4297a_state), GFP_KERNEL))) { + if (!(s = kzalloc(sizeof(struct cs4297a_state), GFP_KERNEL))) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4297a: probe() no memory for state struct.\n")); return -1; } - memset(s, 0, sizeof(struct cs4297a_state)); s->magic = CS4297a_MAGIC; init_waitqueue_head(&s->dma_adc.wait); init_waitqueue_head(&s->dma_dac.wait); diff --git a/sound/oss/trident.c b/sound/oss/trident.c index 6b1f8c9..72a8a0e 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -2729,12 +2729,11 @@ trident_open(struct inode *inode, struct file *file) } for (i = 0; i < NR_HW_CH; i++) { if (card->states[i] == NULL) { - state = card->states[i] = kmalloc(sizeof(*state), GFP_KERNEL); + state = card->states[i] = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) { mutex_unlock(&card->open_mutex); return -ENOMEM; } - memset(state, 0, sizeof(*state)); mutex_init(&state->sem); dmabuf = &state->dmabuf; goto found_virt; @@ -3618,7 +3617,7 @@ ali_allocate_other_states_resources(struct trident_state *state, int chan_nums) } return -EBUSY; } - s = card->states[i] = kmalloc(sizeof(*state), GFP_KERNEL); + s = card->states[i] = kzalloc(sizeof(*state), GFP_KERNEL); if (!s) { num = ali_multi_channels_5_1[state_count]; ali_free_pcm_channel(card, num); @@ -3630,7 +3629,6 @@ ali_allocate_other_states_resources(struct trident_state *state, int chan_nums) } return -ENOMEM; } - memset(s, 0, sizeof(*state)); s->dmabuf.channel = channel; s->dmabuf.ossfragshift = s->dmabuf.ossmaxfrags = @@ -4399,11 +4397,10 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) } rc = -ENOMEM; - if ((card = kmalloc(sizeof(*card), GFP_KERNEL)) == NULL) { + if ((card = kzalloc(sizeof(*card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); goto out_release_region; } - memset(card, 0, sizeof (*card)); init_timer(&card->timer); card->iobase = iobase; diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c index 26a7c6a..b48c729 100644 --- a/sound/oss/waveartist.c +++ b/sound/oss/waveartist.c @@ -1267,12 +1267,10 @@ static int __init waveartist_init(wavnc_info *devc) conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, devc->hw.dma, devc->hw.dma2); - portc = kmalloc(sizeof(wavnc_port_info), GFP_KERNEL); + portc = kzalloc(sizeof(wavnc_port_info), GFP_KERNEL); if (portc == NULL) goto nomem; - memset(portc, 0, sizeof(wavnc_port_info)); - my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &waveartist_audio_driver, sizeof(struct audio_driver), devc->audio_flags, AFMT_U8 | AFMT_S16_LE | AFMT_S8, diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 74ed810..a9eec2a 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -143,6 +143,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x43525970, 0xfffffff8, "CS4202", NULL, NULL }, { 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II { 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different +{ 0x43585431, 0xffffffff, "Cx20551", patch_cx20551, NULL }, { 0x44543031, 0xfffffff0, "DT0398", NULL, NULL }, { 0x454d4328, 0xffffffff, "EM28028", NULL, NULL }, // same as TR28028? { 0x45838308, 0xffffffff, "ESS1988", NULL, NULL }, diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 641d0c8..bfc2fed 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1338,6 +1338,12 @@ int patch_conexant(struct snd_ac97 * ac97) return 0; } +int patch_cx20551(struct snd_ac97 *ac97) +{ + snd_ac97_update_bits(ac97, 0x5c, 0x01, 0x01); + return 0; +} + /* * Analog Device AD18xx, AD19xx codecs */ diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 94340da..555d1c9 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -39,6 +39,7 @@ int patch_sigmatel_stac9758(struct snd_ac97 * ac97); int patch_cirrus_cs4299(struct snd_ac97 * ac97); int patch_cirrus_spdif(struct snd_ac97 * ac97); int patch_conexant(struct snd_ac97 * ac97); +int patch_cx20551(struct snd_ac97 * ac97); int patch_ad1819(struct snd_ac97 * ac97); int patch_ad1881(struct snd_ac97 * ac97); int patch_ad1885(struct snd_ac97 * ac97); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 73f4668..23a1c75 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -57,6 +57,7 @@ struct conexant_spec { * dig_out_nid and hp_nid are optional */ unsigned int cur_eapd; + unsigned int hp_present; unsigned int need_dac_fix; /* capture */ @@ -354,7 +355,7 @@ static struct hda_codec_ops conexant_patch_ops = { * the private value = nid | (invert << 8) */ -static int conexant_eapd_info(struct snd_kcontrol *kcontrol, +static int cxt_eapd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; @@ -364,7 +365,7 @@ static int conexant_eapd_info(struct snd_kcontrol *kcontrol, return 0; } -static int conexant_eapd_get(struct snd_kcontrol *kcontrol, +static int cxt_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -375,9 +376,10 @@ static int conexant_eapd_get(struct snd_kcontrol *kcontrol, else ucontrol->value.integer.value[0] = spec->cur_eapd; return 0; + } -static int conexant_eapd_put(struct snd_kcontrol *kcontrol, +static int cxt_eapd_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -385,11 +387,13 @@ static int conexant_eapd_put(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 8) & 1; hda_nid_t nid = kcontrol->private_value & 0xff; unsigned int eapd; + eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; if (eapd == spec->cur_eapd && !codec->in_resume) return 0; + spec->cur_eapd = eapd; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, @@ -400,6 +404,15 @@ static int conexant_eapd_put(struct snd_kcontrol *kcontrol, /* controls for test mode */ #ifdef CONFIG_SND_DEBUG +#define CXT_EAPD_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = cxt_eapd_info, \ + .get = cxt_eapd_get, \ + .put = cxt_eapd_put, \ + .private_value = nid | (mask<<16) } + + + static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -492,7 +505,7 @@ static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol, .get = cxt_gpio_data_get, \ .put = cxt_gpio_data_put, \ .private_value = nid | (mask<<16) } - +#if 0 static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -547,7 +560,7 @@ static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol, .get = cxt_spdif_ctrl_get, \ .put = cxt_spdif_ctrl_put, \ .private_value = nid | (mask<<16) } - +#endif #endif /* CONFIG_SND_DEBUG */ /* Conexant 5045 specific */ @@ -564,7 +577,7 @@ static struct hda_channel_mode cxt5045_modes[1] = { static struct hda_input_mux cxt5045_capture_source = { .num_items = 2, .items = { - { "ExtMic", 0x1 }, + { "IntMic", 0x1 }, { "LineIn", 0x2 }, } }; @@ -575,15 +588,20 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; + unsigned int bits; - if (!conexant_eapd_put(kcontrol, ucontrol)) + if (!cxt_eapd_put(kcontrol, ucontrol)) return 0; - /* toggle HP mute appropriately */ - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); + /* toggle internal speakers mute depending of presence of + * the headphone jack + */ + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; + snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->cur_eapd ? 0 : 0x80; + snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 0x80, bits); return 1; } @@ -610,14 +628,13 @@ static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, /* mute internal speaker if HP is plugged */ static void cxt5045_hp_automute(struct hda_codec *codec) { - unsigned int present; + struct conexant_spec *spec = codec->spec; + unsigned int bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - present = snd_hda_codec_read(codec, 0x11, 0, + spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); } /* unsolicited event for HP jack sensing */ @@ -640,25 +657,27 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { .get = conexant_mux_enum_get, .put = conexant_mux_enum_put }, - HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Volume", 0x17, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Switch", 0x17, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Ext Mic Volume", 0x17, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Ext Mic Switch", 0x17, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = snd_hda_mixer_amp_volume_info, .get = snd_hda_mixer_amp_volume_get, .put = cxt5045_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .info = conexant_eapd_info, - .get = conexant_eapd_get, + .info = cxt_eapd_info, + .get = cxt_eapd_get, .put = cxt5045_hp_master_sw_put, - .private_value = 0x11, + .private_value = 0x10, }, {} @@ -669,22 +688,26 @@ static struct hda_verb cxt5045_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, /* HP, Amp */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + {0x17, AC_VERB_SET_CONNECT_SEL,0x01}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x01}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x02}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - /* Record selector: Front mic */ - {0x14, AC_VERB_SET_CONNECT_SEL,0x03}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x04}, + /* Record selector: Int mic */ + {0x1a, AC_VERB_SET_CONNECT_SEL,0x0}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, /* SPDIF route: PCM */ { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, /* pin sensing on HP and Mic jacks */ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ + {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ { } /* end */ }; @@ -706,8 +729,6 @@ static struct hda_input_mux cxt5045_test_capture_source = { static struct snd_kcontrol_new cxt5045_test_mixer[] = { /* Output controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), @@ -715,6 +736,9 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), + /* EAPD Switch Control */ + CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), + /* Loopback mixer controls */ HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT), HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT), @@ -725,17 +749,16 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT), - /* Controls for GPIO pins, assuming they exist and are configured as outputs */ - CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), -#if 0 /* limit this to one GPIO pin for now */ - CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), -#endif - CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01), - - HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture-1 Volume", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture-1 Switch", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-2 Volume", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Capture-2 Switch", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-3 Volume", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Capture-3 Switch", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-4 Volume", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Capture-4 Switch", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-5 Volume", 0x17, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("Capture-5 Switch", 0x17, 0x4, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -748,14 +771,9 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { }; static struct hda_verb cxt5045_test_init_verbs[] = { - /* Enable all GPIOs as outputs with an initial value of 0 */ - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, - /* Enable retasking pins as output, initially without power amp */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Disable digital (SPDIF) pins initially, but users can enable * them via a mixer switch. In the case of SPDIF-out, this initverb @@ -823,6 +841,8 @@ static const char *cxt5045_models[CXT5045_MODELS] = { static struct snd_pci_quirk cxt5045_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP), + SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP), {} }; @@ -880,11 +900,11 @@ static int patch_cxt5045(struct hda_codec *codec) /* Conexant 5047 specific */ +#define CXT5047_SPDIF_OUT 0x11 -static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; +static hda_nid_t cxt5047_dac_nids[2] = { 0x10, 0x1c }; static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; -#define CXT5047_SPDIF_OUT 0x11 static struct hda_channel_mode cxt5047_modes[1] = { { 2, NULL }, @@ -893,15 +913,23 @@ static struct hda_channel_mode cxt5047_modes[1] = { static struct hda_input_mux cxt5047_capture_source = { .num_items = 2, .items = { - { "ExtMic", 0x1 }, - { "IntMic", 0x2 }, + { "ExtMic", 0x0 }, + { "IntMic", 0x1 }, } }; static struct hda_input_mux cxt5047_hp_capture_source = { .num_items = 1, .items = { - { "ExtMic", 0x1 }, + { "ExtMic", 0x2 }, + } +}; + +static struct hda_input_mux cxt5047_toshiba_capture_source = { + .num_items = 2, + .items = { + { "ExtMic", 0x2 }, + { "Line-In", 0x1 }, } }; @@ -911,20 +939,24 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; + unsigned int bits; - if (!conexant_eapd_put(kcontrol, ucontrol)) + if (!cxt_eapd_put(kcontrol, ucontrol)) return 0; - /* toggle HP mute appropriately */ - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); + /* toggle internal speakers mute depending of presence of + * the headphone jack + */ + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; + snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->cur_eapd ? 0 : 0x80; + snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 0x80, bits); return 1; } -#if 0 -/* bind volumes of both NID 0x13 and 0x1d */ +/* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -932,9 +964,9 @@ static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change; - change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, + change = snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, + change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x7f, valp[1] & 0x7f); snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x7f, valp[0] & 0x7f); @@ -942,19 +974,20 @@ static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, 0x7f, valp[1] & 0x7f); return change; } -#endif /* mute internal speaker if HP is plugged */ static void cxt5047_hp_automute(struct hda_codec *codec) { - unsigned int present; + struct conexant_spec *spec = codec->spec; + unsigned int bits = spec->hp_present || !spec->cur_eapd ? 0x80 : 0; - present = snd_hda_codec_read(codec, 0x13, 0, + spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + /* Mute/Unmute PCM 2 for good measure - some systems need this */ + snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); } /* toggle input of built-in and mic jack appropriately */ @@ -1009,12 +1042,55 @@ static struct snd_kcontrol_new cxt5047_mixers[] = { HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM-2 Volume", 0x1c, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM-2 Switch", 0x1c, 0x00, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = cxt5047_hp_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), + }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .info = conexant_eapd_info, - .get = conexant_eapd_get, + .info = cxt_eapd_info, + .get = cxt_eapd_get, + .put = cxt5047_hp_master_sw_put, + .private_value = 0x13, + }, + + {} +}; + +static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = conexant_mux_enum_info, + .get = conexant_mux_enum_get, + .put = conexant_mux_enum_put + }, + HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = cxt5047_hp_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = cxt_eapd_info, + .get = cxt_eapd_get, .put = cxt5047_hp_master_sw_put, .private_value = 0x13, }, @@ -1040,8 +1116,8 @@ static struct snd_kcontrol_new cxt5047_hp_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .info = conexant_eapd_info, - .get = conexant_eapd_get, + .info = cxt_eapd_info, + .get = cxt_eapd_get, .put = cxt5047_hp_master_sw_put, .private_value = 0x13, }, @@ -1053,19 +1129,23 @@ static struct hda_verb cxt5047_init_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - /* HP, Amp */ + /* HP, Amp, Speaker */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x03}, + {0x1A, AC_VERB_SET_CONNECT_SEL,0x00}, {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, + {0x1d, AC_VERB_SET_CONNECT_SEL,0x0}, /* Record selector: Front mic */ {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, /* SPDIF route: PCM */ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, + /* Enable unsolicited events */ + {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, { } /* end */ }; @@ -1075,14 +1155,24 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = { /* pin sensing on HP and Mic jacks */ {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + /* Speaker routing */ + {0x1d, AC_VERB_SET_CONNECT_SEL,0x1}, + /* Change default to ExtMic for recording */ + {0x1a, AC_VERB_SET_CONNECT_SEL,0x2}, {} }; /* configuration for HP Laptops */ static struct hda_verb cxt5047_hp_init_verbs[] = { - /* pin sensing on HP and Mic jacks */ + /* pin sensing on HP jack */ {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + /* Record selector: Ext Mic */ + {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, + {0x1a, AC_VERB_SET_CONNECT_SEL,0x02}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, + /* Speaker routing */ + {0x1d, AC_VERB_SET_CONNECT_SEL,0x1}, {} }; @@ -1091,53 +1181,56 @@ static struct hda_verb cxt5047_hp_init_verbs[] = { */ #ifdef CONFIG_SND_DEBUG static struct hda_input_mux cxt5047_test_capture_source = { - .num_items = 5, + .num_items = 4, .items = { - { "MIXER", 0x0 }, - { "LINE1 pin", 0x1 }, - { "MIC1 pin", 0x2 }, - { "MIC2 pin", 0x3 }, - { "CD pin", 0x4 }, + { "LINE1 pin", 0x0 }, + { "MIC1 pin", 0x1 }, + { "MIC2 pin", 0x2 }, + { "CD pin", 0x3 }, }, }; static struct snd_kcontrol_new cxt5047_test_mixer[] = { /* Output only controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), /* Modes for retasking pin widgets */ CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT), - -#if 0 - /* Controls for GPIO pins, assuming they exist and are configured as outputs */ - CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), -#endif - CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01), + /* EAPD Switch Control */ + CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), - HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT), + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), + + HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -1145,16 +1238,18 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { .get = conexant_mux_enum_get, .put = conexant_mux_enum_put, }, + /* Controls for GPIO pins, assuming they exist and are configured + * as outputs + */ + CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), { } /* end */ }; static struct hda_verb cxt5047_test_init_verbs[] = { - /* Enable all GPIOs as outputs with an initial value of 0 */ - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, - /* Enable retasking pins as output, initially without power amp */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -1215,7 +1310,6 @@ static int cxt5047_hp_init(struct hda_codec *codec) { conexant_init(codec); cxt5047_hp_automute(codec); - cxt5047_hp_automic(codec); return 0; } @@ -1242,6 +1336,7 @@ static const char *cxt5047_models[CXT5047_MODELS] = { static struct snd_pci_quirk cxt5047_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), {} @@ -1291,8 +1386,10 @@ static int patch_cxt5047(struct hda_codec *codec) codec->patch_ops.init = cxt5047_hp_init; break; case CXT5047_LAPTOP_EAPD: + spec->input_mux = &cxt5047_toshiba_capture_source; spec->num_init_verbs = 2; spec->init_verbs[1] = cxt5047_toshiba_init_verbs; + spec->mixers[0] = cxt5047_toshiba_mixers; break; #ifdef CONFIG_SND_DEBUG case CXT5047_TEST: @@ -1305,7 +1402,9 @@ static int patch_cxt5047(struct hda_codec *codec) } struct hda_codec_preset snd_hda_preset_conexant[] = { - { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 }, - { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 }, + { .id = 0x14f15045, .name = "CX20549 (Venice)", + .patch = patch_cxt5045 }, + { .id = 0x14f15047, .name = "CX20551 (Waikiki)", + .patch = patch_cxt5047 }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6f4a392..f7ef9c5 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -457,6 +457,10 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { "Dell Latitude 120L", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, "Dell Latitude D820", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, + "Dell Inspiron E1705/9400", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, + "Dell XPS M1710", STAC_REF), {} /* terminator */ }; @@ -1800,6 +1804,7 @@ static int patch_stac925x(struct hda_codec *codec) spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, stac925x_models, stac925x_cfg_tbl); + again: if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); @@ -1825,6 +1830,15 @@ static int patch_stac925x(struct hda_codec *codec) spec->mixer = stac925x_mixer; err = stac92xx_parse_auto_config(codec, 0x8, 0x7); + if (!err) { + if (spec->board_config < 0) { + printk(KERN_WARNING "hda_codec: No auto-config is " + "available, default to model=ref\n"); + spec->board_config = STAC_925x_REF; + goto again; + } + err = -EINVAL; + } if (err < 0) { stac92xx_free(codec); return err; @@ -1850,6 +1864,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, stac922x_models, stac922x_cfg_tbl); + again: if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); @@ -1875,6 +1890,15 @@ static int patch_stac922x(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; err = stac92xx_parse_auto_config(codec, 0x08, 0x09); + if (!err) { + if (spec->board_config < 0) { + printk(KERN_WARNING "hda_codec: No auto-config is " + "available, default to model=ref\n"); + spec->board_config = STAC_D945_REF; + goto again; + } + err = -EINVAL; + } if (err < 0) { stac92xx_free(codec); return err; @@ -1903,6 +1927,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, stac927x_models, stac927x_cfg_tbl); + again: if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); @@ -1945,6 +1970,15 @@ static int patch_stac927x(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); + if (!err) { + if (spec->board_config < 0) { + printk(KERN_WARNING "hda_codec: No auto-config is " + "available, default to model=ref\n"); + spec->board_config = STAC_D965_REF; + goto again; + } + err = -EINVAL; + } if (err < 0) { stac92xx_free(codec); return err; @@ -1970,6 +2004,7 @@ static int patch_stac9205(struct hda_codec *codec) spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, stac9205_models, stac9205_cfg_tbl); + again: if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); @@ -2008,6 +2043,15 @@ static int patch_stac9205(struct hda_codec *codec) AC_VERB_SET_GPIO_MASK, 0x00000001); err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); + if (!err) { + if (spec->board_config < 0) { + printk(KERN_WARNING "hda_codec: No auto-config is " + "available, default to model=ref\n"); + spec->board_config = STAC_9205_REF; + goto again; + } + err = -EINVAL; + } if (err < 0) { stac92xx_free(codec); return err; diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c index fcc544a..9fc0c03 100644 --- a/sound/soc/at91/at91-i2s.c +++ b/sound/soc/at91/at91-i2s.c @@ -20,6 +20,8 @@ #include <linux/device.h> #include <linux/delay.h> #include <linux/clk.h> +#include <linux/atmel_pdc.h> + #include <sound/driver.h> #include <sound/core.h> #include <sound/pcm.h> @@ -29,7 +31,6 @@ #include <asm/arch/hardware.h> #include <asm/arch/at91_pmc.h> #include <asm/arch/at91_ssc.h> -#include <asm/arch/at91_pdc.h> #include "at91-pcm.h" #include "at91-i2s.h" @@ -51,17 +52,17 @@ * SSC PDC registers required by the PCM DMA engine. */ static struct at91_pdc_regs pdc_tx_reg = { - .xpr = AT91_PDC_TPR, - .xcr = AT91_PDC_TCR, - .xnpr = AT91_PDC_TNPR, - .xncr = AT91_PDC_TNCR, + .xpr = ATMEL_PDC_TPR, + .xcr = ATMEL_PDC_TCR, + .xnpr = ATMEL_PDC_TNPR, + .xncr = ATMEL_PDC_TNCR, }; static struct at91_pdc_regs pdc_rx_reg = { - .xpr = AT91_PDC_RPR, - .xcr = AT91_PDC_RCR, - .xnpr = AT91_PDC_RNPR, - .xncr = AT91_PDC_RNCR, + .xpr = ATMEL_PDC_RPR, + .xcr = ATMEL_PDC_RCR, + .xnpr = ATMEL_PDC_RNPR, + .xncr = ATMEL_PDC_RNCR, }; /* @@ -72,8 +73,8 @@ static struct at91_ssc_mask ssc_tx_mask = { .ssc_disable = AT91_SSC_TXDIS, .ssc_endx = AT91_SSC_ENDTX, .ssc_endbuf = AT91_SSC_TXBUFE, - .pdc_enable = AT91_PDC_TXTEN, - .pdc_disable = AT91_PDC_TXTDIS, + .pdc_enable = ATMEL_PDC_TXTEN, + .pdc_disable = ATMEL_PDC_TXTDIS, }; static struct at91_ssc_mask ssc_rx_mask = { @@ -81,8 +82,8 @@ static struct at91_ssc_mask ssc_rx_mask = { .ssc_disable = AT91_SSC_RXDIS, .ssc_endx = AT91_SSC_ENDRX, .ssc_endbuf = AT91_SSC_RXBUFF, - .pdc_enable = AT91_PDC_RXTEN, - .pdc_disable = AT91_PDC_RXTDIS, + .pdc_enable = ATMEL_PDC_RXTEN, + .pdc_disable = ATMEL_PDC_RXTDIS, }; @@ -508,14 +509,14 @@ static int at91_i2s_hw_params(struct snd_pcm_substream *substream, /* Reset the SSC and its PDC registers */ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0); - at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0); if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt, 0, ssc_p->name, ssc_p)) < 0) { diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c index e88b12e..b39b95a 100644 --- a/sound/soc/at91/at91-pcm.c +++ b/sound/soc/at91/at91-pcm.c @@ -21,6 +21,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> #include <sound/driver.h> #include <sound/core.h> @@ -30,7 +31,6 @@ #include <asm/arch/hardware.h> #include <asm/arch/at91_ssc.h> -#include <asm/arch/at91_pdc.h> #include "at91-pcm.h" @@ -83,7 +83,7 @@ static void at91_pcm_dma_irq(u32 ssc_sr, params->name, ssc_sr, count); /* re-start the PDC */ - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); prtd->period_ptr += prtd->period_size; if (prtd->period_ptr >= prtd->dma_buffer_end) { @@ -94,7 +94,7 @@ static void at91_pcm_dma_irq(u32 ssc_sr, at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->period_size / params->pdc_xfer_size); - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); } if (ssc_sr & params->mask->ssc_endx) { @@ -143,7 +143,7 @@ static int at91_pcm_hw_free(struct snd_pcm_substream *substream) struct at91_pcm_dma_params *params = prtd->params; if (params != NULL) { - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); prtd->params->dma_intr_handler = NULL; } @@ -158,7 +158,7 @@ static int at91_pcm_prepare(struct snd_pcm_substream *substream) at91_ssc_write(params->ssc_base + AT91_SSC_IDR, params->mask->ssc_endx | params->mask->ssc_endbuf); - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); return 0; } @@ -192,7 +192,7 @@ static int at91_pcm_trigger(struct snd_pcm_substream *substream, at91_ssc_write(params->ssc_base + AT91_SSC_IER, params->mask->ssc_endx | params->mask->ssc_endbuf); - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR), at91_ssc_read(params->ssc_base + AT91_SSC_IER)); @@ -201,12 +201,12 @@ static int at91_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); break; default: @@ -379,7 +379,7 @@ static int at91_pcm_suspend(struct platform_device *pdev, /* disable the PDC and save the PDC registers */ - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); @@ -408,7 +408,7 @@ static int at91_pcm_resume(struct platform_device *pdev, at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); - at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); return 0; } #else diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 78ac268..ec2a278 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,15 +1,15 @@ config SND_SOC_AC97_CODEC tristate - depends SND_SOC + depends on SND_SOC config SND_SOC_WM8731 tristate - depends SND_SOC + depends on SND_SOC config SND_SOC_WM8750 tristate - depends SND_SOC + depends on SND_SOC config SND_SOC_WM9712 tristate - depends SND_SOC + depends on SND_SOC diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 573e370..ebcac13 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -20,7 +20,6 @@ #include <sound/driver.h> #include <linux/wait.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <sound/core.h> diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 59144ec..680f2b7 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c @@ -20,7 +20,6 @@ #include <sound/driver.h> #include <linux/wait.h> -#include <linux/sched.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/emux_synth.h> diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 4dfb91d..b6d8863 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -325,16 +325,6 @@ static int prepare_capture_urb(struct snd_usb_substream *subs, } urb->transfer_buffer_length = offs; urb->number_of_packets = ctx->packets; -#if 0 // for check - if (! urb->bandwidth) { - int bustime; - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) - return bustime; - printk("urb %d: bandwidth = %d (packets = %d)\n", ctx->index, bustime, urb->number_of_packets); - usb_claim_bandwidth(urb->dev, urb, bustime, 1); - } -#endif // for check return 0; } diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 25b4ab4f..8582620 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -948,6 +948,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, /* TODO: add Edirol M-100FX support */ { + /* has ID 0x004e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x004c), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "EDIROL", + .product_name = "PCR-A", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, +{ /* has ID 0x004f when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x004d), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |