Merge /spare/repo/linux-2.6/
diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl
index 4367f46..42a760c 100644
--- a/Documentation/DocBook/mcabook.tmpl
+++ b/Documentation/DocBook/mcabook.tmpl
@@ -96,7 +96,7 @@
<chapter id="pubfunctions">
<title>Public Functions Provided</title>
-!Earch/i386/kernel/mca.c
+!Edrivers/mca/mca-legacy.c
</chapter>
<chapter id="dmafunctions">
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 84d3d4d..bf1cf98d 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -605,12 +605,13 @@
it will send the proper IPMI commands to do this. This is supported on
several platforms.
-There is a module parameter named "poweroff_control" that may either be zero
-(do a power down) or 2 (do a power cycle, power the system off, then power
-it on in a few seconds). Setting ipmi_poweroff.poweroff_control=x will do
-the same thing on the kernel command line. The parameter is also available
-via the proc filesystem in /proc/ipmi/poweroff_control. Note that if the
-system does not support power cycling, it will always to the power off.
+There is a module parameter named "poweroff_powercycle" that may
+either be zero (do a power down) or non-zero (do a power cycle, power
+the system off, then power it on in a few seconds). Setting
+ipmi_poweroff.poweroff_control=x will do the same thing on the kernel
+command line. The parameter is also available via the proc filesystem
+in /proc/sys/dev/ipmi/poweroff_powercycle. Note that if the system
+does not support power cycling, it will always do the power off.
Note that if you have ACPI enabled, the system will prefer using ACPI to
power off.
diff --git a/Documentation/RCU/NMI-RCU.txt b/Documentation/RCU/NMI-RCU.txt
new file mode 100644
index 0000000..d0634a5
--- /dev/null
+++ b/Documentation/RCU/NMI-RCU.txt
@@ -0,0 +1,112 @@
+Using RCU to Protect Dynamic NMI Handlers
+
+
+Although RCU is usually used to protect read-mostly data structures,
+it is possible to use RCU to provide dynamic non-maskable interrupt
+handlers, as well as dynamic irq handlers. This document describes
+how to do this, drawing loosely from Zwane Mwaikambo's NMI-timer
+work in "arch/i386/oprofile/nmi_timer_int.c" and in
+"arch/i386/kernel/traps.c".
+
+The relevant pieces of code are listed below, each followed by a
+brief explanation.
+
+ static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
+ {
+ return 0;
+ }
+
+The dummy_nmi_callback() function is a "dummy" NMI handler that does
+nothing, but returns zero, thus saying that it did nothing, allowing
+the NMI handler to take the default machine-specific action.
+
+ static nmi_callback_t nmi_callback = dummy_nmi_callback;
+
+This nmi_callback variable is a global function pointer to the current
+NMI handler.
+
+ fastcall void do_nmi(struct pt_regs * regs, long error_code)
+ {
+ int cpu;
+
+ nmi_enter();
+
+ cpu = smp_processor_id();
+ ++nmi_count(cpu);
+
+ if (!rcu_dereference(nmi_callback)(regs, cpu))
+ default_do_nmi(regs);
+
+ nmi_exit();
+ }
+
+The do_nmi() function processes each NMI. It first disables preemption
+in the same way that a hardware irq would, then increments the per-CPU
+count of NMIs. It then invokes the NMI handler stored in the nmi_callback
+function pointer. If this handler returns zero, do_nmi() invokes the
+default_do_nmi() function to handle a machine-specific NMI. Finally,
+preemption is restored.
+
+Strictly speaking, rcu_dereference() is not needed, since this code runs
+only on i386, which does not need rcu_dereference() anyway. However,
+it is a good documentation aid, particularly for anyone attempting to
+do something similar on Alpha.
+
+Quick Quiz: Why might the rcu_dereference() be necessary on Alpha,
+ given that the code referenced by the pointer is read-only?
+
+
+Back to the discussion of NMI and RCU...
+
+ void set_nmi_callback(nmi_callback_t callback)
+ {
+ rcu_assign_pointer(nmi_callback, callback);
+ }
+
+The set_nmi_callback() function registers an NMI handler. Note that any
+data that is to be used by the callback must be initialized up -before-
+the call to set_nmi_callback(). On architectures that do not order
+writes, the rcu_assign_pointer() ensures that the NMI handler sees the
+initialized values.
+
+ void unset_nmi_callback(void)
+ {
+ rcu_assign_pointer(nmi_callback, dummy_nmi_callback);
+ }
+
+This function unregisters an NMI handler, restoring the original
+dummy_nmi_handler(). However, there may well be an NMI handler
+currently executing on some other CPU. We therefore cannot free
+up any data structures used by the old NMI handler until execution
+of it completes on all other CPUs.
+
+One way to accomplish this is via synchronize_sched(), perhaps as
+follows:
+
+ unset_nmi_callback();
+ synchronize_sched();
+ kfree(my_nmi_data);
+
+This works because synchronize_sched() blocks until all CPUs complete
+any preemption-disabled segments of code that they were executing.
+Since NMI handlers disable preemption, synchronize_sched() is guaranteed
+not to return until all ongoing NMI handlers exit. It is therefore safe
+to free up the handler's data as soon as synchronize_sched() returns.
+
+
+Answer to Quick Quiz
+
+ Why might the rcu_dereference() be necessary on Alpha, given
+ that the code referenced by the pointer is read-only?
+
+ Answer: The caller to set_nmi_callback() might well have
+ initialized some data that is to be used by the
+ new NMI handler. In this case, the rcu_dereference()
+ would be needed, because otherwise a CPU that received
+ an NMI just after the new handler was set might see
+ the pointer to the new NMI handler, but the old
+ pre-initialized version of the handler's data.
+
+ More important, the rcu_dereference() makes it clear
+ to someone reading the code that the pointer is being
+ protected by RCU.
diff --git a/Documentation/cdrom/sonycd535 b/Documentation/cdrom/sonycd535
index 59581a4..b81e109 100644
--- a/Documentation/cdrom/sonycd535
+++ b/Documentation/cdrom/sonycd535
@@ -68,7 +68,8 @@
Porfiri Claudio <C.Porfiri@nisms.tei.ericsson.se> for patches
to make the driver work with the older CDU-510/515 series, and
Heiko Eissfeldt <heiko@colossus.escape.de> for pointing out that
-the verify_area() checks were ignoring the results of said checks.
+the verify_area() checks were ignoring the results of said checks
+(note: verify_area() has since been replaced by access_ok()).
(Acknowledgments from Ron Jeppesen in the 0.3 release:)
Thanks to Corey Minyard who wrote the original CDU-31A driver on which
diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
index ad944c0..47f4114 100644
--- a/Documentation/cpusets.txt
+++ b/Documentation/cpusets.txt
@@ -60,6 +60,18 @@
load balancing code trying to pull tasks outside of the cpu exclusive
cpuset only to be prevented by the tasks' cpus_allowed mask.
+A cpuset that is mem_exclusive restricts kernel allocations for
+page, buffer and other data commonly shared by the kernel across
+multiple users. All cpusets, whether mem_exclusive or not, restrict
+allocations of memory for user space. This enables configuring a
+system so that several independent jobs can share common kernel
+data, such as file system pages, while isolating each jobs user
+allocation in its own cpuset. To do this, construct a large
+mem_exclusive cpuset to hold all the jobs, and construct child,
+non-mem_exclusive cpusets for each individual job. Only a small
+amount of typical kernel memory, such as requests from interrupt
+handlers, is allowed to be taken outside even a mem_exclusive cpuset.
+
User level code may create and destroy cpusets by name in the cpuset
virtual file system, manage the attributes and permissions of these
cpusets and which CPUs and Memory Nodes are assigned to each cpuset,
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
index a2d5b49..74dffc6 100644
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -223,6 +223,7 @@
TEA/XTEA algorithm contributors:
Aaron Grothe
+ Michael Ringe
Khazad algorithm contributors:
Aaron Grothe
diff --git a/Documentation/dcdbas.txt b/Documentation/dcdbas.txt
new file mode 100644
index 0000000..e1c52e2
--- /dev/null
+++ b/Documentation/dcdbas.txt
@@ -0,0 +1,91 @@
+Overview
+
+The Dell Systems Management Base Driver provides a sysfs interface for
+systems management software such as Dell OpenManage to perform system
+management interrupts and host control actions (system power cycle or
+power off after OS shutdown) on certain Dell systems.
+
+Dell OpenManage requires this driver on the following Dell PowerEdge systems:
+300, 1300, 1400, 400SC, 500SC, 1500SC, 1550, 600SC, 1600SC, 650, 1655MC,
+700, and 750. Other Dell software such as the open source libsmbios project
+is expected to make use of this driver, and it may include the use of this
+driver on other Dell systems.
+
+The Dell libsmbios project aims towards providing access to as much BIOS
+information as possible. See http://linux.dell.com/libsmbios/main/ for
+more information about the libsmbios project.
+
+
+System Management Interrupt
+
+On some Dell systems, systems management software must access certain
+management information via a system management interrupt (SMI). The SMI data
+buffer must reside in 32-bit address space, and the physical address of the
+buffer is required for the SMI. The driver maintains the memory required for
+the SMI and provides a way for the application to generate the SMI.
+The driver creates the following sysfs entries for systems management
+software to perform these system management interrupts:
+
+/sys/devices/platform/dcdbas/smi_data
+/sys/devices/platform/dcdbas/smi_data_buf_phys_addr
+/sys/devices/platform/dcdbas/smi_data_buf_size
+/sys/devices/platform/dcdbas/smi_request
+
+Systems management software must perform the following steps to execute
+a SMI using this driver:
+
+1) Lock smi_data.
+2) Write system management command to smi_data.
+3) Write "1" to smi_request to generate a calling interface SMI or
+ "2" to generate a raw SMI.
+4) Read system management command response from smi_data.
+5) Unlock smi_data.
+
+
+Host Control Action
+
+Dell OpenManage supports a host control feature that allows the administrator
+to perform a power cycle or power off of the system after the OS has finished
+shutting down. On some Dell systems, this host control feature requires that
+a driver perform a SMI after the OS has finished shutting down.
+
+The driver creates the following sysfs entries for systems management software
+to schedule the driver to perform a power cycle or power off host control
+action after the system has finished shutting down:
+
+/sys/devices/platform/dcdbas/host_control_action
+/sys/devices/platform/dcdbas/host_control_smi_type
+/sys/devices/platform/dcdbas/host_control_on_shutdown
+
+Dell OpenManage performs the following steps to execute a power cycle or
+power off host control action using this driver:
+
+1) Write host control action to be performed to host_control_action.
+2) Write type of SMI that driver needs to perform to host_control_smi_type.
+3) Write "1" to host_control_on_shutdown to enable host control action.
+4) Initiate OS shutdown.
+ (Driver will perform host control SMI when it is notified that the OS
+ has finished shutting down.)
+
+
+Host Control SMI Type
+
+The following table shows the value to write to host_control_smi_type to
+perform a power cycle or power off host control action:
+
+PowerEdge System Host Control SMI Type
+---------------- ---------------------
+ 300 HC_SMITYPE_TYPE1
+ 1300 HC_SMITYPE_TYPE1
+ 1400 HC_SMITYPE_TYPE2
+ 500SC HC_SMITYPE_TYPE2
+ 1500SC HC_SMITYPE_TYPE2
+ 1550 HC_SMITYPE_TYPE2
+ 600SC HC_SMITYPE_TYPE2
+ 1600SC HC_SMITYPE_TYPE2
+ 650 HC_SMITYPE_TYPE2
+ 1655MC HC_SMITYPE_TYPE2
+ 700 HC_SMITYPE_TYPE3
+ 750 HC_SMITYPE_TYPE3
+
+
diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt
new file mode 100644
index 0000000..bcfa5c3
--- /dev/null
+++ b/Documentation/dell_rbu.txt
@@ -0,0 +1,74 @@
+Purpose:
+Demonstrate the usage of the new open sourced rbu (Remote BIOS Update) driver
+for updating BIOS images on Dell servers and desktops.
+
+Scope:
+This document discusses the functionality of the rbu driver only.
+It does not cover the support needed from aplications to enable the BIOS to
+update itself with the image downloaded in to the memory.
+
+Overview:
+This driver works with Dell OpenManage or Dell Update Packages for updating
+the BIOS on Dell servers (starting from servers sold since 1999), desktops
+and notebooks (starting from those sold in 2005).
+Please go to http://support.dell.com register and you can find info on
+OpenManage and Dell Update packages (DUP).
+
+Dell_RBU driver supports BIOS update using the monilothic image and packetized
+image methods. In case of moniolithic the driver allocates a contiguous chunk
+of physical pages having the BIOS image. In case of packetized the app
+using the driver breaks the image in to packets of fixed sizes and the driver
+would place each packet in contiguous physical memory. The driver also
+maintains a link list of packets for reading them back.
+If the dell_rbu driver is unloaded all the allocated memory is freed.
+
+The rbu driver needs to have an application which will inform the BIOS to
+enable the update in the next system reboot.
+
+The user should not unload the rbu driver after downloading the BIOS image
+or updating.
+
+The driver load creates the following directories under the /sys file system.
+/sys/class/firmware/dell_rbu/loading
+/sys/class/firmware/dell_rbu/data
+/sys/devices/platform/dell_rbu/image_type
+/sys/devices/platform/dell_rbu/data
+
+The driver supports two types of update mechanism; monolithic and packetized.
+These update mechanism depends upon the BIOS currently running on the system.
+Most of the Dell systems support a monolithic update where the BIOS image is
+copied to a single contiguous block of physical memory.
+In case of packet mechanism the single memory can be broken in smaller chuks
+of contiguous memory and the BIOS image is scattered in these packets.
+
+By default the driver uses monolithic memory for the update type. This can be
+changed to contiguous during the driver load time by specifying the load
+parameter image_type=packet. This can also be changed later as below
+echo packet > /sys/devices/platform/dell_rbu/image_type
+
+Do the steps below to download the BIOS image.
+1) echo 1 > /sys/class/firmware/dell_rbu/loading
+2) cp bios_image.hdr /sys/class/firmware/dell_rbu/data
+3) echo 0 > /sys/class/firmware/dell_rbu/loading
+
+The /sys/class/firmware/dell_rbu/ entries will remain till the following is
+done.
+echo -1 > /sys/class/firmware/dell_rbu/loading
+
+Until this step is completed the drivr cannot be unloaded.
+
+Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to
+read back the image downloaded. This is useful in case of packet update
+mechanism where the above steps 1,2,3 will repeated for every packet.
+By reading the /sys/devices/platform/dell_rbu/data file all packet data
+downloaded can be verified in a single file.
+The packets are arranged in this file one after the other in a FIFO order.
+
+NOTE:
+This driver requires a patch for firmware_class.c which has the addition
+of request_firmware_nowait_nohotplug function to wortk
+Also after updating the BIOS image an user mdoe application neeeds to execute
+code which message the BIOS update request to the BIOS. So on the next reboot
+the BIOS knows about the new image downloaded and it updates it self.
+Also don't unload the rbu drive if the image has to be updated.
+
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index e6b8d05..4b8c326 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -16,7 +16,7 @@
"Device drivers" => "Multimedia devices"
=> "Video For Linux" => "BT848 Video For Linux"
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+ => "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
3) Loading Modules, described by two approaches
===============================================
diff --git a/Documentation/exception.txt b/Documentation/exception.txt
index f1d4369..3cb39ad 100644
--- a/Documentation/exception.txt
+++ b/Documentation/exception.txt
@@ -7,7 +7,7 @@
In older versions of Linux this was done with the
int verify_area(int type, const void * addr, unsigned long size)
-function.
+function (which has since been replaced by access_ok()).
This function verified that the memory area starting at address
addr and of size size was accessible for the operation specified
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 0665cb1..2e0a01b 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -51,14 +51,6 @@
---------------------------
-What: register_ioctl32_conversion() / unregister_ioctl32_conversion()
-When: April 2005
-Why: Replaced by ->compat_ioctl in file_operations and other method
- vecors.
-Who: Andi Kleen <ak@muc.de>, Christoph Hellwig <hch@lst.de>
-
----------------------------
-
What: RCU API moves to EXPORT_SYMBOL_GPL
When: April 2006
Files: include/linux/rcupdate.h, kernel/rcupdate.c
@@ -74,14 +66,6 @@
---------------------------
-What: remove verify_area()
-When: July 2006
-Files: Various uaccess.h headers.
-Why: Deprecated and redundant. access_ok() should be used instead.
-Who: Jesper Juhl <juhl-lkml@dif.dk>
-
----------------------------
-
What: IEEE1394 Audio and Music Data Transmission Protocol driver,
Connection Management Procedures driver
When: November 2005
@@ -102,16 +86,6 @@
---------------------------
-What: register_serial/unregister_serial
-When: September 2005
-Why: This interface does not allow serial ports to be registered against
- a struct device, and as such does not allow correct power management
- of such ports. 8250-based ports should use serial8250_register_port
- and serial8250_unregister_port, or platform devices instead.
-Who: Russell King <rmk@arm.linux.org.uk>
-
----------------------------
-
What: i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid
When: November 2005
Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 6c98f2b..5024ba7 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -133,6 +133,7 @@
statm Process memory status information
status Process status in human readable form
wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan
+ smaps Extension based on maps, presenting the rss size for each mapped file
..............................................................................
For example, to get the status information of a process, all you have to do is
diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt
new file mode 100644
index 0000000..d24e1b0
--- /dev/null
+++ b/Documentation/filesystems/relayfs.txt
@@ -0,0 +1,362 @@
+
+relayfs - a high-speed data relay filesystem
+============================================
+
+relayfs is a filesystem designed to provide an efficient mechanism for
+tools and facilities to relay large and potentially sustained streams
+of data from kernel space to user space.
+
+The main abstraction of relayfs is the 'channel'. A channel consists
+of a set of per-cpu kernel buffers each represented by a file in the
+relayfs filesystem. Kernel clients write into a channel using
+efficient write functions which automatically log to the current cpu's
+channel buffer. User space applications mmap() the per-cpu files and
+retrieve the data as it becomes available.
+
+The format of the data logged into the channel buffers is completely
+up to the relayfs client; relayfs does however provide hooks which
+allow clients to impose some stucture on the buffer data. Nor does
+relayfs implement any form of data filtering - this also is left to
+the client. The purpose is to keep relayfs as simple as possible.
+
+This document provides an overview of the relayfs API. The details of
+the function parameters are documented along with the functions in the
+filesystem code - please see that for details.
+
+Semantics
+=========
+
+Each relayfs channel has one buffer per CPU, each buffer has one or
+more sub-buffers. Messages are written to the first sub-buffer until
+it is too full to contain a new message, in which case it it is
+written to the next (if available). Messages are never split across
+sub-buffers. At this point, userspace can be notified so it empties
+the first sub-buffer, while the kernel continues writing to the next.
+
+When notified that a sub-buffer is full, the kernel knows how many
+bytes of it are padding i.e. unused. Userspace can use this knowledge
+to copy only valid data.
+
+After copying it, userspace can notify the kernel that a sub-buffer
+has been consumed.
+
+relayfs can operate in a mode where it will overwrite data not yet
+collected by userspace, and not wait for it to consume it.
+
+relayfs itself does not provide for communication of such data between
+userspace and kernel, allowing the kernel side to remain simple and not
+impose a single interface on userspace. It does provide a separate
+helper though, described below.
+
+klog, relay-app & librelay
+==========================
+
+relayfs itself is ready to use, but to make things easier, two
+additional systems are provided. klog is a simple wrapper to make
+writing formatted text or raw data to a channel simpler, regardless of
+whether a channel to write into exists or not, or whether relayfs is
+compiled into the kernel or is configured as a module. relay-app is
+the kernel counterpart of userspace librelay.c, combined these two
+files provide glue to easily stream data to disk, without having to
+bother with housekeeping. klog and relay-app can be used together,
+with klog providing high-level logging functions to the kernel and
+relay-app taking care of kernel-user control and disk-logging chores.
+
+It is possible to use relayfs without relay-app & librelay, but you'll
+have to implement communication between userspace and kernel, allowing
+both to convey the state of buffers (full, empty, amount of padding).
+
+klog, relay-app and librelay can be found in the relay-apps tarball on
+http://relayfs.sourceforge.net
+
+The relayfs user space API
+==========================
+
+relayfs implements basic file operations for user space access to
+relayfs channel buffer data. Here are the file operations that are
+available and some comments regarding their behavior:
+
+open() enables user to open an _existing_ buffer.
+
+mmap() results in channel buffer being mapped into the caller's
+ memory space. Note that you can't do a partial mmap - you must
+ map the entire file, which is NRBUF * SUBBUFSIZE.
+
+read() read the contents of a channel buffer. The bytes read are
+ 'consumed' by the reader i.e. they won't be available again
+ to subsequent reads. If the channel is being used in
+ no-overwrite mode (the default), it can be read at any time
+ even if there's an active kernel writer. If the channel is
+ being used in overwrite mode and there are active channel
+ writers, results may be unpredictable - users should make
+ sure that all logging to the channel has ended before using
+ read() with overwrite mode.
+
+poll() POLLIN/POLLRDNORM/POLLERR supported. User applications are
+ notified when sub-buffer boundaries are crossed.
+
+close() decrements the channel buffer's refcount. When the refcount
+ reaches 0 i.e. when no process or kernel client has the buffer
+ open, the channel buffer is freed.
+
+
+In order for a user application to make use of relayfs files, the
+relayfs filesystem must be mounted. For example,
+
+ mount -t relayfs relayfs /mnt/relay
+
+NOTE: relayfs doesn't need to be mounted for kernel clients to create
+ or use channels - it only needs to be mounted when user space
+ applications need access to the buffer data.
+
+
+The relayfs kernel API
+======================
+
+Here's a summary of the API relayfs provides to in-kernel clients:
+
+
+ channel management functions:
+
+ relay_open(base_filename, parent, subbuf_size, n_subbufs,
+ callbacks)
+ relay_close(chan)
+ relay_flush(chan)
+ relay_reset(chan)
+ relayfs_create_dir(name, parent)
+ relayfs_remove_dir(dentry)
+
+ channel management typically called on instigation of userspace:
+
+ relay_subbufs_consumed(chan, cpu, subbufs_consumed)
+
+ write functions:
+
+ relay_write(chan, data, length)
+ __relay_write(chan, data, length)
+ relay_reserve(chan, length)
+
+ callbacks:
+
+ subbuf_start(buf, subbuf, prev_subbuf, prev_padding)
+ buf_mapped(buf, filp)
+ buf_unmapped(buf, filp)
+
+ helper functions:
+
+ relay_buf_full(buf)
+ subbuf_start_reserve(buf, length)
+
+
+Creating a channel
+------------------
+
+relay_open() is used to create a channel, along with its per-cpu
+channel buffers. Each channel buffer will have an associated file
+created for it in the relayfs filesystem, which can be opened and
+mmapped from user space if desired. The files are named
+basename0...basenameN-1 where N is the number of online cpus, and by
+default will be created in the root of the filesystem. If you want a
+directory structure to contain your relayfs files, you can create it
+with relayfs_create_dir() and pass the parent directory to
+relay_open(). Clients are responsible for cleaning up any directory
+structure they create when the channel is closed - use
+relayfs_remove_dir() for that.
+
+The total size of each per-cpu buffer is calculated by multiplying the
+number of sub-buffers by the sub-buffer size passed into relay_open().
+The idea behind sub-buffers is that they're basically an extension of
+double-buffering to N buffers, and they also allow applications to
+easily implement random-access-on-buffer-boundary schemes, which can
+be important for some high-volume applications. The number and size
+of sub-buffers is completely dependent on the application and even for
+the same application, different conditions will warrant different
+values for these parameters at different times. Typically, the right
+values to use are best decided after some experimentation; in general,
+though, it's safe to assume that having only 1 sub-buffer is a bad
+idea - you're guaranteed to either overwrite data or lose events
+depending on the channel mode being used.
+
+Channel 'modes'
+---------------
+
+relayfs channels can be used in either of two modes - 'overwrite' or
+'no-overwrite'. The mode is entirely determined by the implementation
+of the subbuf_start() callback, as described below. In 'overwrite'
+mode, also known as 'flight recorder' mode, writes continuously cycle
+around the buffer and will never fail, but will unconditionally
+overwrite old data regardless of whether it's actually been consumed.
+In no-overwrite mode, writes will fail i.e. data will be lost, if the
+number of unconsumed sub-buffers equals the total number of
+sub-buffers in the channel. It should be clear that if there is no
+consumer or if the consumer can't consume sub-buffers fast enought,
+data will be lost in either case; the only difference is whether data
+is lost from the beginning or the end of a buffer.
+
+As explained above, a relayfs channel is made of up one or more
+per-cpu channel buffers, each implemented as a circular buffer
+subdivided into one or more sub-buffers. Messages are written into
+the current sub-buffer of the channel's current per-cpu buffer via the
+write functions described below. Whenever a message can't fit into
+the current sub-buffer, because there's no room left for it, the
+client is notified via the subbuf_start() callback that a switch to a
+new sub-buffer is about to occur. The client uses this callback to 1)
+initialize the next sub-buffer if appropriate 2) finalize the previous
+sub-buffer if appropriate and 3) return a boolean value indicating
+whether or not to actually go ahead with the sub-buffer switch.
+
+To implement 'no-overwrite' mode, the userspace client would provide
+an implementation of the subbuf_start() callback something like the
+following:
+
+static int subbuf_start(struct rchan_buf *buf,
+ void *subbuf,
+ void *prev_subbuf,
+ unsigned int prev_padding)
+{
+ if (prev_subbuf)
+ *((unsigned *)prev_subbuf) = prev_padding;
+
+ if (relay_buf_full(buf))
+ return 0;
+
+ subbuf_start_reserve(buf, sizeof(unsigned int));
+
+ return 1;
+}
+
+If the current buffer is full i.e. all sub-buffers remain unconsumed,
+the callback returns 0 to indicate that the buffer switch should not
+occur yet i.e. until the consumer has had a chance to read the current
+set of ready sub-buffers. For the relay_buf_full() function to make
+sense, the consumer is reponsible for notifying relayfs when
+sub-buffers have been consumed via relay_subbufs_consumed(). Any
+subsequent attempts to write into the buffer will again invoke the
+subbuf_start() callback with the same parameters; only when the
+consumer has consumed one or more of the ready sub-buffers will
+relay_buf_full() return 0, in which case the buffer switch can
+continue.
+
+The implementation of the subbuf_start() callback for 'overwrite' mode
+would be very similar:
+
+static int subbuf_start(struct rchan_buf *buf,
+ void *subbuf,
+ void *prev_subbuf,
+ unsigned int prev_padding)
+{
+ if (prev_subbuf)
+ *((unsigned *)prev_subbuf) = prev_padding;
+
+ subbuf_start_reserve(buf, sizeof(unsigned int));
+
+ return 1;
+}
+
+In this case, the relay_buf_full() check is meaningless and the
+callback always returns 1, causing the buffer switch to occur
+unconditionally. It's also meaningless for the client to use the
+relay_subbufs_consumed() function in this mode, as it's never
+consulted.
+
+The default subbuf_start() implementation, used if the client doesn't
+define any callbacks, or doesn't define the subbuf_start() callback,
+implements the simplest possible 'no-overwrite' mode i.e. it does
+nothing but return 0.
+
+Header information can be reserved at the beginning of each sub-buffer
+by calling the subbuf_start_reserve() helper function from within the
+subbuf_start() callback. This reserved area can be used to store
+whatever information the client wants. In the example above, room is
+reserved in each sub-buffer to store the padding count for that
+sub-buffer. This is filled in for the previous sub-buffer in the
+subbuf_start() implementation; the padding value for the previous
+sub-buffer is passed into the subbuf_start() callback along with a
+pointer to the previous sub-buffer, since the padding value isn't
+known until a sub-buffer is filled. The subbuf_start() callback is
+also called for the first sub-buffer when the channel is opened, to
+give the client a chance to reserve space in it. In this case the
+previous sub-buffer pointer passed into the callback will be NULL, so
+the client should check the value of the prev_subbuf pointer before
+writing into the previous sub-buffer.
+
+Writing to a channel
+--------------------
+
+kernel clients write data into the current cpu's channel buffer using
+relay_write() or __relay_write(). relay_write() is the main logging
+function - it uses local_irqsave() to protect the buffer and should be
+used if you might be logging from interrupt context. If you know
+you'll never be logging from interrupt context, you can use
+__relay_write(), which only disables preemption. These functions
+don't return a value, so you can't determine whether or not they
+failed - the assumption is that you wouldn't want to check a return
+value in the fast logging path anyway, and that they'll always succeed
+unless the buffer is full and no-overwrite mode is being used, in
+which case you can detect a failed write in the subbuf_start()
+callback by calling the relay_buf_full() helper function.
+
+relay_reserve() is used to reserve a slot in a channel buffer which
+can be written to later. This would typically be used in applications
+that need to write directly into a channel buffer without having to
+stage data in a temporary buffer beforehand. Because the actual write
+may not happen immediately after the slot is reserved, applications
+using relay_reserve() can keep a count of the number of bytes actually
+written, either in space reserved in the sub-buffers themselves or as
+a separate array. See the 'reserve' example in the relay-apps tarball
+at http://relayfs.sourceforge.net for an example of how this can be
+done. Because the write is under control of the client and is
+separated from the reserve, relay_reserve() doesn't protect the buffer
+at all - it's up to the client to provide the appropriate
+synchronization when using relay_reserve().
+
+Closing a channel
+-----------------
+
+The client calls relay_close() when it's finished using the channel.
+The channel and its associated buffers are destroyed when there are no
+longer any references to any of the channel buffers. relay_flush()
+forces a sub-buffer switch on all the channel buffers, and can be used
+to finalize and process the last sub-buffers before the channel is
+closed.
+
+Misc
+----
+
+Some applications may want to keep a channel around and re-use it
+rather than open and close a new channel for each use. relay_reset()
+can be used for this purpose - it resets a channel to its initial
+state without reallocating channel buffer memory or destroying
+existing mappings. It should however only be called when it's safe to
+do so i.e. when the channel isn't currently being written to.
+
+Finally, there are a couple of utility callbacks that can be used for
+different purposes. buf_mapped() is called whenever a channel buffer
+is mmapped from user space and buf_unmapped() is called when it's
+unmapped. The client can use this notification to trigger actions
+within the kernel application, such as enabling/disabling logging to
+the channel.
+
+
+Resources
+=========
+
+For news, example code, mailing list, etc. see the relayfs homepage:
+
+ http://relayfs.sourceforge.net
+
+
+Credits
+=======
+
+The ideas and specs for relayfs came about as a result of discussions
+on tracing involving the following:
+
+Michel Dagenais <michel.dagenais@polymtl.ca>
+Richard Moore <richardj_moore@uk.ibm.com>
+Bob Wisniewski <bob@watson.ibm.com>
+Karim Yaghmour <karim@opersys.com>
+Tom Zanussi <zanussi@us.ibm.com>
+
+Also thanks to Hubertus Franke for a lot of useful suggestions and bug
+reports.
diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt
index dc27659..c8bce82 100644
--- a/Documentation/filesystems/sysfs.txt
+++ b/Documentation/filesystems/sysfs.txt
@@ -90,7 +90,7 @@
It also defines this helper for defining device attributes:
-#define DEVICE_ATTR(_name,_mode,_show,_store) \
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = { \
.attr = {.name = __stringify(_name) , .mode = _mode }, \
.show = _show, \
@@ -99,14 +99,14 @@
For example, declaring
-static DEVICE_ATTR(foo,0644,show_foo,store_foo);
+static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
is equivalent to doing:
static struct device_attribute dev_attr_foo = {
.attr = {
.name = "foo",
- .mode = 0644,
+ .mode = S_IWUSR | S_IRUGO,
},
.show = show_foo,
.store = store_foo,
@@ -121,8 +121,8 @@
show and store methods of the attribute owners.
struct sysfs_ops {
- ssize_t (*show)(struct kobject *, struct attribute *,char *);
- ssize_t (*store)(struct kobject *,struct attribute *,const char *);
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *, const char *);
};
[ Subsystems should have already defined a struct kobj_type as a
@@ -137,7 +137,7 @@
To illustrate:
-#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
+#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
#define to_dev(d) container_of(d, struct device, kobj)
static ssize_t
@@ -148,7 +148,7 @@
ssize_t ret = 0;
if (dev_attr->show)
- ret = dev_attr->show(dev,buf);
+ ret = dev_attr->show(dev, buf);
return ret;
}
@@ -216,16 +216,16 @@
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf,"%s\n",dev->name);
+ return snprintf(buf, PAGE_SIZE, "%s\n", dev->name);
}
static ssize_t store_name(struct device * dev, const char * buf)
{
- sscanf(buf,"%20s",dev->name);
- return strlen(buf);
+ sscanf(buf, "%20s", dev->name);
+ return strnlen(buf, PAGE_SIZE);
}
-static DEVICE_ATTR(name,S_IRUGO,show_name,store_name);
+static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
(Note that the real implementation doesn't allow userspace to set the
@@ -290,7 +290,7 @@
Declaring:
-DEVICE_ATTR(_name,_str,_mode,_show,_store);
+DEVICE_ATTR(_name, _str, _mode, _show, _store);
Creation/Removal:
@@ -310,7 +310,7 @@
Declaring:
-BUS_ATTR(_name,_mode,_show,_store)
+BUS_ATTR(_name, _mode, _show, _store)
Creation/Removal:
@@ -331,7 +331,7 @@
Declaring:
-DRIVER_ATTR(_name,_mode,_show,_store)
+DRIVER_ATTR(_name, _mode, _show, _store)
Creation/Removal:
diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78
index 357086e..fd5dc7a 100644
--- a/Documentation/hwmon/lm78
+++ b/Documentation/hwmon/lm78
@@ -2,16 +2,11 @@
==================
Supported chips:
- * National Semiconductor LM78
+ * National Semiconductor LM78 / LM78-J
Prefix: 'lm78'
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
- * National Semiconductor LM78-J
- Prefix: 'lm78-j'
- Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
- Datasheet: Publicly available at the National Semiconductor website
- http://www.national.com/
* National Semiconductor LM79
Prefix: 'lm79'
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
diff --git a/Documentation/hwmon/w83792d b/Documentation/hwmon/w83792d
new file mode 100644
index 0000000..8171c28
--- /dev/null
+++ b/Documentation/hwmon/w83792d
@@ -0,0 +1,174 @@
+Kernel driver w83792d
+=====================
+
+Supported chips:
+ * Winbond W83792D
+ Prefix: 'w83792d'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/PDFresult.asp?Pname=1035
+
+Author: Chunhao Huang
+Contact: DZShen <DZShen@Winbond.com.tw>
+
+
+Module Parameters
+-----------------
+
+* init int
+ (default 1)
+ Use 'init=0' to bypass initializing the chip.
+ Try this if your computer crashes when you load the module.
+
+* force_subclients=bus,caddr,saddr,saddr
+ This is used to force the i2c addresses for subclients of
+ a certain chip. Example usage is `force_subclients=0,0x2f,0x4a,0x4b'
+ to force the subclients of chip 0x2f on bus 0 to i2c addresses
+ 0x4a and 0x4b.
+
+
+Description
+-----------
+
+This driver implements support for the Winbond W83792AD/D.
+
+Detection of the chip can sometimes be foiled because it can be in an
+internal state that allows no clean access (Bank with ID register is not
+currently selected). If you know the address of the chip, use a 'force'
+parameter; this will put it into a more well-behaved state first.
+
+The driver implements three temperature sensors, seven fan rotation speed
+sensors, nine voltage sensors, and two automatic fan regulation
+strategies called: Smart Fan I (Thermal Cruise mode) and Smart Fan II.
+Automatic fan control mode is possible only for fan1-fan3. Fan4-fan7 can run
+synchronized with selected fan (fan1-fan3). This functionality and manual PWM
+control for fan4-fan7 is not yet implemented.
+
+Temperatures are measured in degrees Celsius and measurement resolution is 1
+degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
+the temperature gets higher than the Overtemperature Shutdown value; it stays
+on until the temperature falls below the Hysteresis value.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or
+128) to give the readings more range or accuracy.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+Alarms are provided as output from "realtime status register". Following bits
+are defined:
+
+bit - alarm on:
+0 - in0
+1 - in1
+2 - temp1
+3 - temp2
+4 - temp3
+5 - fan1
+6 - fan2
+7 - fan3
+8 - in2
+9 - in3
+10 - in4
+11 - in5
+12 - in6
+13 - VID change
+14 - chassis
+15 - fan7
+16 - tart1
+17 - tart2
+18 - tart3
+19 - in7
+20 - in8
+21 - fan4
+22 - fan5
+23 - fan6
+
+Tart will be asserted while target temperature cannot be achieved after 3 minutes
+of full speed rotation of corresponding fan.
+
+In addition to the alarms described above, there is a CHAS alarm on the chips
+which triggers if your computer case is open (This one is latched, contrary
+to realtime alarms).
+
+The chips only update values each 3 seconds; reading them more often will
+do no harm, but will return 'old' values.
+
+
+W83792D PROBLEMS
+----------------
+Known problems:
+ - This driver is only for Winbond W83792D C version device, there
+ are also some motherboards with B version W83792D device. The
+ calculation method to in6-in7(measured value, limits) is a little
+ different between C and B version. C or B version can be identified
+ by CR[0x49h].
+ - The function of vid and vrm has not been finished, because I'm NOT
+ very familiar with them. Adding support is welcome.
+ - The function of chassis open detection needs more tests.
+ - If you have ASUS server board and chip was not found: Then you will
+ need to upgrade to latest (or beta) BIOS. If it does not help please
+ contact us.
+
+Fan control
+-----------
+
+Manual mode
+-----------
+
+Works as expected. You just need to specify desired PWM/DC value (fan speed)
+in appropriate pwm# file.
+
+Thermal cruise
+--------------
+
+In this mode, W83792D provides the Smart Fan system to automatically control
+fan speed to keep the temperatures of CPU and the system within specific
+range. At first a wanted temperature and interval must be set. This is done
+via thermal_cruise# file. The tolerance# file serves to create T +- tolerance
+interval. The fan speed will be lowered as long as the current temperature
+remains below the thermal_cruise# +- tolerance# value. Once the temperature
+exceeds the high limit (T+tolerance), the fan will be turned on with a
+specific speed set by pwm# and automatically controlled its PWM duty cycle
+with the temperature varying. Three conditions may occur:
+
+(1) If the temperature still exceeds the high limit, PWM duty
+cycle will increase slowly.
+
+(2) If the temperature goes below the high limit, but still above the low
+limit (T-tolerance), the fan speed will be fixed at the current speed because
+the temperature is in the target range.
+
+(3) If the temperature goes below the low limit, PWM duty cycle will decrease
+slowly to 0 or a preset stop value until the temperature exceeds the low
+limit. (The preset stop value handling is not yet implemented in driver)
+
+Smart Fan II
+------------
+
+W83792D also provides a special mode for fan. Four temperature points are
+available. When related temperature sensors detects the temperature in preset
+temperature region (sf2_point@_fan# +- tolerance#) it will cause fans to run
+on programmed value from sf2_level@_fan#. You need to set four temperatures
+for each fan.
+
+
+/sys files
+----------
+
+pwm[1-3] - this file stores PWM duty cycle or DC value (fan speed) in range:
+ 0 (stop) to 255 (full)
+pwm[1-3]_enable - this file controls mode of fan/temperature control:
+ * 0 Disabled
+ * 1 Manual mode
+ * 2 Smart Fan II
+ * 3 Thermal Cruise
+pwm[1-3]_mode - Select PWM of DC mode
+ * 0 DC
+ * 1 PWM
+thermal_cruise[1-3] - Selects the desired temperature for cruise (degC)
+tolerance[1-3] - Value in degrees of Celsius (degC) for +- T
+sf2_point[1-4]_fan[1-3] - four temperature points for each fan for Smart Fan II
+sf2_level[1-3]_fan[1-3] - three PWM/DC levels for each fan for Smart Fan II
diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875
index b020028..96fec56 100644
--- a/Documentation/i2c/chips/max6875
+++ b/Documentation/i2c/chips/max6875
@@ -4,22 +4,13 @@
Supported chips:
* Maxim MAX6874, MAX6875
Prefix: 'max6875'
- Addresses scanned: 0x50, 0x52
+ Addresses scanned: None (see below)
Datasheet:
http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
Author: Ben Gardner <bgardner@wabtec.com>
-Module Parameters
------------------
-
-* allow_write int
- Set to non-zero to enable write permission:
- *0: Read only
- 1: Read and write
-
-
Description
-----------
@@ -33,34 +24,85 @@
The Maxim MAX6874 is a similar, mostly compatible device, with more intputs
and outputs:
-
vin gpi vout
MAX6874 6 4 8
MAX6875 4 3 5
-MAX6874 chips can have four different addresses (as opposed to only two for
-the MAX6875). The additional addresses (0x54 and 0x56) are not probed by
-this driver by default, but the probe module parameter can be used if
-needed.
-
-See the datasheet for details on how to program the EEPROM.
+See the datasheet for more information.
Sysfs entries
-------------
-eeprom_user - 512 bytes of user-defined EEPROM space. Only writable if
- allow_write was set and register 0x43 is 0.
-
-eeprom_config - 70 bytes of config EEPROM. Note that changes will not get
- loaded into register space until a power cycle or device reset.
-
-reg_config - 70 bytes of register space. Any changes take affect immediately.
+eeprom - 512 bytes of user-defined EEPROM space.
General Remarks
---------------
-A typical application will require that the EEPROMs be programmed once and
-never altered afterwards.
+Valid addresses for the MAX6875 are 0x50 and 0x52.
+Valid addresses for the MAX6874 are 0x50, 0x52, 0x54 and 0x56.
+The driver does not probe any address, so you must force the address.
+
+Example:
+$ modprobe max6875 force=0,0x50
+
+The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
+addresses. For example, for address 0x50, it also reserves 0x51.
+The even-address instance is called 'max6875', the odd one is 'max6875 subclient'.
+
+
+Programming the chip using i2c-dev
+----------------------------------
+
+Use the i2c-dev interface to access and program the chips.
+Reads and writes are performed differently depending on the address range.
+
+The configuration registers are at addresses 0x00 - 0x45.
+Use i2c_smbus_write_byte_data() to write a register and
+i2c_smbus_read_byte_data() to read a register.
+The command is the register number.
+
+Examples:
+To write a 1 to register 0x45:
+ i2c_smbus_write_byte_data(fd, 0x45, 1);
+
+To read register 0x45:
+ value = i2c_smbus_read_byte_data(fd, 0x45);
+
+
+The configuration EEPROM is at addresses 0x8000 - 0x8045.
+The user EEPROM is at addresses 0x8100 - 0x82ff.
+
+Use i2c_smbus_write_word_data() to write a byte to EEPROM.
+
+The command is the upper byte of the address: 0x80, 0x81, or 0x82.
+The data word is the lower part of the address or'd with data << 8.
+ cmd = address >> 8;
+ val = (address & 0xff) | (data << 8);
+
+Example:
+To write 0x5a to address 0x8003:
+ i2c_smbus_write_word_data(fd, 0x80, 0x5a03);
+
+
+Reading data from the EEPROM is a little more complicated.
+Use i2c_smbus_write_byte_data() to set the read address and then
+i2c_smbus_read_byte() or i2c_smbus_read_i2c_block_data() to read the data.
+
+Example:
+To read data starting at offset 0x8100, first set the address:
+ i2c_smbus_write_byte_data(fd, 0x81, 0x00);
+
+And then read the data
+ value = i2c_smbus_read_byte(fd);
+
+ or
+
+ count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer);
+
+The block read should read 16 bytes.
+0x84 is the block read command.
+
+See the datasheet for more details.
diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality
index 8a78a95..41ffefb 100644
--- a/Documentation/i2c/functionality
+++ b/Documentation/i2c/functionality
@@ -115,7 +115,7 @@
If you try to access an adapter from a userspace program, you will have
to use the /dev interface. You will still have to check whether the
functionality you need is supported, of course. This is done using
-the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2c_detect
+the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2cdetect
program, is below:
int file;
diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients
index a7adbdd..4849dfd 100644
--- a/Documentation/i2c/porting-clients
+++ b/Documentation/i2c/porting-clients
@@ -1,4 +1,4 @@
-Revision 4, 2004-03-30
+Revision 5, 2005-07-29
Jean Delvare <khali@linux-fr.org>
Greg KH <greg@kroah.com>
@@ -17,20 +17,22 @@
Technical changes:
-* [Includes] Get rid of "version.h". Replace <linux/i2c-proc.h> with
- <linux/i2c-sensor.h>. Includes typically look like that:
+* [Includes] Get rid of "version.h" and <linux/i2c-proc.h>.
+ Includes typically look like that:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
- #include <linux/i2c-sensor.h>
- #include <linux/i2c-vid.h> /* if you need VRM support */
+ #include <linux/hwmon.h> /* for hardware monitoring drivers */
+ #include <linux/hwmon-sysfs.h>
+ #include <linux/hwmon-vid.h> /* if you need VRM support */
#include <asm/io.h> /* if you have I/O operations */
Please respect this inclusion order. Some extra headers may be
required for a given driver (e.g. "lm75.h").
-* [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, SENSORS_ISA_END
- becomes I2C_CLIENT_ISA_END.
+* [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, ISA addresses
+ are no more handled by the i2c core.
+ SENSORS_INSMOD_<n> becomes I2C_CLIENT_INSMOD_<n>.
* [Client data] Get rid of sysctl_id. Try using standard names for
register values (for example, temp_os becomes temp_max). You're
@@ -66,13 +68,15 @@
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
ISA-only drivers of course don't need this.
+ Call i2c_probe() instead of i2c_detect().
* [Detect] As mentioned earlier, the flags parameter is gone.
The type_name and client_name strings are replaced by a single
name string, which will be filled with a lowercase, short string
(typically the driver name, e.g. "lm75").
In i2c-only drivers, drop the i2c_is_isa_adapter check, it's
- useless.
+ useless. Same for isa-only drivers, as the test would always be
+ true. Only hybrid drivers (which are quite rare) still need it.
The errorN labels are reduced to the number needed. If that number
is 2 (i2c-only drivers), it is advised that the labels are named
exit and exit_free. For i2c+isa drivers, labels should be named
@@ -86,6 +90,8 @@
device_create_file. Move the driver initialization before any
sysfs file creation.
Drop client->id.
+ Drop any 24RF08 corruption prevention you find, as this is now done
+ at the i2c-core level, and doing it twice voids it.
* [Init] Limits must not be set by the driver (can be done later in
user-space). Chip should not be reset default (although a module
@@ -93,7 +99,8 @@
limited to the strictly necessary steps.
* [Detach] Get rid of data, remove the call to
- i2c_deregister_entry.
+ i2c_deregister_entry. Do not log an error message if
+ i2c_detach_client fails, as i2c-core will now do it for you.
* [Update] Don't access client->data directly, use
i2c_get_clientdata(client) instead.
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 91664be..0772757 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -148,15 +148,15 @@
detection algorithm.
You do not have to use this parameter interface; but don't try to use
-function i2c_probe() (or i2c_detect()) if you don't.
+function i2c_probe() if you don't.
NOTE: If you want to write a `sensors' driver, the interface is slightly
different! See below.
-Probing classes (i2c)
----------------------
+Probing classes
+---------------
All parameters are given as lists of unsigned 16-bit integers. Lists are
terminated by I2C_CLIENT_END.
@@ -171,12 +171,18 @@
ignore: insmod parameter.
A list of pairs. The first value is a bus number (-1 for any I2C bus),
the second is the I2C address. These addresses are never probed.
- This parameter overrules 'normal' and 'probe', but not the 'force' lists.
+ This parameter overrules the 'normal_i2c' list only.
force: insmod parameter.
A list of pairs. The first value is a bus number (-1 for any I2C bus),
the second is the I2C address. A device is blindly assumed to be on
the given address, no probing is done.
+Additionally, kind-specific force lists may optionally be defined if
+the driver supports several chip kinds. They are grouped in a
+NULL-terminated list of pointers named forces, those first element if the
+generic force list mentioned above. Each additional list correspond to an
+insmod parameter of the form force_<kind>.
+
Fortunately, as a module writer, you just have to define the `normal_i2c'
parameter. The complete declaration could look like this:
@@ -186,66 +192,17 @@
/* Magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
+ /* Or, if your driver supports, say, 2 kind of devices: */
+ I2C_CLIENT_INSMOD_2(foo, bar);
+
+If you use the multi-kind form, an enum will be defined for you:
+ enum chips { any_chip, foo, bar, ... }
+You can then (and certainly should) use it in the driver code.
Note that you *have* to call the defined variable `normal_i2c',
without any prefix!
-Probing classes (sensors)
--------------------------
-
-If you write a `sensors' driver, you use a slightly different interface.
-As well as I2C addresses, we have to cope with ISA addresses. Also, we
-use a enum of chip types. Don't forget to include `sensors.h'.
-
-The following lists are used internally. They are all lists of integers.
-
- normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
- A list of I2C addresses which should normally be examined.
- normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
- A list of ISA addresses which should normally be examined.
- probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
- A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the address. These
- addresses are also probed, as if they were in the 'normal' list.
- ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
- A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the I2C address. These
- addresses are never probed. This parameter overrules 'normal' and
- 'probe', but not the 'force' lists.
-
-Also used is a list of pointers to sensors_force_data structures:
- force_data: insmod parameters. A list, ending with an element of which
- the force field is NULL.
- Each element contains the type of chip and a list of pairs.
- The first value is a bus number (SENSORS_ISA_BUS for the ISA bus,
- -1 for any I2C bus), the second is the address.
- These are automatically translated to insmod variables of the form
- force_foo.
-
-So we have a generic insmod variabled `force', and chip-specific variables
-`force_CHIPNAME'.
-
-Fortunately, as a module writer, you just have to define the `normal_i2c'
-and `normal_isa' parameters, and define what chip names are used.
-The complete declaration could look like this:
- /* Scan i2c addresses 0x37, and 0x48 to 0x4f */
- static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
- 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
- /* Scan ISA address 0x290 */
- static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END};
-
- /* Define chips foo and bar, as well as all module parameters and things */
- SENSORS_INSMOD_2(foo,bar);
-
-If you have one chip, you use macro SENSORS_INSMOD_1(chip), if you have 2
-you use macro SENSORS_INSMOD_2(chip1,chip2), etc. If you do not want to
-bother with chip types, you can use SENSORS_INSMOD_0.
-
-A enum is automatically defined as follows:
- enum chips { any_chip, chip1, chip2, ... }
-
-
Attaching to an adapter
-----------------------
@@ -264,17 +221,10 @@
return i2c_probe(adapter,&addr_data,&foo_detect_client);
}
-For `sensors' drivers, use the i2c_detect function instead:
-
- int foo_attach_adapter(struct i2c_adapter *adapter)
- {
- return i2c_detect(adapter,&addr_data,&foo_detect_client);
- }
-
Remember, structure `addr_data' is defined by the macros explained above,
so you do not have to define it yourself.
-The i2c_probe or i2c_detect function will call the foo_detect_client
+The i2c_probe function will call the foo_detect_client
function only for those i2c addresses that actually have a device on
them (unless a `force' parameter was used). In addition, addresses that
are already in use (by some other registered client) are skipped.
@@ -283,19 +233,18 @@
The detect client function
--------------------------
-The detect client function is called by i2c_probe or i2c_detect.
-The `kind' parameter contains 0 if this call is due to a `force'
-parameter, and -1 otherwise (for i2c_detect, it contains 0 if
-this call is due to the generic `force' parameter, and the chip type
-number if it is due to a specific `force' parameter).
+The detect client function is called by i2c_probe. The `kind' parameter
+contains -1 for a probed detection, 0 for a forced detection, or a positive
+number for a forced detection with a chip type forced.
Below, some things are only needed if this is a `sensors' driver. Those
parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
markers.
-This function should only return an error (any value != 0) if there is
-some reason why no more detection should be done anymore. If the
-detection just fails for this address, return 0.
+Returning an error different from -ENODEV in a detect function will cause
+the detection to stop: other addresses and adapters won't be scanned.
+This should only be done on fatal or internal errors, such as a memory
+shortage or i2c_attach_client failing.
For now, you can ignore the `flags' parameter. It is there for future use.
@@ -320,11 +269,10 @@
const char *type_name = "";
int is_isa = i2c_is_isa_adapter(adapter);
- if (is_isa) {
+ /* Do this only if the chip can additionally be found on the ISA bus
+ (hybrid chip). */
- /* If this client can't be on the ISA bus at all, we can stop now
- (call `goto ERROR0'). But for kicks, we will assume it is all
- right. */
+ if (is_isa) {
/* Discard immediately if this ISA range is already used */
if (check_region(address,FOO_EXTENT))
@@ -495,15 +443,13 @@
/* SENSORS ONLY END */
/* Try to detach the client from i2c space */
- if ((err = i2c_detach_client(client))) {
- printk("foo.o: Client deregistration failed, client not detached.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
- /* SENSORS ONLY START */
+ /* HYBRID SENSORS CHIP ONLY START */
if i2c_is_isa_client(client)
release_region(client->addr,LM78_EXTENT);
- /* SENSORS ONLY END */
+ /* HYBRID SENSORS CHIP ONLY END */
kfree(client); /* Frees client data too, if allocated at the same time */
return 0;
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 1c48f0e..10312be 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -2,7 +2,7 @@
----------------------------
H. Peter Anvin <hpa@zytor.com>
- Last update 2002-01-01
+ Last update 2005-09-02
On the i386 platform, the Linux kernel uses a rather complicated boot
convention. This has evolved partially due to historical aspects, as
@@ -34,6 +34,8 @@
Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible
initrd address available to the bootloader.
+Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes.
+
**** MEMORY LAYOUT
@@ -103,10 +105,9 @@
Offset Proto Name Meaning
/Size
-01F1/1 ALL setup_sects The size of the setup in sectors
+01F1/1 ALL(1 setup_sects The size of the setup in sectors
01F2/2 ALL root_flags If set, the root is mounted readonly
-01F4/2 ALL syssize DO NOT USE - for bootsect.S use only
-01F6/2 ALL swap_dev DO NOT USE - obsolete
+01F4/4 2.04+(2 syssize The size of the 32-bit code in 16-byte paras
01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only
01FA/2 ALL vid_mode Video mode control
01FC/2 ALL root_dev Default root device number
@@ -129,8 +130,12 @@
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
022C/4 2.03+ initrd_addr_max Highest legal initrd address
-For backwards compatibility, if the setup_sects field contains 0, the
-real value is 4.
+(1) For backwards compatibility, if the setup_sects field contains 0, the
+ real value is 4.
+
+(2) For boot protocol prior to 2.04, the upper two bytes of the syssize
+ field are unusable, which means the size of a bzImage kernel
+ cannot be determined.
If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
the boot protocol version is "old". Loading an old kernel, the
@@ -230,12 +235,16 @@
relevant to the boot loader itself, see "special command line options"
below.
-The kernel command line is a null-terminated string up to 255
-characters long, plus the final null.
+The kernel command line is a null-terminated string currently up to
+255 characters long, plus the final null. A string that is too long
+will be automatically truncated by the kernel, a boot loader may allow
+a longer command line to be passed to permit future kernels to extend
+this limit.
If the boot protocol version is 2.02 or later, the address of the
kernel command line is given by the header field cmd_line_ptr (see
-above.)
+above.) This address can be anywhere between the end of the setup
+heap and 0xA0000.
If the protocol version is *not* 2.02 or higher, the kernel
command line is entered using the following protocol:
@@ -255,7 +264,7 @@
**** SAMPLE BOOT CONFIGURATION
As a sample configuration, assume the following layout of the real
-mode segment:
+mode segment (this is a typical, and recommended layout):
0x0000-0x7FFF Real mode kernel
0x8000-0x8FFF Stack and heap
@@ -312,9 +321,9 @@
**** LOADING THE REST OF THE KERNEL
-The non-real-mode kernel starts at offset (setup_sects+1)*512 in the
-kernel file (again, if setup_sects == 0 the real value is 4.) It
-should be loaded at address 0x10000 for Image/zImage kernels and
+The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
+in the kernel file (again, if setup_sects == 0 the real value is 4.)
+It should be loaded at address 0x10000 for Image/zImage kernels and
0x100000 for bzImage kernels.
The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 2616a58..9a15865 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -872,7 +872,13 @@
Assignments to $(targets) are without $(obj)/ prefix.
if_changed may be used in conjunction with custom commands as
defined in 6.7 "Custom kbuild commands".
+
Note: It is a typical mistake to forget the FORCE prerequisite.
+ Another common pitfall is that whitespace is sometimes
+ significant; for instance, the below will fail (note the extra space
+ after the comma):
+ target: source(s) FORCE
+ #WRONG!# $(call if_changed, ld/objcopy/gzip)
ld
Link target. Often LDFLAGS_$@ is used to set specific options to ld.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 3d5cd7a..d2f0c67 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1174,6 +1174,11 @@
New name for the ramdisk parameter.
See Documentation/ramdisk.txt.
+ rdinit= [KNL]
+ Format: <full_path>
+ Run specified binary instead of /init from the ramdisk,
+ used for early userspace startup. See initrd.
+
reboot= [BUGS=IA-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
Format: <reboot_mode>[,<reboot_mode2>[,...]]
See arch/*/kernel/reboot.c.
diff --git a/Documentation/networking/README.ipw2100 b/Documentation/networking/README.ipw2100
new file mode 100644
index 0000000..2046948
--- /dev/null
+++ b/Documentation/networking/README.ipw2100
@@ -0,0 +1,246 @@
+
+===========================
+Intel(R) PRO/Wireless 2100 Network Connection Driver for Linux
+README.ipw2100
+
+March 14, 2005
+
+===========================
+Index
+---------------------------
+0. Introduction
+1. Release 1.1.0 Current Features
+2. Command Line Parameters
+3. Sysfs Helper Files
+4. Radio Kill Switch
+5. Dynamic Firmware
+6. Power Management
+7. Support
+8. License
+
+
+===========================
+0. Introduction
+------------ ----- ----- ---- --- -- -
+
+This document provides a brief overview of the features supported by the
+IPW2100 driver project. The main project website, where the latest
+development version of the driver can be found, is:
+
+ http://ipw2100.sourceforge.net
+
+There you can find the not only the latest releases, but also information about
+potential fixes and patches, as well as links to the development mailing list
+for the driver project.
+
+
+===========================
+1. Release 1.1.0 Current Supported Features
+---------------------------
+- Managed (BSS) and Ad-Hoc (IBSS)
+- WEP (shared key and open)
+- Wireless Tools support
+- 802.1x (tested with XSupplicant 1.0.1)
+
+Enabled (but not supported) features:
+- Monitor/RFMon mode
+- WPA/WPA2
+
+The distinction between officially supported and enabled is a reflection
+on the amount of validation and interoperability testing that has been
+performed on a given feature.
+
+
+===========================
+2. Command Line Parameters
+---------------------------
+
+If the driver is built as a module, the following optional parameters are used
+by entering them on the command line with the modprobe command using this
+syntax:
+
+ modprobe ipw2100 [<option>=<VAL1><,VAL2>...]
+
+For example, to disable the radio on driver loading, enter:
+
+ modprobe ipw2100 disable=1
+
+The ipw2100 driver supports the following module parameters:
+
+Name Value Example:
+debug 0x0-0xffffffff debug=1024
+mode 0,1,2 mode=1 /* AdHoc */
+channel int channel=3 /* Only valid in AdHoc or Monitor */
+associate boolean associate=0 /* Do NOT auto associate */
+disable boolean disable=1 /* Do not power the HW */
+
+
+===========================
+3. Sysfs Helper Files
+---------------------------
+
+There are several ways to control the behavior of the driver. Many of the
+general capabilities are exposed through the Wireless Tools (iwconfig). There
+are a few capabilities that are exposed through entries in the Linux Sysfs.
+
+
+----- Driver Level ------
+For the driver level files, look in /sys/bus/pci/drivers/ipw2100/
+
+ debug_level
+
+ This controls the same global as the 'debug' module parameter. For
+ information on the various debugging levels available, run the 'dvals'
+ script found in the driver source directory.
+
+ NOTE: 'debug_level' is only enabled if CONFIG_IPW2100_DEBUG is turn
+ on.
+
+----- Device Level ------
+For the device level files look in
+
+ /sys/bus/pci/drivers/ipw2100/{PCI-ID}/
+
+For example:
+ /sys/bus/pci/drivers/ipw2100/0000:02:01.0
+
+For the device level files, see /sys/bus/pci/drivers/ipw2100:
+
+ rf_kill
+ read -
+ 0 = RF kill not enabled (radio on)
+ 1 = SW based RF kill active (radio off)
+ 2 = HW based RF kill active (radio off)
+ 3 = Both HW and SW RF kill active (radio off)
+ write -
+ 0 = If SW based RF kill active, turn the radio back on
+ 1 = If radio is on, activate SW based RF kill
+
+ NOTE: If you enable the SW based RF kill and then toggle the HW
+ based RF kill from ON -> OFF -> ON, the radio will NOT come back on
+
+
+===========================
+4. Radio Kill Switch
+---------------------------
+Most laptops provide the ability for the user to physically disable the radio.
+Some vendors have implemented this as a physical switch that requires no
+software to turn the radio off and on. On other laptops, however, the switch
+is controlled through a button being pressed and a software driver then making
+calls to turn the radio off and on. This is referred to as a "software based
+RF kill switch"
+
+See the Sysfs helper file 'rf_kill' for determining the state of the RF switch
+on your system.
+
+
+===========================
+5. Dynamic Firmware
+---------------------------
+As the firmware is licensed under a restricted use license, it can not be
+included within the kernel sources. To enable the IPW2100 you will need a
+firmware image to load into the wireless NIC's processors.
+
+You can obtain these images from <http://ipw2100.sf.net/firmware.php>.
+
+See INSTALL for instructions on installing the firmware.
+
+
+===========================
+6. Power Management
+---------------------------
+The IPW2100 supports the configuration of the Power Save Protocol
+through a private wireless extension interface. The IPW2100 supports
+the following different modes:
+
+ off No power management. Radio is always on.
+ on Automatic power management
+ 1-5 Different levels of power management. The higher the
+ number the greater the power savings, but with an impact to
+ packet latencies.
+
+Power management works by powering down the radio after a certain
+interval of time has passed where no packets are passed through the
+radio. Once powered down, the radio remains in that state for a given
+period of time. For higher power savings, the interval between last
+packet processed to sleep is shorter and the sleep period is longer.
+
+When the radio is asleep, the access point sending data to the station
+must buffer packets at the AP until the station wakes up and requests
+any buffered packets. If you have an AP that does not correctly support
+the PSP protocol you may experience packet loss or very poor performance
+while power management is enabled. If this is the case, you will need
+to try and find a firmware update for your AP, or disable power
+management (via `iwconfig eth1 power off`)
+
+To configure the power level on the IPW2100 you use a combination of
+iwconfig and iwpriv. iwconfig is used to turn power management on, off,
+and set it to auto.
+
+ iwconfig eth1 power off Disables radio power down
+ iwconfig eth1 power on Enables radio power management to
+ last set level (defaults to AUTO)
+ iwpriv eth1 set_power 0 Sets power level to AUTO and enables
+ power management if not previously
+ enabled.
+ iwpriv eth1 set_power 1-5 Set the power level as specified,
+ enabling power management if not
+ previously enabled.
+
+You can view the current power level setting via:
+
+ iwpriv eth1 get_power
+
+It will return the current period or timeout that is configured as a string
+in the form of xxxx/yyyy (z) where xxxx is the timeout interval (amount of
+time after packet processing), yyyy is the period to sleep (amount of time to
+wait before powering the radio and querying the access point for buffered
+packets), and z is the 'power level'. If power management is turned off the
+xxxx/yyyy will be replaced with 'off' -- the level reported will be the active
+level if `iwconfig eth1 power on` is invoked.
+
+
+===========================
+7. Support
+---------------------------
+
+For general development information and support,
+go to:
+
+ http://ipw2100.sf.net/
+
+The ipw2100 1.1.0 driver and firmware can be downloaded from:
+
+ http://support.intel.com
+
+For installation support on the ipw2100 1.1.0 driver on Linux kernels
+2.6.8 or greater, email support is available from:
+
+ http://supportmail.intel.com
+
+===========================
+8. License
+---------------------------
+
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License (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.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ License Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
new file mode 100644
index 0000000..6916080
--- /dev/null
+++ b/Documentation/networking/README.ipw2200
@@ -0,0 +1,300 @@
+
+Intel(R) PRO/Wireless 2915ABG Driver for Linux in support of:
+
+Intel(R) PRO/Wireless 2200BG Network Connection
+Intel(R) PRO/Wireless 2915ABG Network Connection
+
+Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R)
+PRO/Wireless 2200BG Driver for Linux is a unified driver that works on
+both hardware adapters listed above. In this document the Intel(R)
+PRO/Wireless 2915ABG Driver for Linux will be used to reference the
+unified driver.
+
+Copyright (C) 2004-2005, Intel Corporation
+
+README.ipw2200
+
+Version: 1.0.0
+Date : January 31, 2005
+
+
+Index
+-----------------------------------------------
+1. Introduction
+1.1. Overview of features
+1.2. Module parameters
+1.3. Wireless Extension Private Methods
+1.4. Sysfs Helper Files
+2. About the Version Numbers
+3. Support
+4. License
+
+
+1. Introduction
+-----------------------------------------------
+The following sections attempt to provide a brief introduction to using
+the Intel(R) PRO/Wireless 2915ABG Driver for Linux.
+
+This document is not meant to be a comprehensive manual on
+understanding or using wireless technologies, but should be sufficient
+to get you moving without wires on Linux.
+
+For information on building and installing the driver, see the INSTALL
+file.
+
+
+1.1. Overview of Features
+-----------------------------------------------
+The current release (1.0.0) supports the following features:
+
++ BSS mode (Infrastructure, Managed)
++ IBSS mode (Ad-Hoc)
++ WEP (OPEN and SHARED KEY mode)
++ 802.1x EAP via wpa_supplicant and xsupplicant
++ Wireless Extension support
++ Full B and G rate support (2200 and 2915)
++ Full A rate support (2915 only)
++ Transmit power control
++ S state support (ACPI suspend/resume)
++ long/short preamble support
+
+
+
+1.2. Command Line Parameters
+-----------------------------------------------
+
+Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless
+2915ABG Driver for Linux allows certain configuration options to be
+provided as module parameters. The most common way to specify a module
+parameter is via the command line.
+
+The general form is:
+
+% modprobe ipw2200 parameter=value
+
+Where the supported parameter are:
+
+ associate
+ Set to 0 to disable the auto scan-and-associate functionality of the
+ driver. If disabled, the driver will not attempt to scan
+ for and associate to a network until it has been configured with
+ one or more properties for the target network, for example configuring
+ the network SSID. Default is 1 (auto-associate)
+
+ Example: % modprobe ipw2200 associate=0
+
+ auto_create
+ Set to 0 to disable the auto creation of an Ad-Hoc network
+ matching the channel and network name parameters provided.
+ Default is 1.
+
+ channel
+ channel number for association. The normal method for setting
+ the channel would be to use the standard wireless tools
+ (i.e. `iwconfig eth1 channel 10`), but it is useful sometimes
+ to set this while debugging. Channel 0 means 'ANY'
+
+ debug
+ If using a debug build, this is used to control the amount of debug
+ info is logged. See the 'dval' and 'load' script for more info on
+ how to use this (the dval and load scripts are provided as part
+ of the ipw2200 development snapshot releases available from the
+ SourceForge project at http://ipw2200.sf.net)
+
+ mode
+ Can be used to set the default mode of the adapter.
+ 0 = Managed, 1 = Ad-Hoc
+
+
+1.3. Wireless Extension Private Methods
+-----------------------------------------------
+
+As an interface designed to handle generic hardware, there are certain
+capabilities not exposed through the normal Wireless Tool interface. As
+such, a provision is provided for a driver to declare custom, or
+private, methods. The Intel(R) PRO/Wireless 2915ABG Driver for Linux
+defines several of these to configure various settings.
+
+The general form of using the private wireless methods is:
+
+ % iwpriv $IFNAME method parameters
+
+Where $IFNAME is the interface name the device is registered with
+(typically eth1, customized via one of the various network interface
+name managers, such as ifrename)
+
+The supported private methods are:
+
+ get_mode
+ Can be used to report out which IEEE mode the driver is
+ configured to support. Example:
+
+ % iwpriv eth1 get_mode
+ eth1 get_mode:802.11bg (6)
+
+ set_mode
+ Can be used to configure which IEEE mode the driver will
+ support.
+
+ Usage:
+ % iwpriv eth1 set_mode {mode}
+ Where {mode} is a number in the range 1-7:
+ 1 802.11a (2915 only)
+ 2 802.11b
+ 3 802.11ab (2915 only)
+ 4 802.11g
+ 5 802.11ag (2915 only)
+ 6 802.11bg
+ 7 802.11abg (2915 only)
+
+ get_preamble
+ Can be used to report configuration of preamble length.
+
+ set_preamble
+ Can be used to set the configuration of preamble length:
+
+ Usage:
+ % iwpriv eth1 set_preamble {mode}
+ Where {mode} is one of:
+ 1 Long preamble only
+ 0 Auto (long or short based on connection)
+
+
+1.4. Sysfs Helper Files:
+-----------------------------------------------
+
+The Linux kernel provides a pseudo file system that can be used to
+access various components of the operating system. The Intel(R)
+PRO/Wireless 2915ABG Driver for Linux exposes several configuration
+parameters through this mechanism.
+
+An entry in the sysfs can support reading and/or writing. You can
+typically query the contents of a sysfs entry through the use of cat,
+and can set the contents via echo. For example:
+
+% cat /sys/bus/pci/drivers/ipw2200/debug_level
+
+Will report the current debug level of the driver's logging subsystem
+(only available if CONFIG_IPW_DEBUG was configured when the driver was
+built).
+
+You can set the debug level via:
+
+% echo $VALUE > /sys/bus/pci/drivers/ipw2200/debug_level
+
+Where $VALUE would be a number in the case of this sysfs entry. The
+input to sysfs files does not have to be a number. For example, the
+firmware loader used by hotplug utilizes sysfs entries for transferring
+the firmware image from user space into the driver.
+
+The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries
+at two levels -- driver level, which apply to all instances of the
+driver (in the event that there are more than one device installed) and
+device level, which applies only to the single specific instance.
+
+
+1.4.1 Driver Level Sysfs Helper Files
+-----------------------------------------------
+
+For the driver level files, look in /sys/bus/pci/drivers/ipw2200/
+
+ debug_level
+
+ This controls the same global as the 'debug' module parameter
+
+
+1.4.2 Device Level Sysfs Helper Files
+-----------------------------------------------
+
+For the device level files, look in
+
+ /sys/bus/pci/drivers/ipw2200/{PCI-ID}/
+
+For example:
+ /sys/bus/pci/drivers/ipw2200/0000:02:01.0
+
+For the device level files, see /sys/bus/pci/[drivers/ipw2200:
+
+ rf_kill
+ read -
+ 0 = RF kill not enabled (radio on)
+ 1 = SW based RF kill active (radio off)
+ 2 = HW based RF kill active (radio off)
+ 3 = Both HW and SW RF kill active (radio off)
+ write -
+ 0 = If SW based RF kill active, turn the radio back on
+ 1 = If radio is on, activate SW based RF kill
+
+ NOTE: If you enable the SW based RF kill and then toggle the HW
+ based RF kill from ON -> OFF -> ON, the radio will NOT come back on
+
+ ucode
+ read-only access to the ucode version number
+
+
+2. About the Version Numbers
+-----------------------------------------------
+
+Due to the nature of open source development projects, there are
+frequently changes being incorporated that have not gone through
+a complete validation process. These changes are incorporated into
+development snapshot releases.
+
+Releases are numbered with a three level scheme:
+
+ major.minor.development
+
+Any version where the 'development' portion is 0 (for example
+1.0.0, 1.1.0, etc.) indicates a stable version that will be made
+available for kernel inclusion.
+
+Any version where the 'development' portion is not a 0 (for
+example 1.0.1, 1.1.5, etc.) indicates a development version that is
+being made available for testing and cutting edge users. The stability
+and functionality of the development releases are not know. We make
+efforts to try and keep all snapshots reasonably stable, but due to the
+frequency of their release, and the desire to get those releases
+available as quickly as possible, unknown anomalies should be expected.
+
+The major version number will be incremented when significant changes
+are made to the driver. Currently, there are no major changes planned.
+
+
+3. Support
+-----------------------------------------------
+
+For installation support of the 1.0.0 version, you can contact
+http://supportmail.intel.com, or you can use the open source project
+support.
+
+For general information and support, go to:
+
+ http://ipw2200.sf.net/
+
+
+4. License
+-----------------------------------------------
+
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License 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.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+
diff --git a/Documentation/power/swsusp-dmcrypt.txt b/Documentation/power/swsusp-dmcrypt.txt
new file mode 100644
index 0000000..59931b4
--- /dev/null
+++ b/Documentation/power/swsusp-dmcrypt.txt
@@ -0,0 +1,138 @@
+Author: Andreas Steinmetz <ast@domdv.de>
+
+
+How to use dm-crypt and swsusp together:
+========================================
+
+Some prerequisites:
+You know how dm-crypt works. If not, visit the following web page:
+http://www.saout.de/misc/dm-crypt/
+You have read Documentation/power/swsusp.txt and understand it.
+You did read Documentation/initrd.txt and know how an initrd works.
+You know how to create or how to modify an initrd.
+
+Now your system is properly set up, your disk is encrypted except for
+the swap device(s) and the boot partition which may contain a mini
+system for crypto setup and/or rescue purposes. You may even have
+an initrd that does your current crypto setup already.
+
+At this point you want to encrypt your swap, too. Still you want to
+be able to suspend using swsusp. This, however, means that you
+have to be able to either enter a passphrase or that you read
+the key(s) from an external device like a pcmcia flash disk
+or an usb stick prior to resume. So you need an initrd, that sets
+up dm-crypt and then asks swsusp to resume from the encrypted
+swap device.
+
+The most important thing is that you set up dm-crypt in such
+a way that the swap device you suspend to/resume from has
+always the same major/minor within the initrd as well as
+within your running system. The easiest way to achieve this is
+to always set up this swap device first with dmsetup, so that
+it will always look like the following:
+
+brw------- 1 root root 254, 0 Jul 28 13:37 /dev/mapper/swap0
+
+Now set up your kernel to use /dev/mapper/swap0 as the default
+resume partition, so your kernel .config contains:
+
+CONFIG_PM_STD_PARTITION="/dev/mapper/swap0"
+
+Prepare your boot loader to use the initrd you will create or
+modify. For lilo the simplest setup looks like the following
+lines:
+
+image=/boot/vmlinuz
+initrd=/boot/initrd.gz
+label=linux
+append="root=/dev/ram0 init=/linuxrc rw"
+
+Finally you need to create or modify your initrd. Lets assume
+you create an initrd that reads the required dm-crypt setup
+from a pcmcia flash disk card. The card is formatted with an ext2
+fs which resides on /dev/hde1 when the card is inserted. The
+card contains at least the encrypted swap setup in a file
+named "swapkey". /etc/fstab of your initrd contains something
+like the following:
+
+/dev/hda1 /mnt ext3 ro 0 0
+none /proc proc defaults,noatime,nodiratime 0 0
+none /sys sysfs defaults,noatime,nodiratime 0 0
+
+/dev/hda1 contains an unencrypted mini system that sets up all
+of your crypto devices, again by reading the setup from the
+pcmcia flash disk. What follows now is a /linuxrc for your
+initrd that allows you to resume from encrypted swap and that
+continues boot with your mini system on /dev/hda1 if resume
+does not happen:
+
+#!/bin/sh
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+mount /proc
+mount /sys
+mapped=0
+noresume=`grep -c noresume /proc/cmdline`
+if [ "$*" != "" ]
+then
+ noresume=1
+fi
+dmesg -n 1
+/sbin/cardmgr -q
+for i in 1 2 3 4 5 6 7 8 9 0
+do
+ if [ -f /proc/ide/hde/media ]
+ then
+ usleep 500000
+ mount -t ext2 -o ro /dev/hde1 /mnt
+ if [ -f /mnt/swapkey ]
+ then
+ dmsetup create swap0 /mnt/swapkey > /dev/null 2>&1 && mapped=1
+ fi
+ umount /mnt
+ break
+ fi
+ usleep 500000
+done
+killproc /sbin/cardmgr
+dmesg -n 6
+if [ $mapped = 1 ]
+then
+ if [ $noresume != 0 ]
+ then
+ mkswap /dev/mapper/swap0 > /dev/null 2>&1
+ fi
+ echo 254:0 > /sys/power/resume
+ dmsetup remove swap0
+fi
+umount /sys
+mount /mnt
+umount /proc
+cd /mnt
+pivot_root . mnt
+mount /proc
+umount -l /mnt
+umount /proc
+exec chroot . /sbin/init $* < dev/console > dev/console 2>&1
+
+Please don't mind the weird loop above, busybox's msh doesn't know
+the let statement. Now, what is happening in the script?
+First we have to decide if we want to try to resume, or not.
+We will not resume if booting with "noresume" or any parameters
+for init like "single" or "emergency" as boot parameters.
+
+Then we need to set up dmcrypt with the setup data from the
+pcmcia flash disk. If this succeeds we need to reset the swap
+device if we don't want to resume. The line "echo 254:0 > /sys/power/resume"
+then attempts to resume from the first device mapper device.
+Note that it is important to set the device in /sys/power/resume,
+regardless if resuming or not, otherwise later suspend will fail.
+If resume starts, script execution terminates here.
+
+Otherwise we just remove the encrypted swap device and leave it to the
+mini system on /dev/hda1 to set the whole crypto up (it is up to
+you to modify this to your taste).
+
+What then follows is the well known process to change the root
+file system and continue booting from there. I prefer to unmount
+the initrd prior to continue booting but it is up to you to modify
+this.
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 7a6b789..b0d5084 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -1,22 +1,20 @@
-From kernel/suspend.c:
+Some warnings, first.
* BIG FAT WARNING *********************************************************
*
- * If you have unsupported (*) devices using DMA...
- * ...say goodbye to your data.
- *
* If you touch anything on disk between suspend and resume...
* ...kiss your data goodbye.
*
- * If your disk driver does not support suspend... (IDE does)
- * ...you'd better find out how to get along
- * without your data.
+ * If you do resume from initrd after your filesystems are mounted...
+ * ...bye bye root partition.
+ * [this is actually same case as above]
*
- * If you change kernel command line between suspend and resume...
- * ...prepare for nasty fsck or worse.
- *
- * If you change your hardware while system is suspended...
- * ...well, it was not good idea.
+ * If you have unsupported (*) devices using DMA, you may have some
+ * problems. If your disk driver does not support suspend... (IDE does),
+ * it may cause some problems, too. If you change kernel command line
+ * between suspend and resume, it may do something wrong. If you change
+ * your hardware while system is suspended... well, it was not good idea;
+ * but it will probably only crash.
*
* (*) suspend/resume support is needed to make it safe.
@@ -30,6 +28,13 @@
echo platform > /sys/power/disk; echo disk > /sys/power/state
+Encrypted suspend image:
+------------------------
+If you want to store your suspend image encrypted with a temporary
+key to prevent data gathering after resume you must compile
+crypto and the aes algorithm into the kernel - modules won't work
+as they cannot be loaded at resume time.
+
Article about goals and implementation of Software Suspend for Linux
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -85,11 +90,6 @@
You have your server on UPS. Power died, and UPS is indicating 30
seconds to failure. What do you do? Suspend to disk.
-Ethernet card in your server died. You want to replace it. Your
-server is not hotplug capable. What do you do? Suspend to disk,
-replace ethernet card, resume. If you are fast your users will not
-even see broken connections.
-
Q: Maybe I'm missing something, but why don't the regular I/O paths work?
@@ -117,31 +117,6 @@
A: Yes. That's what echo platform > /sys/power/disk does.
-Q: My machine doesn't work with ACPI. How can I use swsusp than ?
-
-A: Do a reboot() syscall with right parameters. Warning: glibc gets in
-its way, so check with strace:
-
-reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 0xd000fce2)
-
-(Thanks to Peter Osterlund:)
-
-#include <unistd.h>
-#include <syscall.h>
-
-#define LINUX_REBOOT_MAGIC1 0xfee1dead
-#define LINUX_REBOOT_MAGIC2 672274793
-#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2
-
-int main()
-{
- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_SW_SUSPEND, 0);
- return 0;
-}
-
-Also /sys/ interface should be still present.
-
Q: What is 'suspend2'?
A: suspend2 is 'Software Suspend 2', a forked implementation of
@@ -311,3 +286,46 @@
system is shut down or suspended. Additionally use the encrypted
suspend image to prevent sensitive data from being stolen after
resume.
+
+Q: Why can't we suspend to a swap file?
+
+A: Because accessing swap file needs the filesystem mounted, and
+filesystem might do something wrong (like replaying the journal)
+during mount.
+
+There are few ways to get that fixed:
+
+1) Probably could be solved by modifying every filesystem to support
+some kind of "really read-only!" option. Patches welcome.
+
+2) suspend2 gets around that by storing absolute positions in on-disk
+image (and blocksize), with resume parameter pointing directly to
+suspend header.
+
+Q: Is there a maximum system RAM size that is supported by swsusp?
+
+A: It should work okay with highmem.
+
+Q: Does swsusp (to disk) use only one swap partition or can it use
+multiple swap partitions (aggregate them into one logical space)?
+
+A: Only one swap partition, sorry.
+
+Q: If my application(s) causes lots of memory & swap space to be used
+(over half of the total system RAM), is it correct that it is likely
+to be useless to try to suspend to disk while that app is running?
+
+A: No, it should work okay, as long as your app does not mlock()
+it. Just prepare big enough swap partition.
+
+Q: What information is usefull for debugging suspend-to-disk problems?
+
+A: Well, last messages on the screen are always useful. If something
+is broken, it is usually some kernel driver, therefore trying with as
+little as possible modules loaded helps a lot. I also prefer people to
+suspend from console, preferably without X running. Booting with
+init=/bin/bash, then swapon and starting suspend sequence manually
+usually does the trick. Then it is good idea to try with latest
+vanilla kernel.
+
+
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index 7a4a503..526d6dd 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -46,6 +46,12 @@
POSTing bios works. Ole Rohne has patch to do just that at
http://dev.gentoo.org/~marineam/patch-radeonfb-2.6.11-rc2-mm2.
+(8) on some systems, you can use the video_post utility mentioned here:
+ http://bugzilla.kernel.org/show_bug.cgi?id=3670. Do echo 3 > /sys/power/state
+ && /usr/sbin/video_post - which will initialize the display in console mode.
+ If you are in X, you can switch to a virtual terminal and back to X using
+ CTRL+ALT+F1 - CTRL+ALT+F7 to get the display working in graphical mode again.
+
Now, if you pass acpi_sleep=something, and it does not work with your
bios, you'll get a hard crash during resume. Be careful. Also it is
safest to do your experiments with plain old VGA console. The vesafb
@@ -64,7 +70,8 @@
------------------------------------------------------------------------------
Acer Aspire 1406LC ole's late BIOS init (7), turn off DRI
Acer TM 242FX vbetool (6)
-Acer TM C300 vga=normal (only suspend on console, not in X), vbetool (6)
+Acer TM C110 video_post (8)
+Acer TM C300 vga=normal (only suspend on console, not in X), vbetool (6) or video_post (8)
Acer TM 4052LCi s3_bios (2)
Acer TM 636Lci s3_bios vga=normal (2)
Acer TM 650 (Radeon M7) vga=normal plus boot-radeon (5) gets text console back
@@ -113,6 +120,7 @@
IBM TP X20 ??? (*)
IBM TP X30 s3_bios (2)
IBM TP X31 / Type 2672-XXH none (1), use radeontool (http://fdd.com/software/radeon/) to turn off backlight.
+IBM TP X32 none (1), but backlight is on and video is trashed after long suspend
IBM Thinkpad X40 Type 2371-7JG s3_bios,s3_mode (4)
Medion MD4220 ??? (*)
Samsung P35 vbetool needed (6)
diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
index 160e735..47e74dd 100644
--- a/Documentation/scsi/aic7xxx.txt
+++ b/Documentation/scsi/aic7xxx.txt
@@ -1,5 +1,5 @@
====================================================================
-= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.28 =
+= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v7.0 =
= README for =
= The Linux Operating System =
====================================================================
@@ -131,6 +131,10 @@
SCSI "stub" effects.
2. Version History
+ 7.0 (4th August, 2005)
+ - Updated driver to use SCSI transport class infrastructure
+ - Upported sequencer and core fixes from last adaptec released
+ version of the driver.
6.2.36 (June 3rd, 2003)
- Correct code that disables PCI parity error checking.
- Correct and simplify handling of the ignore wide residue
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index 7536823..44df89c 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -373,13 +373,11 @@
scsi_activate_tcq - turn on tag command queueing
scsi_add_device - creates new scsi device (lu) instance
scsi_add_host - perform sysfs registration and SCSI bus scan.
- scsi_add_timer - (re-)start timer on a SCSI command.
scsi_adjust_queue_depth - change the queue depth on a SCSI device
scsi_assign_lock - replace default host_lock with given lock
scsi_bios_ptable - return copy of block device's partition table
scsi_block_requests - prevent further commands being queued to given host
scsi_deactivate_tcq - turn off tag command queueing
- scsi_delete_timer - cancel timer on a SCSI command.
scsi_host_alloc - return a new scsi_host instance whose refcount==1
scsi_host_get - increments Scsi_Host instance's refcount
scsi_host_put - decrements Scsi_Host instance's refcount (free if 0)
@@ -458,27 +456,6 @@
/**
- * scsi_add_timer - (re-)start timer on a SCSI command.
- * @scmd: pointer to scsi command instance
- * @timeout: duration of timeout in "jiffies"
- * @complete: pointer to function to call if timeout expires
- *
- * Returns nothing
- *
- * Might block: no
- *
- * Notes: Each scsi command has its own timer, and as it is added
- * to the queue, we set up the timer. When the command completes,
- * we cancel the timer. An LLD can use this function to change
- * the existing timeout value.
- *
- * Defined in: drivers/scsi/scsi_error.c
- **/
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
- void (*complete)(struct scsi_cmnd *))
-
-
-/**
* scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device
* @sdev: pointer to SCSI device to change queue depth on
* @tagged: 0 - no tagged queuing
@@ -566,24 +543,6 @@
/**
- * scsi_delete_timer - cancel timer on a SCSI command.
- * @scmd: pointer to scsi command instance
- *
- * Returns 1 if able to cancel timer else 0 (i.e. too late or already
- * cancelled).
- *
- * Might block: no [may in the future if it invokes del_timer_sync()]
- *
- * Notes: All commands issued by upper levels already have a timeout
- * associated with them. An LLD can use this function to cancel the
- * timer.
- *
- * Defined in: drivers/scsi/scsi_error.c
- **/
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-
-
-/**
* scsi_host_alloc - create a scsi host adapter instance and perform basic
* initialization.
* @sht: pointer to scsi host template
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index ac7eabb..87856d3 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -111,24 +111,17 @@
Interrupts: locally disabled.
This call must not sleep
- stop_tx(port,tty_stop)
+ stop_tx(port)
Stop transmitting characters. This might be due to the CTS
line becoming inactive or the tty layer indicating we want
- to stop transmission.
-
- tty_stop: 1 if this call is due to the TTY layer issuing a
- TTY stop to the driver (equiv to rs_stop).
+ to stop transmission due to an XOFF character.
Locking: port->lock taken.
Interrupts: locally disabled.
This call must not sleep
- start_tx(port,tty_start)
- start transmitting characters. (incidentally, nonempty will
- always be nonzero, and shouldn't be used - it will be dropped).
-
- tty_start: 1 if this call was due to the TTY layer issuing
- a TTY start to the driver (equiv to rs_start)
+ start_tx(port)
+ start transmitting characters.
Locking: port->lock taken.
Interrupts: locally disabled.
diff --git a/Documentation/sonypi.txt b/Documentation/sonypi.txt
index 0f3b240..c1237a92 100644
--- a/Documentation/sonypi.txt
+++ b/Documentation/sonypi.txt
@@ -99,6 +99,7 @@
SONYPI_MEYE_MASK 0x0400
SONYPI_MEMORYSTICK_MASK 0x0800
SONYPI_BATTERY_MASK 0x1000
+ SONYPI_WIRELESS_MASK 0x2000
useinput: if set (which is the default) two input devices are
created, one which interprets the jogdial events as
@@ -137,6 +138,15 @@
speed handling etc). Use ACPI instead of APM if it works on your
laptop.
+ - sonypi lacks the ability to distinguish between certain key
+ events on some models.
+
+ - some models with the nvidia card (geforce go 6200 tc) uses a
+ different way to adjust the backlighting of the screen. There
+ is a userspace utility to adjust the brightness on those models,
+ which can be downloaded from
+ http://www.acc.umu.se/~erikw/program/smartdimmer-0.1.tar.bz2
+
- since all development was done by reverse engineering, there is
_absolutely no guarantee_ that this driver will not crash your
laptop. Permanently.
diff --git a/Documentation/vm/locking b/Documentation/vm/locking
index c3ef09a..f366fa9 100644
--- a/Documentation/vm/locking
+++ b/Documentation/vm/locking
@@ -83,19 +83,18 @@
vmtruncate) does not lose sending ipi's to cloned threads that might
be spawned underneath it and go to user mode to drag in pte's into tlbs.
-swap_list_lock/swap_device_lock
--------------------------------
+swap_lock
+--------------
The swap devices are chained in priority order from the "swap_list" header.
The "swap_list" is used for the round-robin swaphandle allocation strategy.
The #free swaphandles is maintained in "nr_swap_pages". These two together
-are protected by the swap_list_lock.
+are protected by the swap_lock.
-The swap_device_lock, which is per swap device, protects the reference
-counts on the corresponding swaphandles, maintained in the "swap_map"
-array, and the "highest_bit" and "lowest_bit" fields.
+The swap_lock also protects all the device reference counts on the
+corresponding swaphandles, maintained in the "swap_map" array, and the
+"highest_bit" and "lowest_bit" fields.
-Both of these are spinlocks, and are never acquired from intr level. The
-locking hierarchy is swap_list_lock -> swap_device_lock.
+The swap_lock is a spinlock, and is never acquired from intr level.
To prevent races between swap space deletion or async readahead swapins
deciding whether a swap handle is being used, ie worthy of being read in
diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt
index 28388aa..c5beb54 100644
--- a/Documentation/watchdog/watchdog-api.txt
+++ b/Documentation/watchdog/watchdog-api.txt
@@ -228,6 +228,26 @@
The GETSTATUS call returns if the device is open or not.
[FIXME -- silliness again?]
+booke_wdt.c -- PowerPC BookE Watchdog Timer
+
+ Timeout default varies according to frequency, supports
+ SETTIMEOUT
+
+ Watchdog can not be turned off, CONFIG_WATCHDOG_NOWAYOUT
+ does not make sense
+
+ GETSUPPORT returns the watchdog_info struct, and
+ GETSTATUS returns the supported options. GETBOOTSTATUS
+ returns a 1 if the last reset was caused by the
+ watchdog and a 0 otherwise. This watchdog can not be
+ disabled once it has been started. The wdt_period kernel
+ parameter selects which bit of the time base changing
+ from 0->1 will trigger the watchdog exception. Changing
+ the timeout from the ioctl calls will change the
+ wdt_period as defined above. Finally if you would like to
+ replace the default Watchdog Handler you can implement the
+ WatchdogHandler() function in your own code.
+
eurotechwdt.c -- Eurotech CPU-1220/1410
The timeout can be set using the SETTIMEOUT ioctl and defaults
diff --git a/MAINTAINERS b/MAINTAINERS
index e8214fe..8e4e8292 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -202,13 +202,6 @@
M: colin@colino.net
S: Maintained
-ADVANSYS SCSI DRIVER
-P: Bob Frey
-M: linux@advansys.com
-W: http://www.advansys.com/linux.html
-L: linux-scsi@vger.kernel.org
-S: Maintained
-
AEDSP16 DRIVER
P: Riccardo Facchetti
M: fizban@tin.it
@@ -696,6 +689,11 @@
W: http://www.debian.org/~dz/i8k/
S: Maintained
+DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
+P: Doug Warzecha
+M: Douglas_Warzecha@dell.com
+S: Maintained
+
DEVICE-MAPPER
P: Alasdair Kergon
L: dm-devel@redhat.com
@@ -824,6 +822,13 @@
W: http://sourceforge.net/projects/emu10k1/
S: Maintained
+EMULEX LPFC FC SCSI DRIVER
+P: James Smart
+M: james.smart@emulex.com
+L: linux-scsi@vger.kernel.org
+W: http://sourceforge.net/projects/lpfcxxxx
+S: Supported
+
EPSON 1355 FRAMEBUFFER DRIVER
P: Christopher Hoover
M: ch@murgatroid.com, ch@hpl.hp.com
@@ -879,7 +884,7 @@
FILESYSTEMS (VFS and infrastructure)
P: Alexander Viro
-M: viro@parcelfarce.linux.theplanet.co.uk
+M: viro@zeniv.linux.org.uk
S: Maintained
FIRMWARE LOADER (request_firmware)
@@ -933,6 +938,13 @@
W: http://www.kernel.org/pub/linux/utils/net/hdlc/
S: Maintained
+HARDWARE MONITORING
+P: Jean Delvare
+M: khali@linux-fr.org
+L: lm-sensors@lm-sensors.org
+W: http://www.lm-sensors.nu/
+S: Maintained
+
HARMONY SOUND DRIVER
P: Kyle McMartin
M: kyle@parisc-linux.org
@@ -991,6 +1003,13 @@
L: iss_storagedev@hp.com
S: Supported
+HOST AP DRIVER
+P: Jouni Malinen
+M: jkmaline@cc.hut.fi
+L: hostap@shmoo.com
+W: http://hostap.epitest.fi/
+S: Maintained
+
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
P: Jaroslav Kysela
M: perex@suse.cz
@@ -1007,7 +1026,7 @@
M: wli@holomorphy.com
S: Maintained
-I2C AND SENSORS DRIVERS
+I2C SUBSYSTEM
P: Greg Kroah-Hartman
M: greg@kroah.com
P: Jean Delvare
@@ -1953,7 +1972,6 @@
ROCKETPORT DRIVER
P: Comtrol Corp.
-M: support@comtrol.com
W: http://www.comtrol.com
S: Maintained
@@ -2643,11 +2661,6 @@
UCLINUX (AND M68KNOMMU)
P: Greg Ungerer
M: gerg@uclinux.org
-M: gerg@snapgear.com
-P: David McCullough
-M: davidm@snapgear.com
-P: D. Jeff Dionne (created first uClinux port)
-M: jeff@uclinux.org
W: http://www.uclinux.org/
L: uclinux-dev@uclinux.org (subscribers-only)
S: Maintained
diff --git a/Makefile b/Makefile
index 3d84df5..63e5c9f 100644
--- a/Makefile
+++ b/Makefile
@@ -109,10 +109,9 @@
.PHONY: $(MAKECMDGOALS)
$(filter-out _all,$(MAKECMDGOALS)) _all:
- $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
- KBUILD_SRC=$(CURDIR) KBUILD_VERBOSE=$(KBUILD_VERBOSE) \
- KBUILD_CHECK=$(KBUILD_CHECK) KBUILD_EXTMOD="$(KBUILD_EXTMOD)" \
- -f $(CURDIR)/Makefile $@
+ $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
+ KBUILD_SRC=$(CURDIR) \
+ KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
# Leave processing to above invocation of make
skip-makefile := 1
@@ -233,7 +232,7 @@
KBUILD_MODULES := 1
endif
-export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE
+export KBUILD_MODULES KBUILD_BUILTIN
export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
# Beautify output
@@ -309,6 +308,9 @@
# Look for make include files relative to root of kernel src
MAKEFLAGS += --include-dir=$(srctree)
+# We need some generic definitions
+include $(srctree)/scripts/Kbuild.include
+
# For maximum performance (+ possibly random breakage, uncomment
# the following)
@@ -348,7 +350,7 @@
CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
-CFLAGS := -Wall -Wstrict-prototypes -Wno-trigraphs \
+CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common \
-ffreestanding
AFLAGS := -D__ASSEMBLY__
@@ -367,15 +369,10 @@
# even be read-only.
export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
-# The temporary file to save gcc -MD generated dependencies must not
-# contain a comma
-comma := ,
-depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
-
# Files to ignore in find ... statements
-RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc \) -prune -o
-RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg \) -prune -o
+RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg
# ===========================================================================
# Rules shared between *config targets and build targets
@@ -551,6 +548,26 @@
# images. Default is /boot, but you can set it to other values
export INSTALL_PATH ?= /boot
+# If CONFIG_LOCALVERSION_AUTO is set, we automatically perform some tests
+# and try to determine if the current source tree is a release tree, of any sort,
+# or if is a pure development tree.
+#
+# A 'release tree' is any tree with a git TAG associated
+# with it. The primary goal of this is to make it safe for a native
+# git/CVS/SVN user to build a release tree (i.e, 2.6.9) and also to
+# continue developing against the current Linus tree, without having the Linus
+# tree overwrite the 2.6.9 tree when installed.
+#
+# Currently, only git is supported.
+# Other SCMs can edit scripts/setlocalversion and add the appropriate
+# checks as needed.
+
+
+ifdef CONFIG_LOCALVERSION_AUTO
+ localversion-auto := $(shell $(PERL) $(srctree)/scripts/setlocalversion $(srctree))
+ LOCALVERSION := $(LOCALVERSION)$(localversion-auto)
+endif
+
#
# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
# relocations required by build roots. This is not defined in the
@@ -691,8 +708,10 @@
# Update vmlinux version before link
# Use + in front of this rule to silent warning about make -j1
+# First command is ':' to allow us to use + in front of this rule
cmd_ksym_ld = $(cmd_vmlinux__)
define rule_ksym_ld
+ :
+$(call cmd,vmlinux_version)
$(call cmd,vmlinux__)
$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
@@ -722,6 +741,16 @@
# Needs to visit scripts/ before $(KALLSYMS) can be used.
$(KALLSYMS): scripts ;
+# Generate some data for debugging strange kallsyms problems
+debug_kallsyms: .tmp_map$(last_kallsyms)
+
+.tmp_map%: .tmp_vmlinux% FORCE
+ ($(OBJDUMP) -h $< | $(AWK) '/^ +[0-9]/{print $$4 " 0 " $$2}'; $(NM) $<) | sort > $@
+
+.tmp_map3: .tmp_map2
+
+.tmp_map2: .tmp_map1
+
endif # ifdef CONFIG_KALLSYMS
# vmlinux image - including updated kernel symbols
@@ -757,7 +786,7 @@
prepare2:
ifneq ($(KBUILD_SRC),)
@echo ' Using $(srctree) as source for kernel'
- $(Q)if [ -h $(srctree)/include/asm -o -f $(srctree)/.config ]; then \
+ $(Q)if [ -f $(srctree)/.config ]; then \
echo " $(srctree) is not clean, please run 'make mrproper'";\
echo " in the '$(srctree)' directory.";\
/bin/false; \
@@ -769,7 +798,8 @@
# prepare1 creates a makefile if using a separate output directory
prepare1: prepare2 outputmakefile
-prepare0: prepare1 include/linux/version.h include/asm include/config/MARKER
+prepare0: prepare1 include/linux/version.h include/asm \
+ include/config/MARKER
ifneq ($(KBUILD_MODULES),)
$(Q)rm -rf $(MODVERDIR)
$(Q)mkdir -p $(MODVERDIR)
@@ -875,7 +905,7 @@
.PHONY: _modinst_
_modinst_:
- @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \
+ @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
echo "Warning: you may need to install module-init-tools"; \
echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
sleep 1; \
@@ -1159,37 +1189,49 @@
__srctree = $(srctree)/
endif
+ALLSOURCE_ARCHS := $(ARCH)
+
define all-sources
( find $(__srctree) $(RCS_FIND_IGNORE) \
\( -name include -o -name arch \) -prune -o \
-name '*.[chS]' -print; \
- find $(__srctree)arch/$(ARCH) $(RCS_FIND_IGNORE) \
- -name '*.[chS]' -print; \
+ for ARCH in $(ALLSOURCE_ARCHS) ; do \
+ find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
+ -name '*.[chS]' -print; \
+ done ; \
find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \
-name '*.[chS]' -print; \
find $(__srctree)include $(RCS_FIND_IGNORE) \
\( -name config -o -name 'asm-*' \) -prune \
-o -name '*.[chS]' -print; \
- find $(__srctree)include/asm-$(ARCH) $(RCS_FIND_IGNORE) \
- -name '*.[chS]' -print; \
+ for ARCH in $(ALLSOURCE_ARCHS) ; do \
+ find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
+ -name '*.[chS]' -print; \
+ done ; \
find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
-name '*.[chS]' -print )
endef
quiet_cmd_cscope-file = FILELST cscope.files
- cmd_cscope-file = $(all-sources) > cscope.files
+ cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files
quiet_cmd_cscope = MAKE cscope.out
- cmd_cscope = cscope -k -b -q
+ cmd_cscope = cscope -b
cscope: FORCE
$(call cmd,cscope-file)
$(call cmd,cscope)
quiet_cmd_TAGS = MAKE $@
-cmd_TAGS = $(all-sources) | etags -
+define cmd_TAGS
+ rm -f $@; \
+ ETAGSF=`etags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_GPL --extra=+f"`; \
+ $(all-sources) | xargs etags $$ETAGSF -a
+endef
-# Exuberant ctags works better with -I
+TAGS: FORCE
+ $(call cmd,TAGS)
+
quiet_cmd_tags = MAKE $@
define cmd_tags
@@ -1198,9 +1240,6 @@
$(all-sources) | xargs ctags $$CTAGSF -a
endef
-TAGS: FORCE
- $(call cmd,TAGS)
-
tags: FORCE
$(call cmd,tags)
@@ -1268,82 +1307,11 @@
include $(cmd_files)
endif
-# Execute command and generate cmd file
-if_changed = $(if $(strip $? \
- $(filter-out $(cmd_$(1)),$(cmd_$@))\
- $(filter-out $(cmd_$@),$(cmd_$(1)))),\
- @set -e; \
- $(if $($(quiet)cmd_$(1)),echo ' $(subst ','\'',$($(quiet)cmd_$(1)))';) \
- $(cmd_$(1)); \
- echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
-
-
-# execute the command and also postprocess generated .d dependencies
-# file
-if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
- $(filter-out $(cmd_$(1)),$(cmd_$@))\
- $(filter-out $(cmd_$@),$(cmd_$(1)))),\
- $(Q)set -e; \
- $(if $($(quiet)cmd_$(1)),echo ' $(subst ','\'',$($(quiet)cmd_$(1)))';) \
- $(cmd_$(1)); \
- scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
- rm -f $(depfile); \
- mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
-
-# Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
-
-if_changed_rule = $(if $(strip $? \
- $(filter-out $(cmd_$(1)),$(cmd_$(@F)))\
- $(filter-out $(cmd_$(@F)),$(cmd_$(1)))),\
- $(Q)$(rule_$(1)))
-
-# If quiet is set, only print short version of command
-
-cmd = @$(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
-
-# filechk is used to check if the content of a generated file is updated.
-# Sample usage:
-# define filechk_sample
-# echo $KERNELRELEASE
-# endef
-# version.h : Makefile
-# $(call filechk,sample)
-# The rule defined shall write to stdout the content of the new file.
-# The existing file will be compared with the new one.
-# - If no file exist it is created
-# - If the content differ the new file is used
-# - If they are equal no change, and no timestamp update
-
-define filechk
- @set -e; \
- echo ' CHK $@'; \
- mkdir -p $(dir $@); \
- $(filechk_$(1)) < $< > $@.tmp; \
- if [ -r $@ ] && cmp -s $@ $@.tmp; then \
- rm -f $@.tmp; \
- else \
- echo ' UPD $@'; \
- mv -f $@.tmp $@; \
- fi
-endef
-
-# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=dir
-# Usage:
-# $(Q)$(MAKE) $(build)=dir
-build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
-
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir
# Usage:
# $(Q)$(MAKE) $(clean)=dir
clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
-# $(call descend,<dir>,<target>)
-# Recursively call a sub-make in <dir> with target <target>
-# Usage is deprecated, because make does not see this as an invocation of make.
-descend =$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=$(1) $(2)
-
endif # skip-makefile
FORCE:
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 189d5ea..786491f 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -479,6 +479,9 @@
depends on ALPHA_GENERIC || ALPHA_JENSEN || ALPHA_ALCOR || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_RAWHIDE
default y
+config ARCH_MAY_HAVE_PC_FDC
+ def_bool y
+
config SMP
bool "Symmetric multi-processing support"
depends on ALPHA_SABLE || ALPHA_LYNX || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 8226c5c..67be50b 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -149,7 +149,7 @@
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if ((time_status & STA_UNSYNC) == 0
+ if (ntp_synced()
&& xtime.tv_sec > state.last_rtc_update + 660
&& xtime.tv_nsec >= 500000 - ((unsigned) TICK_SIZE) / 2
&& xtime.tv_nsec <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -502,10 +502,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4bf0e87..0f2899b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -64,6 +64,9 @@
config GENERIC_BUST_SPINLOCK
bool
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+
config GENERIC_ISA_DMA
bool
@@ -150,6 +153,7 @@
select ARCH_ACORN
select FIQ
select TIMER_ACORN
+ select ARCH_MAY_HAVE_PC_FDC
help
On the Acorn Risc-PC, Linux can support the internal IDE disk and
CD-ROM interface, serial and parallel port, and the floppy drive.
@@ -365,8 +369,8 @@
Please note that dynamic tick may affect the accuracy of
timekeeping on some platforms depending on the implementation.
- Currently at least OMAP platform is known to have accurate
- timekeeping with dynamic tick.
+ Currently at least OMAP, PXA2xx and SA11x0 platforms are known
+ to have accurate timekeeping with dynamic tick.
config ARCH_DISCONTIGMEM_ENABLE
bool
diff --git a/arch/arm/boot/compressed/head-sharpsl.S b/arch/arm/boot/compressed/head-sharpsl.S
index d6bf8a2..59ad6964 100644
--- a/arch/arm/boot/compressed/head-sharpsl.S
+++ b/arch/arm/boot/compressed/head-sharpsl.S
@@ -7,7 +7,8 @@
* so we have to figure out the machine for ourselves...
*
* Support for Poodle, Corgi (SL-C700), Shepherd (SL-C750)
- * and Husky (SL-C760).
+ * Husky (SL-C760), Tosa (SL-C6000), Spitz (SL-C3000),
+ * Akita (SL-C1000) and Borzoi (SL-C3100).
*
*/
@@ -23,6 +24,22 @@
__SharpSL_start:
+/* Check for TC6393 - if found we have a Tosa */
+ ldr r7, .TOSAID
+ mov r1, #0x10000000 @ Base address of TC6393 chip
+ mov r6, #0x03
+ ldrh r3, [r1, #8] @ Load TC6393XB Revison: This is 0x0003
+ cmp r6, r3
+ beq .SHARPEND @ Success -> tosa
+
+/* Check for pxa270 - if found, branch */
+ mrc p15, 0, r4, c0, c0 @ Get Processor ID
+ and r4, r4, #0xffffff00
+ ldr r3, .PXA270ID
+ cmp r4, r3
+ beq .PXA270
+
+/* Check for w100 - if not found we have a Poodle */
ldr r1, .W100ADDR @ Base address of w100 chip + regs offset
mov r6, #0x31 @ Load Magic Init value
@@ -30,7 +47,7 @@
mov r5, #0x3000
.W100LOOP:
subs r5, r5, #1
- bne .W100LOOP
+ bne .W100LOOP
mov r6, #0x30 @ Load 2nd Magic Init value
str r6, [r1, #0x280] @ to SCRATCH_UMSK
@@ -40,45 +57,52 @@
cmp r6, r3
bne .SHARPEND @ We have no w100 - Poodle
- mrc p15, 0, r6, c0, c0 @ Get Processor ID
- and r6, r6, #0xffffff00
+/* Check for pxa250 - if found we have a Corgi */
ldr r7, .CORGIID
ldr r3, .PXA255ID
- cmp r6, r3
+ cmp r4, r3
blo .SHARPEND @ We have a PXA250 - Corgi
- mov r1, #0x0c000000 @ Base address of NAND chip
- ldrb r3, [r1, #24] @ Load FLASHCTL
- bic r3, r3, #0x11 @ SET NCE
- orr r3, r3, #0x0a @ SET CLR + FLWP
- strb r3, [r1, #24] @ Save to FLASHCTL
- mov r2, #0x90 @ Command "readid"
- strb r2, [r1, #20] @ Save to FLASHIO
- bic r3, r3, #2 @ CLR CLE
- orr r3, r3, #4 @ SET ALE
- strb r3, [r1, #24] @ Save to FLASHCTL
- mov r2, #0 @ Address 0x00
- strb r2, [r1, #20] @ Save to FLASHIO
- bic r3, r3, #4 @ CLR ALE
- strb r3, [r1, #24] @ Save to FLASHCTL
-.SHARP1:
- ldrb r3, [r1, #24] @ Load FLASHCTL
- tst r3, #32 @ Is chip ready?
- beq .SHARP1
- ldrb r2, [r1, #20] @ NAND Manufacturer ID
- ldrb r3, [r1, #20] @ NAND Chip ID
+/* Check for 64MiB flash - if found we have a Shepherd */
+ bl get_flash_ids
ldr r7, .SHEPHERDID
cmp r3, #0x76 @ 64MiB flash
beq .SHARPEND @ We have Shepherd
+
+/* Must be a Husky */
ldr r7, .HUSKYID @ Must be Husky
b .SHARPEND
+.PXA270:
+/* Check for 16MiB flash - if found we have Spitz */
+ bl get_flash_ids
+ ldr r7, .SPITZID
+ cmp r3, #0x73 @ 16MiB flash
+ beq .SHARPEND @ We have Spitz
+
+/* Check for a second SCOOP chip - if found we have Borzoi */
+ ldr r1, .SCOOP2ADDR
+ ldr r7, .BORZOIID
+ mov r6, #0x0140
+ strh r6, [r1]
+ ldrh r6, [r1]
+ cmp r6, #0x0140
+ beq .SHARPEND @ We have Borzoi
+
+/* Must be Akita */
+ ldr r7, .AKITAID
+ b .SHARPEND @ We have Borzoi
+
.PXA255ID:
.word 0x69052d00 @ PXA255 Processor ID
+.PXA270ID:
+ .word 0x69054100 @ PXA270 Processor ID
.W100ID:
.word 0x57411002 @ w100 Chip ID
.W100ADDR:
.word 0x08010000 @ w100 Chip ID Reg Address
+.SCOOP2ADDR:
+ .word 0x08800040
.POODLEID:
.word MACH_TYPE_POODLE
.CORGIID:
@@ -87,6 +111,41 @@
.word MACH_TYPE_SHEPHERD
.HUSKYID:
.word MACH_TYPE_HUSKY
+.TOSAID:
+ .word MACH_TYPE_TOSA
+.SPITZID:
+ .word MACH_TYPE_SPITZ
+.AKITAID:
+ .word MACH_TYPE_AKITA
+.BORZOIID:
+ .word MACH_TYPE_BORZOI
+
+/*
+ * Return: r2 - NAND Manufacturer ID
+ * r3 - NAND Chip ID
+ * Corrupts: r1
+ */
+get_flash_ids:
+ mov r1, #0x0c000000 @ Base address of NAND chip
+ ldrb r3, [r1, #24] @ Load FLASHCTL
+ bic r3, r3, #0x11 @ SET NCE
+ orr r3, r3, #0x0a @ SET CLR + FLWP
+ strb r3, [r1, #24] @ Save to FLASHCTL
+ mov r2, #0x90 @ Command "readid"
+ strb r2, [r1, #20] @ Save to FLASHIO
+ bic r3, r3, #2 @ CLR CLE
+ orr r3, r3, #4 @ SET ALE
+ strb r3, [r1, #24] @ Save to FLASHCTL
+ mov r2, #0 @ Address 0x00
+ strb r2, [r1, #20] @ Save to FLASHIO
+ bic r3, r3, #4 @ CLR ALE
+ strb r3, [r1, #24] @ Save to FLASHCTL
+.fids1:
+ ldrb r3, [r1, #24] @ Load FLASHCTL
+ tst r3, #32 @ Is chip ready?
+ beq .fids1
+ ldrb r2, [r1, #20] @ NAND Manufacturer ID
+ ldrb r3, [r1, #20] @ NAND Chip ID
+ mov pc, lr
+
.SHARPEND:
-
-
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 51dbf54..d749907 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/smp.h>
+#include <linux/cpumask.h>
#include <asm/irq.h>
#include <asm/io.h>
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 41f1265..51f430c 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -177,7 +177,7 @@
d = irq_desc + irq;
for (i = 0; i <= 3; i++, d++, irq++) {
if (req & (0x0100 << i)) {
- d->handle(irq, d, regs);
+ desc_handle_irq(irq, d, regs);
}
}
@@ -220,7 +220,7 @@
if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
d = irq_desc + LOCOMO_IRQ_KEY_START;
- d->handle(LOCOMO_IRQ_KEY_START, d, regs);
+ desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs);
}
}
@@ -273,7 +273,7 @@
d = irq_desc + LOCOMO_IRQ_GPIO_START;
for (i = 0; i <= 15; i++, irq++, d++) {
if (req & (0x0001 << i)) {
- d->handle(irq, d, regs);
+ desc_handle_irq(irq, d, regs);
}
}
}
@@ -328,7 +328,7 @@
if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) {
d = irq_desc + LOCOMO_IRQ_LT_START;
- d->handle(LOCOMO_IRQ_LT_START, d, regs);
+ desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs);
}
}
@@ -379,7 +379,7 @@
for (i = 0; i <= 3; i++, irq++, d++) {
if (req & (0x0001 << i)) {
- d->handle(irq, d, regs);
+ desc_handle_irq(irq, d, regs);
}
}
}
@@ -651,15 +651,15 @@
return ret;
}
+static int locomo_remove_child(struct device *dev, void *data)
+{
+ device_unregister(dev);
+ return 0;
+}
+
static void __locomo_remove(struct locomo *lchip)
{
- struct list_head *l, *n;
-
- list_for_each_safe(l, n, &lchip->dev->children) {
- struct device *d = list_to_dev(l);
-
- device_unregister(d);
- }
+ device_for_each_child(lchip->dev, NULL, locomo_remove_child);
if (lchip->irq != NO_IRQ) {
set_irq_chained_handler(lchip->irq, NULL);
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 38c2eb6..1a47fbf9c 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -268,8 +268,8 @@
.mask = sa1111_mask_lowirq,
.unmask = sa1111_unmask_lowirq,
.retrigger = sa1111_retrigger_lowirq,
- .type = sa1111_type_lowirq,
- .wake = sa1111_wake_lowirq,
+ .set_type = sa1111_type_lowirq,
+ .set_wake = sa1111_wake_lowirq,
};
static void sa1111_mask_highirq(unsigned int irq)
@@ -364,8 +364,8 @@
.mask = sa1111_mask_highirq,
.unmask = sa1111_unmask_highirq,
.retrigger = sa1111_retrigger_highirq,
- .type = sa1111_type_highirq,
- .wake = sa1111_wake_highirq,
+ .set_type = sa1111_type_highirq,
+ .set_wake = sa1111_wake_highirq,
};
static void sa1111_setup_irq(struct sa1111 *sachip)
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index cfd0d3e..688a595 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -17,6 +17,12 @@
#define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
+/* PCMCIA to Scoop linkage structures for pxa2xx_sharpsl.c
+ There is no easy way to link multiple scoop devices into one
+ single entity for the pxa2xx_pcmcia device */
+int scoop_num;
+struct scoop_pcmcia_dev *scoop_devs;
+
struct scoop_dev {
void *base;
spinlock_t scoop_lock;
diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig
index 2495526..4198677 100644
--- a/arch/arm/configs/omap_h2_1610_defconfig
+++ b/arch/arm/configs/omap_h2_1610_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-rc2
-# Fri Jul 8 04:49:34 2005
+# Linux kernel version: 2.6.13
+# Mon Sep 5 18:07:12 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
@@ -102,9 +102,11 @@
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
CONFIG_OMAP_32K_TIMER_HZ=128
+# CONFIG_OMAP_DM_TIMER is not set
CONFIG_OMAP_LL_DEBUG_UART1=y
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
#
# OMAP Core Type
@@ -166,7 +168,6 @@
#
# Kernel Features
#
-# CONFIG_SMP is not set
CONFIG_PREEMPT=y
CONFIG_NO_IDLE_HZ=y
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
@@ -230,6 +231,68 @@
# CONFIG_APM is not set
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_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_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE 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
+
+#
# Device Drivers
#
@@ -243,78 +306,7 @@
#
# Memory Technology Devices (MTD)
#
-CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=3
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_REDBOOT_PARTS is not set
-CONFIG_MTD_CMDLINE_PARTS=y
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL 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=y
-# CONFIG_MTD_CFI_AMDSTD is not set
-# 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_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD 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 is not set
#
# Parallel port support
@@ -403,72 +395,8 @@
#
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_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_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -518,6 +446,8 @@
# CONFIG_SLIP_MODE_SLIP6 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
@@ -615,77 +545,15 @@
#
# 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_ISA is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_PCA_ISA is not set
-
-#
-# Hardware Sensors Chip support
-#
+# CONFIG_I2C is not set
# CONFIG_I2C_SENSOR 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_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_SMSC47B397 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_ISP1301_OMAP=y
#
-# Other I2C Chip support
+# Hardware Monitoring 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_RTC8564 is not set
-CONFIG_ISP1301_OMAP=y
-CONFIG_TPS65010=y
-# 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
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -756,15 +624,9 @@
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_TVMIXER is not set
# CONFIG_SOUND_AD1980 is not set
#
@@ -810,6 +672,7 @@
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -817,6 +680,7 @@
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -857,15 +721,6 @@
# 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=2
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC 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=y
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -1007,4 +862,3 @@
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 2b6b4c7..db07ce4 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -284,7 +284,7 @@
.long sys_fstatfs64
.long sys_tgkill
.long sys_utimes
-/* 270 */ .long sys_fadvise64_64
+/* 270 */ .long sys_arm_fadvise64_64_wrapper
.long sys_pciconfig_iobase
.long sys_pciconfig_read
.long sys_pciconfig_write
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 6540db6..dceb826 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -585,7 +585,7 @@
if (pending) {
struct irqdesc *d = irq_desc + ec->irq;
- d->handle(ec->irq, d, regs);
+ desc_handle_irq(ec->irq, d, regs);
called ++;
}
}
@@ -632,7 +632,7 @@
* Serial cards should go in 0/1, ethernet/scsi in 2/3
* otherwise you will lose serial data at high speeds!
*/
- d->handle(ec->irq, d, regs);
+ desc_handle_irq(ec->irq, d, regs);
} else {
printk(KERN_WARNING "card%d: interrupt from unclaimed "
"card???\n", slot);
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 3f8d0e3..6281d48 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -265,6 +265,10 @@
str r5, [sp, #4] @ push sixth arg
b sys_futex
+sys_arm_fadvise64_64_wrapper:
+ str r5, [sp, #4] @ push r5 to stack
+ b sys_arm_fadvise64_64
+
/*
* Note: off_4k (r5) is always units of 4K. If we can't do the requested
* offset, we return EINVAL.
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 395137a..3284118 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -207,8 +207,8 @@
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
- if (desc->chip->wake)
- desc->chip->wake(irq, 1);
+ if (desc->chip->set_wake)
+ desc->chip->set_wake(irq, 1);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
EXPORT_SYMBOL(enable_irq_wake);
@@ -219,8 +219,8 @@
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
- if (desc->chip->wake)
- desc->chip->wake(irq, 0);
+ if (desc->chip->set_wake)
+ desc->chip->set_wake(irq, 0);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
EXPORT_SYMBOL(disable_irq_wake);
@@ -517,7 +517,7 @@
list_for_each_safe(l, n, &head) {
desc = list_entry(l, struct irqdesc, pend);
list_del_init(&desc->pend);
- desc->handle(desc - irq_desc, desc, regs);
+ desc_handle_irq(desc - irq_desc, desc, regs);
}
/*
@@ -545,7 +545,7 @@
irq_enter();
spin_lock(&irq_controller_lock);
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
/*
* Now re-run any pending interrupts.
@@ -624,9 +624,9 @@
}
desc = irq_desc + irq;
- if (desc->chip->type) {
+ if (desc->chip->set_type) {
spin_lock_irqsave(&irq_controller_lock, flags);
- ret = desc->chip->type(irq, type);
+ ret = desc->chip->set_type(irq, type);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
@@ -846,8 +846,8 @@
irq_desc[i].probing = 1;
irq_desc[i].triggered = 0;
- if (irq_desc[i].chip->type)
- irq_desc[i].chip->type(i, IRQT_PROBE);
+ if (irq_desc[i].chip->set_type)
+ irq_desc[i].chip->set_type(i, IRQT_PROBE);
irq_desc[i].chip->unmask(i);
irqs += 1;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b208573..8261649 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -110,7 +110,7 @@
* We need to tell the secondary core where to find
* its stack and the page tables.
*/
- secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8;
+ secondary_data.stack = (void *)idle->thread_info + THREAD_START_SP;
secondary_data.pgdir = virt_to_phys(pgd);
wmb();
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index f897ce2..42629ff 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -311,3 +311,13 @@
return ret;
}
EXPORT_SYMBOL(execve);
+
+/*
+ * Since loff_t is a 64 bit type we avoid a lot of ABI hastle
+ * with a different argument ordering.
+ */
+asmlinkage long sys_arm_fadvise64_64(int fd, int advice,
+ loff_t offset, loff_t len)
+{
+ return sys_fadvise64_64(fd, offset, len, advice);
+}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 1b7fcd5..69449a8 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -102,7 +102,7 @@
*/
static inline void do_set_rtc(void)
{
- if (time_status & STA_UNSYNC || set_rtc == NULL)
+ if (!ntp_synced() || set_rtc == NULL)
return;
if (next_rtc_update &&
@@ -292,10 +292,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
@@ -433,10 +430,12 @@
{
struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
- write_seqlock(&xtime_lock);
- if (dyn_tick->state & DYN_TICK_ENABLED)
- dyn_tick->reprogram(next_timer_interrupt() - jiffies);
- write_sequnlock(&xtime_lock);
+ if (dyn_tick) {
+ write_seqlock(&xtime_lock);
+ if (dyn_tick->state & DYN_TICK_ENABLED)
+ dyn_tick->reprogram(next_timer_interrupt() - jiffies);
+ write_sequnlock(&xtime_lock);
+ }
}
static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig
index 324d9ed..bdd2579 100644
--- a/arch/arm/mach-footbridge/Kconfig
+++ b/arch/arm/mach-footbridge/Kconfig
@@ -87,6 +87,7 @@
# EBSA285 board in either host or addin mode
config ARCH_EBSA285
+ select ARCH_MAY_HAVE_PC_FDC
bool
endif
diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c
index b210160..e1c43b3 100644
--- a/arch/arm/mach-footbridge/isa-irq.c
+++ b/arch/arm/mach-footbridge/isa-irq.c
@@ -95,7 +95,7 @@
}
desc = irq_desc + isa_irq;
- desc->handle(isa_irq, desc, regs);
+ desc_handle_irq(isa_irq, desc, regs);
}
static struct irqaction irq_cascade = { .handler = no_action, .name = "cascade", };
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index 96aa3af..5110e2e 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -108,7 +108,7 @@
while (mask) {
if (mask & 1) {
IRQDBG("handling irq %d\n", irq);
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
}
irq++;
desc++;
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 593b6a2..4b31993 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -126,7 +126,7 @@
desc = irq_desc + irq;
while (mask) {
if (mask & 1)
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
irq++;
desc++;
mask >>= 1;
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
index 0c27134..eeb8a6d 100644
--- a/arch/arm/mach-imx/irq.c
+++ b/arch/arm/mach-imx/irq.c
@@ -152,7 +152,7 @@
while (mask) {
if (mask & 1) {
DEBUG_IRQ("handling irq %d\n", irq);
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
}
irq++;
desc++;
@@ -214,7 +214,7 @@
.ack = imx_gpio_ack_irq,
.mask = imx_gpio_mask_irq,
.unmask = imx_gpio_unmask_irq,
- .type = imx_gpio_irq_type,
+ .set_type = imx_gpio_irq_type,
};
void __init
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 569f328..2be5c03 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -170,7 +170,7 @@
irq += IRQ_SIC_START;
desc = irq_desc + irq;
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
} while (status);
}
diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c
index d53af16..0039793 100644
--- a/arch/arm/mach-iop3xx/iop321-time.c
+++ b/arch/arm/mach-iop3xx/iop321-time.c
@@ -60,7 +60,7 @@
/*
* Now convert them to usec.
*/
- usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
+ usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
return usec;
}
diff --git a/arch/arm/mach-iop3xx/iop331-time.c b/arch/arm/mach-iop3xx/iop331-time.c
index 1a6d9d6..8eddfac 100644
--- a/arch/arm/mach-iop3xx/iop331-time.c
+++ b/arch/arm/mach-iop3xx/iop331-time.c
@@ -58,7 +58,7 @@
/*
* Now convert them to usec.
*/
- usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
+ usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
return usec;
}
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 45b1865..098c817 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -317,7 +317,7 @@
for (i = 0; i <= 7; i++) {
if (status & (1<<i)) {
desc = irq_desc + i + IRQ_IXP2000_GPIO0;
- desc->handle(i + IRQ_IXP2000_GPIO0, desc, regs);
+ desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc, regs);
}
}
}
@@ -380,10 +380,10 @@
}
static struct irqchip ixp2000_GPIO_irq_chip = {
- .type = ixp2000_GPIO_irq_type,
- .ack = ixp2000_GPIO_irq_mask_ack,
- .mask = ixp2000_GPIO_irq_mask,
- .unmask = ixp2000_GPIO_irq_unmask
+ .ack = ixp2000_GPIO_irq_mask_ack,
+ .mask = ixp2000_GPIO_irq_mask,
+ .unmask = ixp2000_GPIO_irq_unmask,
+ .set_type = ixp2000_GPIO_irq_type,
};
static void ixp2000_pci_irq_mask(unsigned int irq)
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index a43369a..63ba019 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -133,7 +133,7 @@
struct irqdesc *cpld_desc;
int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
cpld_desc = irq_desc + cpld_irq;
- cpld_desc->handle(cpld_irq, cpld_desc, regs);
+ desc_handle_irq(cpld_irq, cpld_desc, regs);
}
}
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 43447da..7a51099 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -82,7 +82,7 @@
struct irqdesc *cpld_desc;
int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
cpld_desc = irq_desc + cpld_irq;
- cpld_desc->handle(cpld_irq, cpld_desc, regs);
+ desc_handle_irq(cpld_irq, cpld_desc, regs);
}
}
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 04490a9..52ad113 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -38,90 +38,6 @@
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-enum ixp4xx_irq_type {
- IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
-};
-static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
-
-/*************************************************************************
- * GPIO acces functions
- *************************************************************************/
-
-/*
- * Configure GPIO line for input, interrupt, or output operation
- *
- * TODO: Enable/disable the irq_desc based on interrupt or output mode.
- * TODO: Should these be named ixp4xx_gpio_?
- */
-void gpio_line_config(u8 line, u32 style)
-{
- static const int gpio2irq[] = {
- 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
- };
- u32 enable;
- volatile u32 *int_reg;
- u32 int_style;
- enum ixp4xx_irq_type irq_type;
-
- enable = *IXP4XX_GPIO_GPOER;
-
- if (style & IXP4XX_GPIO_OUT) {
- enable &= ~((1) << line);
- } else if (style & IXP4XX_GPIO_IN) {
- enable |= ((1) << line);
-
- switch (style & IXP4XX_GPIO_INTSTYLE_MASK)
- {
- case (IXP4XX_GPIO_ACTIVE_HIGH):
- int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
- irq_type = IXP4XX_IRQ_LEVEL;
- break;
- case (IXP4XX_GPIO_ACTIVE_LOW):
- int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
- irq_type = IXP4XX_IRQ_LEVEL;
- break;
- case (IXP4XX_GPIO_RISING_EDGE):
- int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
- irq_type = IXP4XX_IRQ_EDGE;
- break;
- case (IXP4XX_GPIO_FALLING_EDGE):
- int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
- irq_type = IXP4XX_IRQ_EDGE;
- break;
- case (IXP4XX_GPIO_TRANSITIONAL):
- int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
- irq_type = IXP4XX_IRQ_EDGE;
- break;
- default:
- int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
- irq_type = IXP4XX_IRQ_LEVEL;
- break;
- }
-
- if (style & IXP4XX_GPIO_INTSTYLE_MASK)
- ixp4xx_config_irq(gpio2irq[line], irq_type);
-
- if (line >= 8) { /* pins 8-15 */
- line -= 8;
- int_reg = IXP4XX_GPIO_GPIT2R;
- }
- else { /* pins 0-7 */
- int_reg = IXP4XX_GPIO_GPIT1R;
- }
-
- /* Clear the style for the appropriate pin */
- *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
- (line * IXP4XX_GPIO_STYLE_SIZE));
-
- /* Set the new style */
- *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
- }
-
- *IXP4XX_GPIO_GPOER = enable;
-}
-
-EXPORT_SYMBOL(gpio_line_config);
-
/*************************************************************************
* IXP4xx chipset I/O mapping
*************************************************************************/
@@ -165,6 +81,69 @@
* (be it PCI or something else) configures that GPIO line
* as an IRQ.
**************************************************************************/
+enum ixp4xx_irq_type {
+ IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
+};
+
+static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
+
+/*
+ * IRQ -> GPIO mapping table
+ */
+static int irq2gpio[32] = {
+ -1, -1, -1, -1, -1, -1, 0, 1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, -1, -1,
+};
+
+static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
+{
+ int line = irq2gpio[irq];
+ u32 int_style;
+ enum ixp4xx_irq_type irq_type;
+ volatile u32 *int_reg;
+
+ /*
+ * Only for GPIO IRQs
+ */
+ if (line < 0)
+ return -EINVAL;
+
+ if (type & IRQT_BOTHEDGE) {
+ int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
+ irq_type = IXP4XX_IRQ_EDGE;
+ } else if (type & IRQT_RISING) {
+ int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
+ irq_type = IXP4XX_IRQ_EDGE;
+ } else if (type & IRQT_FALLING) {
+ int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
+ irq_type = IXP4XX_IRQ_EDGE;
+ } else if (type & IRQT_HIGH) {
+ int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
+ irq_type = IXP4XX_IRQ_LEVEL;
+ } else if (type & IRQT_LOW) {
+ int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
+ irq_type = IXP4XX_IRQ_LEVEL;
+ }
+
+ ixp4xx_config_irq(irq, irq_type);
+
+ if (line >= 8) { /* pins 8-15 */
+ line -= 8;
+ int_reg = IXP4XX_GPIO_GPIT2R;
+ } else { /* pins 0-7 */
+ int_reg = IXP4XX_GPIO_GPIT1R;
+ }
+
+ /* Clear the style for the appropriate pin */
+ *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
+ (line * IXP4XX_GPIO_STYLE_SIZE));
+
+ /* Set the new style */
+ *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
+}
+
static void ixp4xx_irq_mask(unsigned int irq)
{
if (cpu_is_ixp46x() && irq >= 32)
@@ -183,12 +162,6 @@
static void ixp4xx_irq_ack(unsigned int irq)
{
- static int irq2gpio[32] = {
- -1, -1, -1, -1, -1, -1, 0, 1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, -1, -1,
- };
int line = (irq < 32) ? irq2gpio[irq] : -1;
if (line >= 0)
@@ -206,15 +179,17 @@
}
static struct irqchip ixp4xx_irq_level_chip = {
- .ack = ixp4xx_irq_mask,
- .mask = ixp4xx_irq_mask,
- .unmask = ixp4xx_irq_level_unmask,
+ .ack = ixp4xx_irq_mask,
+ .mask = ixp4xx_irq_mask,
+ .unmask = ixp4xx_irq_level_unmask,
+ .set_type = ixp4xx_set_irq_type,
};
static struct irqchip ixp4xx_irq_edge_chip = {
- .ack = ixp4xx_irq_ack,
- .mask = ixp4xx_irq_mask,
- .unmask = ixp4xx_irq_unmask,
+ .ack = ixp4xx_irq_ack,
+ .mask = ixp4xx_irq_mask,
+ .unmask = ixp4xx_irq_unmask,
+ .set_type = ixp4xx_set_irq_type,
};
static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c
index afafb42..60de8a9 100644
--- a/arch/arm/mach-ixp4xx/coyote-pci.c
+++ b/arch/arm/mach-ixp4xx/coyote-pci.c
@@ -30,11 +30,8 @@
void __init coyote_pci_preinit(void)
{
- gpio_line_config(COYOTE_PCI_SLOT0_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-
- gpio_line_config(COYOTE_PCI_SLOT1_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+ set_irq_type(IRQ_COYOTE_PCI_SLOT0, IRQT_LOW);
+ set_irq_type(IRQ_COYOTE_PCI_SLOT1, IRQT_LOW);
gpio_line_isr_clear(COYOTE_PCI_SLOT0_PIN);
gpio_line_isr_clear(COYOTE_PCI_SLOT1_PIN);
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index 411ea99..8b2f253 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -24,11 +24,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
-void __init coyote_map_io(void)
-{
- ixp4xx_map_io();
-}
-
static struct flash_platform_data coyote_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -107,7 +102,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = coyote_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -125,7 +120,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = coyote_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-pci.c b/arch/arm/mach-ixp4xx/gtwx5715-pci.c
index b180358..a66484b6 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-pci.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-pci.c
@@ -35,26 +35,20 @@
extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
- /*
- * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
- * Slot 0 isn't actually populated with a card connector but
- * we initialize it anyway in case a future version has the
- * slot populated or someone with good soldering skills has
- * some free time.
- */
-
-static void gtwx5715_init_gpio(u8 pin, u32 style)
-{
- gpio_line_config(pin, style | IXP4XX_GPIO_ACTIVE_LOW);
-
- if (style & IXP4XX_GPIO_IN) gpio_line_isr_clear(pin);
-}
-
+/*
+ * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
+ * Slot 0 isn't actually populated with a card connector but
+ * we initialize it anyway in case a future version has the
+ * slot populated or someone with good soldering skills has
+ * some free time.
+ */
void __init gtwx5715_pci_preinit(void)
{
- gtwx5715_init_gpio(GTWX5715_PCI_SLOT0_INTA_GPIO, IXP4XX_GPIO_IN);
- gtwx5715_init_gpio(GTWX5715_PCI_SLOT1_INTA_GPIO, IXP4XX_GPIO_IN);
+ set_irq_type(GTWX5715_PCI_SLOT0_INTA_IRQ, IRQT_LOW);
+ set_irq_type(GTWX5715_PCI_SLOT0_INTB_IRQ, IRQT_LOW);
+ set_irq_type(GTWX5715_PCI_SLOT1_INTA_IRQ, IRQT_LOW);
+ set_irq_type(GTWX5715_PCI_SLOT1_INTB_IRQ, IRQT_LOW);
ixp4xx_pci_preinit();
}
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index 333459d..3fd92c5 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -101,12 +101,6 @@
.resource = gtwx5715_uart_resources,
};
-
-void __init gtwx5715_map_io(void)
-{
- ixp4xx_map_io();
-}
-
static struct flash_platform_data gtwx5715_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -144,7 +138,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_UART2_BASE_PHYS,
.io_pg_offst = ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = gtwx5715_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c
index c2ab9eb..f9a1d3e 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
@@ -27,14 +27,10 @@
void __init ixdp425_pci_preinit(void)
{
- gpio_line_config(IXDP425_PCI_INTA_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(IXDP425_PCI_INTB_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(IXDP425_PCI_INTC_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(IXDP425_PCI_INTD_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTA, IRQT_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTB, IRQT_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTC, IRQT_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTD, IRQT_LOW);
gpio_line_isr_clear(IXDP425_PCI_INTA_PIN);
gpio_line_isr_clear(IXDP425_PCI_INTB_PIN);
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index fa0646c..6c14ff3 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -24,11 +24,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
-void __init ixdp425_map_io(void)
-{
- ixp4xx_map_io();
-}
-
static struct flash_platform_data ixdp425_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -133,7 +128,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -145,7 +140,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -157,7 +152,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -176,7 +171,7 @@
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
index ce4563f..fe5e766 100644
--- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
@@ -29,8 +29,8 @@
void __init ixdpg425_pci_preinit(void)
{
- gpio_line_config(6, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(7, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+ set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW);
+ set_irq_type(IRQ_IXP4XX_GPIO7, IRQT_LOW);
gpio_line_isr_clear(6);
gpio_line_isr_clear(7);
diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h
index beda7c2..578a524 100644
--- a/arch/arm/mach-lh7a40x/common.h
+++ b/arch/arm/mach-lh7a40x/common.h
@@ -13,4 +13,4 @@
extern void lh7a400_init_irq (void);
extern void lh7a404_init_irq (void);
-#define IRQ_DISPATCH(irq) irq_desc[irq].handle ((irq), &irq_desc[irq], regs)
+#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs)
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 7c08f6c..c12a783 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -102,7 +102,7 @@
fpga_irq++, stat >>= 1) {
if (stat & 1) {
d = irq_desc + fpga_irq;
- d->handle(fpga_irq, d, regs);
+ desc_handle_irq(fpga_irq, d, regs);
}
}
}
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index a11b6d8..afd5d67 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -165,10 +165,10 @@
#endif
static struct irqchip omap_irq_chip = {
- .ack = omap_mask_ack_irq,
- .mask = omap_mask_irq,
- .unmask = omap_unmask_irq,
- .wake = omap_wake_irq,
+ .ack = omap_mask_ack_irq,
+ .mask = omap_mask_irq,
+ .unmask = omap_unmask_irq,
+ .set_wake = omap_wake_irq,
};
void __init omap_init_irq(void)
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index efc2f65..33dae99 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -11,7 +11,7 @@
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o ssp.o
+obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o ssp.o
obj-$(CONFIG_MACH_POODLE) += poodle.o
# Support for blinky lights
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 86b862f..29185ac 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -39,7 +39,6 @@
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/scoop.h>
-#include <video/w100fb.h>
#include "generic.h"
@@ -60,6 +59,15 @@
.io_out = CORGI_SCOOP_IO_OUT,
};
+static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
+{
+ .dev = &corgiscoop_device.dev,
+ .irq = CORGI_IRQ_GPIO_CF_IRQ,
+ .cd_irq = CORGI_IRQ_GPIO_CF_CD,
+ .cd_irq_str = "PCMCIA0 CD",
+},
+};
+
struct platform_device corgiscoop_device = {
.name = "sharp-scoop",
.id = -1,
@@ -78,7 +86,7 @@
* also use scoop functions and this makes the power up/down order
* work correctly.
*/
-static struct platform_device corgissp_device = {
+struct platform_device corgissp_device = {
.name = "corgi-ssp",
.dev = {
.parent = &corgiscoop_device.dev,
@@ -88,35 +96,6 @@
/*
- * Corgi w100 Frame Buffer Device
- */
-static struct w100fb_mach_info corgi_fb_info = {
- .w100fb_ssp_send = corgi_ssp_lcdtg_send,
- .comadj = -1,
- .phadadj = -1,
-};
-
-static struct resource corgi_fb_resources[] = {
- [0] = {
- .start = 0x08000000,
- .end = 0x08ffffff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device corgifb_device = {
- .name = "w100fb",
- .id = -1,
- .dev = {
- .platform_data = &corgi_fb_info,
- .parent = &corgissp_device.dev,
- },
- .num_resources = ARRAY_SIZE(corgi_fb_resources),
- .resource = corgi_fb_resources,
-};
-
-
-/*
* Corgi Backlight Device
*/
static struct platform_device corgibl_device = {
@@ -129,6 +108,27 @@
/*
+ * Corgi Keyboard Device
+ */
+static struct platform_device corgikbd_device = {
+ .name = "corgi-keyboard",
+ .id = -1,
+};
+
+
+/*
+ * Corgi Touch Screen Device
+ */
+static struct platform_device corgits_device = {
+ .name = "corgi-ts",
+ .dev = {
+ .parent = &corgissp_device.dev,
+ },
+ .id = -1,
+};
+
+
+/*
* MMC/SD Device
*
* The card detect interrupt isn't debounced so we delay it by HZ/4
@@ -190,6 +190,11 @@
}
}
+static int corgi_mci_get_ro(struct device *dev)
+{
+ return GPLR(CORGI_GPIO_nSD_WP) & GPIO_bit(CORGI_GPIO_nSD_WP);
+}
+
static void corgi_mci_exit(struct device *dev, void *data)
{
free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
@@ -199,11 +204,13 @@
static struct pxamci_platform_data corgi_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.init = corgi_mci_init,
+ .get_ro = corgi_mci_get_ro,
.setpower = corgi_mci_setpower,
.exit = corgi_mci_exit,
};
+
/*
* USB Device Controller
*/
@@ -229,18 +236,20 @@
&corgiscoop_device,
&corgissp_device,
&corgifb_device,
+ &corgikbd_device,
&corgibl_device,
+ &corgits_device,
};
static void __init corgi_init(void)
{
- corgi_fb_info.comadj=sharpsl_param.comadj;
- corgi_fb_info.phadadj=sharpsl_param.phadadj;
-
pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
pxa_set_udc_info(&udc_info);
pxa_set_mci_info(&corgi_mci_platform_data);
+ scoop_num = 1;
+ scoop_devs = &corgi_pcmcia_scoop[0];
+
platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
new file mode 100644
index 0000000..deac29c
--- /dev/null
+++ b/arch/arm/mach-pxa/corgi_lcd.c
@@ -0,0 +1,396 @@
+/*
+ * linux/drivers/video/w100fb.c
+ *
+ * Corgi LCD Specific Code for ATI Imageon w100 (Wallaby)
+ *
+ * Copyright (C) 2005 Richard Purdie
+ *
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <asm/arch/corgi.h>
+#include <asm/mach/sharpsl_param.h>
+#include <video/w100fb.h>
+
+/* Register Addresses */
+#define RESCTL_ADRS 0x00
+#define PHACTRL_ADRS 0x01
+#define DUTYCTRL_ADRS 0x02
+#define POWERREG0_ADRS 0x03
+#define POWERREG1_ADRS 0x04
+#define GPOR3_ADRS 0x05
+#define PICTRL_ADRS 0x06
+#define POLCTRL_ADRS 0x07
+
+/* Resgister Bit Definitions */
+#define RESCTL_QVGA 0x01
+#define RESCTL_VGA 0x00
+
+#define POWER1_VW_ON 0x01 /* VW Supply FET ON */
+#define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */
+#define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */
+
+#define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */
+#define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */
+#define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */
+
+#define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */
+#define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */
+#define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */
+#define POWER0_COM_ON 0x08 /* COM Powewr Supply ON */
+#define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */
+
+#define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */
+#define POWER0_COM_OFF 0x00 /* COM Powewr Supply OFF */
+#define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */
+
+#define PICTRL_INIT_STATE 0x01
+#define PICTRL_INIOFF 0x02
+#define PICTRL_POWER_DOWN 0x04
+#define PICTRL_COM_SIGNAL_OFF 0x08
+#define PICTRL_DAC_SIGNAL_OFF 0x10
+
+#define POLCTRL_SYNC_POL_FALL 0x01
+#define POLCTRL_EN_POL_FALL 0x02
+#define POLCTRL_DATA_POL_FALL 0x04
+#define POLCTRL_SYNC_ACT_H 0x08
+#define POLCTRL_EN_ACT_L 0x10
+
+#define POLCTRL_SYNC_POL_RISE 0x00
+#define POLCTRL_EN_POL_RISE 0x00
+#define POLCTRL_DATA_POL_RISE 0x00
+#define POLCTRL_SYNC_ACT_L 0x00
+#define POLCTRL_EN_ACT_H 0x00
+
+#define PHACTRL_PHASE_MANUAL 0x01
+#define DEFAULT_PHAD_QVGA (9)
+#define DEFAULT_COMADJ (125)
+
+/*
+ * This is only a psuedo I2C interface. We can't use the standard kernel
+ * routines as the interface is write only. We just assume the data is acked...
+ */
+static void lcdtg_ssp_i2c_send(u8 data)
+{
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, data);
+ udelay(10);
+}
+
+static void lcdtg_i2c_send_bit(u8 data)
+{
+ lcdtg_ssp_i2c_send(data);
+ lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
+ lcdtg_ssp_i2c_send(data);
+}
+
+static void lcdtg_i2c_send_start(u8 base)
+{
+ lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+ lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
+ lcdtg_ssp_i2c_send(base);
+}
+
+static void lcdtg_i2c_send_stop(u8 base)
+{
+ lcdtg_ssp_i2c_send(base);
+ lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
+ lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+}
+
+static void lcdtg_i2c_send_byte(u8 base, u8 data)
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (data & 0x80)
+ lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
+ else
+ lcdtg_i2c_send_bit(base);
+ data <<= 1;
+ }
+}
+
+static void lcdtg_i2c_wait_ack(u8 base)
+{
+ lcdtg_i2c_send_bit(base);
+}
+
+static void lcdtg_set_common_voltage(u8 base_data, u8 data)
+{
+ /* Set Common Voltage to M62332FP via I2C */
+ lcdtg_i2c_send_start(base_data);
+ lcdtg_i2c_send_byte(base_data, 0x9c);
+ lcdtg_i2c_wait_ack(base_data);
+ lcdtg_i2c_send_byte(base_data, 0x00);
+ lcdtg_i2c_wait_ack(base_data);
+ lcdtg_i2c_send_byte(base_data, data);
+ lcdtg_i2c_wait_ack(base_data);
+ lcdtg_i2c_send_stop(base_data);
+}
+
+/* Set Phase Adjuct */
+static void lcdtg_set_phadadj(struct w100fb_par *par)
+{
+ int adj;
+ switch(par->xres) {
+ case 480:
+ case 640:
+ /* Setting for VGA */
+ adj = sharpsl_param.phadadj;
+ if (adj < 0) {
+ adj = PHACTRL_PHASE_MANUAL;
+ } else {
+ adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
+ }
+ break;
+ case 240:
+ case 320:
+ default:
+ /* Setting for QVGA */
+ adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
+ break;
+ }
+
+ corgi_ssp_lcdtg_send(PHACTRL_ADRS, adj);
+}
+
+static int lcd_inited;
+
+static void lcdtg_hw_init(struct w100fb_par *par)
+{
+ if (!lcd_inited) {
+ int comadj;
+
+ /* Initialize Internal Logic & Port */
+ corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE
+ | PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF);
+
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF
+ | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+
+ /* VDD(+8V), SVSS(-4V) ON */
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+ mdelay(3);
+
+ /* DAC ON */
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON
+ | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+ /* INIB = H, INI = L */
+ /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
+ corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
+
+ /* Set Common Voltage */
+ comadj = sharpsl_param.comadj;
+ if (comadj < 0)
+ comadj = DEFAULT_COMADJ;
+ lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
+
+ /* VCC5 ON, DAC ON */
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
+ POWER0_COM_OFF | POWER0_VCC5_ON);
+
+ /* GVSS(-8V) ON, VDD ON */
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+ mdelay(2);
+
+ /* COM SIGNAL ON (PICTL[3] = L) */
+ corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIT_STATE);
+
+ /* COM ON, DAC ON, VCC5_ON */
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON
+ | POWER0_COM_ON | POWER0_VCC5_ON);
+
+ /* VW ON, GVSS ON, VDD ON */
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+ /* Signals output enable */
+ corgi_ssp_lcdtg_send(PICTRL_ADRS, 0);
+
+ /* Set Phase Adjuct */
+ lcdtg_set_phadadj(par);
+
+ /* Initialize for Input Signals from ATI */
+ corgi_ssp_lcdtg_send(POLCTRL_ADRS, POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE
+ | POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H);
+ udelay(1000);
+
+ lcd_inited=1;
+ } else {
+ lcdtg_set_phadadj(par);
+ }
+
+ switch(par->xres) {
+ case 480:
+ case 640:
+ /* Set Lcd Resolution (VGA) */
+ corgi_ssp_lcdtg_send(RESCTL_ADRS, RESCTL_VGA);
+ break;
+ case 240:
+ case 320:
+ default:
+ /* Set Lcd Resolution (QVGA) */
+ corgi_ssp_lcdtg_send(RESCTL_ADRS, RESCTL_QVGA);
+ break;
+ }
+}
+
+static void lcdtg_suspend(struct w100fb_par *par)
+{
+ /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
+ mdelay(34);
+
+ /* (1)VW OFF */
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+ /* (2)COM OFF */
+ corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
+
+ /* (3)Set Common Voltage Bias 0V */
+ lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
+
+ /* (4)GVSS OFF */
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+
+ /* (5)VCC5 OFF */
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+ /* (6)Set PDWN, INIOFF, DACOFF */
+ corgi_ssp_lcdtg_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
+ PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
+
+ /* (7)DAC OFF */
+ corgi_ssp_lcdtg_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+ /* (8)VDD OFF */
+ corgi_ssp_lcdtg_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+
+ lcd_inited = 0;
+}
+
+static struct w100_tg_info corgi_lcdtg_info = {
+ .change=lcdtg_hw_init,
+ .suspend=lcdtg_suspend,
+ .resume=lcdtg_hw_init,
+};
+
+/*
+ * Corgi w100 Frame Buffer Device
+ */
+
+static struct w100_mem_info corgi_fb_mem = {
+ .ext_cntl = 0x00040003,
+ .sdram_mode_reg = 0x00650021,
+ .ext_timing_cntl = 0x10002a4a,
+ .io_cntl = 0x7ff87012,
+ .size = 0x1fffff,
+};
+
+static struct w100_gen_regs corgi_fb_regs = {
+ .lcd_format = 0x00000003,
+ .lcdd_cntl1 = 0x01CC0000,
+ .lcdd_cntl2 = 0x0003FFFF,
+ .genlcd_cntl1 = 0x00FFFF0D,
+ .genlcd_cntl2 = 0x003F3003,
+ .genlcd_cntl3 = 0x000102aa,
+};
+
+static struct w100_gpio_regs corgi_fb_gpio = {
+ .init_data1 = 0x000000bf,
+ .init_data2 = 0x00000000,
+ .gpio_dir1 = 0x00000000,
+ .gpio_oe1 = 0x03c0feff,
+ .gpio_dir2 = 0x00000000,
+ .gpio_oe2 = 0x00000000,
+};
+
+static struct w100_mode corgi_fb_modes[] = {
+{
+ .xres = 480,
+ .yres = 640,
+ .left_margin = 0x56,
+ .right_margin = 0x55,
+ .upper_margin = 0x03,
+ .lower_margin = 0x00,
+ .crtc_ss = 0x82360056,
+ .crtc_ls = 0xA0280000,
+ .crtc_gs = 0x80280028,
+ .crtc_vpos_gs = 0x02830002,
+ .crtc_rev = 0x00400008,
+ .crtc_dclk = 0xA0000000,
+ .crtc_gclk = 0x8015010F,
+ .crtc_goe = 0x80100110,
+ .crtc_ps1_active = 0x41060010,
+ .pll_freq = 75,
+ .fast_pll_freq = 100,
+ .sysclk_src = CLK_SRC_PLL,
+ .sysclk_divider = 0,
+ .pixclk_src = CLK_SRC_PLL,
+ .pixclk_divider = 2,
+ .pixclk_divider_rotated = 6,
+},{
+ .xres = 240,
+ .yres = 320,
+ .left_margin = 0x27,
+ .right_margin = 0x2e,
+ .upper_margin = 0x01,
+ .lower_margin = 0x00,
+ .crtc_ss = 0x81170027,
+ .crtc_ls = 0xA0140000,
+ .crtc_gs = 0xC0140014,
+ .crtc_vpos_gs = 0x00010141,
+ .crtc_rev = 0x00400008,
+ .crtc_dclk = 0xA0000000,
+ .crtc_gclk = 0x8015010F,
+ .crtc_goe = 0x80100110,
+ .crtc_ps1_active = 0x41060010,
+ .pll_freq = 0,
+ .fast_pll_freq = 0,
+ .sysclk_src = CLK_SRC_XTAL,
+ .sysclk_divider = 0,
+ .pixclk_src = CLK_SRC_XTAL,
+ .pixclk_divider = 1,
+ .pixclk_divider_rotated = 1,
+},
+
+};
+
+static struct w100fb_mach_info corgi_fb_info = {
+ .tg = &corgi_lcdtg_info,
+ .init_mode = INIT_MODE_ROTATED,
+ .mem = &corgi_fb_mem,
+ .regs = &corgi_fb_regs,
+ .modelist = &corgi_fb_modes[0],
+ .num_modes = 2,
+ .gpio = &corgi_fb_gpio,
+ .xtal_freq = 12500000,
+ .xtal_dbl = 0,
+};
+
+static struct resource corgi_fb_resources[] = {
+ [0] = {
+ .start = 0x08000000,
+ .end = 0x08ffffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device corgifb_device = {
+ .name = "w100fb",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(corgi_fb_resources),
+ .resource = corgi_fb_resources,
+ .dev = {
+ .platform_data = &corgi_fb_info,
+ .parent = &corgissp_device.dev,
+ },
+
+};
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index f3cac43..539b596 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -133,7 +133,7 @@
.ack = pxa_ack_low_gpio,
.mask = pxa_mask_low_irq,
.unmask = pxa_unmask_low_irq,
- .type = pxa_gpio_irq_type,
+ .set_type = pxa_gpio_irq_type,
};
/*
@@ -157,7 +157,7 @@
mask >>= 2;
do {
if (mask & 1)
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
irq++;
desc++;
mask >>= 1;
@@ -172,7 +172,7 @@
desc = irq_desc + irq;
do {
if (mask & 1)
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
irq++;
desc++;
mask >>= 1;
@@ -187,7 +187,7 @@
desc = irq_desc + irq;
do {
if (mask & 1)
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
irq++;
desc++;
mask >>= 1;
@@ -203,7 +203,7 @@
desc = irq_desc + irq;
do {
if (mask & 1)
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
irq++;
desc++;
mask >>= 1;
@@ -241,7 +241,7 @@
.ack = pxa_ack_muxed_gpio,
.mask = pxa_mask_muxed_gpio,
.unmask = pxa_unmask_muxed_gpio,
- .type = pxa_gpio_irq_type,
+ .set_type = pxa_gpio_irq_type,
};
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6309853..923f6eb 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -84,7 +84,7 @@
if (likely(pending)) {
irq = LUBBOCK_IRQ(0) + __ffs(pending);
desc = irq_desc + irq;
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
}
pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
} while (pending);
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 827b7b5..85fdb5b 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -72,7 +72,7 @@
if (likely(pending)) {
irq = MAINSTONE_IRQ(0) + __ffs(pending);
desc = irq_desc + irq;
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
}
pending = MST_INTSETCLR & mainstone_irq_enabled;
} while (pending);
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 0e4f6fa..47cfb8b 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -62,6 +62,15 @@
.resource = poodle_scoop_resources,
};
+static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = {
+{
+ .dev = &poodle_scoop_device.dev,
+ .irq = POODLE_IRQ_GPIO_CF_IRQ,
+ .cd_irq = POODLE_IRQ_GPIO_CF_CD,
+ .cd_irq_str = "PCMCIA0 CD",
+},
+};
+
/* LoCoMo device */
static struct resource locomo_resources[] = {
@@ -147,6 +156,9 @@
set_pxa_fb_info(&poodle_fb_info);
+ scoop_num = 1;
+ scoop_devs = &poodle_pcmcia_scoop[0];
+
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
if (ret) {
printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n");
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 6e52021..7dad3f1 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -70,6 +70,11 @@
return usec;
}
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
static irqreturn_t
pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -77,11 +82,19 @@
write_seqlock(&xtime_lock);
+#ifdef CONFIG_NO_IDLE_HZ
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ }
+#endif
+
/* Loop until we get ahead of the free running timer.
* This ensures an exact clock tick count and time accuracy.
- * IRQs are disabled inside the loop to ensure coherence between
- * lost_ticks (updated in do_timer()) and the match reg value, so we
- * can use do_gettimeofday() from interrupt handlers.
+ * Since IRQs are disabled at this point, coherence between
+ * lost_ticks(updated in do_timer()) and the match reg value is
+ * ensured, hence we can use do_gettimeofday() from interrupt
+ * handlers.
*
* HACK ALERT: it seems that the PXA timer regs aren't updated right
* away in all cases when a write occurs. We therefore compare with
@@ -126,6 +139,42 @@
OSCR = 0; /* initialize free-running timer, force first match */
}
+#ifdef CONFIG_NO_IDLE_HZ
+static int pxa_dyn_tick_enable_disable(void)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static void pxa_dyn_tick_reprogram(unsigned long ticks)
+{
+ if (ticks > 1) {
+ initial_match = OSMR0;
+ OSMR0 = initial_match + ticks * LATCH;
+ match_posponed = 1;
+ }
+}
+
+static irqreturn_t
+pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ if ( (signed long)(initial_match - OSCR) <= 8 )
+ return pxa_timer_interrupt(irq, dev_id, regs);
+ }
+ return IRQ_NONE;
+}
+
+static struct dyn_tick_timer pxa_dyn_tick = {
+ .enable = pxa_dyn_tick_enable_disable,
+ .disable = pxa_dyn_tick_enable_disable,
+ .reprogram = pxa_dyn_tick_reprogram,
+ .handler = pxa_dyn_tick_handler,
+};
+#endif
+
#ifdef CONFIG_PM
static unsigned long osmr[4], oier;
@@ -161,4 +210,7 @@
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
.offset = pxa_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+ .dyn_tick = &pxa_dyn_tick,
+#endif
};
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index d4d03d0..06807c6 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -2,6 +2,13 @@
menu "S3C24XX Implementations"
+config MACH_ANUBIS
+ bool "Simtec Electronics ANUBIS"
+ select CPU_S3C2440
+ help
+ Say Y gere if you are using the Simtec Electronics ANUBIS
+ development system
+
config ARCH_BAST
bool "Simtec Electronics BAST (EB2410ITX)"
select CPU_S3C2410
@@ -11,6 +18,14 @@
Product page: <http://www.simtec.co.uk/products/EB2410ITX/>.
+config BAST_PC104_IRQ
+ bool "BAST PC104 IRQ support"
+ depends on ARCH_BAST
+ default y
+ help
+ Say Y here to enable the PC104 IRQ routing on the
+ Simtec BAST (EB2410ITX)
+
config ARCH_H1940
bool "IPAQ H1940"
select CPU_S3C2410
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 55ed7c7..b4f1e05 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -26,8 +26,13 @@
obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
+# bast extras
+
+obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
+
# machine specific support
+obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
obj-$(CONFIG_MACH_N30) += mach-n30.o
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index 5e5bbe8..fbbeb05 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/bast-irq.c
*
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright (c) 2003,2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://www.simtec.co.uk/products/EB2410ITX/
@@ -21,7 +21,8 @@
*
* Modifications:
* 08-Jan-2003 BJD Moved from central IRQ code
- */
+ * 21-Aug-2005 BJD Fixed missing code and compile errors
+*/
#include <linux/init.h>
@@ -30,12 +31,19 @@
#include <linux/ptrace.h>
#include <linux/sysdev.h>
+#include <asm/mach-types.h>
+
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/mach/irq.h>
-#include <asm/hardware/s3c2410/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-irq.h>
+
+#include "irq.h"
#if 0
#include <asm/debug-ll.h>
@@ -79,15 +87,15 @@
temp = __raw_readb(BAST_VA_PC104_IRQMASK);
temp &= ~bast_pc104_irqmasks[irqno];
__raw_writeb(temp, BAST_VA_PC104_IRQMASK);
-
- if (temp == 0)
- bast_extint_mask(IRQ_ISA);
}
static void
-bast_pc104_ack(unsigned int irqno)
+bast_pc104_maskack(unsigned int irqno)
{
- bast_extint_ack(IRQ_ISA);
+ struct irqdesc *desc = irq_desc + IRQ_ISA;
+
+ bast_pc104_mask(irqno);
+ desc->chip->ack(IRQ_ISA);
}
static void
@@ -98,14 +106,12 @@
temp = __raw_readb(BAST_VA_PC104_IRQMASK);
temp |= bast_pc104_irqmasks[irqno];
__raw_writeb(temp, BAST_VA_PC104_IRQMASK);
-
- bast_extint_unmask(IRQ_ISA);
}
-static struct bast_pc104_chip = {
+static struct irqchip bast_pc104_chip = {
.mask = bast_pc104_mask,
.unmask = bast_pc104_unmask,
- .ack = bast_pc104_ack
+ .ack = bast_pc104_maskack
};
static void
@@ -119,14 +125,49 @@
stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf;
- for (i = 0; i < 4 && stat != 0; i++) {
- if (stat & 1) {
- irqno = bast_pc104_irqs[i];
- desc = irq_desc + irqno;
+ if (unlikely(stat == 0)) {
+ /* ack if we get an irq with nothing (ie, startup) */
- desc->handle(irqno, desc, regs);
+ desc = irq_desc + IRQ_ISA;
+ desc->chip->ack(IRQ_ISA);
+ } else {
+ /* handle the IRQ */
+
+ for (i = 0; stat != 0; i++, stat >>= 1) {
+ if (stat & 1) {
+ irqno = bast_pc104_irqs[i];
+
+ desc_handle_irq(irqno, irq_desc + irqno, regs);
+ }
}
-
- stat >>= 1;
}
}
+
+static __init int bast_irq_init(void)
+{
+ unsigned int i;
+
+ if (machine_is_bast()) {
+ printk(KERN_INFO "BAST PC104 IRQ routing, (c) 2005 Simtec Electronics\n");
+
+ /* zap all the IRQs */
+
+ __raw_writeb(0x0, BAST_VA_PC104_IRQMASK);
+
+ set_irq_chained_handler(IRQ_ISA, bast_irq_pc104_demux);
+
+ /* reigster our IRQs */
+
+ for (i = 0; i < 4; i++) {
+ unsigned int irqno = bast_pc104_irqs[i];
+
+ set_irq_chip(irqno, &bast_pc104_chip);
+ set_irq_handler(irqno, do_level_IRQ);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+ }
+
+ return 0;
+}
+
+arch_initcall(bast_irq_init);
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 9a66050..f596082 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -388,6 +388,7 @@
unsigned long hclk,
unsigned long pclk)
{
+ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
struct clk *clkp = init_clocks;
int ptr;
int ret;
@@ -446,5 +447,13 @@
}
}
+ /* show the clock-slow value */
+
+ printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
+ print_mhz(xtal / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
+ (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
+ (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
+ (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
+
return 0;
}
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 973a5fe..66d8c06 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -184,14 +184,14 @@
.ack = s3c_irq_maskack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
- .wake = s3c_irq_wake
+ .set_wake = s3c_irq_wake
};
static struct irqchip s3c_irq_chip = {
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
- .wake = s3c_irq_wake
+ .set_wake = s3c_irq_wake
};
/* S3C2410_EINTMASK
@@ -350,16 +350,16 @@
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmask,
.ack = s3c_irqext_ack,
- .type = s3c_irqext_type,
- .wake = s3c_irqext_wake
+ .set_type = s3c_irqext_type,
+ .set_wake = s3c_irqext_wake
};
static struct irqchip s3c_irq_eint0t4 = {
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
- .wake = s3c_irq_wake,
- .type = s3c_irqext_type,
+ .set_wake = s3c_irq_wake,
+ .set_type = s3c_irqext_type,
};
/* mask values for the parent registers for each of the interrupt types */
@@ -496,11 +496,11 @@
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_TC;
- mydesc->handle( IRQ_TC, mydesc, regs);
+ desc_handle_irq(IRQ_TC, mydesc, regs);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_ADC;
- mydesc->handle(IRQ_ADC, mydesc, regs);
+ desc_handle_irq(IRQ_ADC, mydesc, regs);
}
}
}
@@ -529,17 +529,17 @@
desc = irq_desc + start;
if (subsrc & 1)
- desc->handle(start, desc, regs);
+ desc_handle_irq(start, desc, regs);
desc++;
if (subsrc & 2)
- desc->handle(start+1, desc, regs);
+ desc_handle_irq(start+1, desc, regs);
desc++;
if (subsrc & 4)
- desc->handle(start+2, desc, regs);
+ desc_handle_irq(start+2, desc, regs);
}
}
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
new file mode 100644
index 0000000..f87aa0b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-anubis.c
@@ -0,0 +1,270 @@
+/* linux/arch/arm/mach-s3c2410/mach-anubis.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ *
+ *
+ * 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.
+ *
+ * Modifications:
+ * 02-May-2005 BJD Copied from mach-bast.c
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/anubis-map.h>
+#include <asm/arch/anubis-irq.h>
+#include <asm/arch/anubis-cpld.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/nand.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+#define COPYRIGHT ", (c) 2005 Simtec Electronics"
+
+static struct map_desc anubis_iodesc[] __initdata = {
+ /* ISA IO areas */
+
+ { (u32)S3C24XX_VA_ISA_BYTE, 0x0, SZ_16M, MT_DEVICE },
+ { (u32)S3C24XX_VA_ISA_WORD, 0x0, SZ_16M, MT_DEVICE },
+
+ /* we could possibly compress the next set down into a set of smaller tables
+ * pagetables, but that would mean using an L2 section, and it still means
+ * we cannot actually feed the same register to an LDR due to 16K spacing
+ */
+
+ /* CPLD control registers */
+
+ { (u32)ANUBIS_VA_CTRL1, ANUBIS_PA_CTRL1, SZ_4K, MT_DEVICE },
+ { (u32)ANUBIS_VA_CTRL2, ANUBIS_PA_CTRL2, SZ_4K, MT_DEVICE },
+
+ /* IDE drives */
+
+ { (u32)ANUBIS_IDEPRI, S3C2410_CS3, SZ_1M, MT_DEVICE },
+ { (u32)ANUBIS_IDEPRIAUX, S3C2410_CS3+(1<<26), SZ_1M, MT_DEVICE },
+
+ { (u32)ANUBIS_IDESEC, S3C2410_CS4, SZ_1M, MT_DEVICE },
+ { (u32)ANUBIS_IDESECAUX, S3C2410_CS4+(1<<26), SZ_1M, MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c24xx_uart_clksrc anubis_serial_clocks[] = {
+ [0] = {
+ .name = "uclk",
+ .divisor = 1,
+ .min_baud = 0,
+ .max_baud = 0,
+ },
+ [1] = {
+ .name = "pclk",
+ .divisor = 1,
+ .min_baud = 0,
+ .max_baud = 0.
+ }
+};
+
+
+static struct s3c2410_uartcfg anubis_uartcfgs[] = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ .clocks = anubis_serial_clocks,
+ .clocks_size = ARRAY_SIZE(anubis_serial_clocks)
+ },
+ [1] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ .clocks = anubis_serial_clocks,
+ .clocks_size = ARRAY_SIZE(anubis_serial_clocks)
+ },
+};
+
+/* NAND Flash on Anubis board */
+
+static int external_map[] = { 2 };
+static int chip0_map[] = { 0 };
+static int chip1_map[] = { 1 };
+
+struct mtd_partition anubis_default_nand_part[] = {
+ [0] = {
+ .name = "Boot Agent",
+ .size = SZ_16K,
+ .offset = 0
+ },
+ [1] = {
+ .name = "/boot",
+ .size = SZ_4M - SZ_16K,
+ .offset = SZ_16K,
+ },
+ [2] = {
+ .name = "user1",
+ .offset = SZ_4M,
+ .size = SZ_32M - SZ_4M,
+ },
+ [3] = {
+ .name = "user2",
+ .offset = SZ_32M,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
+/* the Anubis has 3 selectable slots for nand-flash, the two
+ * on-board chip areas, as well as the external slot.
+ *
+ * Note, there is no current hot-plug support for the External
+ * socket.
+*/
+
+static struct s3c2410_nand_set anubis_nand_sets[] = {
+ [1] = {
+ .name = "External",
+ .nr_chips = 1,
+ .nr_map = external_map,
+ .nr_partitions = ARRAY_SIZE(anubis_default_nand_part),
+ .partitions = anubis_default_nand_part
+ },
+ [0] = {
+ .name = "chip0",
+ .nr_chips = 1,
+ .nr_map = chip0_map,
+ .nr_partitions = ARRAY_SIZE(anubis_default_nand_part),
+ .partitions = anubis_default_nand_part
+ },
+ [2] = {
+ .name = "chip1",
+ .nr_chips = 1,
+ .nr_map = chip1_map,
+ .nr_partitions = ARRAY_SIZE(anubis_default_nand_part),
+ .partitions = anubis_default_nand_part
+ },
+};
+
+static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+ unsigned int tmp;
+
+ slot = set->nr_map[slot] & 3;
+
+ pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n",
+ slot, set, set->nr_map);
+
+ tmp = __raw_readb(ANUBIS_VA_CTRL1);
+ tmp &= ~ANUBIS_CTRL1_NANDSEL;
+ tmp |= slot;
+
+ pr_debug("anubis_nand: ctrl1 now %02x\n", tmp);
+
+ __raw_writeb(tmp, ANUBIS_VA_CTRL1);
+}
+
+static struct s3c2410_platform_nand anubis_nand_info = {
+ .tacls = 25,
+ .twrph0 = 80,
+ .twrph1 = 80,
+ .nr_sets = ARRAY_SIZE(anubis_nand_sets),
+ .sets = anubis_nand_sets,
+ .select_chip = anubis_nand_select,
+};
+
+
+/* Standard Anubis devices */
+
+static struct platform_device *anubis_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_wdt,
+ &s3c_device_adc,
+ &s3c_device_i2c,
+ &s3c_device_rtc,
+ &s3c_device_nand,
+};
+
+static struct clk *anubis_clocks[] = {
+ &s3c24xx_dclk0,
+ &s3c24xx_dclk1,
+ &s3c24xx_clkout0,
+ &s3c24xx_clkout1,
+ &s3c24xx_uclk,
+};
+
+static struct s3c24xx_board anubis_board __initdata = {
+ .devices = anubis_devices,
+ .devices_count = ARRAY_SIZE(anubis_devices),
+ .clocks = anubis_clocks,
+ .clocks_count = ARRAY_SIZE(anubis_clocks)
+};
+
+void __init anubis_map_io(void)
+{
+ /* initialise the clocks */
+
+ s3c24xx_dclk0.parent = NULL;
+ s3c24xx_dclk0.rate = 12*1000*1000;
+
+ s3c24xx_dclk1.parent = NULL;
+ s3c24xx_dclk1.rate = 24*1000*1000;
+
+ s3c24xx_clkout0.parent = &s3c24xx_dclk0;
+ s3c24xx_clkout1.parent = &s3c24xx_dclk1;
+
+ s3c24xx_uclk.parent = &s3c24xx_clkout1;
+
+ s3c_device_nand.dev.platform_data = &anubis_nand_info;
+
+ s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
+ s3c24xx_init_clocks(0);
+ s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
+ s3c24xx_set_board(&anubis_board);
+
+ /* ensure that the GPIO is setup */
+ s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+}
+
+MACHINE_START(ANUBIS, "Simtec-Anubis")
+ /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = anubis_map_io,
+ .init_irq = s3c24xx_init_irq,
+ .timer = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 79044d9..66bf5bb 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -110,34 +110,24 @@
s3c24xx_init_irq();
}
-
-static int n30_usbstart_thread(void *unused)
-{
- /* Turn off suspend on both USB ports, and switch the
- * selectable USB port to USB device mode. */
- writel(readl(S3C2410_MISCCR) & ~0x00003008, S3C2410_MISCCR);
-
- /* Turn off the D+ pull up for 3 seconds so that the USB host
- * at the other end will do a rescan of the USB bus. */
- s3c2410_gpio_setpin(S3C2410_GPB3, 0);
-
- msleep_interruptible(3*HZ);
-
- s3c2410_gpio_setpin(S3C2410_GPB3, 1);
-
- return 0;
-}
-
+/* GPB3 is the line that controls the pull-up for the USB D+ line */
void __init n30_init(void)
{
s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
- kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
+ /* Turn off suspend on both USB ports, and switch the
+ * selectable USB port to USB device mode. */
+
+ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+ S3C2410_MISCCR_USBSUSPND0 |
+ S3C2410_MISCCR_USBSUSPND1, 0x0);
}
MACHINE_START(N30, "Acer-N30")
- /* Maintainer: Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org> */
+ /* Maintainer: Christer Weinigel <christer@weinigel.se>,
+ Ben Dooks <ben-linux@fluff.org>
+ */
.phys_ram = S3C2410_SDRAM_PA,
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
index 2cb7988..4c7ccef 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/mach-s3c2410/pm-simtec.c
@@ -48,7 +48,7 @@
/* check which machine we are running on */
- if (!machine_is_bast() && !machine_is_vr1000())
+ if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis())
return 0;
printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index 13a48ee..fe57d96 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -585,14 +585,16 @@
s3c2410_pm_check_store();
- // need to make some form of time-delta
-
/* send the cpu to sleep... */
__raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
s3c2410_cpu_suspend(regs_save);
+ /* restore the cpu state */
+
+ cpu_init();
+
/* unset the return-from-sleep flag, to ensure reset */
tmp = __raw_readl(S3C2410_GSTATUS2);
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c
index b018a1f..c67e097 100644
--- a/arch/arm/mach-s3c2410/s3c2440-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2440-clock.c
@@ -68,6 +68,7 @@
static int s3c2440_clk_add(struct sys_device *sysdev)
{
unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+ unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
struct clk *clk_h;
struct clk *clk_p;
struct clk *clk_xtal;
@@ -80,8 +81,9 @@
s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal->rate);
- printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
- print_mhz(s3c2440_clk_upll.rate));
+ printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz, DVS %s\n",
+ print_mhz(s3c2440_clk_upll.rate),
+ (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
clk_p = clk_get(NULL, "pclk");
clk_h = clk_get(NULL, "hclk");
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2410/s3c2440-irq.c
index 7cb9912..278d004 100644
--- a/arch/arm/mach-s3c2410/s3c2440-irq.c
+++ b/arch/arm/mach-s3c2410/s3c2440-irq.c
@@ -64,11 +64,11 @@
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_S3C2440_WDT;
- mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_WDT, mydesc, regs);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_S3C2440_AC97;
- mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_AC97, mydesc, regs);
}
}
}
@@ -122,11 +122,11 @@
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_S3C2440_CAM_C;
- mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_S3C2440_CAM_P;
- mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
}
}
}
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c
index 765a3a9..c0acfb2 100644
--- a/arch/arm/mach-s3c2410/time.c
+++ b/arch/arm/mach-s3c2410/time.c
@@ -164,7 +164,7 @@
/* configure the system for whichever machine is in use */
- if (machine_is_bast() || machine_is_vr1000()) {
+ if (machine_is_bast() || machine_is_vr1000() || machine_is_anubis()) {
/* timer is at 12MHz, scaler is 1 */
timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
tcnt = 12000000 / HZ;
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 66a929c..c131a52 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -98,8 +98,8 @@
.ack = sa1100_low_gpio_ack,
.mask = sa1100_low_gpio_mask,
.unmask = sa1100_low_gpio_unmask,
- .type = sa1100_gpio_type,
- .wake = sa1100_low_gpio_wake,
+ .set_type = sa1100_gpio_type,
+ .set_wake = sa1100_low_gpio_wake,
};
/*
@@ -126,7 +126,7 @@
mask >>= 11;
do {
if (mask & 1)
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
mask >>= 1;
irq++;
desc++;
@@ -181,8 +181,8 @@
.ack = sa1100_high_gpio_ack,
.mask = sa1100_high_gpio_mask,
.unmask = sa1100_high_gpio_unmask,
- .type = sa1100_gpio_type,
- .wake = sa1100_high_gpio_wake,
+ .set_type = sa1100_gpio_type,
+ .set_wake = sa1100_high_gpio_wake,
};
/*
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 1405383..fc06164 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -61,12 +61,12 @@
if (irr & IRR_ETHERNET) {
d = irq_desc + IRQ_NEPONSET_SMC9196;
- d->handle(IRQ_NEPONSET_SMC9196, d, regs);
+ desc_handle_irq(IRQ_NEPONSET_SMC9196, d, regs);
}
if (irr & IRR_USAR) {
d = irq_desc + IRQ_NEPONSET_USAR;
- d->handle(IRQ_NEPONSET_USAR, d, regs);
+ desc_handle_irq(IRQ_NEPONSET_USAR, d, regs);
}
desc->chip->unmask(irq);
@@ -74,7 +74,7 @@
if (irr & IRR_SA1111) {
d = irq_desc + IRQ_NEPONSET_SA1111;
- d->handle(IRQ_NEPONSET_SA1111, d, regs);
+ desc_handle_irq(IRQ_NEPONSET_SA1111, d, regs);
}
}
}
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 0eeb361..47e0420 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -70,15 +70,11 @@
return usec;
}
-/*
- * We will be entered with IRQs enabled.
- *
- * Loop until we get ahead of the free running timer.
- * This ensures an exact clock tick count and time accuracy.
- * IRQs are disabled inside the loop to ensure coherence between
- * lost_ticks (updated in do_timer()) and the match reg value, so we
- * can use do_gettimeofday() from interrupt handlers.
- */
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
static irqreturn_t
sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -86,6 +82,21 @@
write_seqlock(&xtime_lock);
+#ifdef CONFIG_NO_IDLE_HZ
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ }
+#endif
+
+ /*
+ * Loop until we get ahead of the free running timer.
+ * This ensures an exact clock tick count and time accuracy.
+ * Since IRQs are disabled at this point, coherence between
+ * lost_ticks(updated in do_timer()) and the match reg value is
+ * ensured, hence we can use do_gettimeofday() from interrupt
+ * handlers.
+ */
do {
timer_tick(regs);
OSSR = OSSR_M0; /* Clear match on timer 0 */
@@ -120,6 +131,42 @@
OSCR = 0; /* initialize free-running timer, force first match */
}
+#ifdef CONFIG_NO_IDLE_HZ
+static int sa1100_dyn_tick_enable_disable(void)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static void sa1100_dyn_tick_reprogram(unsigned long ticks)
+{
+ if (ticks > 1) {
+ initial_match = OSMR0;
+ OSMR0 = initial_match + ticks * LATCH;
+ match_posponed = 1;
+ }
+}
+
+static irqreturn_t
+sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ if ((signed long)(initial_match - OSCR) <= 0)
+ return sa1100_timer_interrupt(irq, dev_id, regs);
+ }
+ return IRQ_NONE;
+}
+
+static struct dyn_tick_timer sa1100_dyn_tick = {
+ .enable = sa1100_dyn_tick_enable_disable,
+ .disable = sa1100_dyn_tick_enable_disable,
+ .reprogram = sa1100_dyn_tick_reprogram,
+ .handler = sa1100_dyn_tick_handler,
+};
+#endif
+
#ifdef CONFIG_PM
unsigned long osmr[4], oier;
@@ -156,4 +203,7 @@
.suspend = sa1100_timer_suspend,
.resume = sa1100_timer_resume,
.offset = sa1100_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+ .dyn_tick = &sa1100_dyn_tick,
+#endif
};
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index f01c0f8..3c8862f 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -108,7 +108,7 @@
irq += IRQ_SIC_START;
desc = irq_desc + irq;
- desc->handle(irq, desc, regs);
+ desc_handle_irq(irq, desc, regs);
} while (status);
}
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 81f4a8a..4b39d86 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -45,7 +45,7 @@
#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
-#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
+#define LDSTHD_I_BIT(i) (i & (1 << 22)) /* double/half-word immed */
#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
#define RN_BITS(i) ((i >> 16) & 15) /* Rn */
@@ -68,6 +68,7 @@
static unsigned long ai_skipped;
static unsigned long ai_half;
static unsigned long ai_word;
+static unsigned long ai_dword;
static unsigned long ai_multi;
static int ai_usermode;
@@ -93,6 +94,8 @@
p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
p += sprintf(p, "Half:\t\t%lu\n", ai_half);
p += sprintf(p, "Word:\t\t%lu\n", ai_word);
+ if (cpu_architecture() >= CPU_ARCH_ARMv5TE)
+ p += sprintf(p, "DWord:\t\t%lu\n", ai_dword);
p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
usermode_action[ai_usermode]);
@@ -283,12 +286,6 @@
{
unsigned int rd = RD_BITS(instr);
- if ((instr & 0x01f00ff0) == 0x01000090)
- goto swp;
-
- if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
- goto bad;
-
ai_half += 1;
if (user_mode(regs))
@@ -323,10 +320,47 @@
return TYPE_LDST;
- swp:
- printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
- bad:
- return TYPE_ERROR;
+ fault:
+ return TYPE_FAULT;
+}
+
+static int
+do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
+ struct pt_regs *regs)
+{
+ unsigned int rd = RD_BITS(instr);
+
+ ai_dword += 1;
+
+ if (user_mode(regs))
+ goto user;
+
+ if ((instr & 0xf0) == 0xd0) {
+ unsigned long val;
+ get32_unaligned_check(val, addr);
+ regs->uregs[rd] = val;
+ get32_unaligned_check(val, addr+4);
+ regs->uregs[rd+1] = val;
+ } else {
+ put32_unaligned_check(regs->uregs[rd], addr);
+ put32_unaligned_check(regs->uregs[rd+1], addr+4);
+ }
+
+ return TYPE_LDST;
+
+ user:
+ if ((instr & 0xf0) == 0xd0) {
+ unsigned long val;
+ get32t_unaligned_check(val, addr);
+ regs->uregs[rd] = val;
+ get32t_unaligned_check(val, addr+4);
+ regs->uregs[rd+1] = val;
+ } else {
+ put32t_unaligned_check(regs->uregs[rd], addr);
+ put32t_unaligned_check(regs->uregs[rd+1], addr+4);
+ }
+
+ return TYPE_LDST;
fault:
return TYPE_FAULT;
@@ -617,12 +651,20 @@
regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
switch (CODING_BITS(instr)) {
- case 0x00000000: /* ldrh or strh */
- if (LDSTH_I_BIT(instr))
+ case 0x00000000: /* 3.13.4 load/store instruction extensions */
+ if (LDSTHD_I_BIT(instr))
offset.un = (instr & 0xf00) >> 4 | (instr & 15);
else
offset.un = regs->uregs[RM_BITS(instr)];
- handler = do_alignment_ldrhstrh;
+
+ if ((instr & 0x000000f0) == 0x000000b0 || /* LDRH, STRH */
+ (instr & 0x001000f0) == 0x001000f0) /* LDRSH */
+ handler = do_alignment_ldrhstrh;
+ else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */
+ (instr & 0x001000f0) == 0x000000f0) /* STRD */
+ handler = do_alignment_ldrdstrd;
+ else
+ goto bad;
break;
case 0x04000000: /* ldr or str immediate */
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 3c655c5..d125a3d 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -275,11 +275,9 @@
int i;
for (i = 0; i < 16; i += 1) {
- alloc_init_section(virt, phys & SUPERSECTION_MASK,
- prot | PMD_SECT_SUPER);
+ alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
virt += (PGDIR_SIZE / 2);
- phys += (PGDIR_SIZE / 2);
}
}
@@ -297,14 +295,10 @@
pte_t *ptep;
if (pmd_none(*pmdp)) {
- unsigned long pmdval;
ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
sizeof(pte_t));
- pmdval = __pa(ptep) | prot_l1;
- pmdp[0] = __pmd(pmdval);
- pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
- flush_pmd_entry(pmdp);
+ __pmd_populate(pmdp, __pa(ptep) | prot_l1);
}
ptep = pte_offset_kernel(pmdp, virt);
@@ -459,7 +453,7 @@
for (i = 0; i < 16; i++) {
unsigned long v = pgprot_val(protection_map[i]);
- v &= (~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
+ v = (v & ~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
protection_map[i] = __pgprot(v);
}
@@ -583,23 +577,23 @@
*/
void setup_mm_for_reboot(char mode)
{
- unsigned long pmdval;
+ unsigned long base_pmdval;
pgd_t *pgd;
- pmd_t *pmd;
int i;
- int cpu_arch = cpu_architecture();
if (current->mm && current->mm->pgd)
pgd = current->mm->pgd;
else
pgd = init_mm.pgd;
- for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) {
- pmdval = (i << PGDIR_SHIFT) |
- PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
- PMD_TYPE_SECT;
- if (cpu_arch <= CPU_ARCH_ARMv5TEJ)
- pmdval |= PMD_BIT4;
+ base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
+ if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ)
+ base_pmdval |= PMD_BIT4;
+
+ for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
+ unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
+ pmd_t *pmd;
+
pmd = pmd_off(pgd, i << PGDIR_SHIFT);
pmd[0] = __pmd(pmdval);
pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
index 0ee214b..189ef6a 100644
--- a/arch/arm/mm/proc-arm6_7.S
+++ b/arch/arm/mm/proc-arm6_7.S
@@ -38,8 +38,8 @@
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
ldr r8, [r0] @ read arm instruction
- tst r8, #1 << 20 @ L = 1 -> write?
- orreq r1, r1, #1 << 8 @ yes.
+ tst r8, #1 << 20 @ L = 0 -> write?
+ orreq r1, r1, #1 << 11 @ yes.
and r7, r8, #15 << 24
add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine
nop
@@ -71,8 +71,8 @@
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
ldr r8, [r2] @ read arm instruction
- tst r8, #1 << 20 @ L = 1 -> write?
- orreq r1, r1, #1 << 8 @ yes.
+ tst r8, #1 << 20 @ L = 0 -> write?
+ orreq r1, r1, #1 << 11 @ yes.
and r7, r8, #14 << 24
teq r7, #8 << 24 @ was it ldm/stm
movne pc, lr
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 3453658..9693e9b 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -91,6 +91,13 @@
Kernel internal timer frequency should be a divisor of 32768,
such as 64 or 128.
+config OMAP_DM_TIMER
+ bool "Use dual-mode timer"
+ default n
+ depends on ARCH_OMAP16XX
+ help
+ Select this option if you want to use OMAP Dual-Mode timers.
+
choice
prompt "Low-level debug console UART"
depends on ARCH_OMAP
@@ -107,6 +114,15 @@
endchoice
+config OMAP_SERIAL_WAKE
+ bool "Enable wake-up events for serial ports"
+ depends OMAP_MUX
+ default y
+ help
+ Select this option if you want to have your system wake up
+ to data on the serial RX line. This allows you to wake the
+ system from serial console.
+
endmenu
endif
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 531e11a..7e144f9 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -3,7 +3,7 @@
#
# Common support
-obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
+obj-y := common.o sram.o sram-fn.o clock.o dma.o mux.o gpio.o mcbsp.o usb.o
obj-m :=
obj-n :=
obj- :=
@@ -15,3 +15,5 @@
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
+obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
+
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 59d91b3..52a58b2 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -21,6 +21,7 @@
#include <asm/arch/usb.h>
#include "clock.h"
+#include "sram.h"
static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
@@ -141,7 +142,7 @@
static struct clk armper_ck = {
.name = "armper_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
RATE_CKCTL,
.enable_reg = ARM_IDLECT2,
.enable_bit = EN_PERCK,
@@ -385,7 +386,8 @@
.name = "uart2_ck",
/* Direct from ULPD, no parent */
.rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+ ALWAYS_ENABLED,
.enable_reg = MOD_CONF_CTRL_0,
.enable_bit = 30, /* Chooses between 12MHz and 48MHz */
.set_rate = &set_uart_rate,
@@ -443,6 +445,15 @@
.enable_bit = 8 /* UHOST_EN */,
};
+static struct clk usb_dc_ck = {
+ .name = "usb_dc_ck",
+ /* Direct from ULPD, no parent */
+ .rate = 48000000,
+ .flags = CLOCK_IN_OMAP16XX | RATE_FIXED,
+ .enable_reg = SOFT_REQ_REG,
+ .enable_bit = 4,
+};
+
static struct clk mclk_1510 = {
.name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
@@ -552,6 +563,7 @@
&uart3_16xx,
&usb_clko,
&usb_hhc_ck1510, &usb_hhc_ck16xx,
+ &usb_dc_ck,
&mclk_1510, &mclk_16xx,
&bclk_1510, &bclk_16xx,
&mmc1_ck,
@@ -946,14 +958,13 @@
if (!ptr->rate)
return -EINVAL;
- if (!ptr->rate)
- return -EINVAL;
+ /*
+ * In most cases we should not need to reprogram DPLL.
+ * Reprogramming the DPLL is tricky, it must be done from SRAM.
+ */
+ omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
- if (unlikely(ck_dpll1.rate == 0)) {
- omap_writew(ptr->dpllctl_val, DPLL_CTL);
- ck_dpll1.rate = ptr->pll_rate;
- }
- omap_writew(ptr->ckctl_val, ARM_CKCTL);
+ ck_dpll1.rate = ptr->pll_rate;
propagate_rate(&ck_dpll1);
return 0;
}
@@ -1224,9 +1235,11 @@
#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
propagate_rate(&ck_ref);
- printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
+ "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
- ck_dpll1.rate, arm_ck.rate);
+ ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
+ arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
#ifdef CONFIG_MACH_OMAP_PERSEUS2
/* Select slicer output as OMAP input clock */
@@ -1271,7 +1284,9 @@
struct clk *p;
__u32 regval32;
- omap_writew(0, SOFT_REQ_REG);
+ /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
+ regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
+ omap_writew(regval32, SOFT_REQ_REG);
omap_writew(0, SOFT_REQ_REG2);
list_for_each_entry(p, &clocks, node) {
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index ea967a8..6cb20ae 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -26,6 +26,7 @@
#include <asm/hardware/clock.h>
#include <asm/io.h>
#include <asm/mach-types.h>
+#include <asm/setup.h>
#include <asm/arch/board.h>
#include <asm/arch/mux.h>
@@ -35,11 +36,11 @@
#define NO_LENGTH_CHECK 0xffffffff
-extern int omap_bootloader_tag_len;
-extern u8 omap_bootloader_tag[];
+unsigned char omap_bootloader_tag[512];
+int omap_bootloader_tag_len;
struct omap_board_config_kernel *omap_board_config;
-int omap_board_config_size = 0;
+int omap_board_config_size;
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
{
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c0a5c2f..da7b651 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -425,7 +425,7 @@
dma_chan[ch + 6].saved_csr = csr >> 7;
csr &= 0x7f;
}
- if (!csr)
+ if ((csr & 0x3f) == 0)
return 0;
if (unlikely(dma_chan[ch].dev_id == -1)) {
printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n",
@@ -890,11 +890,11 @@
w |= 1 << 8;
omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+ lcd_dma.active = 1;
+
w = omap_readw(OMAP1610_DMA_LCD_CCR);
w |= 1 << 7;
omap_writew(w, OMAP1610_DMA_LCD_CCR);
-
- lcd_dma.active = 1;
}
void omap_setup_lcd_dma(void)
@@ -965,8 +965,8 @@
*/
dma_addr_t omap_get_dma_src_pos(int lch)
{
- return (dma_addr_t) (OMAP_DMA_CSSA_L(lch) |
- (OMAP_DMA_CSSA_U(lch) << 16));
+ return (dma_addr_t) (omap_readw(OMAP_DMA_CSSA_L(lch)) |
+ (omap_readw(OMAP_DMA_CSSA_U(lch)) << 16));
}
/*
@@ -979,8 +979,18 @@
*/
dma_addr_t omap_get_dma_dst_pos(int lch)
{
- return (dma_addr_t) (OMAP_DMA_CDSA_L(lch) |
- (OMAP_DMA_CDSA_U(lch) << 16));
+ return (dma_addr_t) (omap_readw(OMAP_DMA_CDSA_L(lch)) |
+ (omap_readw(OMAP_DMA_CDSA_U(lch)) << 16));
+}
+
+/*
+ * Returns current source transfer counting for the given DMA channel.
+ * Can be used to monitor the progress of a transfer inside a block.
+ * It must be called with disabled interrupts.
+ */
+int omap_get_dma_src_addr_counter(int lch)
+{
+ return (dma_addr_t) omap_readw(OMAP_DMA_CSAC(lch));
}
int omap_dma_running(void)
@@ -1076,6 +1086,7 @@
EXPORT_SYMBOL(omap_get_dma_src_pos);
EXPORT_SYMBOL(omap_get_dma_dst_pos);
+EXPORT_SYMBOL(omap_get_dma_src_addr_counter);
EXPORT_SYMBOL(omap_clear_dma);
EXPORT_SYMBOL(omap_set_dma_priority);
EXPORT_SYMBOL(omap_request_dma);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
new file mode 100644
index 0000000..a1468d7
--- /dev/null
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -0,0 +1,260 @@
+/*
+ * linux/arch/arm/plat-omap/dmtimer.c
+ *
+ * OMAP Dual-Mode Timers
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/dmtimer.h>
+#include <asm/io.h>
+#include <asm/arch/irqs.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define OMAP_TIMER_COUNT 8
+
+#define OMAP_TIMER_ID_REG 0x00
+#define OMAP_TIMER_OCP_CFG_REG 0x10
+#define OMAP_TIMER_SYS_STAT_REG 0x14
+#define OMAP_TIMER_STAT_REG 0x18
+#define OMAP_TIMER_INT_EN_REG 0x1c
+#define OMAP_TIMER_WAKEUP_EN_REG 0x20
+#define OMAP_TIMER_CTRL_REG 0x24
+#define OMAP_TIMER_COUNTER_REG 0x28
+#define OMAP_TIMER_LOAD_REG 0x2c
+#define OMAP_TIMER_TRIGGER_REG 0x30
+#define OMAP_TIMER_WRITE_PEND_REG 0x34
+#define OMAP_TIMER_MATCH_REG 0x38
+#define OMAP_TIMER_CAPTURE_REG 0x3c
+#define OMAP_TIMER_IF_CTRL_REG 0x40
+
+
+static struct dmtimer_info_struct {
+ struct list_head unused_timers;
+ struct list_head reserved_timers;
+} dm_timer_info;
+
+static struct omap_dm_timer dm_timers[] = {
+ { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
+ { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
+ { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
+ { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
+ { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
+ { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
+ { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
+ { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
+ { .base=0x0 },
+};
+
+
+static spinlock_t dm_timer_lock;
+
+
+inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
+{
+ omap_writel(value, timer->base + reg);
+ while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
+ ;
+}
+
+u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
+{
+ return omap_readl(timer->base + reg);
+}
+
+int omap_dm_timers_active(void)
+{
+ struct omap_dm_timer *timer;
+
+ for (timer = &dm_timers[0]; timer->base; ++timer)
+ if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
+ OMAP_TIMER_CTRL_ST)
+ return 1;
+
+ return 0;
+}
+
+
+void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
+{
+ int n = (timer - dm_timers) << 1;
+ u32 l;
+
+ l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+ l |= source << n;
+ omap_writel(l, MOD_CONF_CTRL_1);
+}
+
+
+static void omap_dm_timer_reset(struct omap_dm_timer *timer)
+{
+ /* Reset and set posted mode */
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
+
+ omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
+}
+
+
+
+struct omap_dm_timer * omap_dm_timer_request(void)
+{
+ struct omap_dm_timer *timer = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dm_timer_lock, flags);
+ if (!list_empty(&dm_timer_info.unused_timers)) {
+ timer = (struct omap_dm_timer *)
+ dm_timer_info.unused_timers.next;
+ list_move_tail((struct list_head *)timer,
+ &dm_timer_info.reserved_timers);
+ }
+ spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+ return timer;
+}
+
+
+void omap_dm_timer_free(struct omap_dm_timer *timer)
+{
+ unsigned long flags;
+
+ omap_dm_timer_reset(timer);
+
+ spin_lock_irqsave(&dm_timer_lock, flags);
+ list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
+ spin_unlock_irqrestore(&dm_timer_lock, flags);
+}
+
+void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
+ unsigned int value)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
+}
+
+unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
+{
+ return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+}
+
+void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
+}
+
+void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
+{
+ u32 l;
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ l |= OMAP_TIMER_CTRL_AR;
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+void omap_dm_timer_trigger(struct omap_dm_timer *timer)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
+}
+
+void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
+{
+ u32 l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ l |= value & 0x3;
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+void omap_dm_timer_start(struct omap_dm_timer *timer)
+{
+ u32 l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ l |= OMAP_TIMER_CTRL_ST;
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+void omap_dm_timer_stop(struct omap_dm_timer *timer)
+{
+ u32 l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ l &= ~0x1;
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
+{
+ return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+}
+
+void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
+}
+
+void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+}
+
+void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
+{
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+}
+
+void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
+{
+ u32 l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ l |= OMAP_TIMER_CTRL_CE;
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+}
+
+
+static inline void __dm_timer_init(void)
+{
+ struct omap_dm_timer *timer;
+
+ spin_lock_init(&dm_timer_lock);
+ INIT_LIST_HEAD(&dm_timer_info.unused_timers);
+ INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
+
+ timer = &dm_timers[0];
+ while (timer->base) {
+ list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
+ omap_dm_timer_reset(timer);
+ timer++;
+ }
+}
+
+static int __init omap_dm_timer_init(void)
+{
+ if (cpu_is_omap16xx())
+ __dm_timer_init();
+ return 0;
+}
+
+arch_initcall(omap_dm_timer_init);
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 1c85b4e..55059a2 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -3,7 +3,7 @@
*
* Support functions for OMAP GPIO
*
- * Copyright (C) 2003 Nokia Corporation
+ * Copyright (C) 2003-2005 Nokia Corporation
* Written by Juha Yrjölä <juha.yrjola@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,11 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/err.h>
#include <asm/hardware.h>
+#include <asm/hardware/clock.h>
#include <asm/irq.h>
#include <asm/arch/irqs.h>
#include <asm/arch/gpio.h>
@@ -29,7 +32,7 @@
/*
* OMAP1510 GPIO registers
*/
-#define OMAP1510_GPIO_BASE 0xfffce000
+#define OMAP1510_GPIO_BASE (void __iomem *)0xfffce000
#define OMAP1510_GPIO_DATA_INPUT 0x00
#define OMAP1510_GPIO_DATA_OUTPUT 0x04
#define OMAP1510_GPIO_DIR_CONTROL 0x08
@@ -43,34 +46,37 @@
/*
* OMAP1610 specific GPIO registers
*/
-#define OMAP1610_GPIO1_BASE 0xfffbe400
-#define OMAP1610_GPIO2_BASE 0xfffbec00
-#define OMAP1610_GPIO3_BASE 0xfffbb400
-#define OMAP1610_GPIO4_BASE 0xfffbbc00
+#define OMAP1610_GPIO1_BASE (void __iomem *)0xfffbe400
+#define OMAP1610_GPIO2_BASE (void __iomem *)0xfffbec00
+#define OMAP1610_GPIO3_BASE (void __iomem *)0xfffbb400
+#define OMAP1610_GPIO4_BASE (void __iomem *)0xfffbbc00
#define OMAP1610_GPIO_REVISION 0x0000
#define OMAP1610_GPIO_SYSCONFIG 0x0010
#define OMAP1610_GPIO_SYSSTATUS 0x0014
#define OMAP1610_GPIO_IRQSTATUS1 0x0018
#define OMAP1610_GPIO_IRQENABLE1 0x001c
+#define OMAP1610_GPIO_WAKEUPENABLE 0x0028
#define OMAP1610_GPIO_DATAIN 0x002c
#define OMAP1610_GPIO_DATAOUT 0x0030
#define OMAP1610_GPIO_DIRECTION 0x0034
#define OMAP1610_GPIO_EDGE_CTRL1 0x0038
#define OMAP1610_GPIO_EDGE_CTRL2 0x003c
#define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
+#define OMAP1610_GPIO_CLEAR_WAKEUPENA 0x00a8
#define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0
#define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc
+#define OMAP1610_GPIO_SET_WAKEUPENA 0x00e8
#define OMAP1610_GPIO_SET_DATAOUT 0x00f0
/*
* OMAP730 specific GPIO registers
*/
-#define OMAP730_GPIO1_BASE 0xfffbc000
-#define OMAP730_GPIO2_BASE 0xfffbc800
-#define OMAP730_GPIO3_BASE 0xfffbd000
-#define OMAP730_GPIO4_BASE 0xfffbd800
-#define OMAP730_GPIO5_BASE 0xfffbe000
-#define OMAP730_GPIO6_BASE 0xfffbe800
+#define OMAP730_GPIO1_BASE (void __iomem *)0xfffbc000
+#define OMAP730_GPIO2_BASE (void __iomem *)0xfffbc800
+#define OMAP730_GPIO3_BASE (void __iomem *)0xfffbd000
+#define OMAP730_GPIO4_BASE (void __iomem *)0xfffbd800
+#define OMAP730_GPIO5_BASE (void __iomem *)0xfffbe000
+#define OMAP730_GPIO6_BASE (void __iomem *)0xfffbe800
#define OMAP730_GPIO_DATA_INPUT 0x00
#define OMAP730_GPIO_DATA_OUTPUT 0x04
#define OMAP730_GPIO_DIR_CONTROL 0x08
@@ -78,14 +84,43 @@
#define OMAP730_GPIO_INT_MASK 0x10
#define OMAP730_GPIO_INT_STATUS 0x14
+/*
+ * omap24xx specific GPIO registers
+ */
+#define OMAP24XX_GPIO1_BASE (void __iomem *)0x48018000
+#define OMAP24XX_GPIO2_BASE (void __iomem *)0x4801a000
+#define OMAP24XX_GPIO3_BASE (void __iomem *)0x4801c000
+#define OMAP24XX_GPIO4_BASE (void __iomem *)0x4801e000
+#define OMAP24XX_GPIO_REVISION 0x0000
+#define OMAP24XX_GPIO_SYSCONFIG 0x0010
+#define OMAP24XX_GPIO_SYSSTATUS 0x0014
+#define OMAP24XX_GPIO_IRQSTATUS1 0x0018
+#define OMAP24XX_GPIO_IRQENABLE1 0x001c
+#define OMAP24XX_GPIO_CTRL 0x0030
+#define OMAP24XX_GPIO_OE 0x0034
+#define OMAP24XX_GPIO_DATAIN 0x0038
+#define OMAP24XX_GPIO_DATAOUT 0x003c
+#define OMAP24XX_GPIO_LEVELDETECT0 0x0040
+#define OMAP24XX_GPIO_LEVELDETECT1 0x0044
+#define OMAP24XX_GPIO_RISINGDETECT 0x0048
+#define OMAP24XX_GPIO_FALLINGDETECT 0x004c
+#define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060
+#define OMAP24XX_GPIO_SETIRQENABLE1 0x0064
+#define OMAP24XX_GPIO_CLEARWKUENA 0x0080
+#define OMAP24XX_GPIO_SETWKUENA 0x0084
+#define OMAP24XX_GPIO_CLEARDATAOUT 0x0090
+#define OMAP24XX_GPIO_SETDATAOUT 0x0094
+
#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff)
struct gpio_bank {
- u32 base;
+ void __iomem *base;
u16 irq;
u16 virtual_irq_start;
- u8 method;
+ int method;
u32 reserved_map;
+ u32 suspend_wakeup;
+ u32 saved_wakeup;
spinlock_t lock;
};
@@ -93,8 +128,9 @@
#define METHOD_GPIO_1510 1
#define METHOD_GPIO_1610 2
#define METHOD_GPIO_730 3
+#define METHOD_GPIO_24XX 4
-#if defined(CONFIG_ARCH_OMAP16XX)
+#ifdef CONFIG_ARCH_OMAP16XX
static struct gpio_bank gpio_bank_1610[5] = {
{ OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO},
{ OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 },
@@ -123,6 +159,15 @@
};
#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+static struct gpio_bank gpio_bank_24xx[4] = {
+ { OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
+ { OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
+ { OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
+ { OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
+};
+#endif
+
static struct gpio_bank *gpio_bank;
static int gpio_bank_count;
@@ -149,14 +194,23 @@
return &gpio_bank[1 + (gpio >> 5)];
}
#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (cpu_is_omap24xx())
+ return &gpio_bank[gpio >> 5];
+#endif
}
static inline int get_gpio_index(int gpio)
{
+#ifdef CONFIG_ARCH_OMAP730
if (cpu_is_omap730())
return gpio & 0x1f;
- else
- return gpio & 0x0f;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (cpu_is_omap24xx())
+ return gpio & 0x1f;
+#endif
+ return gpio & 0x0f;
}
static inline int gpio_valid(int gpio)
@@ -180,6 +234,10 @@
if (cpu_is_omap730() && gpio < 192)
return 0;
#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (cpu_is_omap24xx() && gpio < 128)
+ return 0;
+#endif
return -1;
}
@@ -195,7 +253,7 @@
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
{
- u32 reg = bank->base;
+ void __iomem *reg = bank->base;
u32 l;
switch (bank->method) {
@@ -211,6 +269,9 @@
case METHOD_GPIO_730:
reg += OMAP730_GPIO_DIR_CONTROL;
break;
+ case METHOD_GPIO_24XX:
+ reg += OMAP24XX_GPIO_OE;
+ break;
}
l = __raw_readl(reg);
if (is_input)
@@ -234,7 +295,7 @@
static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
{
- u32 reg = bank->base;
+ void __iomem *reg = bank->base;
u32 l = 0;
switch (bank->method) {
@@ -269,6 +330,13 @@
else
l &= ~(1 << gpio);
break;
+ case METHOD_GPIO_24XX:
+ if (enable)
+ reg += OMAP24XX_GPIO_SETDATAOUT;
+ else
+ reg += OMAP24XX_GPIO_CLEARDATAOUT;
+ l = 1 << gpio;
+ break;
default:
BUG();
return;
@@ -291,7 +359,7 @@
int omap_get_gpio_datain(int gpio)
{
struct gpio_bank *bank;
- u32 reg;
+ void __iomem *reg;
if (check_gpio(gpio) < 0)
return -1;
@@ -310,109 +378,132 @@
case METHOD_GPIO_730:
reg += OMAP730_GPIO_DATA_INPUT;
break;
+ case METHOD_GPIO_24XX:
+ reg += OMAP24XX_GPIO_DATAIN;
+ break;
default:
BUG();
return -1;
}
- return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
+ return (__raw_readl(reg)
+ & (1 << get_gpio_index(gpio))) != 0;
}
-static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge)
+#define MOD_REG_BIT(reg, bit_mask, set) \
+do { \
+ int l = __raw_readl(base + reg); \
+ if (set) l |= bit_mask; \
+ else l &= ~bit_mask; \
+ __raw_writel(l, base + reg); \
+} while(0)
+
+static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
{
- u32 reg = bank->base;
- u32 l;
+ u32 gpio_bit = 1 << gpio;
+
+ MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
+ trigger & IRQT_LOW);
+ MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
+ trigger & IRQT_HIGH);
+ MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
+ trigger & IRQT_RISING);
+ MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
+ trigger & IRQT_FALLING);
+ /* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level
+ * triggering requested. */
+}
+
+static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
+{
+ void __iomem *reg = bank->base;
+ u32 l = 0;
switch (bank->method) {
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_INT_EDGE;
l = __raw_readl(reg);
- if (edge == OMAP_GPIO_RISING_EDGE)
+ if (trigger == IRQT_RISING)
l |= 1 << gpio;
- else
+ else if (trigger == IRQT_FALLING)
l &= ~(1 << gpio);
- __raw_writel(l, reg);
+ else
+ goto bad;
break;
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_CONTROL;
l = __raw_readl(reg);
- if (edge == OMAP_GPIO_RISING_EDGE)
+ if (trigger == IRQT_RISING)
l |= 1 << gpio;
- else
+ else if (trigger == IRQT_FALLING)
l &= ~(1 << gpio);
- __raw_writel(l, reg);
+ else
+ goto bad;
break;
case METHOD_GPIO_1610:
- edge &= 0x03;
if (gpio & 0x08)
reg += OMAP1610_GPIO_EDGE_CTRL2;
else
reg += OMAP1610_GPIO_EDGE_CTRL1;
gpio &= 0x07;
+ /* We allow only edge triggering, i.e. two lowest bits */
+ if (trigger & ~IRQT_BOTHEDGE)
+ BUG();
+ /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */
+ trigger &= 0x03;
l = __raw_readl(reg);
l &= ~(3 << (gpio << 1));
- l |= edge << (gpio << 1);
- __raw_writel(l, reg);
+ l |= trigger << (gpio << 1);
break;
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_CONTROL;
l = __raw_readl(reg);
- if (edge == OMAP_GPIO_RISING_EDGE)
+ if (trigger == IRQT_RISING)
l |= 1 << gpio;
- else
+ else if (trigger == IRQT_FALLING)
l &= ~(1 << gpio);
- __raw_writel(l, reg);
+ else
+ goto bad;
+ break;
+ case METHOD_GPIO_24XX:
+ set_24xx_gpio_triggering(reg, gpio, trigger);
break;
default:
BUG();
- return;
+ goto bad;
}
+ __raw_writel(l, reg);
+ return 0;
+bad:
+ return -EINVAL;
}
-void omap_set_gpio_edge_ctrl(int gpio, int edge)
+static int gpio_irq_type(unsigned irq, unsigned type)
{
struct gpio_bank *bank;
+ unsigned gpio;
+ int retval;
+
+ if (irq > IH_MPUIO_BASE)
+ gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
+ else
+ gpio = irq - IH_GPIO_BASE;
if (check_gpio(gpio) < 0)
- return;
+ return -EINVAL;
+
+ if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE))
+ return -EINVAL;
+
bank = get_gpio_bank(gpio);
spin_lock(&bank->lock);
- _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge);
+ retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
spin_unlock(&bank->lock);
-}
-
-
-static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio)
-{
- u32 reg = bank->base, l;
-
- switch (bank->method) {
- case METHOD_MPUIO:
- l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE);
- return (l & (1 << gpio)) ?
- OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
- case METHOD_GPIO_1510:
- l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL);
- return (l & (1 << gpio)) ?
- OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
- case METHOD_GPIO_1610:
- if (gpio & 0x08)
- reg += OMAP1610_GPIO_EDGE_CTRL2;
- else
- reg += OMAP1610_GPIO_EDGE_CTRL1;
- return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03;
- case METHOD_GPIO_730:
- l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL);
- return (l & (1 << gpio)) ?
- OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
- default:
- BUG();
- return -1;
- }
+ return retval;
}
static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
{
- u32 reg = bank->base;
+ void __iomem *reg = bank->base;
switch (bank->method) {
case METHOD_MPUIO:
@@ -428,6 +519,9 @@
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_STATUS;
break;
+ case METHOD_GPIO_24XX:
+ reg += OMAP24XX_GPIO_IRQSTATUS1;
+ break;
default:
BUG();
return;
@@ -442,7 +536,7 @@
static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable)
{
- u32 reg = bank->base;
+ void __iomem *reg = bank->base;
u32 l;
switch (bank->method) {
@@ -477,6 +571,13 @@
else
l |= gpio_mask;
break;
+ case METHOD_GPIO_24XX:
+ if (enable)
+ reg += OMAP24XX_GPIO_SETIRQENABLE1;
+ else
+ reg += OMAP24XX_GPIO_CLEARIRQENABLE1;
+ l = gpio_mask;
+ break;
default:
BUG();
return;
@@ -489,6 +590,50 @@
_enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
}
+/*
+ * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register.
+ * 1510 does not seem to have a wake-up register. If JTAG is connected
+ * to the target, system will wake up always on GPIO events. While
+ * system is running all registered GPIO interrupts need to have wake-up
+ * enabled. When system is suspended, only selected GPIO interrupts need
+ * to have wake-up enabled.
+ */
+static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
+{
+ switch (bank->method) {
+ case METHOD_GPIO_1610:
+ case METHOD_GPIO_24XX:
+ spin_lock(&bank->lock);
+ if (enable)
+ bank->suspend_wakeup |= (1 << gpio);
+ else
+ bank->suspend_wakeup &= ~(1 << gpio);
+ spin_unlock(&bank->lock);
+ return 0;
+ default:
+ printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
+ bank->method);
+ return -EINVAL;
+ }
+}
+
+/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
+static int gpio_wake_enable(unsigned int irq, unsigned int enable)
+{
+ unsigned int gpio = irq - IH_GPIO_BASE;
+ struct gpio_bank *bank;
+ int retval;
+
+ if (check_gpio(gpio) < 0)
+ return -ENODEV;
+ bank = get_gpio_bank(gpio);
+ spin_lock(&bank->lock);
+ retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
+ spin_unlock(&bank->lock);
+
+ return retval;
+}
+
int omap_request_gpio(int gpio)
{
struct gpio_bank *bank;
@@ -505,15 +650,33 @@
return -1;
}
bank->reserved_map |= (1 << get_gpio_index(gpio));
+
+ /* Set trigger to none. You need to enable the trigger after request_irq */
+ _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
+
#ifdef CONFIG_ARCH_OMAP1510
if (bank->method == METHOD_GPIO_1510) {
- u32 reg;
+ void __iomem *reg;
- /* Claim the pin for the ARM */
+ /* Claim the pin for MPU */
reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
}
#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+ if (bank->method == METHOD_GPIO_1610) {
+ /* Enable wake-up during idle for dynamic tick */
+ void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+ __raw_writel(1 << get_gpio_index(gpio), reg);
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (bank->method == METHOD_GPIO_24XX) {
+ /* Enable wake-up during idle for dynamic tick */
+ void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
+ __raw_writel(1 << get_gpio_index(gpio), reg);
+ }
+#endif
spin_unlock(&bank->lock);
return 0;
@@ -533,6 +696,20 @@
spin_unlock(&bank->lock);
return;
}
+#ifdef CONFIG_ARCH_OMAP16XX
+ if (bank->method == METHOD_GPIO_1610) {
+ /* Disable wake-up during idle for dynamic tick */
+ void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+ __raw_writel(1 << get_gpio_index(gpio), reg);
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (bank->method == METHOD_GPIO_24XX) {
+ /* Disable wake-up during idle for dynamic tick */
+ void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
+ __raw_writel(1 << get_gpio_index(gpio), reg);
+ }
+#endif
bank->reserved_map &= ~(1 << get_gpio_index(gpio));
_set_gpio_direction(bank, get_gpio_index(gpio), 1);
_set_gpio_irqenable(bank, gpio, 0);
@@ -552,7 +729,7 @@
static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
struct pt_regs *regs)
{
- u32 isr_reg = 0;
+ void __iomem *isr_reg = NULL;
u32 isr;
unsigned int gpio_irq;
struct gpio_bank *bank;
@@ -574,24 +751,30 @@
if (bank->method == METHOD_GPIO_730)
isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (bank->method == METHOD_GPIO_24XX)
+ isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
+#endif
- isr = __raw_readl(isr_reg);
- _enable_gpio_irqbank(bank, isr, 0);
- _clear_gpio_irqbank(bank, isr);
- _enable_gpio_irqbank(bank, isr, 1);
- desc->chip->unmask(irq);
+ while(1) {
+ isr = __raw_readl(isr_reg);
+ _enable_gpio_irqbank(bank, isr, 0);
+ _clear_gpio_irqbank(bank, isr);
+ _enable_gpio_irqbank(bank, isr, 1);
+ desc->chip->unmask(irq);
- if (unlikely(!isr))
- return;
+ if (!isr)
+ break;
- gpio_irq = bank->virtual_irq_start;
- for (; isr != 0; isr >>= 1, gpio_irq++) {
- struct irqdesc *d;
- if (!(isr & 1))
- continue;
- d = irq_desc + gpio_irq;
- d->handle(gpio_irq, d, regs);
- }
+ gpio_irq = bank->virtual_irq_start;
+ for (; isr != 0; isr >>= 1, gpio_irq++) {
+ struct irqdesc *d;
+ if (!(isr & 1))
+ continue;
+ d = irq_desc + gpio_irq;
+ desc_handle_irq(gpio_irq, d, regs);
+ }
+ }
}
static void gpio_ack_irq(unsigned int irq)
@@ -613,14 +796,10 @@
static void gpio_unmask_irq(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
+ unsigned int gpio_idx = get_gpio_index(gpio);
struct gpio_bank *bank = get_gpio_bank(gpio);
- if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) {
- printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n",
- gpio);
- _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE);
- }
- _set_gpio_irqenable(bank, gpio, 1);
+ _set_gpio_irqenable(bank, gpio_idx, 1);
}
static void mpuio_ack_irq(unsigned int irq)
@@ -645,9 +824,11 @@
}
static struct irqchip gpio_irq_chip = {
- .ack = gpio_ack_irq,
- .mask = gpio_mask_irq,
- .unmask = gpio_unmask_irq,
+ .ack = gpio_ack_irq,
+ .mask = gpio_mask_irq,
+ .unmask = gpio_unmask_irq,
+ .set_type = gpio_irq_type,
+ .set_wake = gpio_wake_enable,
};
static struct irqchip mpuio_irq_chip = {
@@ -657,6 +838,7 @@
};
static int initialized = 0;
+static struct clk * gpio_ck = NULL;
static int __init _omap_gpio_init(void)
{
@@ -665,6 +847,14 @@
initialized = 1;
+ if (cpu_is_omap1510()) {
+ gpio_ck = clk_get(NULL, "arm_gpio_ck");
+ if (IS_ERR(gpio_ck))
+ printk("Could not get arm_gpio_ck\n");
+ else
+ clk_use(gpio_ck);
+ }
+
#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
printk(KERN_INFO "OMAP1510 GPIO hardware\n");
@@ -674,7 +864,7 @@
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
if (cpu_is_omap16xx()) {
- int rev;
+ u32 rev;
gpio_bank_count = 5;
gpio_bank = gpio_bank_1610;
@@ -690,6 +880,17 @@
gpio_bank = gpio_bank_730;
}
#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (cpu_is_omap24xx()) {
+ int rev;
+
+ gpio_bank_count = 4;
+ gpio_bank = gpio_bank_24xx;
+ rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+ printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n",
+ (rev >> 4) & 0x0f, rev & 0x0f);
+ }
+#endif
for (i = 0; i < gpio_bank_count; i++) {
int j, gpio_count = 16;
@@ -710,6 +911,7 @@
if (bank->method == METHOD_GPIO_1610) {
__raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
__raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
+ __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG);
}
#endif
#ifdef CONFIG_ARCH_OMAP730
@@ -720,6 +922,14 @@
gpio_count = 32; /* 730 has 32-bit GPIOs */
}
#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ if (bank->method == METHOD_GPIO_24XX) {
+ __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
+ __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
+
+ gpio_count = 32;
+ }
+#endif
for (j = bank->virtual_irq_start;
j < bank->virtual_irq_start + gpio_count; j++) {
if (bank->method == METHOD_MPUIO)
@@ -735,12 +945,97 @@
/* Enable system clock for GPIO module.
* The CAM_CLK_CTRL *is* really the right place. */
- if (cpu_is_omap1610() || cpu_is_omap1710())
+ if (cpu_is_omap16xx())
omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
return 0;
}
+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
+static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
+{
+ int i;
+
+ if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
+ return 0;
+
+ for (i = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ void __iomem *wake_status;
+ void __iomem *wake_clear;
+ void __iomem *wake_set;
+
+ switch (bank->method) {
+ case METHOD_GPIO_1610:
+ wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
+ wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+ wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+ break;
+ case METHOD_GPIO_24XX:
+ wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
+ wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
+ wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
+ break;
+ default:
+ continue;
+ }
+
+ spin_lock(&bank->lock);
+ bank->saved_wakeup = __raw_readl(wake_status);
+ __raw_writel(0xffffffff, wake_clear);
+ __raw_writel(bank->suspend_wakeup, wake_set);
+ spin_unlock(&bank->lock);
+ }
+
+ return 0;
+}
+
+static int omap_gpio_resume(struct sys_device *dev)
+{
+ int i;
+
+ if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
+ return 0;
+
+ for (i = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ void __iomem *wake_clear;
+ void __iomem *wake_set;
+
+ switch (bank->method) {
+ case METHOD_GPIO_1610:
+ wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+ wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+ break;
+ case METHOD_GPIO_24XX:
+ wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
+ wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+ break;
+ default:
+ continue;
+ }
+
+ spin_lock(&bank->lock);
+ __raw_writel(0xffffffff, wake_clear);
+ __raw_writel(bank->saved_wakeup, wake_set);
+ spin_unlock(&bank->lock);
+ }
+
+ return 0;
+}
+
+static struct sysdev_class omap_gpio_sysclass = {
+ set_kset_name("gpio"),
+ .suspend = omap_gpio_suspend,
+ .resume = omap_gpio_resume,
+};
+
+static struct sys_device omap_gpio_device = {
+ .id = 0,
+ .cls = &omap_gpio_sysclass,
+};
+#endif
+
/*
* This may get called early from board specific init
*/
@@ -752,11 +1047,30 @@
return 0;
}
+static int __init omap_gpio_sysinit(void)
+{
+ int ret = 0;
+
+ if (!initialized)
+ ret = _omap_gpio_init();
+
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
+ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ if (ret == 0) {
+ ret = sysdev_class_register(&omap_gpio_sysclass);
+ if (ret == 0)
+ ret = sysdev_register(&omap_gpio_device);
+ }
+ }
+#endif
+
+ return ret;
+}
+
EXPORT_SYMBOL(omap_request_gpio);
EXPORT_SYMBOL(omap_free_gpio);
EXPORT_SYMBOL(omap_set_gpio_direction);
EXPORT_SYMBOL(omap_set_gpio_dataout);
EXPORT_SYMBOL(omap_get_gpio_datain);
-EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);
-arch_initcall(omap_gpio_init);
+arch_initcall(omap_gpio_sysinit);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 43567d5..9c9b7df 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -27,6 +27,7 @@
#include <asm/arch/dma.h>
#include <asm/arch/mux.h>
#include <asm/arch/irqs.h>
+#include <asm/arch/dsp_common.h>
#include <asm/arch/mcbsp.h>
#include <asm/hardware/clock.h>
@@ -187,9 +188,6 @@
return -1;
}
-#define EN_XORPCK 1
-#define DSP_RSTCT2 0xe1008014
-
static void omap_mcbsp_dsp_request(void)
{
if (cpu_is_omap1510() || cpu_is_omap16xx()) {
@@ -198,6 +196,11 @@
/* enable 12MHz clock to mcbsp 1 & 3 */
clk_use(mcbsp_dspxor_ck);
+
+ /*
+ * DSP external peripheral reset
+ * FIXME: This should be moved to dsp code
+ */
__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
DSP_RSTCT2);
}
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index ea7b955..6448204 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -48,6 +48,9 @@
pull_orig = 0, pull = 0;
unsigned int mask, warn = 0;
+ if (cpu_is_omap7xx())
+ return 0;
+
if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
return -EINVAL;
diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
index 2ede2ee..1fb16f9 100644
--- a/arch/arm/plat-omap/ocpi.c
+++ b/arch/arm/plat-omap/ocpi.c
@@ -25,6 +25,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c
index e6536b1..e15c6c1 100644
--- a/arch/arm/plat-omap/pm.c
+++ b/arch/arm/plat-omap/pm.c
@@ -39,24 +39,32 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/pm.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/mach/time.h>
-#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
-#include <asm/arch/omap16xx.h>
+#include <asm/mach-types.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/tc.h>
#include <asm/arch/pm.h>
#include <asm/arch/mux.h>
-#include <asm/arch/tc.h>
#include <asm/arch/tps65010.h>
+#include <asm/arch/dsp_common.h>
#include "clock.h"
+#include "sram.h"
static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+static void (*omap_sram_idle)(void) = NULL;
+static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+
/*
* Let's power down on idle, but only if we are really
* idle, because once we start down the path of
@@ -65,7 +73,6 @@
*/
void omap_pm_idle(void)
{
- int (*func_ptr)(void) = 0;
unsigned int mask32 = 0;
/*
@@ -84,6 +91,13 @@
mask32 = omap_readl(ARM_SYSST);
/*
+ * Prevent the ULPD from entering low power state by setting
+ * POWER_CTRL_REG:4 = 0
+ */
+ omap_writew(omap_readw(ULPD_POWER_CTRL) &
+ ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL);
+
+ /*
* Since an interrupt may set up a timer, we don't want to
* reprogram the hardware timer with interrupts enabled.
* Re-enable interrupts only after returning from idle.
@@ -92,18 +106,9 @@
if ((mask32 & DSP_IDLE) == 0) {
__asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
- } else {
+ } else
+ omap_sram_idle();
- if (cpu_is_omap1510()) {
- func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND);
- } else if (cpu_is_omap1610() || cpu_is_omap1710()) {
- func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND);
- } else if (cpu_is_omap5912()) {
- func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND);
- }
-
- func_ptr();
- }
local_fiq_enable();
local_irq_enable();
}
@@ -115,58 +120,55 @@
*/
static void omap_pm_wakeup_setup(void)
{
- /*
- * Enable ARM XOR clock and release peripheral from reset by
- * writing 1 to PER_EN bit in ARM_RSTCT2, this is required
- * for UART configuration to use UART2 to wake up.
- */
-
- omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2);
- omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2);
- omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL);
+ u32 level1_wake = OMAP_IRQ_BIT(INT_IH2_IRQ);
+ u32 level2_wake = OMAP_IRQ_BIT(INT_UART2) | OMAP_IRQ_BIT(INT_KEYBOARD);
/*
- * Turn off all interrupts except L1-2nd level cascade,
- * and the L2 wakeup interrupts: keypad and UART2.
+ * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
+ * and the L2 wakeup interrupts: keypad and UART2. Note that the
+ * drivers must still separately call omap_set_gpio_wakeup() to
+ * wake up to a GPIO interrupt.
*/
+ if (cpu_is_omap1510() || cpu_is_omap16xx())
+ level1_wake |= OMAP_IRQ_BIT(INT_GPIO_BANK1);
+ else if (cpu_is_omap730())
+ level1_wake |= OMAP_IRQ_BIT(INT_730_GPIO_BANK1);
- omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR);
+ omap_writel(~level1_wake, OMAP_IH1_MIR);
- if (cpu_is_omap1510()) {
- omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_MIR);
- }
+ if (cpu_is_omap1510())
+ omap_writel(~level2_wake, OMAP_IH2_MIR);
+ /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
if (cpu_is_omap16xx()) {
- omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR);
-
- omap_writel(~0x0, OMAP_IH2_1_MIR);
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+ omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
omap_writel(~0x0, OMAP_IH2_2_MIR);
omap_writel(~0x0, OMAP_IH2_3_MIR);
}
- /* New IRQ agreement */
+ /* New IRQ agreement, recalculate in cascade order */
+ omap_writel(1, OMAP_IH2_CONTROL);
omap_writel(1, OMAP_IH1_CONTROL);
-
- /* external PULL to down, bit 22 = 0 */
- omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2);
}
void omap_pm_suspend(void)
{
- unsigned int mask32 = 0;
unsigned long arg0 = 0, arg1 = 0;
- int (*func_ptr)(unsigned short, unsigned short) = 0;
- unsigned short save_dsp_idlect2;
- printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev);
+ printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
+
+ omap_serial_wake_trigger(1);
if (machine_is_omap_osk()) {
/* Stop LED1 (D9) blink */
tps65010_set_led(LED1, OFF);
}
+ omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+
/*
- * Step 1: turn off interrupts
+ * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
*/
local_irq_disable();
@@ -207,6 +209,8 @@
ARM_SAVE(ARM_CKCTL);
ARM_SAVE(ARM_IDLECT1);
ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap1510()))
+ ARM_SAVE(ARM_IDLECT3);
ARM_SAVE(ARM_EWUPCT);
ARM_SAVE(ARM_RSTCT1);
ARM_SAVE(ARM_RSTCT2);
@@ -214,42 +218,12 @@
ULPD_SAVE(ULPD_CLOCK_CTRL);
ULPD_SAVE(ULPD_STATUS_REQ);
- /*
- * Step 3: LOW_PWR signal enabling
- *
- * Allow the LOW_PWR signal to be visible on MPUIO5 ball.
- */
- if (cpu_is_omap1510()) {
- /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
- omap_writew(omap_readw(ULPD_POWER_CTRL) |
- OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
- } else if (cpu_is_omap16xx()) {
- /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
- omap_writew(omap_readw(ULPD_POWER_CTRL) |
- OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
- }
-
- /* configure LOW_PWR pin */
- omap_cfg_reg(T20_1610_LOW_PWR);
+ /* (Step 3 removed - we now allow deep sleep by default) */
/*
* Step 4: OMAP DSP Shutdown
*/
- /* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
- omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
- ARM_RSTCT1);
-
- /* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
- omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
-
- /* Set EN_DSPCK = 0, stop DSP block clock */
- omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
-
- /* Stop any DSP domain clocks */
- omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
- save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
- __raw_writew(0, DSP_IDLECT2);
/*
* Step 5: Wakeup Event Setup
@@ -258,24 +232,9 @@
omap_pm_wakeup_setup();
/*
- * Step 6a: ARM and Traffic controller shutdown
- *
- * Step 6 starts here with clock and watchdog disable
+ * Step 6: ARM and Traffic controller shutdown
*/
- /* stop clocks */
- mask32 = omap_readl(ARM_IDLECT2);
- mask32 &= ~(1<<EN_WDTCK); /* bit 0 -> 0 (WDT clock) */
- mask32 |= (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */
- mask32 &= ~(1<<EN_PERCK); /* bit 2 -> 0 (MPUPER_CK clock) */
- mask32 &= ~(1<<EN_LCDCK); /* bit 3 -> 0 (LCDC clock) */
- mask32 &= ~(1<<EN_LBCK); /* bit 4 -> 0 (local bus clock) */
- mask32 |= (1<<EN_APICK); /* bit 6 -> 1 (MPUI clock) */
- mask32 &= ~(1<<EN_TIMCK); /* bit 7 -> 0 (MPU timer clock) */
- mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */
- mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */
- omap_writel(mask32, ARM_IDLECT2);
-
/* disable ARM watchdog */
omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
@@ -295,47 +254,24 @@
arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
- if (cpu_is_omap1510()) {
- func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND);
- } else if (cpu_is_omap1610() || cpu_is_omap1710()) {
- func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND);
- } else if (cpu_is_omap5912()) {
- func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND);
- }
-
/*
* Step 6c: ARM and Traffic controller shutdown
*
* Jump to assembly code. The processor will stay there
* until wake up.
*/
-
- func_ptr(arg0, arg1);
+ omap_sram_suspend(arg0, arg1);
/*
* If we are here, processor is woken up!
*/
- if (cpu_is_omap1510()) {
- /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
- omap_writew(omap_readw(ULPD_POWER_CTRL) &
- ~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
- } else if (cpu_is_omap16xx()) {
- /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
- omap_writew(omap_readw(ULPD_POWER_CTRL) &
- ~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
- }
-
-
- /* Restore DSP clocks */
- omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
- __raw_writew(save_dsp_idlect2, DSP_IDLECT2);
- ARM_RESTORE(ARM_IDLECT2);
-
/*
* Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
*/
+ if (!(cpu_is_omap1510()))
+ ARM_RESTORE(ARM_IDLECT3);
ARM_RESTORE(ARM_CKCTL);
ARM_RESTORE(ARM_EWUPCT);
ARM_RESTORE(ARM_RSTCT1);
@@ -366,6 +302,8 @@
MPUI1610_RESTORE(OMAP_IH2_3_MIR);
}
+ omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+
/*
* Reenable interrupts
*/
@@ -373,6 +311,8 @@
local_irq_enable();
local_fiq_enable();
+ omap_serial_wake_trigger(0);
+
printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
if (machine_is_omap_osk()) {
@@ -401,6 +341,8 @@
ARM_SAVE(ARM_CKCTL);
ARM_SAVE(ARM_IDLECT1);
ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap1510()))
+ ARM_SAVE(ARM_IDLECT3);
ARM_SAVE(ARM_EWUPCT);
ARM_SAVE(ARM_RSTCT1);
ARM_SAVE(ARM_RSTCT2);
@@ -436,6 +378,7 @@
"ARM_CKCTL_REG: 0x%-8x \n"
"ARM_IDLECT1_REG: 0x%-8x \n"
"ARM_IDLECT2_REG: 0x%-8x \n"
+ "ARM_IDLECT3_REG: 0x%-8x \n"
"ARM_EWUPCT_REG: 0x%-8x \n"
"ARM_RSTCT1_REG: 0x%-8x \n"
"ARM_RSTCT2_REG: 0x%-8x \n"
@@ -449,6 +392,7 @@
ARM_SHOW(ARM_CKCTL),
ARM_SHOW(ARM_IDLECT1),
ARM_SHOW(ARM_IDLECT2),
+ ARM_SHOW(ARM_IDLECT3),
ARM_SHOW(ARM_EWUPCT),
ARM_SHOW(ARM_RSTCT1),
ARM_SHOW(ARM_RSTCT2),
@@ -507,7 +451,7 @@
entry = create_proc_read_entry("driver/omap_pm",
S_IWUSR | S_IRUGO, NULL,
- omap_pm_read_proc, 0);
+ omap_pm_read_proc, NULL);
}
#endif /* DEBUG && CONFIG_PROC_FS */
@@ -580,7 +524,21 @@
}
-struct pm_ops omap_pm_ops ={
+static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
+ struct pt_regs * regs)
+{
+ return IRQ_HANDLED;
+}
+
+static struct irqaction omap_wakeup_irq = {
+ .name = "peripheral wakeup",
+ .flags = SA_INTERRUPT,
+ .handler = omap_wakeup_interrupt
+};
+
+
+
+static struct pm_ops omap_pm_ops ={
.pm_disk_mode = 0,
.prepare = omap_pm_prepare,
.enter = omap_pm_enter,
@@ -590,42 +548,61 @@
static int __init omap_pm_init(void)
{
printk("Power Management for TI OMAP.\n");
- pm_idle = omap_pm_idle;
/*
* We copy the assembler sleep/wakeup routines to SRAM.
* These routines need to be in SRAM as that's the only
* memory the MPU can see when it wakes up.
*/
-
-#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
- memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND,
- omap1510_idle_loop_suspend,
- omap1510_idle_loop_suspend_sz);
- memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend,
- omap1510_cpu_suspend_sz);
- } else
-#endif
- if (cpu_is_omap1610() || cpu_is_omap1710()) {
- memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND,
- omap1610_idle_loop_suspend,
- omap1610_idle_loop_suspend_sz);
- memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend,
- omap1610_cpu_suspend_sz);
- } else if (cpu_is_omap5912()) {
- memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND,
- omap1610_idle_loop_suspend,
- omap1610_idle_loop_suspend_sz);
- memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend,
- omap1610_cpu_suspend_sz);
+ omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
+ omap1510_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
+ omap1510_cpu_suspend_sz);
+ } else if (cpu_is_omap16xx()) {
+ omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
+ omap1610_idle_loop_suspend_sz);
+ omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
+ omap1610_cpu_suspend_sz);
}
+ if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
+ printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
+ return -ENODEV;
+ }
+
+ pm_idle = omap_pm_idle;
+
+ setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+#if 0
+ /* --- BEGIN BOARD-DEPENDENT CODE --- */
+ /* Sleepx mask direction */
+ omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
+ /* Unmask sleepx signal */
+ omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
+ /* --- END BOARD-DEPENDENT CODE --- */
+#endif
+
+ /* Program new power ramp-up time
+ * (0 for most boards since we don't lower voltage when in deep sleep)
+ */
+ omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
+
+ /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
+ omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
+
+ /* Configure IDLECT3 */
+ if (cpu_is_omap16xx())
+ omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
+
pm_set_ops(&omap_pm_ops);
#if defined(DEBUG) && defined(CONFIG_PROC_FS)
omap_pm_init_proc();
#endif
+ /* configure LOW_PWR pin */
+ omap_cfg_reg(T20_1610_LOW_PWR);
+
return 0;
}
__initcall(omap_pm_init);
diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/plat-omap/sleep.S
index 279490c..9f74583 100644
--- a/arch/arm/plat-omap/sleep.S
+++ b/arch/arm/plat-omap/sleep.S
@@ -66,7 +66,7 @@
@ get ARM_IDLECT2 into r2
ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
- orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+ orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
@@ -76,7 +76,7 @@
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
- orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+ orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1510: subs r5, r5, #1
bne l_1510
/*
@@ -96,7 +96,7 @@
strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
- ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ENTRY(omap1510_idle_loop_suspend_sz)
.word . - omap1510_idle_loop_suspend
@@ -115,8 +115,8 @@
@ turn off clock domains
@ get ARM_IDLECT2 into r2
ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
- mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
- orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
+ mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
+ orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
@@ -126,7 +126,7 @@
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
- orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+ orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1610: subs r5, r5, #1
bne l_1610
/*
@@ -146,7 +146,7 @@
strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
- ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ENTRY(omap1610_idle_loop_suspend_sz)
.word . - omap1610_idle_loop_suspend
@@ -208,7 +208,7 @@
@ turn off clock domains
mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
- orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+ orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
@@ -217,7 +217,7 @@
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
- orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+ orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1510_2:
subs r5, r5, #1
bne l_1510_2
@@ -237,7 +237,7 @@
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
@ restore regs and return
- ldmfd sp!, {r0 - r12, pc}
+ ldmfd sp!, {r0 - r12, pc}
ENTRY(omap1510_cpu_suspend_sz)
.word . - omap1510_cpu_suspend
@@ -249,21 +249,26 @@
@ save registers on stack
stmfd sp!, {r0 - r12, lr}
+ @ Drain write cache
+ mov r4, #0
+ mcr p15, 0, r0, c7, c10, 4
+ nop
+
@ load base address of Traffic Controller
- mov r4, #TCMIF_ASM_BASE & 0xff000000
- orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
- orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+ mov r6, #TCMIF_ASM_BASE & 0xff000000
+ orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
+ orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
@ prepare to put SDRAM into self-refresh manually
- ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
- orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
- orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
- str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+ ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+ orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
+ orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
+ str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
@ prepare to put EMIFS to Sleep
- ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
- orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
- str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+ ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+ orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
+ str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
@ load base address of ARM_IDLECT1 and ARM_IDLECT2
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
@@ -271,26 +276,22 @@
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
@ turn off clock domains
- mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
- orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
- strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
-
- @ work around errata of OMAP1610/5912. Enable (!) peripheral
- @ clock to let the chip go into deep sleep
- ldrh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
- orr r5,r5, #EN_PERCK_BIT & 0xff
+ @ do not disable PERCK (0x04)
+ mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
+ orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
- mov r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
- orr r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
+ mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
+ orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
- mov r5, #IDLE_WAIT_CYCLES & 0xff
- orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
-l_1610_2:
- subs r5, r5, #1
- bne l_1610_2
+ @ disable instruction cache
+ mrc p15, 0, r9, c1, c0, 0
+ bic r2, r9, #0x1000
+ mcr p15, 0, r2, c1, c0, 0
+ nop
+
/*
* Let's wait for the next wake up event to wake us up. r0 can't be
* used here because r0 holds ARM_IDLECT1
@@ -301,13 +302,21 @@
* omap1610_cpu_suspend()'s resume point.
*
* It will just start executing here, so we'll restore stuff from the
- * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ * stack.
*/
+ @ re-enable Icache
+ mcr p15, 0, r9, c1, c0, 0
+
+ @ reset the ARM_IDLECT1 and ARM_IDLECT2.
strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+ @ Restore EMIFF controls
+ str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+ str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
@ restore regs and return
- ldmfd sp!, {r0 - r12, pc}
+ ldmfd sp!, {r0 - r12, pc}
ENTRY(omap1610_cpu_suspend_sz)
.word . - omap1610_cpu_suspend
diff --git a/arch/arm/plat-omap/sram-fn.S b/arch/arm/plat-omap/sram-fn.S
new file mode 100644
index 0000000..4bea369
--- /dev/null
+++ b/arch/arm/plat-omap/sram-fn.S
@@ -0,0 +1,58 @@
+/*
+ * linux/arch/arm/plat-omap/sram.S
+ *
+ * Functions that need to be run in internal SRAM
+ *
+ * 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/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+
+ .text
+
+/*
+ * Reprograms ULPD and CKCTL.
+ */
+ENTRY(sram_reprogram_clock)
+ stmfd sp!, {r0 - r12, lr} @ save registers on stack
+
+ mov r2, #IO_ADDRESS(DPLL_CTL) & 0xff000000
+ orr r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x00ff0000
+ orr r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x0000ff00
+
+ mov r3, #IO_ADDRESS(ARM_CKCTL) & 0xff000000
+ orr r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x00ff0000
+ orr r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x0000ff00
+
+ tst r0, #1 << 4 @ want lock mode?
+ beq newck @ nope
+ bic r0, r0, #1 << 4 @ else clear lock bit
+ strh r0, [r2] @ set dpll into bypass mode
+ orr r0, r0, #1 << 4 @ set lock bit again
+
+newck:
+ strh r1, [r3] @ write new ckctl value
+ strh r0, [r2] @ write new dpll value
+
+ mov r4, #0x0700 @ let the clocks settle
+ orr r4, r4, #0x00ff
+delay: sub r4, r4, #1
+ cmp r4, #0
+ bne delay
+
+lock: ldrh r4, [r2], #0 @ read back dpll value
+ tst r0, #1 << 4 @ want lock mode?
+ beq out @ nope
+ tst r4, #1 << 0 @ dpll rate locked?
+ beq lock @ try again
+
+out:
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+ENTRY(sram_reprogram_clock_sz)
+ .word . - sram_reprogram_clock
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
new file mode 100644
index 0000000..7719a40
--- /dev/null
+++ b/arch/arm/plat-omap/sram.c
@@ -0,0 +1,116 @@
+/*
+ * linux/arch/arm/plat-omap/sram.c
+ *
+ * OMAP SRAM detection and management
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach/map.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+#include "sram.h"
+
+#define OMAP1_SRAM_BASE 0xd0000000
+#define OMAP1_SRAM_START 0x20000000
+#define SRAM_BOOTLOADER_SZ 0x80
+
+static unsigned long omap_sram_base;
+static unsigned long omap_sram_size;
+static unsigned long omap_sram_ceil;
+
+/*
+ * The amount of SRAM depends on the core type:
+ * 730 = 200K, 1510 = 512K, 5912 = 256K, 1610 = 16K, 1710 = 16K
+ * Note that we cannot try to test for SRAM here because writes
+ * to secure SRAM will hang the system. Also the SRAM is not
+ * yet mapped at this point.
+ */
+void __init omap_detect_sram(void)
+{
+ omap_sram_base = OMAP1_SRAM_BASE;
+
+ if (cpu_is_omap730())
+ omap_sram_size = 0x32000;
+ else if (cpu_is_omap1510())
+ omap_sram_size = 0x80000;
+ else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
+ omap_sram_size = 0x4000;
+ else if (cpu_is_omap1611())
+ omap_sram_size = 0x3e800;
+ else {
+ printk(KERN_ERR "Could not detect SRAM size\n");
+ omap_sram_size = 0x4000;
+ }
+
+ printk(KERN_INFO "SRAM size: 0x%lx\n", omap_sram_size);
+ omap_sram_ceil = omap_sram_base + omap_sram_size;
+}
+
+static struct map_desc omap_sram_io_desc[] __initdata = {
+ { OMAP1_SRAM_BASE, OMAP1_SRAM_START, 0, MT_DEVICE }
+};
+
+/*
+ * In order to use last 2kB of SRAM on 1611b, we must round the size
+ * up to multiple of PAGE_SIZE. We cannot use ioremap for SRAM, as
+ * clock init needs SRAM early.
+ */
+void __init omap_map_sram(void)
+{
+ if (omap_sram_size == 0)
+ return;
+
+ omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
+ omap_sram_io_desc[0].length *= PAGE_SIZE;
+ iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
+
+ /*
+ * Looks like we need to preserve some bootloader code at the
+ * beginning of SRAM for jumping to flash for reboot to work...
+ */
+ memset((void *)omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
+ omap_sram_size - SRAM_BOOTLOADER_SZ);
+}
+
+static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl) = NULL;
+
+void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
+{
+ if (_omap_sram_reprogram_clock == NULL)
+ panic("Cannot use SRAM");
+
+ return _omap_sram_reprogram_clock(dpllctl, ckctl);
+}
+
+void * omap_sram_push(void * start, unsigned long size)
+{
+ if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) {
+ printk(KERN_ERR "Not enough space in SRAM\n");
+ return NULL;
+ }
+ omap_sram_ceil -= size;
+ omap_sram_ceil &= ~0x3;
+ memcpy((void *)omap_sram_ceil, start, size);
+
+ return (void *)omap_sram_ceil;
+}
+
+void __init omap_sram_init(void)
+{
+ omap_detect_sram();
+ omap_map_sram();
+ _omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock,
+ sram_reprogram_clock_sz);
+}
diff --git a/arch/arm/plat-omap/sram.h b/arch/arm/plat-omap/sram.h
new file mode 100644
index 0000000..71984ef
--- /dev/null
+++ b/arch/arm/plat-omap/sram.h
@@ -0,0 +1,21 @@
+/*
+ * linux/arch/arm/plat-omap/sram.h
+ *
+ * Interface for functions that need to be run in internal SRAM
+ *
+ * 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 __ARCH_ARM_OMAP_SRAM_H
+#define __ARCH_ARM_OMAP_SRAM_H
+
+extern void * omap_sram_push(void * start, unsigned long size);
+extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
+
+/* Do not use these */
+extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
+extern unsigned long sram_reprogram_clock_sz;
+
+#endif
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 25bc4a8..98f1c76 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -41,6 +41,7 @@
/* These routines should handle the standard chip-specific modes
* for usb0/1/2 ports, covering basic mux and transceiver setup.
+ * Call omap_usb_init() once, from INIT_MACHINE().
*
* Some board-*.c files will need to set up additional mux options,
* like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index 1f03732..1f00b3d 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -55,6 +55,10 @@
config GENERIC_ISA_DMA
bool
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
source "init/Kconfig"
diff --git a/arch/arm26/Makefile b/arch/arm26/Makefile
index ada8985..e9cb8ef 100644
--- a/arch/arm26/Makefile
+++ b/arch/arm26/Makefile
@@ -17,10 +17,6 @@
CFLAGS +=-fno-omit-frame-pointer -mno-sched-prolog
endif
-ifeq ($(CONFIG_DEBUG_INFO),y)
-CFLAGS +=-g
-endif
-
CFLAGS_BOOT :=-mapcs-26 -mcpu=arm3 -msoft-float -Uarm
CFLAGS +=-mapcs-26 -mcpu=arm3 -msoft-float -Uarm
AFLAGS +=-mapcs-26 -mcpu=arm3 -msoft-float
diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c
index 549a6b2..e66aedd 100644
--- a/arch/arm26/kernel/time.c
+++ b/arch/arm26/kernel/time.c
@@ -114,7 +114,7 @@
*/
static inline void do_set_rtc(void)
{
- if (time_status & STA_UNSYNC || set_rtc == NULL)
+ if (!ntp_synced() || set_rtc == NULL)
return;
//FIXME - timespec.tv_sec is a time_t not unsigned long
@@ -189,10 +189,7 @@
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_nsec;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/cris/Kconfig.debug b/arch/cris/Kconfig.debug
index cd72324..0a1d62a 100644
--- a/arch/cris/Kconfig.debug
+++ b/arch/cris/Kconfig.debug
@@ -5,10 +5,13 @@
bool "Kernel profiling support"
config SYSTEM_PROFILER
- bool "System profiling support"
+ bool "System profiling support"
+
+source "lib/Kconfig.debug"
config ETRAX_KGDB
bool "Use kernel GDB debugger"
+ depends on DEBUG_KERNEL
---help---
The CRIS version of gdb can be used to remotely debug a running
Linux kernel via the serial debug port. Provided you have gdb-cris
@@ -22,25 +25,11 @@
this option is turned on!
-config DEBUG_INFO
- bool "Compile the kernel with debug info"
- help
- If you say Y here the resulting kernel image will include
- debugging info resulting in a larger kernel image.
- Say Y here only if you plan to use gdb to debug the kernel.
- If you don't debug the kernel, you can say N.
-
-config FRAME_POINTER
- bool "Compile the kernel with frame pointers"
- help
- If you say Y here the resulting kernel image will be slightly larger
- and slower, but it will give very useful debugging information.
- If you don't debug the kernel, you can say N, but we may not be able
- to solve problems without frame pointers.
-
config DEBUG_NMI_OOPS
- bool "NMI causes oops printout"
- help
- If the system locks up without any debug information you can say Y
- here to make it possible to dump an OOPS with an external NMI.
+ bool "NMI causes oops printout"
+ depends on DEBUG_KERNEL
+ help
+ If the system locks up without any debug information you can say Y
+ here to make it possible to dump an OOPS with an external NMI.
+
endmenu
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
index 6b7b4e0..dc3dfe9 100644
--- a/arch/cris/arch-v10/kernel/time.c
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -240,7 +240,7 @@
* The division here is not time critical since it will run once in
* 11 minutes
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
index fa2d432..a2d99b4 100644
--- a/arch/cris/kernel/time.c
+++ b/arch/cris/kernel/time.c
@@ -114,10 +114,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c
index 62cfbd9..1a76d52 100644
--- a/arch/frv/kernel/frv_ksyms.c
+++ b/arch/frv/kernel/frv_ksyms.c
@@ -71,7 +71,6 @@
EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(get_wchan);
diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c
index 075db66..8d6558b 100644
--- a/arch/frv/kernel/time.c
+++ b/arch/frv/kernel/time.c
@@ -85,7 +85,7 @@
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2
@@ -216,10 +216,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
index 8a60021..af8c5d2 100644
--- a/arch/h8300/kernel/time.c
+++ b/arch/h8300/kernel/time.c
@@ -116,10 +116,7 @@
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_nsec;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 619d843..5d51b38 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -14,6 +14,10 @@
486, 586, Pentiums, and various instruction-set-compatible chips by
AMD, Cyrix, and others.
+config SEMAPHORE_SLEEPERS
+ bool
+ default y
+
config MMU
bool
default y
@@ -33,6 +37,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
source "init/Kconfig"
menu "Processor type and features"
@@ -754,6 +762,7 @@
depends on SMP && HIGHMEM64G && (X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI))
default n if X86_PC
default y if (X86_NUMAQ || X86_SUMMIT)
+ select SPARSEMEM_STATIC
# Need comments to help the hapless user trying to turn on NUMA support
comment "NUMA (NUMA-Q) requires SMP, 64GB highmem support"
@@ -1313,6 +1322,11 @@
bool
default y
+config GENERIC_PENDING_IRQ
+ bool
+ depends on GENERIC_HARDIRQS && SMP
+ default y
+
config X86_SMP
bool
depends on SMP && !X86_VOYAGER
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 8cb420f..ca668d9 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -82,7 +82,7 @@
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
.ascii "HdrS" # header signature
- .word 0x0203 # header version number (>= 0x0105)
+ .word 0x0204 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
start_sys_seg: .word SYSSEG
diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
index 6835f6d..0579841 100644
--- a/arch/i386/boot/tools/build.c
+++ b/arch/i386/boot/tools/build.c
@@ -177,7 +177,9 @@
die("Output: seek failed");
buf[0] = (sys_size & 0xff);
buf[1] = ((sys_size >> 8) & 0xff);
- if (write(1, buf, 2) != 2)
+ buf[2] = ((sys_size >> 16) & 0xff);
+ buf[3] = ((sys_size >> 24) & 0xff);
+ if (write(1, buf, 4) != 4)
die("Write of image length failed");
return 0; /* Everything is OK */
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 4cc83b3..64682a0 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -7,7 +7,7 @@
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
- doublefault.o quirks.o
+ doublefault.o quirks.o i8237.o
obj-y += cpu/
obj-y += timers/
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index b7808a8..34ee500 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -833,6 +833,9 @@
if (!error) {
acpi_lapic = 1;
+#ifdef CONFIG_X86_GENERICARCH
+ generic_bigsmp_probe();
+#endif
/*
* Parse MADT IO-APIC entries
*/
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 4553ffd..46ce9b2 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -613,8 +613,8 @@
memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu),
GDT_ENTRY_TLS_ENTRIES * 8);
- __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu]));
- __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
+ load_gdt(&cpu_gdt_descr[cpu]);
+ load_idt(&idt_descr);
/*
* Delete NT
@@ -642,12 +642,12 @@
asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
/* Clear all 6 debug registers: */
-
-#define CD(register) set_debugreg(0, register)
-
- CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
-
-#undef CD
+ set_debugreg(0, 0);
+ set_debugreg(0, 1);
+ set_debugreg(0, 2);
+ set_debugreg(0, 3);
+ set_debugreg(0, 6);
+ set_debugreg(0, 7);
/*
* Force FPU initialization:
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 04e3563d..bf02b502 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -64,8 +64,6 @@
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
-#define __hlt() __asm__ __volatile__("hlt": : :"memory")
-
/* Clock ratios multiplied by 10 */
static int clock_ratio[32];
static int eblcr_table[32];
@@ -168,11 +166,9 @@
outb(0xFE,0x21); /* TMR0 only */
outb(0xFF,0x80); /* delay */
- local_irq_enable();
-
- __hlt();
+ safe_halt();
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
- __hlt();
+ halt();
local_irq_disable();
@@ -251,9 +247,7 @@
bcr2.bits.CLOCKMUL = clock_ratio_index;
local_irq_disable();
wrmsrl (MSR_VIA_BCR2, bcr2.val);
- local_irq_enable();
-
- __hlt();
+ safe_halt();
/* Disable software clock multiplier */
rdmsrl (MSR_VIA_BCR2, bcr2.val);
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index ba4b011..ff87cc2 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -132,11 +132,7 @@
setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
/* set 'Not Write-through' */
cr0 = 0x20000000;
- __asm__("movl %%cr0,%%eax\n\t"
- "orl %0,%%eax\n\t"
- "movl %%eax,%%cr0\n"
- : : "r" (cr0)
- :"ax");
+ write_cr0(read_cr0() | cr0);
/* CCR2 bit 2: lock NW bit and set WT1 */
setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14 );
}
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index a2c33c1..43601de 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -82,16 +82,13 @@
*/
static int __devinit num_cpu_cores(struct cpuinfo_x86 *c)
{
- unsigned int eax;
+ unsigned int eax, ebx, ecx, edx;
if (c->cpuid_level < 4)
return 1;
- __asm__("cpuid"
- : "=a" (eax)
- : "0" (4), "c" (0)
- : "bx", "dx");
-
+ /* Intel has a non-standard dependency on %ecx for this CPUID level. */
+ cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
if (eax & 0x1f)
return ((eax >> 26) + 1);
else
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index 6c55b50..9e0d5f8 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -305,6 +305,9 @@
{
struct _cpuid4_info *this_leaf;
unsigned long num_threads_sharing;
+#ifdef CONFIG_X86_HT
+ struct cpuinfo_x86 *c = cpu_data + cpu;
+#endif
this_leaf = CPUID4_INFO_IDX(cpu, index);
num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;
@@ -314,10 +317,12 @@
#ifdef CONFIG_X86_HT
else if (num_threads_sharing == smp_num_siblings)
this_leaf->shared_cpu_map = cpu_sibling_map[cpu];
-#endif
+ else if (num_threads_sharing == (c->x86_num_cores * smp_num_siblings))
+ this_leaf->shared_cpu_map = cpu_core_map[cpu];
else
- printk(KERN_INFO "Number of CPUs sharing cache didn't match "
+ printk(KERN_DEBUG "Number of CPUs sharing cache didn't match "
"any known set of CPUs\n");
+#endif
}
#else
static void __init cache_shared_cpu_map_setup(unsigned int cpu, int index) {}
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 764cac6..dd4ebd6 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -561,7 +561,7 @@
static struct mtrr_value * mtrr_state;
-static int mtrr_save(struct sys_device * sysdev, u32 state)
+static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
{
int i;
int size = num_var_ranges * sizeof(struct mtrr_value);
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index e5fab12..913be77 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -153,7 +153,7 @@
disable_local_APIC();
atomic_dec(&waiting_for_crash_ipi);
/* Assume hlt works */
- __asm__("hlt");
+ halt();
for(;;);
return 1;
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
index a3cdf89..58516e2 100644
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -6,32 +6,28 @@
#include <linux/bootmem.h>
-struct dmi_header {
- u8 type;
- u8 length;
- u16 handle;
-};
-
-#undef DMI_DEBUG
-
-#ifdef DMI_DEBUG
-#define dmi_printk(x) printk x
-#else
-#define dmi_printk(x)
-#endif
-
static char * __init dmi_string(struct dmi_header *dm, u8 s)
{
u8 *bp = ((u8 *) dm) + dm->length;
+ char *str = "";
- if (!s)
- return "";
- s--;
- while (s > 0 && *bp) {
- bp += strlen(bp) + 1;
+ if (s) {
s--;
- }
- return bp;
+ while (s > 0 && *bp) {
+ bp += strlen(bp) + 1;
+ s--;
+ }
+
+ if (*bp != 0) {
+ str = alloc_bootmem(strlen(bp) + 1);
+ if (str != NULL)
+ strcpy(str, bp);
+ else
+ printk(KERN_ERR "dmi_string: out of memory.\n");
+ }
+ }
+
+ return str;
}
/*
@@ -84,7 +80,111 @@
return sum == 0;
}
-static int __init dmi_iterate(void (*decode)(struct dmi_header *))
+static char *dmi_ident[DMI_STRING_MAX];
+static LIST_HEAD(dmi_devices);
+
+/*
+ * Save a DMI string
+ */
+static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
+{
+ char *p, *d = (char*) dm;
+
+ if (dmi_ident[slot])
+ return;
+
+ p = dmi_string(dm, d[string]);
+ if (p == NULL)
+ return;
+
+ dmi_ident[slot] = p;
+}
+
+static void __init dmi_save_devices(struct dmi_header *dm)
+{
+ int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
+ struct dmi_device *dev;
+
+ for (i = 0; i < count; i++) {
+ char *d = ((char *) dm) + (i * 2);
+
+ /* Skip disabled device */
+ if ((*d & 0x80) == 0)
+ continue;
+
+ dev = alloc_bootmem(sizeof(*dev));
+ if (!dev) {
+ printk(KERN_ERR "dmi_save_devices: out of memory.\n");
+ break;
+ }
+
+ dev->type = *d++ & 0x7f;
+ dev->name = dmi_string(dm, *d);
+ dev->device_data = NULL;
+
+ list_add(&dev->list, &dmi_devices);
+ }
+}
+
+static void __init dmi_save_ipmi_device(struct dmi_header *dm)
+{
+ struct dmi_device *dev;
+ void * data;
+
+ data = alloc_bootmem(dm->length);
+ if (data == NULL) {
+ printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
+ return;
+ }
+
+ memcpy(data, dm, dm->length);
+
+ dev = alloc_bootmem(sizeof(*dev));
+ if (!dev) {
+ printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
+ return;
+ }
+
+ dev->type = DMI_DEV_TYPE_IPMI;
+ dev->name = "IPMI controller";
+ dev->device_data = data;
+
+ list_add(&dev->list, &dmi_devices);
+}
+
+/*
+ * Process a DMI table entry. Right now all we care about are the BIOS
+ * and machine entries. For 2.5 we should pull the smbus controller info
+ * out of here.
+ */
+static void __init dmi_decode(struct dmi_header *dm)
+{
+ switch(dm->type) {
+ case 0: /* BIOS Information */
+ dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+ dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+ dmi_save_ident(dm, DMI_BIOS_DATE, 8);
+ break;
+ case 1: /* System Information */
+ dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+ dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+ dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+ dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
+ break;
+ case 2: /* Base Board Information */
+ dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+ dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+ dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
+ break;
+ case 10: /* Onboard Devices Information */
+ dmi_save_devices(dm);
+ break;
+ case 38: /* IPMI Device Information */
+ dmi_save_ipmi_device(dm);
+ }
+}
+
+void __init dmi_scan_machine(void)
{
u8 buf[15];
char __iomem *p, *q;
@@ -96,7 +196,7 @@
*/
p = ioremap(0xF0000, 0x10000);
if (p == NULL)
- return -1;
+ goto out;
for (q = p; q < p + 0x10000; q += 16) {
memcpy_fromio(buf, q, 15);
@@ -116,82 +216,12 @@
else
printk(KERN_INFO "DMI present.\n");
- dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
- num, len));
- dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
-
- if (dmi_table(base,len, num, decode) == 0)
- return 0;
+ if (dmi_table(base,len, num, dmi_decode) == 0)
+ return;
}
}
- return -1;
-}
-static char *dmi_ident[DMI_STRING_MAX];
-
-/*
- * Save a DMI string
- */
-static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
-{
- char *d = (char*)dm;
- char *p = dmi_string(dm, d[string]);
-
- if (p == NULL || *p == 0)
- return;
- if (dmi_ident[slot])
- return;
-
- dmi_ident[slot] = alloc_bootmem(strlen(p) + 1);
- if(dmi_ident[slot])
- strcpy(dmi_ident[slot], p);
- else
- printk(KERN_ERR "dmi_save_ident: out of memory.\n");
-}
-
-/*
- * Process a DMI table entry. Right now all we care about are the BIOS
- * and machine entries. For 2.5 we should pull the smbus controller info
- * out of here.
- */
-static void __init dmi_decode(struct dmi_header *dm)
-{
- u8 *data __attribute__((__unused__)) = (u8 *)dm;
-
- switch(dm->type) {
- case 0:
- dmi_printk(("BIOS Vendor: %s\n", dmi_string(dm, data[4])));
- dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
- dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5])));
- dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
- dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8])));
- dmi_save_ident(dm, DMI_BIOS_DATE, 8);
- break;
- case 1:
- dmi_printk(("System Vendor: %s\n", dmi_string(dm, data[4])));
- dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
- dmi_printk(("Product Name: %s\n", dmi_string(dm, data[5])));
- dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
- dmi_printk(("Version: %s\n", dmi_string(dm, data[6])));
- dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
- dmi_printk(("Serial Number: %s\n", dmi_string(dm, data[7])));
- dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
- break;
- case 2:
- dmi_printk(("Board Vendor: %s\n", dmi_string(dm, data[4])));
- dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
- dmi_printk(("Board Name: %s\n", dmi_string(dm, data[5])));
- dmi_save_ident(dm, DMI_BOARD_NAME, 5);
- dmi_printk(("Board Version: %s\n", dmi_string(dm, data[6])));
- dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
- break;
- }
-}
-
-void __init dmi_scan_machine(void)
-{
- if (dmi_iterate(dmi_decode))
- printk(KERN_INFO "DMI not present.\n");
+out: printk(KERN_INFO "DMI not present.\n");
}
@@ -218,9 +248,9 @@
/* No match */
goto fail;
}
+ count++;
if (d->callback && d->callback(d))
break;
- count++;
fail: d++;
}
@@ -240,3 +270,32 @@
return dmi_ident[field];
}
EXPORT_SYMBOL(dmi_get_system_info);
+
+/**
+ * dmi_find_device - find onboard device by type/name
+ * @type: device type or %DMI_DEV_TYPE_ANY to match all device types
+ * @desc: device name string or %NULL to match all
+ * @from: previous device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known onboard devices. If a device is
+ * found with a matching @vendor and @device, a pointer to its device
+ * structure is returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * If @from is not %NULL, searches continue from next device.
+ */
+struct dmi_device * dmi_find_device(int type, const char *name,
+ struct dmi_device *from)
+{
+ struct list_head *d, *head = from ? &from->list : &dmi_devices;
+
+ for(d = head->next; d != &dmi_devices; d = d->next) {
+ struct dmi_device *dev = list_entry(d, struct dmi_device, list);
+
+ if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
+ ((name == NULL) || (strcmp(dev->name, name) == 0)))
+ return dev;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(dmi_find_device);
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index 789af3e..5edb1d3 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -20,7 +20,7 @@
struct Xgt_desc_struct gdt_desc = {0, 0};
unsigned long gdt, tss;
- __asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory");
+ store_gdt(&gdt_desc);
gdt = gdt_desc.address;
printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index 385883e..ecad519 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -79,7 +79,7 @@
* directory. If I have PSE, I just need to duplicate one entry in
* page directory.
*/
- __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
+ cr4 = read_cr4();
if (cr4 & X86_CR4_PSE) {
efi_bak_pg_dir_pointer[0].pgd =
@@ -104,8 +104,7 @@
local_flush_tlb();
cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address);
- __asm__ __volatile__("lgdt %0":"=m"
- (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])));
+ load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0]));
}
static void efi_call_phys_epilog(void)
@@ -114,8 +113,8 @@
cpu_gdt_descr[0].address =
(unsigned long) __va(cpu_gdt_descr[0].address);
- __asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr));
- __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
+ load_gdt(&cpu_gdt_descr[0]);
+ cr4 = read_cr4();
if (cr4 & X86_CR4_PSE) {
swapper_pg_dir[pgd_index(0)].pgd =
@@ -233,22 +232,23 @@
{
memmap.map = NULL;
- memmap.map = (efi_memory_desc_t *)
- bt_ioremap((unsigned long) memmap.phys_map,
- (memmap.nr_map * sizeof(efi_memory_desc_t)));
-
+ memmap.map = bt_ioremap((unsigned long) memmap.phys_map,
+ (memmap.nr_map * memmap.desc_size));
if (memmap.map == NULL)
printk(KERN_ERR PFX "Could not remap the EFI memmap!\n");
+
+ memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
}
#if EFI_DEBUG
static void __init print_efi_memmap(void)
{
efi_memory_desc_t *md;
+ void *p;
int i;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) {
+ md = p;
printk(KERN_INFO "mem%02u: type=%u, attr=0x%llx, "
"range=[0x%016llx-0x%016llx) (%lluMB)\n",
i, md->type, md->attribute, md->phys_addr,
@@ -271,10 +271,10 @@
} prev, curr;
efi_memory_desc_t *md;
unsigned long start, end;
- int i;
+ void *p;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
if ((md->num_pages == 0) || (!is_available_memory(md)))
continue;
@@ -325,6 +325,7 @@
memmap.phys_map = EFI_MEMMAP;
memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
memmap.desc_version = EFI_MEMDESC_VERSION;
+ memmap.desc_size = EFI_MEMDESC_SIZE;
efi.systab = (efi_system_table_t *)
boot_ioremap((unsigned long) efi_phys.systab,
@@ -428,22 +429,30 @@
printk(KERN_ERR PFX "Could not map the runtime service table!\n");
/* Map the EFI memory map for use until paging_init() */
-
- memmap.map = (efi_memory_desc_t *)
- boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE);
-
+ memmap.map = boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE);
if (memmap.map == NULL)
printk(KERN_ERR PFX "Could not map the EFI memory map!\n");
- if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) {
- printk(KERN_WARNING PFX "Warning! Kernel-defined memdesc doesn't "
- "match the one from EFI!\n");
- }
+ memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
#if EFI_DEBUG
print_efi_memmap();
#endif
}
+static inline void __init check_range_for_systab(efi_memory_desc_t *md)
+{
+ if (((unsigned long)md->phys_addr <= (unsigned long)efi_phys.systab) &&
+ ((unsigned long)efi_phys.systab < md->phys_addr +
+ ((unsigned long)md->num_pages << EFI_PAGE_SHIFT))) {
+ unsigned long addr;
+
+ addr = md->virt_addr - md->phys_addr +
+ (unsigned long)efi_phys.systab;
+ efi.systab = (efi_system_table_t *)addr;
+ }
+}
+
/*
* This function will switch the EFI runtime services to virtual mode.
* Essentially, look through the EFI memmap and map every region that
@@ -457,43 +466,32 @@
{
efi_memory_desc_t *md;
efi_status_t status;
- int i;
+ void *p;
efi.systab = NULL;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
- if (md->attribute & EFI_MEMORY_RUNTIME) {
- md->virt_addr =
- (unsigned long)ioremap(md->phys_addr,
- md->num_pages << EFI_PAGE_SHIFT);
- if (!(unsigned long)md->virt_addr) {
- printk(KERN_ERR PFX "ioremap of 0x%lX failed\n",
- (unsigned long)md->phys_addr);
- }
+ if (!(md->attribute & EFI_MEMORY_RUNTIME))
+ continue;
- if (((unsigned long)md->phys_addr <=
- (unsigned long)efi_phys.systab) &&
- ((unsigned long)efi_phys.systab <
- md->phys_addr +
- ((unsigned long)md->num_pages <<
- EFI_PAGE_SHIFT))) {
- unsigned long addr;
-
- addr = md->virt_addr - md->phys_addr +
- (unsigned long)efi_phys.systab;
- efi.systab = (efi_system_table_t *)addr;
- }
+ md->virt_addr = (unsigned long)ioremap(md->phys_addr,
+ md->num_pages << EFI_PAGE_SHIFT);
+ if (!(unsigned long)md->virt_addr) {
+ printk(KERN_ERR PFX "ioremap of 0x%lX failed\n",
+ (unsigned long)md->phys_addr);
}
+ /* update the virtual address of the EFI system table */
+ check_range_for_systab(md);
}
if (!efi.systab)
BUG();
status = phys_efi_set_virtual_address_map(
- sizeof(efi_memory_desc_t) * memmap.nr_map,
- sizeof(efi_memory_desc_t),
+ memmap.desc_size * memmap.nr_map,
+ memmap.desc_size,
memmap.desc_version,
memmap.phys_map);
@@ -533,10 +531,10 @@
{
struct resource *res;
efi_memory_desc_t *md;
- int i;
+ void *p;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >
0x100000000ULL)
@@ -613,10 +611,10 @@
u32 efi_mem_type(unsigned long phys_addr)
{
efi_memory_desc_t *md;
- int i;
+ void *p;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
if ((md->phys_addr <= phys_addr) && (phys_addr <
(md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
return md->type;
@@ -627,10 +625,10 @@
u64 efi_mem_attributes(unsigned long phys_addr)
{
efi_memory_desc_t *md;
- int i;
+ void *p;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
if ((md->phys_addr <= phys_addr) && (phys_addr <
(md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
return md->attribute;
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index a991d4e..3aad038 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -203,7 +203,7 @@
GET_THREAD_INFO(%ebp)
/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
- testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
+ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax
jae syscall_badsys
@@ -226,9 +226,9 @@
pushl %eax # save orig_eax
SAVE_ALL
GET_THREAD_INFO(%ebp)
- # system call tracing in operation
+ # system call tracing in operation / emulation
/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
- testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
+ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax
jae syscall_badsys
@@ -338,6 +338,9 @@
movl %esp, %eax
xorl %edx,%edx
call do_syscall_trace
+ cmpl $0, %eax
+ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU,
+ # so must skip actual syscall
movl ORIG_EAX(%esp), %eax
cmpl $(nr_syscalls), %eax
jnae syscall_call
@@ -504,7 +507,7 @@
pushl $__KERNEL_CS; \
pushl $sysenter_past_esp
-ENTRY(debug)
+KPROBE_ENTRY(debug)
cmpl $sysenter_entry,(%esp)
jne debug_stack_correct
FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
@@ -515,7 +518,7 @@
movl %esp,%eax # pt_regs pointer
call do_debug
jmp ret_from_exception
-
+ .previous .text
/*
* NMI is doubly nasty. It can happen _while_ we're handling
* a debug fault, and the debug fault hasn't yet been able to
@@ -588,13 +591,14 @@
.long 1b,iret_exc
.previous
-ENTRY(int3)
+KPROBE_ENTRY(int3)
pushl $-1 # mark this as an int
SAVE_ALL
xorl %edx,%edx # zero error code
movl %esp,%eax # pt_regs pointer
call do_int3
jmp ret_from_exception
+ .previous .text
ENTRY(overflow)
pushl $0
@@ -628,17 +632,19 @@
pushl $do_stack_segment
jmp error_code
-ENTRY(general_protection)
+KPROBE_ENTRY(general_protection)
pushl $do_general_protection
jmp error_code
+ .previous .text
ENTRY(alignment_check)
pushl $do_alignment_check
jmp error_code
-ENTRY(page_fault)
+KPROBE_ENTRY(page_fault)
pushl $do_page_fault
jmp error_code
+ .previous .text
#ifdef CONFIG_X86_MCE
ENTRY(machine_check)
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 4477bb1..0480ca9 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -77,6 +77,32 @@
subl %edi,%ecx
shrl $2,%ecx
rep ; stosl
+/*
+ * Copy bootup parameters out of the way.
+ * Note: %esi still has the pointer to the real-mode data.
+ * With the kexec as boot loader, parameter segment might be loaded beyond
+ * kernel image and might not even be addressable by early boot page tables.
+ * (kexec on panic case). Hence copy out the parameters before initializing
+ * page tables.
+ */
+ movl $(boot_params - __PAGE_OFFSET),%edi
+ movl $(PARAM_SIZE/4),%ecx
+ cld
+ rep
+ movsl
+ movl boot_params - __PAGE_OFFSET + NEW_CL_POINTER,%esi
+ andl %esi,%esi
+ jnz 2f # New command line protocol
+ cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
+ jne 1f
+ movzwl OLD_CL_OFFSET,%esi
+ addl $(OLD_CL_BASE_ADDR),%esi
+2:
+ movl $(saved_command_line - __PAGE_OFFSET),%edi
+ movl $(COMMAND_LINE_SIZE/4),%ecx
+ rep
+ movsl
+1:
/*
* Initialize page tables. This creates a PDE and a set of page
@@ -214,28 +240,6 @@
*/
call setup_idt
-/*
- * Copy bootup parameters out of the way.
- * Note: %esi still has the pointer to the real-mode data.
- */
- movl $boot_params,%edi
- movl $(PARAM_SIZE/4),%ecx
- cld
- rep
- movsl
- movl boot_params+NEW_CL_POINTER,%esi
- andl %esi,%esi
- jnz 2f # New command line protocol
- cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
- jne 1f
- movzwl OLD_CL_OFFSET,%esi
- addl $(OLD_CL_BASE_ADDR),%esi
-2:
- movl $saved_command_line,%edi
- movl $(COMMAND_LINE_SIZE/4),%ecx
- rep
- movsl
-1:
checkCPUtype:
movl $-1,X86_CPUID # -1 for no CPUID initially
diff --git a/arch/i386/kernel/i8237.c b/arch/i386/kernel/i8237.c
new file mode 100644
index 0000000..c36d1c0
--- /dev/null
+++ b/arch/i386/kernel/i8237.c
@@ -0,0 +1,67 @@
+/*
+ * i8237.c: 8237A DMA controller suspend functions.
+ *
+ * Written by Pierre Ossman, 2005.
+ */
+
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+
+/*
+ * This module just handles suspend/resume issues with the
+ * 8237A DMA controller (used for ISA and LPC).
+ * Allocation is handled in kernel/dma.c and normal usage is
+ * in asm/dma.h.
+ */
+
+static int i8237A_resume(struct sys_device *dev)
+{
+ unsigned long flags;
+ int i;
+
+ flags = claim_dma_lock();
+
+ dma_outb(DMA1_RESET_REG, 0);
+ dma_outb(DMA2_RESET_REG, 0);
+
+ for (i = 0;i < 8;i++) {
+ set_dma_addr(i, 0x000000);
+ /* DMA count is a bit weird so this is not 0 */
+ set_dma_count(i, 1);
+ }
+
+ /* Enable cascade DMA or channel 0-3 won't work */
+ enable_dma(4);
+
+ release_dma_lock(flags);
+
+ return 0;
+}
+
+static int i8237A_suspend(struct sys_device *dev, pm_message_t state)
+{
+ return 0;
+}
+
+static struct sysdev_class i8237_sysdev_class = {
+ set_kset_name("i8237"),
+ .suspend = i8237A_suspend,
+ .resume = i8237A_resume,
+};
+
+static struct sys_device device_i8237A = {
+ .id = 0,
+ .cls = &i8237_sysdev_class,
+};
+
+static int __init i8237A_init_sysfs(void)
+{
+ int error = sysdev_class_register(&i8237_sysdev_class);
+ if (!error)
+ error = sysdev_register(&device_i8237A);
+ return error;
+}
+
+device_initcall(i8237A_init_sysfs);
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 6578f40..0e727e6 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -33,6 +33,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/sysdev.h>
+
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/desc.h>
@@ -77,7 +78,7 @@
int apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
#ifdef CONFIG_PCI_MSI
#define vector_to_irq(vector) \
(platform_legacy_irq(vector) ? vector : vector_irq[vector])
@@ -222,13 +223,21 @@
clear_IO_APIC_pin(apic, pin);
}
+#ifdef CONFIG_SMP
static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
{
unsigned long flags;
int pin;
struct irq_pin_list *entry = irq_2_pin + irq;
unsigned int apicid_value;
+ cpumask_t tmp;
+ cpus_and(tmp, cpumask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(cpumask, tmp, CPU_MASK_ALL);
+
apicid_value = cpu_mask_to_apicid(cpumask);
/* Prepare to do the io_apic_write */
apicid_value = apicid_value << 24;
@@ -242,6 +251,7 @@
break;
entry = irq_2_pin + entry->next;
}
+ set_irq_info(irq, cpumask);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -259,7 +269,6 @@
# define Dprintk(x...)
# endif
-cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
#define IRQBALANCE_CHECK_ARCH -999
static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
@@ -328,12 +337,7 @@
cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]);
new_cpu = move(cpu, allowed_mask, now, 1);
if (cpu != new_cpu) {
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu);
- spin_unlock_irqrestore(&desc->lock, flags);
+ set_pending_irq(irq, cpumask_of_cpu(new_cpu));
}
}
@@ -528,16 +532,12 @@
cpus_and(tmp, target_cpu_mask, allowed_mask);
if (!cpus_empty(tmp)) {
- irq_desc_t *desc = irq_desc + selected_irq;
- unsigned long flags;
Dprintk("irq = %d moved to cpu = %d\n",
selected_irq, min_loaded);
/* mark for change destination */
- spin_lock_irqsave(&desc->lock, flags);
- pending_irq_balance_cpumask[selected_irq] =
- cpumask_of_cpu(min_loaded);
- spin_unlock_irqrestore(&desc->lock, flags);
+ set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
+
/* Since we made a change, come back sooner to
* check for more variation.
*/
@@ -568,7 +568,8 @@
/* push everything to CPU 0 to give us a starting point. */
for (i = 0 ; i < NR_IRQS ; i++) {
- pending_irq_balance_cpumask[i] = cpumask_of_cpu(0);
+ pending_irq_cpumask[i] = cpumask_of_cpu(0);
+ set_pending_irq(i, cpumask_of_cpu(0));
}
for ( ; ; ) {
@@ -647,20 +648,9 @@
__setup("noirqbalance", irqbalance_disable);
-static inline void move_irq(int irq)
-{
- /* note - we hold the desc->lock */
- if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) {
- set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]);
- cpus_clear(pending_irq_balance_cpumask[irq]);
- }
-}
-
late_initcall(balanced_irq_init);
-
-#else /* !CONFIG_IRQBALANCE */
-static inline void move_irq(int irq) { }
#endif /* CONFIG_IRQBALANCE */
+#endif /* CONFIG_SMP */
#ifndef CONFIG_SMP
void fastcall send_IPI_self(int vector)
@@ -820,6 +810,7 @@
* we need to reprogram the ioredtbls to cater for the cpus which have come online
* so mask in all cases should simply be TARGET_CPUS
*/
+#ifdef CONFIG_SMP
void __init setup_ioapic_dest(void)
{
int pin, ioapic, irq, irq_entry;
@@ -838,6 +829,7 @@
}
}
+#endif
/*
* EISA Edge/Level control register, ELCR
@@ -1127,7 +1119,7 @@
}
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
int assign_irq_vector(int irq)
{
@@ -1249,6 +1241,7 @@
spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+ set_native_irq_info(irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
}
@@ -1944,6 +1937,7 @@
{
int irq = vector_to_irq(vector);
+ move_irq(vector);
ack_edge_ioapic_irq(irq);
}
@@ -1958,6 +1952,7 @@
{
int irq = vector_to_irq(vector);
+ move_irq(vector);
end_level_ioapic_irq(irq);
}
@@ -1975,14 +1970,17 @@
unmask_IO_APIC_irq(irq);
}
+#ifdef CONFIG_SMP
static void set_ioapic_affinity_vector (unsigned int vector,
cpumask_t cpu_mask)
{
int irq = vector_to_irq(vector);
+ set_native_irq_info(vector, cpu_mask);
set_ioapic_affinity_irq(irq, cpu_mask);
}
#endif
+#endif
/*
* Level and edge triggered IO-APIC interrupts need different handling,
@@ -1992,7 +1990,7 @@
* edge-triggered handler, without risking IRQ storms and other ugly
* races.
*/
-static struct hw_interrupt_type ioapic_edge_type = {
+static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
.typename = "IO-APIC-edge",
.startup = startup_edge_ioapic,
.shutdown = shutdown_edge_ioapic,
@@ -2000,10 +1998,12 @@
.disable = disable_edge_ioapic,
.ack = ack_edge_ioapic,
.end = end_edge_ioapic,
+#ifdef CONFIG_SMP
.set_affinity = set_ioapic_affinity,
+#endif
};
-static struct hw_interrupt_type ioapic_level_type = {
+static struct hw_interrupt_type ioapic_level_type __read_mostly = {
.typename = "IO-APIC-level",
.startup = startup_level_ioapic,
.shutdown = shutdown_level_ioapic,
@@ -2011,7 +2011,9 @@
.disable = disable_level_ioapic,
.ack = mask_and_ack_level_ioapic,
.end = end_level_ioapic,
+#ifdef CONFIG_SMP
.set_affinity = set_ioapic_affinity,
+#endif
};
static inline void init_IO_APIC_traps(void)
@@ -2074,7 +2076,7 @@
static void end_lapic_irq (unsigned int i) { /* nothing */ }
-static struct hw_interrupt_type lapic_irq_type = {
+static struct hw_interrupt_type lapic_irq_type __read_mostly = {
.typename = "local-APIC-edge",
.startup = NULL, /* startup_irq() not used for IRQ0 */
.shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
@@ -2569,6 +2571,7 @@
spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+ set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
index 8b25160..f2b3765 100644
--- a/arch/i386/kernel/ioport.c
+++ b/arch/i386/kernel/ioport.c
@@ -132,6 +132,7 @@
volatile struct pt_regs * regs = (struct pt_regs *) &unused;
unsigned int level = regs->ebx;
unsigned int old = (regs->eflags >> 12) & 3;
+ struct thread_struct *t = ¤t->thread;
if (level > 3)
return -EINVAL;
@@ -140,8 +141,8 @@
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
}
- regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12);
- /* Make sure we return the long way (not sysenter) */
- set_thread_flag(TIF_IRET);
+ t->iopl = level << 12;
+ regs->eflags = (regs->eflags & ~X86_EFLAGS_IOPL) | t->iopl;
+ set_iopl_mask(t->iopl);
return 0;
}
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index a6d8c45..6345b43 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -62,32 +62,32 @@
return 0;
}
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
return 0;
}
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
}
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
{
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
{
}
@@ -127,7 +127,8 @@
regs->eip = (unsigned long)&p->ainsn.insn;
}
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+ struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)®s->esp;
struct kretprobe_instance *ri;
@@ -150,7 +151,7 @@
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
* remain disabled thorough out this function.
*/
-static int kprobe_handler(struct pt_regs *regs)
+static int __kprobes kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
int ret = 0;
@@ -176,7 +177,8 @@
Disarm the probe we just hit, and ignore it. */
p = get_kprobe(addr);
if (p) {
- if (kprobe_status == KPROBE_HIT_SS) {
+ if (kprobe_status == KPROBE_HIT_SS &&
+ *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
regs->eflags &= ~TF_MASK;
regs->eflags |= kprobe_saved_eflags;
unlock_kprobes();
@@ -220,7 +222,10 @@
* either a probepoint or a debugger breakpoint
* at this address. In either case, no further
* handling of this interrupt is appropriate.
+ * Back up over the (now missing) int3 and run
+ * the original instruction.
*/
+ regs->eip -= sizeof(kprobe_opcode_t);
ret = 1;
}
/* Not one of ours: let kernel handle it */
@@ -259,7 +264,7 @@
/*
* Called when we hit the probe point at kretprobe_trampoline
*/
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head;
@@ -338,7 +343,7 @@
* that is atop the stack is the address following the copied instruction.
* We need to make it the address following the original instruction.
*/
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
unsigned long *tos = (unsigned long *)®s->esp;
unsigned long next_eip = 0;
@@ -444,8 +449,8 @@
/*
* Wrapper routine to for handling exceptions.
*/
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
- void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
switch (val) {
@@ -473,7 +478,7 @@
return NOTIFY_DONE;
}
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
unsigned long addr;
@@ -495,7 +500,7 @@
return 1;
}
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
{
preempt_enable_no_resched();
asm volatile (" xchgl %%ebx,%%esp \n"
@@ -506,7 +511,7 @@
(jprobe_saved_esp):"memory");
}
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
u8 *addr = (u8 *) (regs->eip - 1);
unsigned long stack_addr = (unsigned long)jprobe_saved_esp;
diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
index bb50afb..fe1ffa5 100644
--- a/arch/i386/kernel/ldt.c
+++ b/arch/i386/kernel/ldt.c
@@ -177,7 +177,7 @@
static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
{
struct mm_struct * mm = current->mm;
- __u32 entry_1, entry_2, *lp;
+ __u32 entry_1, entry_2;
int error;
struct user_desc ldt_info;
@@ -205,8 +205,6 @@
goto out_unlock;
}
- lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
-
/* Allow LDTs to be cleared by the user. */
if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
if (oldmode || LDT_empty(&ldt_info)) {
@@ -223,8 +221,7 @@
/* Install the new entry ... */
install:
- *lp = entry_1;
- *(lp+1) = entry_2;
+ write_ldt_entry(mm->context.ldt, ldt_info.entry_number, entry_1, entry_2);
error = 0;
out_unlock:
diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c
index cb699a2..a912fed 100644
--- a/arch/i386/kernel/machine_kexec.c
+++ b/arch/i386/kernel/machine_kexec.c
@@ -17,13 +17,7 @@
#include <asm/apic.h>
#include <asm/cpufeature.h>
#include <asm/desc.h>
-
-static inline unsigned long read_cr3(void)
-{
- unsigned long cr3;
- asm volatile("movl %%cr3,%0": "=r"(cr3));
- return cr3;
-}
+#include <asm/system.h>
#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
@@ -99,10 +93,7 @@
curidt.size = limit;
curidt.address = (unsigned long)newidt;
- __asm__ __volatile__ (
- "lidtl %0\n"
- : : "m" (curidt)
- );
+ load_idt(&curidt);
};
@@ -114,10 +105,7 @@
curgdt.size = limit;
curgdt.address = (unsigned long)newgdt;
- __asm__ __volatile__ (
- "lgdtl %0\n"
- : : "m" (curgdt)
- );
+ load_gdt(&curgdt);
};
static void load_segments(void)
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index a77c612..165f131 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -164,7 +164,8 @@
}
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+ /* see notes above for revision 1.07. Apparent chip bug */
+ serialize_cpu();
/* get the current revision from MSR 0x8B */
rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
@@ -377,7 +378,9 @@
(unsigned long) uci->mc->bits >> 16 >> 16);
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+ /* see notes above for revision 1.07. Apparent chip bug */
+ serialize_cpu();
+
/* get the current revision from MSR 0x8B */
rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index ce838ab..5d0b9a8f 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -65,6 +65,8 @@
int pic_mode;
unsigned long mp_lapic_addr;
+unsigned int def_to_bigsmp = 0;
+
/* Processor that is doing the boot up */
unsigned int boot_cpu_physical_apicid = -1U;
/* Internal processor count */
@@ -120,7 +122,7 @@
static void __init MP_processor_info (struct mpc_config_processor *m)
{
- int ver, apicid;
+ int ver, apicid, cpu, found_bsp = 0;
physid_mask_t tmp;
if (!(m->mpc_cpuflag & CPU_ENABLED))
@@ -179,6 +181,7 @@
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
Dprintk(" Bootup CPU\n");
boot_cpu_physical_apicid = m->mpc_apicid;
+ found_bsp = 1;
}
if (num_processors >= NR_CPUS) {
@@ -202,6 +205,11 @@
return;
}
+ if (found_bsp)
+ cpu = 0;
+ else
+ cpu = num_processors - 1;
+ cpu_set(cpu, cpu_possible_map);
tmp = apicid_to_cpu_present(apicid);
physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp);
@@ -213,6 +221,13 @@
ver = 0x10;
}
apic_version[m->mpc_apicid] = ver;
+ if ((num_processors > 8) &&
+ APIC_XAPIC(ver) &&
+ (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL))
+ def_to_bigsmp = 1;
+ else
+ def_to_bigsmp = 0;
+
bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;
}
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
index b2f03c3..03100d6 100644
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -46,23 +46,13 @@
static struct class *msr_class;
-/* Note: "err" is handled in a funny way below. Otherwise one version
- of gcc or another breaks. */
-
static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
{
int err;
- asm volatile ("1: wrmsr\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- "3: movl %4,%0\n"
- " jmp 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n" " .long 1b,3b\n" ".previous":"=&bDS" (err)
- :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0));
-
+ err = wrmsr_safe(reg, eax, edx);
+ if (err)
+ err = -EIO;
return err;
}
@@ -70,18 +60,9 @@
{
int err;
- asm volatile ("1: rdmsr\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- "3: movl %4,%0\n"
- " jmp 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,3b\n"
- ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx)
- :"c"(reg), "i"(-EIO), "0"(0));
-
+ err = rdmsr_safe(reg, eax, edx);
+ if (err)
+ err = -EIO;
return err;
}
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 8c242bb..0178457 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -478,6 +478,11 @@
*/
for (i = 0; i < NR_CPUS; i++)
alert_counter[i] = 0;
+
+ /*
+ * Tickle the softlockup detector too:
+ */
+ touch_softlockup_watchdog();
}
extern void die_nmi(struct pt_regs *, const char *msg);
@@ -501,8 +506,11 @@
*/
alert_counter[cpu]++;
if (alert_counter[cpu] == 5*nmi_hz)
+ /*
+ * die_nmi will return ONLY if NOTIFY_STOP happens..
+ */
die_nmi(regs, "NMI Watchdog detected LOCKUP");
- } else {
+
last_irq_sums[cpu] = sum;
alert_counter[cpu] = 0;
}
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index e3f362e..b45cbf9 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -164,7 +164,7 @@
*/
local_irq_disable();
while (1)
- __asm__ __volatile__("hlt":::"memory");
+ halt();
}
#else
static inline void play_dead(void)
@@ -313,16 +313,12 @@
printk(" DS: %04x ES: %04x\n",
0xffff & regs->xds,0xffff & regs->xes);
- __asm__("movl %%cr0, %0": "=r" (cr0));
- __asm__("movl %%cr2, %0": "=r" (cr2));
- __asm__("movl %%cr3, %0": "=r" (cr3));
- /* This could fault if %cr4 does not exist */
- __asm__("1: movl %%cr4, %0 \n"
- "2: \n"
- ".section __ex_table,\"a\" \n"
- ".long 1b,2b \n"
- ".previous \n"
- : "=r" (cr4): "0" (0));
+ cr0 = read_cr0();
+ cr2 = read_cr2();
+ cr3 = read_cr3();
+ if (current_cpu_data.x86 > 4) {
+ cr4 = read_cr4();
+ }
printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
show_trace(NULL, ®s->esp);
}
@@ -682,23 +678,28 @@
__unlazy_fpu(prev_p);
/*
- * Reload esp0, LDT and the page table pointer:
+ * Reload esp0.
*/
load_esp0(tss, next);
/*
+ * Save away %fs and %gs. 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 where we temporarily have non-reloadable
+ * segments in %fs and %gs. This could be an issue if the
+ * NMI handler ever 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.
*/
load_TLS(next, cpu);
/*
- * Save away %fs and %gs. No need to save %es and %ds, as
- * those are always kernel segments while inside the kernel.
- */
- asm volatile("mov %%fs,%0":"=m" (prev->fs));
- asm volatile("mov %%gs,%0":"=m" (prev->gs));
-
- /*
* Restore %fs and %gs if needed.
*
* Glibc normally makes %fs be zero, and %gs is one of
@@ -711,6 +712,12 @@
loadsegment(gs, next->gs);
/*
+ * Restore IOPL if needed.
+ */
+ if (unlikely(prev->iopl != next->iopl))
+ set_iopl_mask(next->iopl);
+
+ /*
* Now maybe reload the debug registers
*/
if (unlikely(next->debugreg[7])) {
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 0da59b4..34098020 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -271,6 +271,8 @@
void ptrace_disable(struct task_struct *child)
{
clear_singlestep(child);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
}
/*
@@ -509,15 +511,20 @@
}
break;
+ case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* restart after signal. */
ret = -EIO;
if (!valid_signal(data))
break;
- if (request == PTRACE_SYSCALL) {
+ if (request == PTRACE_SYSEMU) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ } else if (request == PTRACE_SYSCALL) {
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- else {
+ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ } else {
+ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
child->exit_code = data;
@@ -542,10 +549,17 @@
wake_up_process(child);
break;
+ case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
case PTRACE_SINGLESTEP: /* set the trap flag. */
ret = -EIO;
if (!valid_signal(data))
break;
+
+ if (request == PTRACE_SYSEMU_SINGLESTEP)
+ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
set_singlestep(child);
child->exit_code = data;
@@ -678,26 +692,52 @@
* - triggered by current->work.syscall_trace
*/
__attribute__((regparm(3)))
-void do_syscall_trace(struct pt_regs *regs, int entryexit)
+int do_syscall_trace(struct pt_regs *regs, int entryexit)
{
+ int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0;
+ /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
+ * interception. */
+ int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
+
/* do the secure computing check first */
secure_computing(regs->orig_eax);
- if (unlikely(current->audit_context) && entryexit)
- audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
+ if (unlikely(current->audit_context)) {
+ if (entryexit)
+ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
+ /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
+ * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
+ * not used, entry.S will call us only on syscall exit, not
+ * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
+ * calling send_sigtrap() on syscall entry.
+ *
+ * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
+ * is_singlestep is false, despite his name, so we will still do
+ * the correct thing.
+ */
+ else if (is_singlestep)
+ goto out;
+ }
if (!(current->ptrace & PT_PTRACED))
goto out;
+ /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
+ * and then is resumed with SYSEMU_SINGLESTEP, it will come in
+ * here. We have to check this and return */
+ if (is_sysemu && entryexit)
+ return 0;
+
/* Fake a debug trap */
- if (test_thread_flag(TIF_SINGLESTEP))
+ if (is_singlestep)
send_sigtrap(current, regs, 0);
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
goto out;
/* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
+ /* Note that the debugger could change the result of test_thread_flag!*/
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
/*
@@ -709,9 +749,16 @@
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
+ ret = is_sysemu;
out:
if (unlikely(current->audit_context) && !entryexit)
audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
regs->ebx, regs->ecx, regs->edx, regs->esi);
+ if (ret == 0)
+ return 0;
+ regs->orig_eax = -1; /* force skip of syscall restarting */
+ if (unlikely(current->audit_context))
+ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
+ return 1;
}
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index c71fef3..1cbb9c0 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -13,6 +13,7 @@
#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/apic.h>
+#include <asm/desc.h>
#include "mach_reboot.h"
#include <linux/reboot_fixups.h>
@@ -242,13 +243,13 @@
/* Set up the IDT for real mode. */
- __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
+ load_idt(&real_mode_idt);
/* Set up a GDT from which we can load segment descriptors for real
mode. The GDT is not used in real mode; it is just needed here to
prepare the descriptors. */
- __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
+ load_gdt(&real_mode_gdt);
/* Load the data segment registers, and thus the descriptors ready for
real mode. The base address of each segment is 0x100, 16 times the
@@ -316,7 +317,7 @@
if (!reboot_thru_bios) {
if (efi_enabled) {
efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
- __asm__ __volatile__("lidt %0": :"m" (no_idt));
+ load_idt(&no_idt);
__asm__ __volatile__("int3");
}
/* rebooting needs to touch the page at absolute addr 0 */
@@ -325,7 +326,7 @@
mach_reboot_fixups(); /* for board specific fixups */
mach_reboot();
/* That didn't work - force a triple fault.. */
- __asm__ __volatile__("lidt %0": :"m" (no_idt));
+ load_idt(&no_idt);
__asm__ __volatile__("int3");
}
}
diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c
index 469f496..7455ab6 100644
--- a/arch/i386/kernel/semaphore.c
+++ b/arch/i386/kernel/semaphore.c
@@ -13,171 +13,9 @@
* rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
*/
#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/err.h>
-#include <linux/init.h>
#include <asm/semaphore.h>
/*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to acquire the semaphore, while the "sleeping"
- * variable is a count of such acquires.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * "sleeping" and the contention routine ordering is protected
- * by the spinlock in the semaphore's waitqueue head.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
- */
-
-/*
- * Logic:
- * - only on a boundary condition do we need to care. When we go
- * from a negative count to a non-negative, we wake people up.
- * - when we go from a non-negative count to a negative do we
- * (a) synchronize with the "sleeper" count and (b) make sure
- * that we're on the wakeup list before we synchronize so that
- * we cannot lose wakeup events.
- */
-
-static fastcall void __attribute_used__ __up(struct semaphore *sem)
-{
- wake_up(&sem->wait);
-}
-
-static fastcall void __attribute_used__ __sched __down(struct semaphore * sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
- unsigned long flags;
-
- tsk->state = TASK_UNINTERRUPTIBLE;
- spin_lock_irqsave(&sem->wait.lock, flags);
- add_wait_queue_exclusive_locked(&sem->wait, &wait);
-
- sem->sleepers++;
- for (;;) {
- int sleepers = sem->sleepers;
-
- /*
- * Add "everybody else" into it. They aren't
- * playing, because we own the spinlock in
- * the wait_queue_head.
- */
- if (!atomic_add_negative(sleepers - 1, &sem->count)) {
- sem->sleepers = 0;
- break;
- }
- sem->sleepers = 1; /* us - see -1 above */
- spin_unlock_irqrestore(&sem->wait.lock, flags);
-
- schedule();
-
- spin_lock_irqsave(&sem->wait.lock, flags);
- tsk->state = TASK_UNINTERRUPTIBLE;
- }
- remove_wait_queue_locked(&sem->wait, &wait);
- wake_up_locked(&sem->wait);
- spin_unlock_irqrestore(&sem->wait.lock, flags);
- tsk->state = TASK_RUNNING;
-}
-
-static fastcall int __attribute_used__ __sched __down_interruptible(struct semaphore * sem)
-{
- int retval = 0;
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
- unsigned long flags;
-
- tsk->state = TASK_INTERRUPTIBLE;
- spin_lock_irqsave(&sem->wait.lock, flags);
- add_wait_queue_exclusive_locked(&sem->wait, &wait);
-
- sem->sleepers++;
- for (;;) {
- int sleepers = sem->sleepers;
-
- /*
- * With signals pending, this turns into
- * the trylock failure case - we won't be
- * sleeping, and we* can't get the lock as
- * it has contention. Just correct the count
- * and exit.
- */
- if (signal_pending(current)) {
- retval = -EINTR;
- sem->sleepers = 0;
- atomic_add(sleepers, &sem->count);
- break;
- }
-
- /*
- * Add "everybody else" into it. They aren't
- * playing, because we own the spinlock in
- * wait_queue_head. The "-1" is because we're
- * still hoping to get the semaphore.
- */
- if (!atomic_add_negative(sleepers - 1, &sem->count)) {
- sem->sleepers = 0;
- break;
- }
- sem->sleepers = 1; /* us - see -1 above */
- spin_unlock_irqrestore(&sem->wait.lock, flags);
-
- schedule();
-
- spin_lock_irqsave(&sem->wait.lock, flags);
- tsk->state = TASK_INTERRUPTIBLE;
- }
- remove_wait_queue_locked(&sem->wait, &wait);
- wake_up_locked(&sem->wait);
- spin_unlock_irqrestore(&sem->wait.lock, flags);
-
- tsk->state = TASK_RUNNING;
- return retval;
-}
-
-/*
- * Trylock failed - make sure we correct for
- * having decremented the count.
- *
- * We could have done the trylock with a
- * single "cmpxchg" without failure cases,
- * but then it wouldn't work on a 386.
- */
-static fastcall int __attribute_used__ __down_trylock(struct semaphore * sem)
-{
- int sleepers;
- unsigned long flags;
-
- spin_lock_irqsave(&sem->wait.lock, flags);
- sleepers = sem->sleepers + 1;
- sem->sleepers = 0;
-
- /*
- * Add "everybody else" and us into it. They aren't
- * playing, because we own the spinlock in the
- * wait_queue_head.
- */
- if (!atomic_add_negative(sleepers, &sem->count)) {
- wake_up_locked(&sem->wait);
- }
-
- spin_unlock_irqrestore(&sem->wait.lock, flags);
- return 1;
-}
-
-
-/*
* The semaphore operations have a special calling sequence that
* allow us to do a simpler in-line version of them. These routines
* need to convert that sequence back into the C sequence when
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index af4de58..e29fd5a 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -82,7 +82,7 @@
/* cpu data as detected by the assembly code in head.S */
struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
/* common cpu data for all cpus */
-struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
EXPORT_SYMBOL(boot_cpu_data);
unsigned long mmu_cr4_features;
@@ -370,12 +370,16 @@
int i;
if (efi_enabled) {
- for (i = 0; i < memmap.nr_map; i++) {
- current_addr = memmap.map[i].phys_addr +
- (memmap.map[i].num_pages << 12);
- if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) {
+ efi_memory_desc_t *md;
+ void *p;
+
+ for (p = memmap.map, i = 0; p < memmap.map_end;
+ p += memmap.desc_size, i++) {
+ md = p;
+ current_addr = md->phys_addr + (md->num_pages << 12);
+ if (md->type == EFI_CONVENTIONAL_MEMORY) {
if (current_addr >= size) {
- memmap.map[i].num_pages -=
+ md->num_pages -=
(((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT);
memmap.nr_map = i + 1;
return;
@@ -1581,8 +1585,14 @@
*/
acpi_boot_table_init();
acpi_boot_init();
-#endif
+#if defined(CONFIG_SMP) && defined(CONFIG_X86_PC)
+ if (def_to_bigsmp)
+ printk(KERN_WARNING "More than 8 CPUs detected and "
+ "CONFIG_X86_PC cannot handle it.\nUse "
+ "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n");
+#endif
+#endif
#ifdef CONFIG_X86_LOCAL_APIC
if (smp_found_config)
get_smp_config();
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 140e340..61eb0c8 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -278,9 +278,9 @@
int tmp, err = 0;
tmp = 0;
- __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+ savesegment(gs, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
- __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+ savesegment(fs, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
err |= __put_user(regs->xes, (unsigned int __user *)&sc->es);
@@ -604,7 +604,9 @@
* We want the common case to go fast, which
* is why we may in certain cases get here from
* kernel mode. Just return without doing anything
- * if so.
+ * if so. vm86 regs switched out by assembly code
+ * before reaching here, so testing against kernel
+ * CS suffices.
*/
if (!user_mode(regs))
return 1;
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index cec4bde..48b55db 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -576,7 +576,7 @@
local_irq_disable();
disable_local_APIC();
if (cpu_data[smp_processor_id()].hlt_works_ok)
- for(;;) __asm__("hlt");
+ for(;;) halt();
for (;;);
}
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 8ac8e9f..5e4893d 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -88,6 +88,8 @@
cpumask_t cpu_callin_map;
cpumask_t cpu_callout_map;
EXPORT_SYMBOL(cpu_callout_map);
+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
@@ -1017,8 +1019,8 @@
tsc_sync_disabled = 1;
/* init low mem mapping */
- memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ KERNEL_PGD_PTRS);
flush_tlb_all();
schedule_work(&task);
wait_for_completion(&done);
@@ -1265,6 +1267,7 @@
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callout_map);
cpu_set(smp_processor_id(), cpu_present_map);
+ cpu_set(smp_processor_id(), cpu_possible_map);
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
}
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 0ee9dee..eefea7c 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -194,10 +194,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
@@ -252,8 +249,7 @@
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static inline void do_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
{
#ifdef CONFIG_X86_IO_APIC
if (timer_ack) {
@@ -307,7 +303,7 @@
cur_timer->mark_offset();
- do_timer_interrupt(irq, NULL, regs);
+ do_timer_interrupt(irq, regs);
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
@@ -348,7 +344,7 @@
* This code is run on a timer. If the clock is set, that timer
* may not expire at the correct time. Thus, we adjust...
*/
- if ((time_status & STA_UNSYNC) != 0)
+ if (!ntp_synced())
/*
* Not synced, exit, do not restart a timer (if one is
* running, let it run out).
@@ -383,6 +379,7 @@
static long clock_cmos_diff, sleep_start;
+static struct timer_opts *last_timer;
static int timer_suspend(struct sys_device *dev, pm_message_t state)
{
/*
@@ -391,6 +388,10 @@
clock_cmos_diff = -get_cmos_time();
clock_cmos_diff += get_seconds();
sleep_start = get_cmos_time();
+ last_timer = cur_timer;
+ cur_timer = &timer_none;
+ if (last_timer->suspend)
+ last_timer->suspend(state);
return 0;
}
@@ -404,6 +405,7 @@
if (is_hpet_enabled())
hpet_reenable();
#endif
+ setup_pit_timer();
sec = get_cmos_time() + clock_cmos_diff;
sleep_length = (get_cmos_time() - sleep_start) * HZ;
write_seqlock_irqsave(&xtime_lock, flags);
@@ -412,6 +414,11 @@
write_sequnlock_irqrestore(&xtime_lock, flags);
jiffies += sleep_length;
wall_jiffies += sleep_length;
+ if (last_timer->resume)
+ last_timer->resume();
+ cur_timer = last_timer;
+ last_timer = NULL;
+ touch_softlockup_watchdog();
return 0;
}
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
index ef8dac5..d973a8b 100644
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ b/arch/i386/kernel/timers/timer_hpet.c
@@ -18,8 +18,8 @@
#include "mach_timer.h"
#include <asm/hpet.h>
-static unsigned long __read_mostly hpet_usec_quotient; /* convert hpet clks to usec */
-static unsigned long tsc_hpet_quotient; /* convert tsc to hpet clks */
+static unsigned long hpet_usec_quotient __read_mostly; /* convert hpet clks to usec */
+static unsigned long tsc_hpet_quotient __read_mostly; /* convert tsc to hpet clks */
static unsigned long hpet_last; /* hpet counter value at last tick*/
static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */
@@ -136,6 +136,8 @@
} while ((hpet_end - hpet_start) < (loops));
}
+static struct timer_opts timer_hpet;
+
static int __init init_hpet(char* override)
{
unsigned long result, remain;
@@ -163,6 +165,8 @@
}
set_cyc2ns_scale(cpu_khz/1000);
}
+ /* set this only when cpu_has_tsc */
+ timer_hpet.read_timer = read_timer_tsc;
}
/*
@@ -177,6 +181,19 @@
return 0;
}
+static int hpet_resume(void)
+{
+ write_seqlock(&monotonic_lock);
+ /* Assume this is the last mark offset time */
+ rdtsc(last_tsc_low, last_tsc_high);
+
+ if (hpet_use_timer)
+ hpet_last = hpet_readl(HPET_T0_CMP) - hpet_tick;
+ else
+ hpet_last = hpet_readl(HPET_COUNTER);
+ write_sequnlock(&monotonic_lock);
+ return 0;
+}
/************************************************************/
/* tsc timer_opts struct */
@@ -186,7 +203,7 @@
.get_offset = get_offset_hpet,
.monotonic_clock = monotonic_clock_hpet,
.delay = delay_hpet,
- .read_timer = read_timer_tsc,
+ .resume = hpet_resume,
};
struct init_timer_opts __initdata timer_hpet_init = {
diff --git a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
index 06de036a..eddb640 100644
--- a/arch/i386/kernel/timers/timer_pit.c
+++ b/arch/i386/kernel/timers/timer_pit.c
@@ -175,30 +175,3 @@
outb(LATCH >> 8 , PIT_CH0); /* MSB */
spin_unlock_irqrestore(&i8253_lock, flags);
}
-
-static int timer_resume(struct sys_device *dev)
-{
- setup_pit_timer();
- return 0;
-}
-
-static struct sysdev_class timer_sysclass = {
- set_kset_name("timer_pit"),
- .resume = timer_resume,
-};
-
-static struct sys_device device_timer = {
- .id = 0,
- .cls = &timer_sysclass,
-};
-
-static int __init init_timer_sysfs(void)
-{
- int error = sysdev_class_register(&timer_sysclass);
- if (!error)
- error = sysdev_register(&device_timer);
- return error;
-}
-
-device_initcall(init_timer_sysfs);
-
diff --git a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
index 4ef20e6..264edaa 100644
--- a/arch/i386/kernel/timers/timer_pm.c
+++ b/arch/i386/kernel/timers/timer_pm.c
@@ -186,6 +186,14 @@
}
}
+static int pmtmr_resume(void)
+{
+ write_seqlock(&monotonic_lock);
+ /* Assume this is the last mark offset time */
+ offset_tick = read_pmtmr();
+ write_sequnlock(&monotonic_lock);
+ return 0;
+}
static unsigned long long monotonic_clock_pmtmr(void)
{
@@ -247,6 +255,7 @@
.monotonic_clock = monotonic_clock_pmtmr,
.delay = delay_pmtmr,
.read_timer = read_timer_tsc,
+ .resume = pmtmr_resume,
};
struct init_timer_opts __initdata timer_pmtmr_init = {
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
index 8f4e4d5..6dd470c 100644
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ b/arch/i386/kernel/timers/timer_tsc.c
@@ -543,6 +543,19 @@
return -ENODEV;
}
+static int tsc_resume(void)
+{
+ write_seqlock(&monotonic_lock);
+ /* Assume this is the last mark offset time */
+ rdtsc(last_tsc_low, last_tsc_high);
+#ifdef CONFIG_HPET_TIMER
+ if (is_hpet_enabled() && hpet_use_timer)
+ hpet_last = hpet_readl(HPET_COUNTER);
+#endif
+ write_sequnlock(&monotonic_lock);
+ return 0;
+}
+
#ifndef CONFIG_X86_TSC
/* disable flag for tsc. Takes effect by clearing the TSC cpu flag
* in cpu/common.c */
@@ -573,6 +586,7 @@
.monotonic_clock = monotonic_clock_tsc,
.delay = delay_tsc,
.read_timer = read_timer_tsc,
+ .resume = tsc_resume,
};
struct init_timer_opts __initdata timer_tsc_init = {
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index cd2d5d5..09a58cb 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -210,7 +210,7 @@
unsigned short ss;
esp = (unsigned long) (®s->esp);
- ss = __KERNEL_DS;
+ savesegment(ss, ss);
if (user_mode(regs)) {
in_kernel = 0;
esp = regs->esp;
@@ -267,9 +267,6 @@
char c;
unsigned long eip;
- if (user_mode(regs))
- goto no_bug; /* Not in kernel */
-
eip = regs->eip;
if (eip < PAGE_OFFSET)
@@ -366,8 +363,9 @@
die(str, regs, err);
}
-static void do_trap(int trapnr, int signr, char *str, int vm86,
- struct pt_regs * regs, long error_code, siginfo_t *info)
+static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
+ struct pt_regs * regs, long error_code,
+ siginfo_t *info)
{
struct task_struct *tsk = current;
tsk->thread.error_code = error_code;
@@ -463,7 +461,8 @@
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
-fastcall void do_general_protection(struct pt_regs * regs, long error_code)
+fastcall void __kprobes do_general_protection(struct pt_regs * regs,
+ long error_code)
{
int cpu = get_cpu();
struct tss_struct *tss = &per_cpu(init_tss, cpu);
@@ -568,6 +567,10 @@
void die_nmi (struct pt_regs *regs, const char *msg)
{
+ if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 0, SIGINT) ==
+ NOTIFY_STOP)
+ return;
+
spin_lock(&nmi_print_lock);
/*
* We are in trouble anyway, lets at least try
@@ -656,7 +659,7 @@
++nmi_count(cpu);
- if (!nmi_callback(regs, cpu))
+ if (!rcu_dereference(nmi_callback)(regs, cpu))
default_do_nmi(regs);
nmi_exit();
@@ -664,7 +667,7 @@
void set_nmi_callback(nmi_callback_t callback)
{
- nmi_callback = callback;
+ rcu_assign_pointer(nmi_callback, callback);
}
EXPORT_SYMBOL_GPL(set_nmi_callback);
@@ -675,7 +678,7 @@
EXPORT_SYMBOL_GPL(unset_nmi_callback);
#ifdef CONFIG_KPROBES
-fastcall void do_int3(struct pt_regs *regs, long error_code)
+fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
{
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
== NOTIFY_STOP)
@@ -709,7 +712,7 @@
* find every occurrence of the TF bit that could be saved away even
* by user code)
*/
-fastcall void do_debug(struct pt_regs * regs, long error_code)
+fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
{
unsigned int condition;
struct task_struct *tsk = current;
@@ -1008,7 +1011,7 @@
* it uses the read-only mapped virtual address.
*/
idt_descr.address = fix_to_virt(FIX_F00F_IDT);
- __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
+ load_idt(&idt_descr);
}
#endif
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index ec0f68c..16b4850 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -294,8 +294,8 @@
*/
info->regs32->eax = 0;
tsk->thread.saved_esp0 = tsk->thread.esp0;
- asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs));
- asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs));
+ savesegment(fs, tsk->thread.saved_fs);
+ savesegment(gs, tsk->thread.saved_gs);
tss = &per_cpu(init_tss, get_cpu());
tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
@@ -542,7 +542,7 @@
unsigned char opcode;
unsigned char __user *csp;
unsigned char __user *ssp;
- unsigned short ip, sp;
+ unsigned short ip, sp, orig_flags;
int data32, pref_done;
#define CHECK_IF_IN_TRAP \
@@ -551,8 +551,12 @@
#define VM86_FAULT_RETURN do { \
if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \
return_to_32bit(regs, VM86_PICRETURN); \
+ if (orig_flags & TF_MASK) \
+ handle_vm86_trap(regs, 0, 1); \
return; } while (0)
+ orig_flags = *(unsigned short *)®s->eflags;
+
csp = (unsigned char __user *) (regs->cs << 4);
ssp = (unsigned char __user *) (regs->ss << 4);
sp = SP(regs);
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 761972f..13b9c62 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -22,6 +22,7 @@
*(.text)
SCHED_TEXT
LOCK_TEXT
+ KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
} = 0x9090
diff --git a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn.S
index c8fcf75..68afa50 100644
--- a/arch/i386/kernel/vsyscall-sigreturn.S
+++ b/arch/i386/kernel/vsyscall-sigreturn.S
@@ -15,7 +15,7 @@
*/
.text
- .org __kernel_vsyscall+32
+ .org __kernel_vsyscall+32,0x90
.globl __kernel_sigreturn
.type __kernel_sigreturn,@function
__kernel_sigreturn:
@@ -35,6 +35,7 @@
int $0x80
.LEND_rt_sigreturn:
.size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
+ .balign 32
.previous
.section .eh_frame,"a",@progbits
diff --git a/arch/i386/mach-default/topology.c b/arch/i386/mach-default/topology.c
index 23395ff..b643140 100644
--- a/arch/i386/mach-default/topology.c
+++ b/arch/i386/mach-default/topology.c
@@ -76,7 +76,7 @@
for_each_online_node(i)
arch_register_node(i);
- for_each_cpu(i)
+ for_each_present_cpu(i)
arch_register_cpu(i);
return 0;
}
@@ -87,7 +87,7 @@
{
int i;
- for_each_cpu(i)
+ for_each_present_cpu(i)
arch_register_cpu(i);
return 0;
}
diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h
index 70691f0..898ed90 100644
--- a/arch/i386/mach-es7000/es7000.h
+++ b/arch/i386/mach-es7000/es7000.h
@@ -104,7 +104,8 @@
#define MIP_SW_APIC 0x1020b
#define MIP_FUNC(VALUE) (VALUE & 0xff)
-extern int parse_unisys_oem (char *oemptr, int oem_entries);
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length);
+extern int parse_unisys_oem (char *oemptr);
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void setup_unisys ();
extern int es7000_start_cpu(int cpu, unsigned long eip);
extern void es7000_sw_apic(void);
diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c
index d5936d5..2000bdc 100644
--- a/arch/i386/mach-es7000/es7000plat.c
+++ b/arch/i386/mach-es7000/es7000plat.c
@@ -75,12 +75,29 @@
#endif // (CONFIG_X86_IO_APIC) && (CONFIG_ACPI_INTERPRETER || CONFIG_ACPI_BOOT)
+void __init
+setup_unisys ()
+{
+ /*
+ * Determine the generation of the ES7000 currently running.
+ *
+ * es7000_plat = 1 if the machine is a 5xx ES7000 box
+ * es7000_plat = 2 if the machine is a x86_64 ES7000 box
+ *
+ */
+ if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
+ es7000_plat = 2;
+ else
+ es7000_plat = 1;
+ ioapic_renumber_irq = es7000_rename_gsi;
+}
+
/*
* Parse the OEM Table
*/
int __init
-parse_unisys_oem (char *oemptr, int oem_entries)
+parse_unisys_oem (char *oemptr)
{
int i;
int success = 0;
@@ -95,7 +112,7 @@
tp += 8;
- for (i=0; i <= oem_entries; i++) {
+ for (i=0; i <= 6; i++) {
type = *tp++;
size = *tp++;
tp -= 2;
@@ -130,34 +147,18 @@
default:
break;
}
- if (i == 6) break;
tp += size;
}
if (success < 2) {
es7000_plat = 0;
- } else {
- printk("\nEnabling ES7000 specific features...\n");
- /*
- * Determine the generation of the ES7000 currently running.
- *
- * es7000_plat = 0 if the machine is NOT a Unisys ES7000 box
- * es7000_plat = 1 if the machine is a 5xx ES7000 box
- * es7000_plat = 2 if the machine is a x86_64 ES7000 box
- *
- */
- if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
- es7000_plat = 2;
- else
- es7000_plat = 1;
-
- ioapic_renumber_irq = es7000_rename_gsi;
- }
+ } else
+ setup_unisys();
return es7000_plat;
}
int __init
-find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length)
+find_unisys_acpi_oem_table(unsigned long *oem_addr)
{
struct acpi_table_rsdp *rsdp = NULL;
unsigned long rsdp_phys = 0;
@@ -201,13 +202,11 @@
acpi_table_print(header, sdt.entry[i].pa);
t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length);
addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize);
- *length = header->length;
*oem_addr = (unsigned long) addr;
return 0;
}
}
}
- Dprintk("ES7000: did not find Unisys ACPI OEM table!\n");
return -1;
}
diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
index 25883b4..037b2af 100644
--- a/arch/i386/mach-generic/bigsmp.c
+++ b/arch/i386/mach-generic/bigsmp.c
@@ -47,7 +47,10 @@
static __init int probe_bigsmp(void)
{
- dmi_check_system(bigsmp_dmi_table);
+ if (def_to_bigsmp)
+ dmi_bigsmp = 1;
+ else
+ dmi_check_system(bigsmp_dmi_table);
return dmi_bigsmp;
}
diff --git a/arch/i386/mach-generic/probe.c b/arch/i386/mach-generic/probe.c
index 5497c65..cea5b3c 100644
--- a/arch/i386/mach-generic/probe.c
+++ b/arch/i386/mach-generic/probe.c
@@ -30,6 +30,25 @@
NULL,
};
+static int cmdline_apic;
+
+void __init generic_bigsmp_probe(void)
+{
+ /*
+ * This routine is used to switch to bigsmp mode when
+ * - There is no apic= option specified by the user
+ * - generic_apic_probe() has choosen apic_default as the sub_arch
+ * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
+ */
+
+ if (!cmdline_apic && genapic == &apic_default)
+ if (apic_bigsmp.probe()) {
+ genapic = &apic_bigsmp;
+ printk(KERN_INFO "Overriding APIC driver with %s\n",
+ genapic->name);
+ }
+}
+
void __init generic_apic_probe(char *command_line)
{
char *s;
@@ -52,6 +71,7 @@
if (!changed)
printk(KERN_ERR "Unknown genapic `%s' specified.\n", s);
*p = old;
+ cmdline_apic = changed;
}
for (i = 0; !changed && apic_probe[i]; i++) {
if (apic_probe[i]->probe()) {
diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c
index c638406..cc69875 100644
--- a/arch/i386/mach-voyager/voyager_basic.c
+++ b/arch/i386/mach-voyager/voyager_basic.c
@@ -234,10 +234,9 @@
#endif
}
/* and wait for it to happen */
- for(;;) {
- __asm("cli");
- __asm("hlt");
- }
+ local_irq_disable();
+ for(;;)
+ halt();
}
/* copied from process.c */
@@ -278,10 +277,9 @@
outb(basebd | 0x08, VOYAGER_MC_SETUP);
outb(0x02, catbase + 0x21);
}
- for(;;) {
- asm("cli");
- asm("hlt");
- }
+ local_irq_disable();
+ for(;;)
+ halt();
}
void
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index 0e1f420..46b0cf4 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -242,6 +242,8 @@
cpumask_t cpu_callin_map = CPU_MASK_NONE;
cpumask_t cpu_callout_map = CPU_MASK_NONE;
EXPORT_SYMBOL(cpu_callout_map);
+cpumask_t cpu_possible_map = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_possible_map);
/* The per processor IRQ masks (these are usually kept in sync) */
static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned;
@@ -1015,7 +1017,7 @@
cpu_clear(smp_processor_id(), cpu_online_map);
local_irq_disable();
for(;;)
- __asm__("hlt");
+ halt();
}
static DEFINE_SPINLOCK(call_lock);
@@ -1910,6 +1912,7 @@
{
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callout_map);
+ cpu_set(smp_processor_id(), cpu_possible_map);
}
int __devinit
diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c
index 9117573..9819b70 100644
--- a/arch/i386/math-emu/get_address.c
+++ b/arch/i386/math-emu/get_address.c
@@ -155,7 +155,6 @@
{
struct desc_struct descriptor;
unsigned long base_address, limit, address, seg_top;
- unsigned short selector;
segment--;
@@ -173,17 +172,11 @@
/* fs and gs aren't used by the kernel, so they still have their
user-space values. */
case PREFIX_FS_-1:
- /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
- in the assembler statement. */
-
- __asm__("mov %%fs,%0":"=r" (selector));
- addr->selector = selector;
+ /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
+ savesegment(fs, addr->selector);
break;
case PREFIX_GS_-1:
- /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
- in the assembler statement. */
- __asm__("mov %%gs,%0":"=r" (selector));
- addr->selector = selector;
+ savesegment(gs, addr->selector);
break;
default:
addr->selector = PM_REG_(segment);
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index 6711ce3..244d8ec 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -37,7 +37,7 @@
#include <asm/mmzone.h>
#include <bios_ebda.h>
-struct pglist_data *node_data[MAX_NUMNODES];
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
EXPORT_SYMBOL(node_data);
bootmem_data_t node0_bdata;
@@ -49,8 +49,8 @@
* 2) node_start_pfn - the starting page frame number for a node
* 3) node_end_pfn - the ending page fram number for a node
*/
-unsigned long node_start_pfn[MAX_NUMNODES];
-unsigned long node_end_pfn[MAX_NUMNODES];
+unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly;
+unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
#ifdef CONFIG_DISCONTIGMEM
@@ -66,7 +66,7 @@
* physnode_map[4-7] = 1;
* physnode_map[8- ] = -1;
*/
-s8 physnode_map[MAX_ELEMENTS] = { [0 ... (MAX_ELEMENTS - 1)] = -1};
+s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1};
EXPORT_SYMBOL(physnode_map);
void memory_present(int nid, unsigned long start, unsigned long end)
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 8e90339..9edd448 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -21,6 +21,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/highmem.h>
#include <linux/module.h>
+#include <linux/kprobes.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -199,6 +200,18 @@
return 0;
}
+static noinline void force_sig_info_fault(int si_signo, int si_code,
+ unsigned long address, struct task_struct *tsk)
+{
+ siginfo_t info;
+
+ info.si_signo = si_signo;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = (void __user *)address;
+ force_sig_info(si_signo, &info, tsk);
+}
+
fastcall void do_invalid_op(struct pt_regs *, unsigned long);
/*
@@ -211,18 +224,18 @@
* bit 1 == 0 means read, 1 means write
* bit 2 == 0 means kernel, 1 means user-mode
*/
-fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+fastcall void __kprobes do_page_fault(struct pt_regs *regs,
+ unsigned long error_code)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
unsigned long address;
unsigned long page;
- int write;
- siginfo_t info;
+ int write, si_code;
/* get the address */
- __asm__("movl %%cr2,%0":"=r" (address));
+ address = read_cr2();
if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
SIGSEGV) == NOTIFY_STOP)
@@ -233,7 +246,7 @@
tsk = current;
- info.si_code = SEGV_MAPERR;
+ si_code = SEGV_MAPERR;
/*
* We fault-in kernel-space virtual memory on-demand. The
@@ -313,7 +326,7 @@
* we can handle it..
*/
good_area:
- info.si_code = SEGV_ACCERR;
+ si_code = SEGV_ACCERR;
write = 0;
switch (error_code & 3) {
default: /* 3: write, present */
@@ -387,11 +400,7 @@
/* Kernel addresses are always protection faults */
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.trap_no = 14;
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* info.si_code has been set above */
- info.si_addr = (void __user *)address;
- force_sig_info(SIGSEGV, &info, tsk);
+ force_sig_info_fault(SIGSEGV, si_code, address, tsk);
return;
}
@@ -446,7 +455,7 @@
printk(" at virtual address %08lx\n",address);
printk(KERN_ALERT " printing eip:\n");
printk("%08lx\n", regs->eip);
- asm("movl %%cr3,%0":"=r" (page));
+ page = read_cr3();
page = ((unsigned long *) __va(page))[address >> 22];
printk(KERN_ALERT "*pde = %08lx\n", page);
/*
@@ -500,11 +509,7 @@
tsk->thread.cr2 = address;
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 14;
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRERR;
- info.si_addr = (void __user *)address;
- force_sig_info(SIGBUS, &info, tsk);
+ force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
return;
vmalloc_fault:
@@ -523,7 +528,7 @@
pmd_t *pmd, *pmd_k;
pte_t *pte_k;
- asm("movl %%cr3,%0":"=r" (pgd_paddr));
+ pgd_paddr = read_cr3();
pgd = index + (pgd_t *)__va(pgd_paddr);
pgd_k = init_mm.pgd + index;
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
index 3b099f3..d524127 100644
--- a/arch/i386/mm/hugetlbpage.c
+++ b/arch/i386/mm/hugetlbpage.c
@@ -22,12 +22,15 @@
{
pgd_t *pgd;
pud_t *pud;
- pmd_t *pmd = NULL;
+ pte_t *pte = NULL;
pgd = pgd_offset(mm, addr);
pud = pud_alloc(mm, pgd, addr);
- pmd = pmd_alloc(mm, pud, addr);
- return (pte_t *) pmd;
+ if (pud)
+ pte = (pte_t *) pmd_alloc(mm, pud, addr);
+ BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte));
+
+ return pte;
}
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
@@ -37,8 +40,11 @@
pmd_t *pmd = NULL;
pgd = pgd_offset(mm, addr);
- pud = pud_offset(pgd, addr);
- pmd = pmd_offset(pud, addr);
+ if (pgd_present(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (pud_present(*pud))
+ pmd = pmd_offset(pud, addr);
+ }
return (pte_t *) pmd;
}
@@ -118,17 +124,6 @@
}
#endif
-void hugetlb_clean_stale_pgtable(pte_t *pte)
-{
- pmd_t *pmd = (pmd_t *) pte;
- struct page *page;
-
- page = pmd_page(*pmd);
- pmd_clear(pmd);
- dec_page_state(nr_page_table_pages);
- page_cache_release(page);
-}
-
/* x86_64 also uses this file */
#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 12216b5..2ebaf75 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -198,9 +198,10 @@
if (efi_enabled) {
efi_memory_desc_t *md;
+ void *p;
- for (i = 0; i < memmap.nr_map; i++) {
- md = &memmap.map[i];
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
if (!is_available_memory(md))
continue;
addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
@@ -348,7 +349,7 @@
* All user-space mappings are explicitly cleared after
* SMP startup.
*/
- pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
+ set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]);
#endif
}
@@ -392,7 +393,7 @@
}
static int disable_nx __initdata = 0;
-u64 __supported_pte_mask = ~_PAGE_NX;
+u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
/*
* noexec = on|off
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index cb3da6b..f600fc2 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -12,6 +12,7 @@
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
static DEFINE_SPINLOCK(cpa_lock);
static struct list_head df_list = LIST_HEAD_INIT(df_list);
@@ -52,8 +53,8 @@
addr = address & LARGE_PAGE_MASK;
pbase = (pte_t *)page_address(base);
for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
- pbase[i] = pfn_pte(addr >> PAGE_SHIFT,
- addr == address ? prot : PAGE_KERNEL);
+ set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
+ addr == address ? prot : PAGE_KERNEL));
}
return base;
}
@@ -62,7 +63,7 @@
{
/* Could use CLFLUSH here if the CPU supports it (Hammer,P4) */
if (boot_cpu_data.x86_model >= 4)
- asm volatile("wbinvd":::"memory");
+ wbinvd();
/* Flush all to work around Errata in early athlons regarding
* large page flushing.
*/
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index bd2f7af..dcdce2c 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -207,19 +207,19 @@
{
unsigned long flags;
- if (PTRS_PER_PMD == 1)
+ if (PTRS_PER_PMD == 1) {
+ memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
spin_lock_irqsave(&pgd_lock, flags);
+ }
- memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
+ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-
+ KERNEL_PGD_PTRS);
if (PTRS_PER_PMD > 1)
return;
pgd_list_add(pgd);
spin_unlock_irqrestore(&pgd_lock, flags);
- memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
}
/* never called when PTRS_PER_PMD > 1 */
diff --git a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c
index c90332d..5341d48 100644
--- a/arch/i386/oprofile/init.c
+++ b/arch/i386/oprofile/init.c
@@ -15,9 +15,9 @@
* with the NMI mode driver.
*/
-extern int nmi_init(struct oprofile_operations * ops);
-extern int nmi_timer_init(struct oprofile_operations * ops);
-extern void nmi_exit(void);
+extern int op_nmi_init(struct oprofile_operations * ops);
+extern int op_nmi_timer_init(struct oprofile_operations * ops);
+extern void op_nmi_exit(void);
extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
@@ -28,11 +28,11 @@
ret = -ENODEV;
#ifdef CONFIG_X86_LOCAL_APIC
- ret = nmi_init(ops);
+ ret = op_nmi_init(ops);
#endif
#ifdef CONFIG_X86_IO_APIC
if (ret < 0)
- ret = nmi_timer_init(ops);
+ ret = op_nmi_timer_init(ops);
#endif
ops->backtrace = x86_backtrace;
@@ -43,6 +43,6 @@
void oprofile_arch_exit(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
- nmi_exit();
+ op_nmi_exit();
#endif
}
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 255e470..0493e8b 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -355,7 +355,7 @@
/* in order to get driverfs right */
static int using_nmi;
-int __init nmi_init(struct oprofile_operations *ops)
+int __init op_nmi_init(struct oprofile_operations *ops)
{
__u8 vendor = boot_cpu_data.x86_vendor;
__u8 family = boot_cpu_data.x86;
@@ -420,7 +420,7 @@
}
-void nmi_exit(void)
+void op_nmi_exit(void)
{
if (using_nmi)
exit_driverfs();
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
index c58d0c1..ad93cdd 100644
--- a/arch/i386/oprofile/nmi_timer_int.c
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -40,7 +40,7 @@
}
-int __init nmi_timer_init(struct oprofile_operations * ops)
+int __init op_nmi_timer_init(struct oprofile_operations * ops)
{
extern int nmi_active;
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index c547c1a..7b0b9ad 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -42,25 +42,25 @@
/*
* descriptor tables
*/
- asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
- asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
- asm volatile ("str %0" : "=m" (ctxt->tr));
+ store_gdt(&ctxt->gdt_limit);
+ store_idt(&ctxt->idt_limit);
+ store_tr(ctxt->tr);
/*
* segment registers
*/
- asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
- asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
- asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
- asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
+ savesegment(es, ctxt->es);
+ savesegment(fs, ctxt->fs);
+ savesegment(gs, ctxt->gs);
+ savesegment(ss, ctxt->ss);
/*
* control registers
*/
- asm volatile ("movl %%cr0, %0" : "=r" (ctxt->cr0));
- asm volatile ("movl %%cr2, %0" : "=r" (ctxt->cr2));
- asm volatile ("movl %%cr3, %0" : "=r" (ctxt->cr3));
- asm volatile ("movl %%cr4, %0" : "=r" (ctxt->cr4));
+ ctxt->cr0 = read_cr0();
+ ctxt->cr2 = read_cr2();
+ ctxt->cr3 = read_cr3();
+ ctxt->cr4 = read_cr4();
}
void save_processor_state(void)
@@ -84,7 +84,6 @@
struct tss_struct * t = &per_cpu(init_tss, cpu);
set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
- per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff;
load_TR_desc(); /* This does ltr */
load_LDT(¤t->active_mm->context); /* This does lldt */
@@ -109,25 +108,25 @@
/*
* control registers
*/
- asm volatile ("movl %0, %%cr4" :: "r" (ctxt->cr4));
- asm volatile ("movl %0, %%cr3" :: "r" (ctxt->cr3));
- asm volatile ("movl %0, %%cr2" :: "r" (ctxt->cr2));
- asm volatile ("movl %0, %%cr0" :: "r" (ctxt->cr0));
+ write_cr4(ctxt->cr4);
+ write_cr3(ctxt->cr3);
+ write_cr2(ctxt->cr2);
+ write_cr2(ctxt->cr0);
/*
* now restore the descriptor tables to their proper values
* ltr is done i fix_processor_context().
*/
- asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
- asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
+ load_gdt(&ctxt->gdt_limit);
+ load_idt(&ctxt->idt_limit);
/*
* segment registers
*/
- asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
- asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
- asm volatile ("movw %0, %%gs" :: "r" (ctxt->gs));
- asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
+ loadsegment(es, ctxt->es);
+ loadsegment(fs, ctxt->fs);
+ loadsegment(gs, ctxt->gs);
+ loadsegment(ss, ctxt->ss);
/*
* sysenter MSRs
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 8098813..17b5dbf 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -383,6 +383,12 @@
endif
+if PM
+
+source "arch/ia64/kernel/cpufreq/Kconfig"
+
+endif
+
endmenu
if !IA64_HP_SIM
@@ -428,6 +434,11 @@
bool
default y
+config GENERIC_PENDING_IRQ
+ bool
+ depends on GENERIC_HARDIRQS && SMP
+ default y
+
source "arch/ia64/hp/sim/Kconfig"
source "arch/ia64/oprofile/Kconfig"
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 5c46928..30fdfb1 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -237,17 +237,6 @@
return ((struct sal_ret_values) {status, r9, r10, r11});
}
-
-/*
- * This is here to work around a bug in egcs-1.1.1b that causes the
- * compiler to crash (seems like a bug in the new alias analysis code.
- */
-void *
-id (long addr)
-{
- return (void *) addr;
-}
-
struct ia64_boot_param *
sys_fw_init (const char *args, int arglen)
{
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 7dcb858..b42ec37 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -130,7 +130,7 @@
static void rs_start(struct tty_struct *tty)
{
-#if SIMSERIAL_DEBUG
+#ifdef SIMSERIAL_DEBUG
printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
tty->stopped, tty->hw_stopped, tty->flow_stopped);
#endif
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index 829a6d8..0708edb 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -215,7 +215,7 @@
data8 sys32_fork
data8 sys_read
data8 sys_write
- data8 sys32_open /* 5 */
+ data8 compat_sys_open /* 5 */
data8 sys_close
data8 sys32_waitpid
data8 sys_creat
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index ebb89be..aa891c9 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -29,7 +29,6 @@
#include <asm/uaccess.h>
#include <asm/rse.h>
#include <asm/sigcontext.h>
-#include <asm/segment.h>
#include "ia32priv.h"
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index c1e20d6..e29a8a5 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -2359,37 +2359,6 @@
return ret;
}
-/*
- * Exactly like fs/open.c:sys_open(), except that it doesn't set the O_LARGEFILE flag.
- */
-asmlinkage long
-sys32_open (const char __user * filename, int flags, int mode)
-{
- char * tmp;
- int fd, error;
-
- tmp = getname(filename);
- fd = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
- if (fd >= 0) {
- struct file *f = filp_open(tmp, flags, mode);
- error = PTR_ERR(f);
- if (IS_ERR(f))
- goto out_error;
- fd_install(fd, f);
- }
-out:
- putname(tmp);
- }
- return fd;
-
-out_error:
- put_unused_fd(fd);
- fd = error;
- goto out;
-}
-
/* Structure for ia32 emulation on ia64 */
struct epoll_event32
{
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index e1fb68d..307514f 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -16,10 +16,11 @@
obj-$(CONFIG_IA64_PALINFO) += palinfo.o
obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_SMP) += smp.o smpboot.o domain.o
+obj-$(CONFIG_SMP) += smp.o smpboot.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
diff --git a/arch/ia64/kernel/cpufreq/Kconfig b/arch/ia64/kernel/cpufreq/Kconfig
new file mode 100644
index 0000000..2d9d527
--- /dev/null
+++ b/arch/ia64/kernel/cpufreq/Kconfig
@@ -0,0 +1,29 @@
+
+#
+# CPU Frequency scaling
+#
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+if CPU_FREQ
+
+comment "CPUFreq processor drivers"
+
+config IA64_ACPI_CPUFREQ
+ tristate "ACPI Processor P-States driver"
+ select CPU_FREQ_TABLE
+ depends on ACPI_PROCESSOR
+ help
+ This driver adds a CPUFreq driver which utilizes the ACPI
+ Processor Performance States.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+endif # CPU_FREQ
+
+endmenu
+
diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile
new file mode 100644
index 0000000..f748d34
--- /dev/null
+++ b/arch/ia64/kernel/cpufreq/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
new file mode 100644
index 0000000..da4d5cf
--- /dev/null
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -0,0 +1,499 @@
+/*
+ * arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+ * This file provides the ACPI based P-state support. This
+ * module works with generic cpufreq infrastructure. Most of
+ * the code is based on i386 version
+ * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
+ *
+ * Copyright (C) 2005 Intel Corp
+ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pal.h>
+
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
+
+MODULE_AUTHOR("Venkatesh Pallipadi");
+MODULE_DESCRIPTION("ACPI Processor P-States Driver");
+MODULE_LICENSE("GPL");
+
+
+struct cpufreq_acpi_io {
+ struct acpi_processor_performance acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int resume;
+};
+
+static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
+
+static struct cpufreq_driver acpi_cpufreq_driver;
+
+
+static int
+processor_set_pstate (
+ u32 value)
+{
+ s64 retval;
+
+ dprintk("processor_set_pstate\n");
+
+ retval = ia64_pal_set_pstate((u64)value);
+
+ if (retval) {
+ dprintk("Failed to set freq to 0x%x, with error 0x%x\n",
+ value, retval);
+ return -ENODEV;
+ }
+ return (int)retval;
+}
+
+
+static int
+processor_get_pstate (
+ u32 *value)
+{
+ u64 pstate_index = 0;
+ s64 retval;
+
+ dprintk("processor_get_pstate\n");
+
+ retval = ia64_pal_get_pstate(&pstate_index);
+ *value = (u32) pstate_index;
+
+ if (retval)
+ dprintk("Failed to get current freq with "
+ "error 0x%x, idx 0x%x\n", retval, *value);
+
+ return (int)retval;
+}
+
+
+/* To be used only after data->acpi_data is initialized */
+static unsigned
+extract_clock (
+ struct cpufreq_acpi_io *data,
+ unsigned value,
+ unsigned int cpu)
+{
+ unsigned long i;
+
+ dprintk("extract_clock\n");
+
+ for (i = 0; i < data->acpi_data.state_count; i++) {
+ if (value >= data->acpi_data.states[i].control)
+ return data->acpi_data.states[i].core_frequency;
+ }
+ return data->acpi_data.states[i-1].core_frequency;
+}
+
+
+static unsigned int
+processor_get_freq (
+ struct cpufreq_acpi_io *data,
+ unsigned int cpu)
+{
+ int ret = 0;
+ u32 value = 0;
+ cpumask_t saved_mask;
+ unsigned long clock_freq;
+
+ dprintk("processor_get_freq\n");
+
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (smp_processor_id() != cpu) {
+ ret = -EAGAIN;
+ goto migrate_end;
+ }
+
+ /*
+ * processor_get_pstate gets the average frequency since the
+ * last get. So, do two PAL_get_freq()...
+ */
+ ret = processor_get_pstate(&value);
+ ret = processor_get_pstate(&value);
+
+ if (ret) {
+ set_cpus_allowed(current, saved_mask);
+ printk(KERN_WARNING "get performance failed with error %d\n",
+ ret);
+ ret = -EAGAIN;
+ goto migrate_end;
+ }
+ clock_freq = extract_clock(data, value, cpu);
+ ret = (clock_freq*1000);
+
+migrate_end:
+ set_cpus_allowed(current, saved_mask);
+ return ret;
+}
+
+
+static int
+processor_set_freq (
+ struct cpufreq_acpi_io *data,
+ unsigned int cpu,
+ int state)
+{
+ int ret = 0;
+ u32 value = 0;
+ struct cpufreq_freqs cpufreq_freqs;
+ cpumask_t saved_mask;
+ int retval;
+
+ dprintk("processor_set_freq\n");
+
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (smp_processor_id() != cpu) {
+ retval = -EAGAIN;
+ goto migrate_end;
+ }
+
+ if (state == data->acpi_data.state) {
+ if (unlikely(data->resume)) {
+ dprintk("Called after resume, resetting to P%d\n", state);
+ data->resume = 0;
+ } else {
+ dprintk("Already at target state (P%d)\n", state);
+ retval = 0;
+ goto migrate_end;
+ }
+ }
+
+ dprintk("Transitioning from P%d to P%d\n",
+ data->acpi_data.state, state);
+
+ /* cpufreq frequency struct */
+ cpufreq_freqs.cpu = cpu;
+ cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
+ cpufreq_freqs.new = data->freq_table[state].frequency;
+
+ /* notify cpufreq */
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+
+ /*
+ * First we write the target state's 'control' value to the
+ * control_register.
+ */
+
+ value = (u32) data->acpi_data.states[state].control;
+
+ dprintk("Transitioning to state: 0x%08x\n", value);
+
+ ret = processor_set_pstate(value);
+ if (ret) {
+ unsigned int tmp = cpufreq_freqs.new;
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freqs.new = cpufreq_freqs.old;
+ cpufreq_freqs.old = tmp;
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ printk(KERN_WARNING "Transition failed with error %d\n", ret);
+ retval = -ENODEV;
+ goto migrate_end;
+ }
+
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+
+ data->acpi_data.state = state;
+
+ retval = 0;
+
+migrate_end:
+ set_cpus_allowed(current, saved_mask);
+ return (retval);
+}
+
+
+static unsigned int
+acpi_cpufreq_get (
+ unsigned int cpu)
+{
+ struct cpufreq_acpi_io *data = acpi_io_data[cpu];
+
+ dprintk("acpi_cpufreq_get\n");
+
+ return processor_get_freq(data, cpu);
+}
+
+
+static int
+acpi_cpufreq_target (
+ struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+ unsigned int next_state = 0;
+ unsigned int result = 0;
+
+ dprintk("acpi_cpufreq_setpolicy\n");
+
+ result = cpufreq_frequency_table_target(policy,
+ data->freq_table, target_freq, relation, &next_state);
+ if (result)
+ return (result);
+
+ result = processor_set_freq(data, policy->cpu, next_state);
+
+ return (result);
+}
+
+
+static int
+acpi_cpufreq_verify (
+ struct cpufreq_policy *policy)
+{
+ unsigned int result = 0;
+ struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+ dprintk("acpi_cpufreq_verify\n");
+
+ result = cpufreq_frequency_table_verify(policy,
+ data->freq_table);
+
+ return (result);
+}
+
+
+/*
+ * processor_init_pdc - let BIOS know about the SMP capabilities
+ * of this driver
+ * @perf: processor-specific acpi_io_data struct
+ * @cpu: CPU being initialized
+ *
+ * To avoid issues with legacy OSes, some BIOSes require to be informed of
+ * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC
+ * accordingly. Actual call to _PDC is done in driver/acpi/processor.c
+ */
+static void
+processor_init_pdc (
+ struct acpi_processor_performance *perf,
+ unsigned int cpu,
+ struct acpi_object_list *obj_list
+ )
+{
+ union acpi_object *obj;
+ u32 *buf;
+
+ dprintk("processor_init_pdc\n");
+
+ perf->pdc = NULL;
+ /* Initialize pdc. It will be used later. */
+ if (!obj_list)
+ return;
+
+ if (!(obj_list->count && obj_list->pointer))
+ return;
+
+ obj = obj_list->pointer;
+ if ((obj->buffer.length == 12) && obj->buffer.pointer) {
+ buf = (u32 *)obj->buffer.pointer;
+ buf[0] = ACPI_PDC_REVISION_ID;
+ buf[1] = 1;
+ buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
+ perf->pdc = obj_list;
+ }
+ return;
+}
+
+
+static int
+acpi_cpufreq_cpu_init (
+ struct cpufreq_policy *policy)
+{
+ unsigned int i;
+ unsigned int cpu = policy->cpu;
+ struct cpufreq_acpi_io *data;
+ unsigned int result = 0;
+
+ union acpi_object arg0 = {ACPI_TYPE_BUFFER};
+ u32 arg0_buf[3];
+ struct acpi_object_list arg_list = {1, &arg0};
+
+ dprintk("acpi_cpufreq_cpu_init\n");
+ /* setup arg_list for _PDC settings */
+ arg0.buffer.length = 12;
+ arg0.buffer.pointer = (u8 *) arg0_buf;
+
+ data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+ if (!data)
+ return (-ENOMEM);
+
+ memset(data, 0, sizeof(struct cpufreq_acpi_io));
+
+ acpi_io_data[cpu] = data;
+
+ processor_init_pdc(&data->acpi_data, cpu, &arg_list);
+ result = acpi_processor_register_performance(&data->acpi_data, cpu);
+ data->acpi_data.pdc = NULL;
+
+ if (result)
+ goto err_free;
+
+ /* capability check */
+ if (data->acpi_data.state_count <= 1) {
+ dprintk("No P-States\n");
+ result = -ENODEV;
+ goto err_unreg;
+ }
+
+ if ((data->acpi_data.control_register.space_id !=
+ ACPI_ADR_SPACE_FIXED_HARDWARE) ||
+ (data->acpi_data.status_register.space_id !=
+ ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+ dprintk("Unsupported address space [%d, %d]\n",
+ (u32) (data->acpi_data.control_register.space_id),
+ (u32) (data->acpi_data.status_register.space_id));
+ result = -ENODEV;
+ goto err_unreg;
+ }
+
+ /* alloc freq_table */
+ data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+ (data->acpi_data.state_count + 1),
+ GFP_KERNEL);
+ if (!data->freq_table) {
+ result = -ENOMEM;
+ goto err_unreg;
+ }
+
+ /* detect transition latency */
+ policy->cpuinfo.transition_latency = 0;
+ for (i=0; i<data->acpi_data.state_count; i++) {
+ if ((data->acpi_data.states[i].transition_latency * 1000) >
+ policy->cpuinfo.transition_latency) {
+ policy->cpuinfo.transition_latency =
+ data->acpi_data.states[i].transition_latency * 1000;
+ }
+ }
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cur = processor_get_freq(data, policy->cpu);
+
+ /* table init */
+ for (i = 0; i <= data->acpi_data.state_count; i++)
+ {
+ data->freq_table[i].index = i;
+ if (i < data->acpi_data.state_count) {
+ data->freq_table[i].frequency =
+ data->acpi_data.states[i].core_frequency * 1000;
+ } else {
+ data->freq_table[i].frequency = CPUFREQ_TABLE_END;
+ }
+ }
+
+ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+ if (result) {
+ goto err_freqfree;
+ }
+
+ /* notify BIOS that we exist */
+ acpi_processor_notify_smm(THIS_MODULE);
+
+ printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management "
+ "activated.\n", cpu);
+
+ for (i = 0; i < data->acpi_data.state_count; i++)
+ dprintk(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
+ (i == data->acpi_data.state?'*':' '), i,
+ (u32) data->acpi_data.states[i].core_frequency,
+ (u32) data->acpi_data.states[i].power,
+ (u32) data->acpi_data.states[i].transition_latency,
+ (u32) data->acpi_data.states[i].bus_master_latency,
+ (u32) data->acpi_data.states[i].status,
+ (u32) data->acpi_data.states[i].control);
+
+ cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
+
+ /* the first call to ->target() should result in us actually
+ * writing something to the appropriate registers. */
+ data->resume = 1;
+
+ return (result);
+
+ err_freqfree:
+ kfree(data->freq_table);
+ err_unreg:
+ acpi_processor_unregister_performance(&data->acpi_data, cpu);
+ err_free:
+ kfree(data);
+ acpi_io_data[cpu] = NULL;
+
+ return (result);
+}
+
+
+static int
+acpi_cpufreq_cpu_exit (
+ struct cpufreq_policy *policy)
+{
+ struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+ dprintk("acpi_cpufreq_cpu_exit\n");
+
+ if (data) {
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ acpi_io_data[policy->cpu] = NULL;
+ acpi_processor_unregister_performance(&data->acpi_data,
+ policy->cpu);
+ kfree(data);
+ }
+
+ return (0);
+}
+
+
+static struct freq_attr* acpi_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+
+static struct cpufreq_driver acpi_cpufreq_driver = {
+ .verify = acpi_cpufreq_verify,
+ .target = acpi_cpufreq_target,
+ .get = acpi_cpufreq_get,
+ .init = acpi_cpufreq_cpu_init,
+ .exit = acpi_cpufreq_cpu_exit,
+ .name = "acpi-cpufreq",
+ .owner = THIS_MODULE,
+ .attr = acpi_cpufreq_attr,
+};
+
+
+static int __init
+acpi_cpufreq_init (void)
+{
+ dprintk("acpi_cpufreq_init\n");
+
+ return cpufreq_register_driver(&acpi_cpufreq_driver);
+}
+
+
+static void __exit
+acpi_cpufreq_exit (void)
+{
+ dprintk("acpi_cpufreq_exit\n");
+
+ cpufreq_unregister_driver(&acpi_cpufreq_driver);
+ return;
+}
+
+
+late_initcall(acpi_cpufreq_init);
+module_exit(acpi_cpufreq_exit);
+
diff --git a/arch/ia64/kernel/domain.c b/arch/ia64/kernel/domain.c
deleted file mode 100644
index bbb8efe..0000000
--- a/arch/ia64/kernel/domain.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * arch/ia64/kernel/domain.c
- * Architecture specific sched-domains builder.
- *
- * Copyright (C) 2004 Jesse Barnes
- * Copyright (C) 2004 Silicon Graphics, Inc.
- */
-
-#include <linux/sched.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-#include <linux/cpumask.h>
-#include <linux/init.h>
-#include <linux/topology.h>
-#include <linux/nodemask.h>
-
-#define SD_NODES_PER_DOMAIN 16
-
-#ifdef CONFIG_NUMA
-/**
- * find_next_best_node - find the next node to include in a sched_domain
- * @node: node whose sched_domain we're building
- * @used_nodes: nodes already in the sched_domain
- *
- * Find the next node to include in a given scheduling domain. Simply
- * finds the closest node not already in the @used_nodes map.
- *
- * Should use nodemask_t.
- */
-static int find_next_best_node(int node, unsigned long *used_nodes)
-{
- int i, n, val, min_val, best_node = 0;
-
- min_val = INT_MAX;
-
- for (i = 0; i < MAX_NUMNODES; i++) {
- /* Start at @node */
- n = (node + i) % MAX_NUMNODES;
-
- if (!nr_cpus_node(n))
- continue;
-
- /* Skip already used nodes */
- if (test_bit(n, used_nodes))
- continue;
-
- /* Simple min distance search */
- val = node_distance(node, n);
-
- if (val < min_val) {
- min_val = val;
- best_node = n;
- }
- }
-
- set_bit(best_node, used_nodes);
- return best_node;
-}
-
-/**
- * sched_domain_node_span - get a cpumask for a node's sched_domain
- * @node: node whose cpumask we're constructing
- * @size: number of nodes to include in this span
- *
- * Given a node, construct a good cpumask for its sched_domain to span. It
- * should be one that prevents unnecessary balancing, but also spreads tasks
- * out optimally.
- */
-static cpumask_t sched_domain_node_span(int node)
-{
- int i;
- cpumask_t span, nodemask;
- DECLARE_BITMAP(used_nodes, MAX_NUMNODES);
-
- cpus_clear(span);
- bitmap_zero(used_nodes, MAX_NUMNODES);
-
- nodemask = node_to_cpumask(node);
- cpus_or(span, span, nodemask);
- set_bit(node, used_nodes);
-
- for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
- int next_node = find_next_best_node(node, used_nodes);
- nodemask = node_to_cpumask(next_node);
- cpus_or(span, span, nodemask);
- }
-
- return span;
-}
-#endif
-
-/*
- * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
- * can switch it on easily if needed.
- */
-#ifdef CONFIG_SCHED_SMT
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static struct sched_group sched_group_cpus[NR_CPUS];
-static int cpu_to_cpu_group(int cpu)
-{
- return cpu;
-}
-#endif
-
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group sched_group_phys[NR_CPUS];
-static int cpu_to_phys_group(int cpu)
-{
-#ifdef CONFIG_SCHED_SMT
- return first_cpu(cpu_sibling_map[cpu]);
-#else
- return cpu;
-#endif
-}
-
-#ifdef CONFIG_NUMA
-/*
- * The init_sched_build_groups can't handle what we want to do with node
- * groups, so roll our own. Now each node has its own list of groups which
- * gets dynamically allocated.
- */
-static DEFINE_PER_CPU(struct sched_domain, node_domains);
-static struct sched_group *sched_group_nodes[MAX_NUMNODES];
-
-static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
-static struct sched_group sched_group_allnodes[MAX_NUMNODES];
-
-static int cpu_to_allnodes_group(int cpu)
-{
- return cpu_to_node(cpu);
-}
-#endif
-
-/*
- * Build sched domains for a given set of cpus and attach the sched domains
- * to the individual cpus
- */
-void build_sched_domains(const cpumask_t *cpu_map)
-{
- int i;
-
- /*
- * Set up domains for cpus specified by the cpu_map.
- */
- for_each_cpu_mask(i, *cpu_map) {
- int group;
- struct sched_domain *sd = NULL, *p;
- cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
-
- cpus_and(nodemask, nodemask, *cpu_map);
-
-#ifdef CONFIG_NUMA
- if (num_online_cpus()
- > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
- sd = &per_cpu(allnodes_domains, i);
- *sd = SD_ALLNODES_INIT;
- sd->span = *cpu_map;
- group = cpu_to_allnodes_group(i);
- sd->groups = &sched_group_allnodes[group];
- p = sd;
- } else
- p = NULL;
-
- sd = &per_cpu(node_domains, i);
- *sd = SD_NODE_INIT;
- sd->span = sched_domain_node_span(cpu_to_node(i));
- sd->parent = p;
- cpus_and(sd->span, sd->span, *cpu_map);
-#endif
-
- p = sd;
- sd = &per_cpu(phys_domains, i);
- group = cpu_to_phys_group(i);
- *sd = SD_CPU_INIT;
- sd->span = nodemask;
- sd->parent = p;
- sd->groups = &sched_group_phys[group];
-
-#ifdef CONFIG_SCHED_SMT
- p = sd;
- sd = &per_cpu(cpu_domains, i);
- group = cpu_to_cpu_group(i);
- *sd = SD_SIBLING_INIT;
- sd->span = cpu_sibling_map[i];
- cpus_and(sd->span, sd->span, *cpu_map);
- sd->parent = p;
- sd->groups = &sched_group_cpus[group];
-#endif
- }
-
-#ifdef CONFIG_SCHED_SMT
- /* Set up CPU (sibling) groups */
- for_each_cpu_mask(i, *cpu_map) {
- cpumask_t this_sibling_map = cpu_sibling_map[i];
- cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
- if (i != first_cpu(this_sibling_map))
- continue;
-
- init_sched_build_groups(sched_group_cpus, this_sibling_map,
- &cpu_to_cpu_group);
- }
-#endif
-
- /* Set up physical groups */
- for (i = 0; i < MAX_NUMNODES; i++) {
- cpumask_t nodemask = node_to_cpumask(i);
-
- cpus_and(nodemask, nodemask, *cpu_map);
- if (cpus_empty(nodemask))
- continue;
-
- init_sched_build_groups(sched_group_phys, nodemask,
- &cpu_to_phys_group);
- }
-
-#ifdef CONFIG_NUMA
- init_sched_build_groups(sched_group_allnodes, *cpu_map,
- &cpu_to_allnodes_group);
-
- for (i = 0; i < MAX_NUMNODES; i++) {
- /* Set up node groups */
- struct sched_group *sg, *prev;
- cpumask_t nodemask = node_to_cpumask(i);
- cpumask_t domainspan;
- cpumask_t covered = CPU_MASK_NONE;
- int j;
-
- cpus_and(nodemask, nodemask, *cpu_map);
- if (cpus_empty(nodemask))
- continue;
-
- domainspan = sched_domain_node_span(i);
- cpus_and(domainspan, domainspan, *cpu_map);
-
- sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
- sched_group_nodes[i] = sg;
- for_each_cpu_mask(j, nodemask) {
- struct sched_domain *sd;
- sd = &per_cpu(node_domains, j);
- sd->groups = sg;
- if (sd->groups == NULL) {
- /* Turn off balancing if we have no groups */
- sd->flags = 0;
- }
- }
- if (!sg) {
- printk(KERN_WARNING
- "Can not alloc domain group for node %d\n", i);
- continue;
- }
- sg->cpu_power = 0;
- sg->cpumask = nodemask;
- cpus_or(covered, covered, nodemask);
- prev = sg;
-
- for (j = 0; j < MAX_NUMNODES; j++) {
- cpumask_t tmp, notcovered;
- int n = (i + j) % MAX_NUMNODES;
-
- cpus_complement(notcovered, covered);
- cpus_and(tmp, notcovered, *cpu_map);
- cpus_and(tmp, tmp, domainspan);
- if (cpus_empty(tmp))
- break;
-
- nodemask = node_to_cpumask(n);
- cpus_and(tmp, tmp, nodemask);
- if (cpus_empty(tmp))
- continue;
-
- sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
- if (!sg) {
- printk(KERN_WARNING
- "Can not alloc domain group for node %d\n", j);
- break;
- }
- sg->cpu_power = 0;
- sg->cpumask = tmp;
- cpus_or(covered, covered, tmp);
- prev->next = sg;
- prev = sg;
- }
- prev->next = sched_group_nodes[i];
- }
-#endif
-
- /* Calculate CPU power for physical packages and nodes */
- for_each_cpu_mask(i, *cpu_map) {
- int power;
- struct sched_domain *sd;
-#ifdef CONFIG_SCHED_SMT
- sd = &per_cpu(cpu_domains, i);
- power = SCHED_LOAD_SCALE;
- sd->groups->cpu_power = power;
-#endif
-
- sd = &per_cpu(phys_domains, i);
- power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
- (cpus_weight(sd->groups->cpumask)-1) / 10;
- sd->groups->cpu_power = power;
-
-#ifdef CONFIG_NUMA
- sd = &per_cpu(allnodes_domains, i);
- if (sd->groups) {
- power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
- (cpus_weight(sd->groups->cpumask)-1) / 10;
- sd->groups->cpu_power = power;
- }
-#endif
- }
-
-#ifdef CONFIG_NUMA
- for (i = 0; i < MAX_NUMNODES; i++) {
- struct sched_group *sg = sched_group_nodes[i];
- int j;
-
- if (sg == NULL)
- continue;
-next_sg:
- for_each_cpu_mask(j, sg->cpumask) {
- struct sched_domain *sd;
- int power;
-
- sd = &per_cpu(phys_domains, j);
- if (j != first_cpu(sd->groups->cpumask)) {
- /*
- * Only add "power" once for each
- * physical package.
- */
- continue;
- }
- power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
- (cpus_weight(sd->groups->cpumask)-1) / 10;
-
- sg->cpu_power += power;
- }
- sg = sg->next;
- if (sg != sched_group_nodes[i])
- goto next_sg;
- }
-#endif
-
- /* Attach the domains */
- for_each_cpu_mask(i, *cpu_map) {
- struct sched_domain *sd;
-#ifdef CONFIG_SCHED_SMT
- sd = &per_cpu(cpu_domains, i);
-#else
- sd = &per_cpu(phys_domains, i);
-#endif
- cpu_attach_domain(sd, i);
- }
-}
-/*
- * Set up scheduler domains and groups. Callers must hold the hotplug lock.
- */
-void arch_init_sched_domains(const cpumask_t *cpu_map)
-{
- cpumask_t cpu_default_map;
-
- /*
- * Setup mask for cpus without special case scheduling requirements.
- * For now this just excludes isolated cpus, but could be used to
- * exclude other special cases in the future.
- */
- cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
-
- build_sched_domains(&cpu_default_map);
-}
-
-void arch_destroy_sched_domains(const cpumask_t *cpu_map)
-{
-#ifdef CONFIG_NUMA
- int i;
- for (i = 0; i < MAX_NUMNODES; i++) {
- cpumask_t nodemask = node_to_cpumask(i);
- struct sched_group *oldsg, *sg = sched_group_nodes[i];
-
- cpus_and(nodemask, nodemask, *cpu_map);
- if (cpus_empty(nodemask))
- continue;
-
- if (sg == NULL)
- continue;
- sg = sg->next;
-next_sg:
- oldsg = sg;
- sg = sg->next;
- kfree(oldsg);
- if (oldsg != sched_group_nodes[i])
- goto next_sg;
- sched_group_nodes[i] = NULL;
- }
-#endif
-}
-
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 28f2aad..205d980 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -91,23 +91,8 @@
}
#ifdef CONFIG_SMP
-/*
- * This is updated when the user sets irq affinity via /proc
- */
-static cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
-static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)];
-
static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
-/*
- * Arch specific routine for deferred write to iosapic rte to reprogram
- * intr destination.
- */
-void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
-{
- pending_irq_cpumask[irq] = mask_val;
-}
-
void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
{
cpumask_t mask = CPU_MASK_NONE;
@@ -116,32 +101,10 @@
if (irq < NR_IRQS) {
irq_affinity[irq] = mask;
+ set_irq_info(irq, mask);
irq_redir[irq] = (char) (redir & 0xff);
}
}
-
-
-void move_irq(int irq)
-{
- /* note - we hold desc->lock */
- cpumask_t tmp;
- irq_desc_t *desc = irq_descp(irq);
- int redir = test_bit(irq, pending_irq_redir);
-
- if (unlikely(!desc->handler->set_affinity))
- return;
-
- if (!cpus_empty(pending_irq_cpumask[irq])) {
- cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
- if (unlikely(!cpus_empty(tmp))) {
- desc->handler->set_affinity(irq | (redir ? IA64_IRQ_REDIRECTED : 0),
- pending_irq_cpumask[irq]);
- }
- cpus_clear(pending_irq_cpumask[irq]);
- }
-}
-
-
#endif /* CONFIG_SMP */
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S
index b7fa3cc..2323377 100644
--- a/arch/ia64/kernel/jprobes.S
+++ b/arch/ia64/kernel/jprobes.S
@@ -49,6 +49,7 @@
/*
* void jprobe_break(void)
*/
+ .section .kprobes.text, "ax"
ENTRY(jprobe_break)
break.m 0x80300
END(jprobe_break)
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 884f5cd..471086b 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -87,12 +87,25 @@
* is IP relative instruction and update the kprobe
* inst flag accordingly
*/
-static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode,
- unsigned long kprobe_inst, struct kprobe *p)
+static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst,
+ struct kprobe *p)
{
p->ainsn.inst_flag = 0;
p->ainsn.target_br_reg = 0;
+ /* Check for Break instruction
+ * Bits 37:40 Major opcode to be zero
+ * Bits 27:32 X6 to be zero
+ * Bits 32:35 X3 to be zero
+ */
+ if ((!major_opcode) && (!((kprobe_inst >> 27) & 0x1FF)) ) {
+ /* is a break instruction */
+ p->ainsn.inst_flag |= INST_FLAG_BREAK_INST;
+ return;
+ }
+
if (bundle_encoding[template][slot] == B) {
switch (major_opcode) {
case INDIRECT_CALL_OPCODE:
@@ -126,8 +139,10 @@
* Returns 0 if supported
* Returns -EINVAL if unsupported
*/
-static int unsupported_inst(uint template, uint slot, uint major_opcode,
- unsigned long kprobe_inst, struct kprobe *p)
+static int __kprobes unsupported_inst(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst,
+ struct kprobe *p)
{
unsigned long addr = (unsigned long)p->addr;
@@ -168,8 +183,9 @@
* on which we are inserting kprobe is cmp instruction
* with ctype as unc.
*/
-static uint is_cmp_ctype_unc_inst(uint template, uint slot, uint major_opcode,
-unsigned long kprobe_inst)
+static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst)
{
cmp_inst_t cmp_inst;
uint ctype_unc = 0;
@@ -201,8 +217,10 @@
* In this function we override the bundle with
* the break instruction at the given slot.
*/
-static void prepare_break_inst(uint template, uint slot, uint major_opcode,
- unsigned long kprobe_inst, struct kprobe *p)
+static void __kprobes prepare_break_inst(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst,
+ struct kprobe *p)
{
unsigned long break_inst = BREAK_INST;
bundle_t *bundle = &p->ainsn.insn.bundle;
@@ -271,7 +289,8 @@
&& addr < (unsigned long)__end_ivt_text);
}
-static int valid_kprobe_addr(int template, int slot, unsigned long addr)
+static int __kprobes valid_kprobe_addr(int template, int slot,
+ unsigned long addr)
{
if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
printk(KERN_WARNING "Attempting to insert unaligned kprobe "
@@ -323,7 +342,7 @@
* - cleanup by marking the instance as unused
* - long jump back to the original return address
*/
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head;
@@ -381,7 +400,8 @@
return 1;
}
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+ struct pt_regs *regs)
{
struct kretprobe_instance *ri;
@@ -399,7 +419,7 @@
}
}
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
unsigned long addr = (unsigned long) p->addr;
unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
@@ -430,7 +450,7 @@
return 0;
}
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
{
unsigned long addr = (unsigned long)p->addr;
unsigned long arm_addr = addr & ~0xFULL;
@@ -439,7 +459,7 @@
flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
}
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
unsigned long addr = (unsigned long)p->addr;
unsigned long arm_addr = addr & ~0xFULL;
@@ -449,7 +469,7 @@
flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
}
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
{
}
@@ -461,7 +481,7 @@
* to original stack address, handle the case where we need to fixup the
* relative IP address and/or fixup branch register.
*/
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
@@ -528,13 +548,16 @@
ia64_psr(regs)->ss = 0;
}
-static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
{
unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
unsigned long slot = (unsigned long)p->addr & 0xf;
- /* Update instruction pointer (IIP) and slot number (IPSR.ri) */
- regs->cr_iip = bundle_addr & ~0xFULL;
+ /* single step inline if break instruction */
+ if (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)
+ regs->cr_iip = (unsigned long)p->addr & ~0xFULL;
+ else
+ regs->cr_iip = bundle_addr & ~0xFULL;
if (slot > 2)
slot = 0;
@@ -545,7 +568,39 @@
ia64_psr(regs)->ss = 1;
}
-static int pre_kprobes_handler(struct die_args *args)
+static int __kprobes is_ia64_break_inst(struct pt_regs *regs)
+{
+ unsigned int slot = ia64_psr(regs)->ri;
+ unsigned int template, major_opcode;
+ unsigned long kprobe_inst;
+ unsigned long *kprobe_addr = (unsigned long *)regs->cr_iip;
+ bundle_t bundle;
+
+ memcpy(&bundle, kprobe_addr, sizeof(bundle_t));
+ template = bundle.quad0.template;
+
+ /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
+ if (slot == 1 && bundle_encoding[template][1] == L)
+ slot++;
+
+ /* Get Kprobe probe instruction at given slot*/
+ get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);
+
+ /* For break instruction,
+ * Bits 37:40 Major opcode to be zero
+ * Bits 27:32 X6 to be zero
+ * Bits 32:35 X3 to be zero
+ */
+ if (major_opcode || ((kprobe_inst >> 27) & 0x1FF) ) {
+ /* Not a break instruction */
+ return 0;
+ }
+
+ /* Is a break instruction */
+ return 1;
+}
+
+static int __kprobes pre_kprobes_handler(struct die_args *args)
{
struct kprobe *p;
int ret = 0;
@@ -558,7 +613,9 @@
if (kprobe_running()) {
p = get_kprobe(addr);
if (p) {
- if (kprobe_status == KPROBE_HIT_SS) {
+ if ( (kprobe_status == KPROBE_HIT_SS) &&
+ (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) {
+ ia64_psr(regs)->ss = 0;
unlock_kprobes();
goto no_kprobe;
}
@@ -592,6 +649,19 @@
p = get_kprobe(addr);
if (!p) {
unlock_kprobes();
+ if (!is_ia64_break_inst(regs)) {
+ /*
+ * The breakpoint instruction was removed right
+ * after we hit it. Another cpu has removed
+ * either a probepoint or a debugger breakpoint
+ * at this address. In either case, no further
+ * handling of this interrupt is appropriate.
+ */
+ ret = 1;
+
+ }
+
+ /* Not one of our break, let kernel handle it */
goto no_kprobe;
}
@@ -616,7 +686,7 @@
return ret;
}
-static int post_kprobes_handler(struct pt_regs *regs)
+static int __kprobes post_kprobes_handler(struct pt_regs *regs)
{
if (!kprobe_running())
return 0;
@@ -641,7 +711,7 @@
return 1;
}
-static int kprobes_fault_handler(struct pt_regs *regs, int trapnr)
+static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
{
if (!kprobe_running())
return 0;
@@ -659,8 +729,8 @@
return 0;
}
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
- void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
switch(val) {
@@ -681,7 +751,7 @@
return NOTIFY_DONE;
}
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
@@ -703,7 +773,7 @@
return 1;
}
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
*regs = jprobe_saved_regs;
return 1;
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index 770fab3..f2dbcd1 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -35,7 +35,7 @@
return -ENOMEM;
#ifdef CONFIG_HUGETLB_PAGE
- if (REGION_NUMBER(addr) == REGION_HPAGE)
+ if (REGION_NUMBER(addr) == RGN_HPAGE)
addr = 0;
#endif
if (!addr)
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 4440c83..f970359 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -15,6 +15,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/module.h> /* for EXPORT_SYMBOL */
#include <linux/hardirq.h>
+#include <linux/kprobes.h>
#include <asm/fpswa.h>
#include <asm/ia32.h>
@@ -122,7 +123,7 @@
}
void
-ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
+__kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
{
siginfo_t siginfo;
int sig, code;
@@ -444,7 +445,7 @@
return rv;
}
-void
+void __kprobes
ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
unsigned long iim, unsigned long itir, long arg5, long arg6,
long arg7, struct pt_regs regs)
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index 490dfc9..4e9d06c 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -184,7 +184,7 @@
{
int node;
- node = nasid_to_cnodeid(NASID_GET(maddr));
+ node = paddr_to_nid(maddr - __IA64_UNCACHED_OFFSET);
dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node);
@@ -217,7 +217,7 @@
memset((char *)vstart, 0, length);
- node = nasid_to_cnodeid(NASID_GET(start));
+ node = paddr_to_nid(start);
for (; vstart < vend ; vstart += PAGE_SIZE) {
dprintk(KERN_INFO "sticking %lx into the pool!\n", vstart);
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index a676e79..30d8564 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -48,6 +48,7 @@
*(.text)
SCHED_TEXT
LOCK_TEXT
+ KPROBES_TEXT
*(.gnu.linkonce.t*)
}
.text2 : AT(ADDR(.text2) - LOAD_OFFSET)
diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile
index 1902c3c..799407e 100644
--- a/arch/ia64/lib/Makefile
+++ b/arch/ia64/lib/Makefile
@@ -6,7 +6,7 @@
lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \
- bitop.o checksum.o clear_page.o csum_partial_copy.o copy_page.o \
+ bitop.o checksum.o clear_page.o csum_partial_copy.o \
clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \
flush.o ip_fast_csum.o do_csum.o \
memset.o strlen.o swiotlb.o
diff --git a/arch/ia64/lib/flush.S b/arch/ia64/lib/flush.S
index 3e2cfa2..2a0d27f 100644
--- a/arch/ia64/lib/flush.S
+++ b/arch/ia64/lib/flush.S
@@ -20,6 +20,7 @@
*
* Note: "in0" and "in1" are preserved for debugging purposes.
*/
+ .section .kprobes.text,"ax"
GLOBAL_ENTRY(flush_icache_range)
.prologue
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
index ab7b3ad..dbc0b3e 100644
--- a/arch/ia64/lib/swiotlb.c
+++ b/arch/ia64/lib/swiotlb.c
@@ -93,8 +93,7 @@
setup_io_tlb_npages(char *str)
{
if (isdigit(*str)) {
- io_tlb_nslabs = simple_strtoul(str, &str, 0) <<
- (PAGE_SHIFT - IO_TLB_SHIFT);
+ io_tlb_nslabs = simple_strtoul(str, &str, 0);
/* avoid tail segment of size < IO_TLB_SEGSIZE */
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
@@ -117,7 +116,7 @@
unsigned long i;
if (!io_tlb_nslabs) {
- io_tlb_nslabs = (default_size >> PAGE_SHIFT);
+ io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index ff62551..2461486 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
+#include <linux/kprobes.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -76,7 +77,7 @@
return pte_present(pte);
}
-void
+void __kprobes
ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs)
{
int signal = SIGSEGV, code = SEGV_MAPERR;
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index e0a776a..2d13889 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -76,7 +76,7 @@
return -EINVAL;
if (addr & ~HPAGE_MASK)
return -EINVAL;
- if (REGION_NUMBER(addr) != REGION_HPAGE)
+ if (REGION_NUMBER(addr) != RGN_HPAGE)
return -EINVAL;
return 0;
@@ -87,7 +87,7 @@
struct page *page;
pte_t *ptep;
- if (REGION_NUMBER(addr) != REGION_HPAGE)
+ if (REGION_NUMBER(addr) != RGN_HPAGE)
return ERR_PTR(-EINVAL);
ptep = huge_pte_offset(mm, addr);
@@ -142,8 +142,8 @@
return -ENOMEM;
if (len & ~HPAGE_MASK)
return -EINVAL;
- /* This code assumes that REGION_HPAGE != 0. */
- if ((REGION_NUMBER(addr) != REGION_HPAGE) || (addr & (HPAGE_SIZE - 1)))
+ /* This code assumes that RGN_HPAGE != 0. */
+ if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1)))
addr = HPAGE_REGION_BASE;
else
addr = ALIGN(addr, HPAGE_SIZE);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index f9472c5..9977c12 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -24,7 +24,6 @@
#include <asm/machvec.h>
#include <asm/page.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/sal.h>
diff --git a/arch/ia64/sn/include/tio.h b/arch/ia64/sn/include/tio.h
index 0139124..6b2e7b7 100644
--- a/arch/ia64/sn/include/tio.h
+++ b/arch/ia64/sn/include/tio.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_TIO_H
@@ -26,6 +26,10 @@
#define TIO_ITTE_VALID_MASK 0x1
#define TIO_ITTE_VALID_SHIFT 16
+#define TIO_ITTE_WIDGET(itte) \
+ (((itte) >> TIO_ITTE_WIDGET_SHIFT) & TIO_ITTE_WIDGET_MASK)
+#define TIO_ITTE_VALID(itte) \
+ (((itte) >> TIO_ITTE_VALID_SHIFT) & TIO_ITTE_VALID_MASK)
#define TIO_ITTE_PUT(nasid, bigwin, widget, addr, valid) \
REMOTE_HUB_S((nasid), TIO_ITTE(bigwin), \
diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h
index 580a1c0..71c2b27 100644
--- a/arch/ia64/sn/include/xtalk/hubdev.h
+++ b/arch/ia64/sn/include/xtalk/hubdev.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_XTALK_HUBDEV_H
#define _ASM_IA64_SN_XTALK_HUBDEV_H
@@ -16,6 +16,9 @@
#define IIO_ITTE_WIDGET_MASK ((1<<IIO_ITTE_WIDGET_BITS)-1)
#define IIO_ITTE_WIDGET_SHIFT 8
+#define IIO_ITTE_WIDGET(itte) \
+ (((itte) >> IIO_ITTE_WIDGET_SHIFT) & IIO_ITTE_WIDGET_MASK)
+
/*
* Use the top big window as a surrogate for the first small window
*/
@@ -34,7 +37,8 @@
unsigned long sfdl_force_int_addr;
unsigned long sfdl_flush_value;
volatile unsigned long *sfdl_flush_addr;
- uint64_t sfdl_persistent_busnum;
+ uint32_t sfdl_persistent_busnum;
+ uint32_t sfdl_persistent_segment;
struct pcibus_info *sfdl_pcibus_info;
spinlock_t sfdl_flush_lock;
};
@@ -58,7 +62,8 @@
void *hdi_nodepda;
void *hdi_node_vertex;
- void *hdi_xtalk_vertex;
+ uint32_t max_segment_number;
+ uint32_t max_pcibus_number;
};
extern void hubdev_init_node(nodepda_t *, cnodeid_t);
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c
index 647deae..45854c6 100644
--- a/arch/ia64/sn/kernel/bte.c
+++ b/arch/ia64/sn/kernel/bte.c
@@ -29,16 +29,30 @@
/* two interfaces on two btes */
#define MAX_INTERFACES_TO_TRY 4
+#define MAX_NODES_TO_TRY 2
static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface)
{
nodepda_t *tmp_nodepda;
+ if (nasid_to_cnodeid(nasid) == -1)
+ return (struct bteinfo_s *)NULL;;
+
tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid));
return &tmp_nodepda->bte_if[interface];
}
+static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode)
+{
+ if (is_shub2()) {
+ BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24)));
+ } else {
+ BTE_LNSTAT_STORE(bte, len);
+ BTE_CTRL_STORE(bte, mode);
+ }
+}
+
/************************************************************************
* Block Transfer Engine copy related functions.
*
@@ -67,13 +81,15 @@
{
u64 transfer_size;
u64 transfer_stat;
+ u64 notif_phys_addr;
struct bteinfo_s *bte;
bte_result_t bte_status;
unsigned long irq_flags;
unsigned long itc_end = 0;
- struct bteinfo_s *btes_to_try[MAX_INTERFACES_TO_TRY];
- int bte_if_index;
- int bte_pri, bte_sec;
+ int nasid_to_try[MAX_NODES_TO_TRY];
+ int my_nasid = get_nasid();
+ int bte_if_index, nasid_index;
+ int bte_first, btes_per_node = BTES_PER_NODE;
BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n",
src, dest, len, mode, notification));
@@ -86,36 +102,26 @@
(src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK));
BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)));
- /* CPU 0 (per node) tries bte0 first, CPU 1 try bte1 first */
- if (cpuid_to_subnode(smp_processor_id()) == 0) {
- bte_pri = 0;
- bte_sec = 1;
- } else {
- bte_pri = 1;
- bte_sec = 0;
- }
+ /*
+ * Start with interface corresponding to cpu number
+ */
+ bte_first = raw_smp_processor_id() % btes_per_node;
if (mode & BTE_USE_DEST) {
/* try remote then local */
- btes_to_try[0] = bte_if_on_node(NASID_GET(dest), bte_pri);
- btes_to_try[1] = bte_if_on_node(NASID_GET(dest), bte_sec);
+ nasid_to_try[0] = NASID_GET(dest);
if (mode & BTE_USE_ANY) {
- btes_to_try[2] = bte_if_on_node(get_nasid(), bte_pri);
- btes_to_try[3] = bte_if_on_node(get_nasid(), bte_sec);
+ nasid_to_try[1] = my_nasid;
} else {
- btes_to_try[2] = NULL;
- btes_to_try[3] = NULL;
+ nasid_to_try[1] = (int)NULL;
}
} else {
/* try local then remote */
- btes_to_try[0] = bte_if_on_node(get_nasid(), bte_pri);
- btes_to_try[1] = bte_if_on_node(get_nasid(), bte_sec);
+ nasid_to_try[0] = my_nasid;
if (mode & BTE_USE_ANY) {
- btes_to_try[2] = bte_if_on_node(NASID_GET(dest), bte_pri);
- btes_to_try[3] = bte_if_on_node(NASID_GET(dest), bte_sec);
+ nasid_to_try[1] = NASID_GET(dest);
} else {
- btes_to_try[2] = NULL;
- btes_to_try[3] = NULL;
+ nasid_to_try[1] = (int)NULL;
}
}
@@ -123,11 +129,12 @@
do {
local_irq_save(irq_flags);
- bte_if_index = 0;
+ bte_if_index = bte_first;
+ nasid_index = 0;
/* Attempt to lock one of the BTE interfaces. */
- while (bte_if_index < MAX_INTERFACES_TO_TRY) {
- bte = btes_to_try[bte_if_index++];
+ while (nasid_index < MAX_NODES_TO_TRY) {
+ bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index);
if (bte == NULL) {
continue;
@@ -143,6 +150,15 @@
break;
}
}
+
+ bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */
+ if (bte_if_index == bte_first) {
+ /*
+ * We've tried all interfaces on this node
+ */
+ nasid_index++;
+ }
+
bte = NULL;
}
@@ -169,7 +185,13 @@
/* Initialize the notification to a known value. */
*bte->most_rcnt_na = BTE_WORD_BUSY;
+ notif_phys_addr = TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na));
+ if (is_shub2()) {
+ src = SH2_TIO_PHYS_TO_DMA(src);
+ dest = SH2_TIO_PHYS_TO_DMA(dest);
+ notif_phys_addr = SH2_TIO_PHYS_TO_DMA(notif_phys_addr);
+ }
/* Set the source and destination registers */
BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src))));
BTE_SRC_STORE(bte, TO_PHYS(src));
@@ -177,14 +199,12 @@
BTE_DEST_STORE(bte, TO_PHYS(dest));
/* Set the notification register */
- BTE_PRINTKV(("IBNA = 0x%lx)\n",
- TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))));
- BTE_NOTIF_STORE(bte,
- TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)));
+ BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr));
+ BTE_NOTIF_STORE(bte, notif_phys_addr);
/* Initiate the transfer */
BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode)));
- BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode));
+ bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode));
itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec);
@@ -195,6 +215,7 @@
}
while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) {
+ cpu_relax();
if (ia64_get_itc() > itc_end) {
BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n",
NASID_GET(bte->bte_base_addr), bte->bte_num,
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index 5c39b43..5c5eb01 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -76,7 +76,7 @@
*/
REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
- udelay(1);
+ cpu_relax();
}
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 414cdf2..906622d 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -18,6 +18,7 @@
#include <asm/sn/simulator.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/tioca_provider.h>
+#include <asm/sn/tioce_provider.h>
#include "xtalk/hubdev.h"
#include "xtalk/xwidgetdev.h"
@@ -44,6 +45,9 @@
struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */
+static int max_segment_number = 0; /* Default highest segment number */
+static int max_pcibus_number = 255; /* Default highest pci bus number */
+
/*
* Hooks and struct for unsupported pci providers
*/
@@ -157,13 +161,28 @@
uint64_t nasid;
int i, widget;
+ /*
+ * Get SGI Specific HUB chipset information.
+ * Inform Prom that this kernel can support domain bus numbering.
+ */
for (i = 0; i < numionodes; i++) {
hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
nasid = cnodeid_to_nasid(i);
+ hubdev->max_segment_number = 0xffffffff;
+ hubdev->max_pcibus_number = 0xff;
status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
if (status)
continue;
+ /* Save the largest Domain and pcibus numbers found. */
+ if (hubdev->max_segment_number) {
+ /*
+ * Dealing with a Prom that supports segments.
+ */
+ max_segment_number = hubdev->max_segment_number;
+ max_pcibus_number = hubdev->max_pcibus_number;
+ }
+
/* Attach the error interrupt handlers */
if (nasid & 1)
ice_error_init(hubdev);
@@ -230,7 +249,7 @@
void sn_pci_fixup_slot(struct pci_dev *dev)
{
int idx;
- int segment = 0;
+ int segment = pci_domain_nr(dev->bus);
int status = 0;
struct pcibus_bussoft *bs;
struct pci_bus *host_pci_bus;
@@ -283,9 +302,9 @@
* PCI host_pci_dev struct and set up host bus linkages
*/
- bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
+ bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
- host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+ host_pci_bus = pci_find_bus(segment, bus_no);
host_pci_dev = pci_get_slot(host_pci_bus, devfn);
SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
@@ -333,6 +352,7 @@
prom_bussoft_ptr = __va(prom_bussoft_ptr);
controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+ controller->segment = segment;
if (!controller)
BUG();
@@ -390,7 +410,7 @@
if (controller->node >= num_online_nodes()) {
struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
- printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%lu"
+ printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u"
"L_IO=%lx L_MEM=%lx BASE=%lx\n",
b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
@@ -411,7 +431,7 @@
{
struct sysdata_el *element;
- element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
+ element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL);
if (!element) {
dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
return;
@@ -445,6 +465,7 @@
static int __init sn_pci_init(void)
{
int i = 0;
+ int j = 0;
struct pci_dev *pci_dev = NULL;
extern void sn_init_cpei_timer(void);
#ifdef CONFIG_PROC_FS
@@ -464,6 +485,7 @@
pcibr_init_provider();
tioca_init_provider();
+ tioce_init_provider();
/*
* This is needed to avoid bounce limit checks in the blk layer
@@ -479,8 +501,9 @@
#endif
/* busses are not known yet ... */
- for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
- sn_pci_controller_fixup(0, i, NULL);
+ for (i = 0; i <= max_segment_number; i++)
+ for (j = 0; j <= max_pcibus_number; j++)
+ sn_pci_controller_fixup(i, j, NULL);
/*
* Generic Linux PCI Layer has created the pci_bus and pci_dev
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 84d276a..9fc7463 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*/
#include <linux/irq.h>
@@ -76,16 +76,14 @@
static void sn_ack_irq(unsigned int irq)
{
- uint64_t event_occurred, mask = 0;
- int nasid;
+ u64 event_occurred, mask = 0;
irq = irq & 0xff;
- nasid = get_nasid();
event_occurred =
- HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED));
+ HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED));
mask = event_occurred & SH_ALL_INT_MASK;
- HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS),
- mask);
+ HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
+ mask);
__set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
move_irq(irq);
@@ -93,15 +91,12 @@
static void sn_end_irq(unsigned int irq)
{
- int nasid;
int ivec;
- uint64_t event_occurred;
+ u64 event_occurred;
ivec = irq & 0xff;
if (ivec == SGI_UART_VECTOR) {
- nasid = get_nasid();
- event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
- (nasid, SH_EVENT_OCCURRED));
+ event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR (SH_EVENT_OCCURRED));
/* If the UART bit is set here, we may have received an
* interrupt from the UART that the driver missed. To
* make sure, we IPI ourselves to force us to look again.
@@ -132,6 +127,7 @@
int local_widget, status;
nasid_t local_nasid;
struct sn_irq_info *new_irq_info;
+ struct sn_pcibus_provider *pci_provider;
new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
if (new_irq_info == NULL)
@@ -171,8 +167,9 @@
new_irq_info->irq_cpuid = cpuid;
register_intr_pda(new_irq_info);
- if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type))
- pcibr_change_devices_irq(new_irq_info);
+ pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+ if (pci_provider && pci_provider->target_interrupt)
+ (pci_provider->target_interrupt)(new_irq_info);
spin_lock(&sn_irq_info_lock);
list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
@@ -317,6 +314,16 @@
pci_dev_put(pci_dev);
}
+static inline void
+sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info)
+{
+ struct sn_pcibus_provider *pci_provider;
+
+ pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type];
+ if (pci_provider && pci_provider->force_interrupt)
+ (*pci_provider->force_interrupt)(sn_irq_info);
+}
+
static void force_interrupt(int irq)
{
struct sn_irq_info *sn_irq_info;
@@ -325,11 +332,9 @@
return;
rcu_read_lock();
- list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) {
- if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
- (sn_irq_info->irq_bridge != NULL))
- pcibr_force_interrupt(sn_irq_info);
- }
+ list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list)
+ sn_call_force_intr_provider(sn_irq_info);
+
rcu_read_unlock();
}
@@ -351,6 +356,14 @@
struct pcidev_info *pcidev_info;
struct pcibus_info *pcibus_info;
+ /*
+ * Bridge types attached to TIO (anything but PIC) do not need this WAR
+ * since they do not target Shub II interrupt registers. If that
+ * ever changes, this check needs to accomodate.
+ */
+ if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC)
+ return;
+
pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
if (!pcidev_info)
return;
@@ -377,16 +390,12 @@
break;
}
if (!test_bit(irr_bit, &irr_reg)) {
- if (!test_bit(irq, pda->sn_soft_irr)) {
- if (!test_bit(irq, pda->sn_in_service_ivecs)) {
- regval &= 0xff;
- if (sn_irq_info->irq_int_bit & regval &
- sn_irq_info->irq_last_intr) {
- regval &=
- ~(sn_irq_info->
- irq_int_bit & regval);
- pcibr_force_interrupt(sn_irq_info);
- }
+ if (!test_bit(irq, pda->sn_in_service_ivecs)) {
+ regval &= 0xff;
+ if (sn_irq_info->irq_int_bit & regval &
+ sn_irq_info->irq_last_intr) {
+ regval &= ~(sn_irq_info->irq_int_bit & regval);
+ sn_call_force_intr_provider(sn_irq_info);
}
}
}
@@ -404,13 +413,7 @@
rcu_read_lock();
for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
- /*
- * Only call for PCI bridges that are fully
- * initialized.
- */
- if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
- (sn_irq_info->irq_bridge != NULL))
- sn_check_intr(i, sn_irq_info);
+ sn_check_intr(i, sn_irq_info);
}
}
rcu_read_unlock();
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 7c7fe44..a594aca 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -80,8 +80,6 @@
DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
EXPORT_PER_CPU_SYMBOL(__sn_nodepda);
-partid_t sn_partid = -1;
-EXPORT_SYMBOL(sn_partid);
char sn_system_serial_number_string[128];
EXPORT_SYMBOL(sn_system_serial_number_string);
u64 sn_partition_serial_number;
@@ -403,6 +401,7 @@
memset(nodepdaindr[cnode], 0, sizeof(nodepda_t));
memset(nodepdaindr[cnode]->phys_cpuid, -1,
sizeof(nodepdaindr[cnode]->phys_cpuid));
+ spin_lock_init(&nodepdaindr[cnode]->ptc_lock);
}
/*
@@ -532,8 +531,8 @@
*/
{
u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0};
- u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1,
- SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3};
+ u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_2,
+ SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3};
u64 *pio;
pio = is_shub1() ? pio1 : pio2;
pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]);
diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
index 96cb71d..3fa9506 100644
--- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
+++ b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <asm/types.h>
@@ -11,7 +11,7 @@
#define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT
#define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK
-#define ALIAS_OFFSET (SH1_PIO_WRITE_STATUS_0_ALIAS-SH1_PIO_WRITE_STATUS_0)
+#define ALIAS_OFFSET 8
.global sn2_ptc_deadlock_recovery_core
@@ -36,13 +36,15 @@
extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address
dep piowcphy=-1,piowcphy,63,1
movl mask=WRITECOUNTMASK
+ mov r8=r0
1:
add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register
- mov scr1=7;; // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR
- st8.rel [scr2]=scr1;;
+ ;;
+ ld8.acq scr1=[scr2];;
5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete.
+ hint @pause
and scr2=scr1,mask;; // mask of writecount bits
cmp.ne p6,p0=zeroval,scr2
(p6) br.cond.sptk 5b
@@ -57,6 +59,7 @@
st8.rel [ptc0]=data0 // Write PTC0 & wait for completion.
5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete.
+ hint @pause
and scr2=scr1,mask;; // mask of writecount bits
cmp.ne p6,p0=zeroval,scr2
(p6) br.cond.sptk 5b;;
@@ -67,6 +70,7 @@
(p7) st8.rel [ptc1]=data1;; // Now write PTC1.
5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete.
+ hint @pause
and scr2=scr1,mask;; // mask of writecount bits
cmp.ne p6,p0=zeroval,scr2
(p6) br.cond.sptk 5b
@@ -77,6 +81,7 @@
srlz.i;;
////////////// END PHYSICAL MODE ////////////////////
+(p8) add r8=1,r8
(p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred.
br.ret.sptk rp
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index 7af05a7..0a4ee50 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/init.h>
@@ -20,6 +20,8 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/nodemask.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/processor.h>
#include <asm/irq.h>
@@ -39,12 +41,120 @@
#include <asm/sn/nodepda.h>
#include <asm/sn/rw_mmr.h>
-void sn2_ptc_deadlock_recovery(volatile unsigned long *, unsigned long data0,
- volatile unsigned long *, unsigned long data1);
+DEFINE_PER_CPU(struct ptc_stats, ptcstats);
+DECLARE_PER_CPU(struct ptc_stats, ptcstats);
static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
-static unsigned long sn2_ptc_deadlock_count;
+void sn2_ptc_deadlock_recovery(short *, short, int, volatile unsigned long *, unsigned long data0,
+ volatile unsigned long *, unsigned long data1);
+
+#ifdef DEBUG_PTC
+/*
+ * ptctest:
+ *
+ * xyz - 3 digit hex number:
+ * x - Force PTC purges to use shub:
+ * 0 - no force
+ * 1 - force
+ * y - interupt enable
+ * 0 - disable interrupts
+ * 1 - leave interuupts enabled
+ * z - type of lock:
+ * 0 - global lock
+ * 1 - node local lock
+ * 2 - no lock
+ *
+ * Note: on shub1, only ptctest == 0 is supported. Don't try other values!
+ */
+
+static unsigned int sn2_ptctest = 0;
+
+static int __init ptc_test(char *str)
+{
+ get_option(&str, &sn2_ptctest);
+ return 1;
+}
+__setup("ptctest=", ptc_test);
+
+static inline int ptc_lock(unsigned long *flagp)
+{
+ unsigned long opt = sn2_ptctest & 255;
+
+ switch (opt) {
+ case 0x00:
+ spin_lock_irqsave(&sn2_global_ptc_lock, *flagp);
+ break;
+ case 0x01:
+ spin_lock_irqsave(&sn_nodepda->ptc_lock, *flagp);
+ break;
+ case 0x02:
+ local_irq_save(*flagp);
+ break;
+ case 0x10:
+ spin_lock(&sn2_global_ptc_lock);
+ break;
+ case 0x11:
+ spin_lock(&sn_nodepda->ptc_lock);
+ break;
+ case 0x12:
+ break;
+ default:
+ BUG();
+ }
+ return opt;
+}
+
+static inline void ptc_unlock(unsigned long flags, int opt)
+{
+ switch (opt) {
+ case 0x00:
+ spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+ break;
+ case 0x01:
+ spin_unlock_irqrestore(&sn_nodepda->ptc_lock, flags);
+ break;
+ case 0x02:
+ local_irq_restore(flags);
+ break;
+ case 0x10:
+ spin_unlock(&sn2_global_ptc_lock);
+ break;
+ case 0x11:
+ spin_unlock(&sn_nodepda->ptc_lock);
+ break;
+ case 0x12:
+ break;
+ default:
+ BUG();
+ }
+}
+#else
+
+#define sn2_ptctest 0
+
+static inline int ptc_lock(unsigned long *flagp)
+{
+ spin_lock_irqsave(&sn2_global_ptc_lock, *flagp);
+ return 0;
+}
+
+static inline void ptc_unlock(unsigned long flags, int opt)
+{
+ spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+}
+#endif
+
+struct ptc_stats {
+ unsigned long ptc_l;
+ unsigned long change_rid;
+ unsigned long shub_ptc_flushes;
+ unsigned long nodes_flushed;
+ unsigned long deadlocks;
+ unsigned long lock_itc_clocks;
+ unsigned long shub_itc_clocks;
+ unsigned long shub_itc_clocks_max;
+};
static inline unsigned long wait_piowc(void)
{
@@ -89,9 +199,9 @@
sn2_global_tlb_purge(unsigned long start, unsigned long end,
unsigned long nbits)
{
- int i, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0;
+ int i, opt, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0;
volatile unsigned long *ptc0, *ptc1;
- unsigned long flags = 0, data0 = 0, data1 = 0;
+ unsigned long itc, itc2, flags, data0 = 0, data1 = 0;
struct mm_struct *mm = current->active_mm;
short nasids[MAX_NUMNODES], nix;
nodemask_t nodes_flushed;
@@ -114,16 +224,19 @@
start += (1UL << nbits);
} while (start < end);
ia64_srlz_i();
+ __get_cpu_var(ptcstats).ptc_l++;
preempt_enable();
return;
}
if (atomic_read(&mm->mm_users) == 1) {
flush_tlb_mm(mm);
+ __get_cpu_var(ptcstats).change_rid++;
preempt_enable();
return;
}
+ itc = ia64_get_itc();
nix = 0;
for_each_node_mask(cnode, nodes_flushed)
nasids[nix++] = cnodeid_to_nasid(cnode);
@@ -148,7 +261,12 @@
mynasid = get_nasid();
- spin_lock_irqsave(&sn2_global_ptc_lock, flags);
+ itc = ia64_get_itc();
+ opt = ptc_lock(&flags);
+ itc2 = ia64_get_itc();
+ __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc;
+ __get_cpu_var(ptcstats).shub_ptc_flushes++;
+ __get_cpu_var(ptcstats).nodes_flushed += nix;
do {
if (shub1)
@@ -157,7 +275,7 @@
data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK);
for (i = 0; i < nix; i++) {
nasid = nasids[i];
- if (unlikely(nasid == mynasid)) {
+ if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid)) {
ia64_ptcga(start, nbits << 2);
ia64_srlz_i();
} else {
@@ -169,18 +287,22 @@
flushed = 1;
}
}
-
if (flushed
&& (wait_piowc() &
- SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK)) {
- sn2_ptc_deadlock_recovery(ptc0, data0, ptc1, data1);
+ (SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK))) {
+ sn2_ptc_deadlock_recovery(nasids, nix, mynasid, ptc0, data0, ptc1, data1);
}
start += (1UL << nbits);
} while (start < end);
- spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+ itc2 = ia64_get_itc() - itc2;
+ __get_cpu_var(ptcstats).shub_itc_clocks += itc2;
+ if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max)
+ __get_cpu_var(ptcstats).shub_itc_clocks_max = itc2;
+
+ ptc_unlock(flags, opt);
preempt_enable();
}
@@ -192,31 +314,29 @@
* TLB flush transaction. The recovery sequence is somewhat tricky & is
* coded in assembly language.
*/
-void sn2_ptc_deadlock_recovery(volatile unsigned long *ptc0, unsigned long data0,
+void sn2_ptc_deadlock_recovery(short *nasids, short nix, int mynasid, volatile unsigned long *ptc0, unsigned long data0,
volatile unsigned long *ptc1, unsigned long data1)
{
extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long);
- int cnode, mycnode, nasid;
- volatile unsigned long *piows;
- volatile unsigned long zeroval;
+ short nasid, i;
+ unsigned long *piows, zeroval;
- sn2_ptc_deadlock_count++;
+ __get_cpu_var(ptcstats).deadlocks++;
- piows = pda->pio_write_status_addr;
+ piows = (unsigned long *) pda->pio_write_status_addr;
zeroval = pda->pio_write_status_val;
- mycnode = numa_node_id();
-
- for_each_online_node(cnode) {
- if (is_headless_node(cnode) || cnode == mycnode)
+ for (i=0; i < nix; i++) {
+ nasid = nasids[i];
+ if (!(sn2_ptctest & 3) && nasid == mynasid)
continue;
- nasid = cnodeid_to_nasid(cnode);
ptc0 = CHANGE_NASID(nasid, ptc0);
if (ptc1)
ptc1 = CHANGE_NASID(nasid, ptc1);
sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval);
}
+
}
/**
@@ -293,3 +413,93 @@
sn_send_IPI_phys(nasid, physid, vector, delivery_mode);
}
+
+#ifdef CONFIG_PROC_FS
+
+#define PTC_BASENAME "sgi_sn/ptc_statistics"
+
+static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
+{
+ if (*offset < NR_CPUS)
+ return offset;
+ return NULL;
+}
+
+static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset)
+{
+ (*offset)++;
+ if (*offset < NR_CPUS)
+ return offset;
+ return NULL;
+}
+
+static void sn2_ptc_seq_stop(struct seq_file *file, void *data)
+{
+}
+
+static int sn2_ptc_seq_show(struct seq_file *file, void *data)
+{
+ struct ptc_stats *stat;
+ int cpu;
+
+ cpu = *(loff_t *) data;
+
+ if (!cpu) {
+ seq_printf(file, "# ptc_l change_rid shub_ptc_flushes shub_nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max\n");
+ seq_printf(file, "# ptctest %d\n", sn2_ptctest);
+ }
+
+ if (cpu < NR_CPUS && cpu_online(cpu)) {
+ stat = &per_cpu(ptcstats, cpu);
+ seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
+ stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
+ stat->deadlocks,
+ 1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
+ 1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
+ 1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec);
+ }
+
+ return 0;
+}
+
+static struct seq_operations sn2_ptc_seq_ops = {
+ .start = sn2_ptc_seq_start,
+ .next = sn2_ptc_seq_next,
+ .stop = sn2_ptc_seq_stop,
+ .show = sn2_ptc_seq_show
+};
+
+int sn2_ptc_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &sn2_ptc_seq_ops);
+}
+
+static struct file_operations proc_sn2_ptc_operations = {
+ .open = sn2_ptc_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static struct proc_dir_entry *proc_sn2_ptc;
+
+static int __init sn2_ptc_init(void)
+{
+ if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) {
+ printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);
+ return -EINVAL;
+ }
+ proc_sn2_ptc->proc_fops = &proc_sn2_ptc_operations;
+ spin_lock_init(&sn2_global_ptc_lock);
+ return 0;
+}
+
+static void __exit sn2_ptc_exit(void)
+{
+ remove_proc_entry(PTC_BASENAME, NULL);
+}
+
+module_init(sn2_ptc_init);
+module_exit(sn2_ptc_exit);
+#endif /* CONFIG_PROC_FS */
+
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 833e700..0513aac 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -36,7 +36,6 @@
#include <asm/topology.h>
#include <asm/smp.h>
#include <asm/semaphore.h>
-#include <asm/segment.h>
#include <asm/uaccess.h>
#include <asm/sal.h>
#include <asm/sn/io.h>
@@ -59,7 +58,7 @@
struct sn_hwperf_object_info *objbuf = NULL;
if ((e = sn_hwperf_init()) < 0) {
- printk("sn_hwperf_init failed: err %d\n", e);
+ printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e);
goto out;
}
@@ -111,7 +110,7 @@
if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
return -1;
- for (cnode = 0; cnode < numionodes; cnode++) {
+ for_each_node(cnode) {
geoid = cnodeid_get_geoid(cnode);
module_id = geo_module(geoid);
this_rack = MODULE_GET_RACK(module_id);
@@ -124,11 +123,13 @@
}
}
- return cnode < numionodes ? cnode : -1;
+ return node_possible(cnode) ? cnode : -1;
}
static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
{
+ if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
+ BUG();
if (!obj->sn_hwp_this_part)
return -1;
return sn_hwperf_geoid_to_cnode(obj->location);
@@ -174,31 +175,199 @@
return slabname;
}
-static void print_pci_topology(struct seq_file *s,
- struct sn_hwperf_object_info *obj, int *ordinal,
- u64 rack, u64 bay, u64 slot, u64 slab)
+static void print_pci_topology(struct seq_file *s)
{
- char *p1;
- char *p2;
- char *pg;
+ char *p;
+ size_t sz;
+ int e;
- if (!(pg = (char *)get_zeroed_page(GFP_KERNEL)))
- return; /* ignore */
- if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab,
- __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) {
- for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) {
- if (!(p2 = strchr(p1, '\n')))
- break;
- *p2 = '\0';
- seq_printf(s, "pcibus %d %s-%s\n",
- *ordinal, obj->location, p1);
- (*ordinal)++;
- p1 = p2 + 1;
+ for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {
+ if (!(p = (char *)kmalloc(sz, GFP_KERNEL)))
+ break;
+ e = ia64_sn_ioif_get_pci_topology(__pa(p), sz);
+ if (e == SALRET_OK)
+ seq_puts(s, p);
+ kfree(p);
+ if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED)
+ break;
+ }
+}
+
+static inline int sn_hwperf_has_cpus(cnodeid_t node)
+{
+ return node_online(node) && nr_cpus_node(node);
+}
+
+static inline int sn_hwperf_has_mem(cnodeid_t node)
+{
+ return node_online(node) && NODE_DATA(node)->node_present_pages;
+}
+
+static struct sn_hwperf_object_info *
+sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf,
+ int nobj, int id)
+{
+ int i;
+ struct sn_hwperf_object_info *p = objbuf;
+
+ for (i=0; i < nobj; i++, p++) {
+ if (p->id == id)
+ return p;
+ }
+
+ return NULL;
+
+}
+
+static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf,
+ int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
+{
+ int e;
+ struct sn_hwperf_object_info *nodeobj = NULL;
+ struct sn_hwperf_object_info *op;
+ struct sn_hwperf_object_info *dest;
+ struct sn_hwperf_object_info *router;
+ struct sn_hwperf_port_info ptdata[16];
+ int sz, i, j;
+ cnodeid_t c;
+ int found_mem = 0;
+ int found_cpu = 0;
+
+ if (!node_possible(node))
+ return -EINVAL;
+
+ if (sn_hwperf_has_cpus(node)) {
+ if (near_cpu_node)
+ *near_cpu_node = node;
+ found_cpu++;
+ }
+
+ if (sn_hwperf_has_mem(node)) {
+ if (near_mem_node)
+ *near_mem_node = node;
+ found_mem++;
+ }
+
+ if (found_cpu && found_mem)
+ return 0; /* trivially successful */
+
+ /* find the argument node object */
+ for (i=0, op=objbuf; i < nobj; i++, op++) {
+ if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op))
+ continue;
+ if (node == sn_hwperf_obj_to_cnode(op)) {
+ nodeobj = op;
+ break;
}
}
- free_page((unsigned long)pg);
+ if (!nodeobj) {
+ e = -ENOENT;
+ goto err;
+ }
+
+ /* get it's interconnect topology */
+ sz = op->ports * sizeof(struct sn_hwperf_port_info);
+ if (sz > sizeof(ptdata))
+ BUG();
+ e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+ SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,
+ (u64)&ptdata, 0, 0, NULL);
+ if (e != SN_HWPERF_OP_OK) {
+ e = -EINVAL;
+ goto err;
+ }
+
+ /* find nearest node with cpus and nearest memory */
+ for (router=NULL, j=0; j < op->ports; j++) {
+ dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id);
+ if (!dest || SN_HWPERF_FOREIGN(dest) ||
+ !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) {
+ continue;
+ }
+ c = sn_hwperf_obj_to_cnode(dest);
+ if (!found_cpu && sn_hwperf_has_cpus(c)) {
+ if (near_cpu_node)
+ *near_cpu_node = c;
+ found_cpu++;
+ }
+ if (!found_mem && sn_hwperf_has_mem(c)) {
+ if (near_mem_node)
+ *near_mem_node = c;
+ found_mem++;
+ }
+ if (SN_HWPERF_IS_ROUTER(dest))
+ router = dest;
+ }
+
+ if (router && (!found_cpu || !found_mem)) {
+ /* search for a node connected to the same router */
+ sz = router->ports * sizeof(struct sn_hwperf_port_info);
+ if (sz > sizeof(ptdata))
+ BUG();
+ e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+ SN_HWPERF_ENUM_PORTS, router->id, sz,
+ (u64)&ptdata, 0, 0, NULL);
+ if (e != SN_HWPERF_OP_OK) {
+ e = -EINVAL;
+ goto err;
+ }
+ for (j=0; j < router->ports; j++) {
+ dest = sn_hwperf_findobj_id(objbuf, nobj,
+ ptdata[j].conn_id);
+ if (!dest || dest->id == node ||
+ SN_HWPERF_FOREIGN(dest) ||
+ !SN_HWPERF_IS_NODE(dest) ||
+ SN_HWPERF_IS_IONODE(dest)) {
+ continue;
+ }
+ c = sn_hwperf_obj_to_cnode(dest);
+ if (!found_cpu && sn_hwperf_has_cpus(c)) {
+ if (near_cpu_node)
+ *near_cpu_node = c;
+ found_cpu++;
+ }
+ if (!found_mem && sn_hwperf_has_mem(c)) {
+ if (near_mem_node)
+ *near_mem_node = c;
+ found_mem++;
+ }
+ if (found_cpu && found_mem)
+ break;
+ }
+ }
+
+ if (!found_cpu || !found_mem) {
+ /* resort to _any_ node with CPUs and memory */
+ for (i=0, op=objbuf; i < nobj; i++, op++) {
+ if (SN_HWPERF_FOREIGN(op) ||
+ SN_HWPERF_IS_IONODE(op) ||
+ !SN_HWPERF_IS_NODE(op)) {
+ continue;
+ }
+ c = sn_hwperf_obj_to_cnode(op);
+ if (!found_cpu && sn_hwperf_has_cpus(c)) {
+ if (near_cpu_node)
+ *near_cpu_node = c;
+ found_cpu++;
+ }
+ if (!found_mem && sn_hwperf_has_mem(c)) {
+ if (near_mem_node)
+ *near_mem_node = c;
+ found_mem++;
+ }
+ if (found_cpu && found_mem)
+ break;
+ }
+ }
+
+ if (!found_cpu || !found_mem)
+ e = -ENODATA;
+
+err:
+ return e;
}
+
static int sn_topology_show(struct seq_file *s, void *d)
{
int sz;
@@ -215,7 +384,6 @@
struct sn_hwperf_object_info *p;
struct sn_hwperf_object_info *obj = d; /* this object */
struct sn_hwperf_object_info *objs = s->private; /* all objects */
- int rack, bay, slot, slab;
u8 shubtype;
u8 system_size;
u8 sharing_size;
@@ -225,7 +393,6 @@
u8 region_size;
u16 nasid_mask;
int nasid_msb;
- int pci_bus_ordinal = 0;
if (obj == objs) {
seq_printf(s, "# sn_topology version 2\n");
@@ -253,6 +420,8 @@
shubtype ? "shub2" : "shub1",
(u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
system_size, sharing_size, coher, region_size);
+
+ print_pci_topology(s);
}
if (SN_HWPERF_FOREIGN(obj)) {
@@ -272,11 +441,24 @@
if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
seq_putc(s, '\n');
else {
+ cnodeid_t near_mem = -1;
+ cnodeid_t near_cpu = -1;
+
seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));
- for (i=0; i < numionodes; i++) {
- seq_printf(s, i ? ":%d" : ", dist %d",
- node_distance(ordinal, i));
+
+ if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt,
+ ordinal, &near_mem, &near_cpu) == 0) {
+ seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d",
+ near_mem, near_cpu);
}
+
+ if (!SN_HWPERF_IS_IONODE(obj)) {
+ for_each_online_node(i) {
+ seq_printf(s, i ? ":%d" : ", dist %d",
+ node_distance(ordinal, i));
+ }
+ }
+
seq_putc(s, '\n');
/*
@@ -300,17 +482,6 @@
seq_putc(s, '\n');
}
}
-
- /*
- * PCI busses attached to this node, if any
- */
- if (sn_hwperf_location_to_bpos(obj->location,
- &rack, &bay, &slot, &slab)) {
- /* export pci bus info */
- print_pci_topology(s, obj, &pci_bus_ordinal,
- rack, bay, slot, slab);
-
- }
}
if (obj->ports) {
@@ -572,6 +743,8 @@
if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
memset(p, 0, a.sz);
for (i = 0; i < nobj; i++) {
+ if (!SN_HWPERF_IS_NODE(objs + i))
+ continue;
node = sn_hwperf_obj_to_cnode(objs + i);
for_each_online_cpu(j) {
if (node != cpu_to_node(j))
@@ -598,7 +771,7 @@
case SN_HWPERF_GET_NODE_NASID:
if (a.sz != sizeof(u64) ||
- (node = a.arg) < 0 || node >= numionodes) {
+ (node = a.arg) < 0 || !node_possible(node)) {
r = -EINVAL;
goto error;
}
@@ -627,6 +800,14 @@
vfree(objs);
goto error;
}
+
+ if (!SN_HWPERF_IS_NODE(objs + i) &&
+ !SN_HWPERF_IS_IONODE(objs + i)) {
+ r = -ENOENT;
+ vfree(objs);
+ goto error;
+ }
+
*(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);
vfree(objs);
}
@@ -692,6 +873,7 @@
/* single threaded, once-only initialization */
down(&sn_hwperf_init_mutex);
+
if (sn_hwperf_salheap) {
up(&sn_hwperf_init_mutex);
return e;
@@ -742,19 +924,6 @@
sn_hwperf_salheap = NULL;
sn_hwperf_obj_cnt = 0;
}
-
- if (!e) {
- /*
- * Register a dynamic misc device for ioctl. Platforms
- * supporting hotplug will create /dev/sn_hwperf, else
- * user can to look up the minor number in /proc/misc.
- */
- if ((e = misc_register(&sn_hwperf_dev)) != 0) {
- printk(KERN_ERR "sn_hwperf_init: misc register "
- "for \"sn_hwperf\" failed, err %d\n", e);
- }
- }
-
up(&sn_hwperf_init_mutex);
return e;
}
@@ -782,3 +951,41 @@
vfree(seq->private);
return seq_release(inode, file);
}
+
+int sn_hwperf_get_nearest_node(cnodeid_t node,
+ cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
+{
+ int e;
+ int nobj;
+ struct sn_hwperf_object_info *objbuf;
+
+ if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {
+ e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj,
+ node, near_mem_node, near_cpu_node);
+ vfree(objbuf);
+ }
+
+ return e;
+}
+
+static int __devinit sn_hwperf_misc_register_init(void)
+{
+ int e;
+
+ sn_hwperf_init();
+
+ /*
+ * Register a dynamic misc device for hwperf ioctls. Platforms
+ * supporting hotplug will create /dev/sn_hwperf, else user
+ * can to look up the minor number in /proc/misc.
+ */
+ if ((e = misc_register(&sn_hwperf_dev)) != 0) {
+ printk(KERN_ERR "sn_hwperf_misc_register_init: failed to "
+ "register misc device for \"%s\"\n", sn_hwperf_dev.name);
+ }
+
+ return e;
+}
+
+device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */
+EXPORT_SYMBOL(sn_hwperf_get_nearest_node);
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
index 6a80fca..51bf827 100644
--- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
+++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/config.h>
#include <asm/uaccess.h>
@@ -15,7 +15,7 @@
static int partition_id_show(struct seq_file *s, void *p)
{
- seq_printf(s, "%d\n", sn_local_partid());
+ seq_printf(s, "%d\n", sn_partition_id);
return 0;
}
diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
index cde7375..adf5db2 100644
--- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c
+++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
@@ -1,7 +1,7 @@
/*
*
*
- * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -50,14 +50,16 @@
LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT);
}
- if (enable_shub_wars_1_1()) {
- /* Bugfix code for SHUB 1.1 */
- if (pda->pio_shub_war_cam_addr)
- *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
+ if (is_shub1()) {
+ if (enable_shub_wars_1_1()) {
+ /* Bugfix code for SHUB 1.1 */
+ if (pda->pio_shub_war_cam_addr)
+ *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
+ }
+ if (pda->sn_lb_int_war_ticks == 0)
+ sn_lb_int_war_check();
+ pda->sn_lb_int_war_ticks++;
+ if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
+ pda->sn_lb_int_war_ticks = 0;
}
- if (pda->sn_lb_int_war_ticks == 0)
- sn_lb_int_war_check();
- pda->sn_lb_int_war_ticks++;
- if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
- pda->sn_lb_int_war_ticks = 0;
}
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 254fe15..b45db51 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -191,7 +191,7 @@
{
struct cx_dev *cx_dev;
- cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL);
+ cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL);
DBG("cx_dev= 0x%p\n", cx_dev);
if (cx_dev == NULL)
return -ENOMEM;
diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile
index 2f915bc..321576b 100644
--- a/arch/ia64/sn/pci/Makefile
+++ b/arch/ia64/sn/pci/Makefile
@@ -7,4 +7,4 @@
#
# Makefile for the sn pci general routines.
-obj-y := pci_dma.o tioca_provider.o pcibr/
+obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index b058dc2..3409347 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/types.h>
@@ -215,8 +215,8 @@
int is_tio;
int wid_num;
int i, j;
- int bwin;
uint64_t flags;
+ uint64_t itte;
struct hubdev_info *hubinfo;
volatile struct sn_flush_device_list *p;
struct sn_flush_nasid_entry *flush_nasid_list;
@@ -233,31 +233,36 @@
if (!hubinfo) {
BUG();
}
- is_tio = (nasid & 1);
- if (is_tio) {
- wid_num = TIO_SWIN_WIDGETNUM(addr);
- bwin = TIO_BWIN_WINDOWNUM(addr);
- } else {
- wid_num = SWIN_WIDGETNUM(addr);
- bwin = BWIN_WINDOWNUM(addr);
- }
flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
if (flush_nasid_list->widget_p == NULL)
return;
- if (bwin > 0) {
- uint64_t itte = flush_nasid_list->iio_itte[bwin];
- if (is_tio) {
- wid_num = (itte >> TIO_ITTE_WIDGET_SHIFT) &
- TIO_ITTE_WIDGET_MASK;
- } else {
- wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) &
- IIO_ITTE_WIDGET_MASK;
- }
+ is_tio = (nasid & 1);
+ if (is_tio) {
+ int itte_index;
+
+ if (TIO_HWIN(addr))
+ itte_index = 0;
+ else if (TIO_BWIN_WINDOWNUM(addr))
+ itte_index = TIO_BWIN_WINDOWNUM(addr);
+ else
+ itte_index = -1;
+
+ if (itte_index >= 0) {
+ itte = flush_nasid_list->iio_itte[itte_index];
+ if (! TIO_ITTE_VALID(itte))
+ return;
+ wid_num = TIO_ITTE_WIDGET(itte);
+ } else
+ wid_num = TIO_SWIN_WIDGETNUM(addr);
+ } else {
+ if (BWIN_WINDOWNUM(addr)) {
+ itte = flush_nasid_list->iio_itte[BWIN_WINDOWNUM(addr)];
+ wid_num = IIO_ITTE_WIDGET(itte);
+ } else
+ wid_num = SWIN_WIDGETNUM(addr);
}
- if (flush_nasid_list->widget_p == NULL)
- return;
if (flush_nasid_list->widget_p[wid_num] == NULL)
return;
p = &flush_nasid_list->widget_p[wid_num][0];
@@ -283,10 +288,16 @@
/*
* For TIOCP use the Device(x) Write Request Buffer Flush Bridge
* register since it ensures the data has entered the coherence
- * domain, unlike PIC
+ * domain, unlike PIC.
*/
if (is_tio) {
- uint32_t tio_id = REMOTE_HUB_L(nasid, TIO_NODE_ID);
+ /*
+ * Note: devices behind TIOCE should never be matched in the
+ * above code, and so the following code is PIC/CP centric.
+ * If CE ever needs the sn_dma_flush mechanism, we will have
+ * to account for that here and in tioce_bus_fixup().
+ */
+ uint32_t tio_id = HUB_L(TIO_IOSPACE_ADDR(nasid, TIO_NODE_ID));
uint32_t revnum = XWIDGET_PART_REV_NUM(tio_id);
/* TIOCP BRINGUP WAR (PV907516): Don't write buffer flush reg */
@@ -306,7 +317,8 @@
*(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
/* wait for the interrupt to come back. */
- while (*(p->sfdl_flush_addr) != 0x10f) ;
+ while (*(p->sfdl_flush_addr) != 0x10f)
+ cpu_relax();
/* okay, everything is synched up. */
spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index b95e9286..7b03b80 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -15,6 +15,7 @@
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
#include <asm/sn/sn_sal.h>
+#include <asm/sn/sn2/sn_hwperf.h>
#include "xtalk/xwidgetdev.h"
#include "xtalk/hubdev.h"
@@ -60,7 +61,7 @@
ret_stuff.status = 0;
ret_stuff.v0 = 0;
- segment = 0;
+ segment = soft->pbi_buscommon.bs_persist_segment;
busnum = soft->pbi_buscommon.bs_persist_busnum;
SAL_CALL_NOLOCK(ret_stuff,
(u64) SN_SAL_IOIF_ERROR_INTERRUPT,
@@ -88,6 +89,7 @@
pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
{
int nasid, cnode, j;
+ cnodeid_t near_cnode;
struct hubdev_info *hubdev_info;
struct pcibus_info *soft;
struct sn_flush_device_list *sn_flush_device_list;
@@ -115,7 +117,7 @@
/*
* register the bridge's error interrupt handler
*/
- if (request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler,
+ if (request_irq(SGI_PCIASIC_ERROR, (void *)pcibr_error_intr_handler,
SA_SHIRQ, "PCIBR error", (void *)(soft))) {
printk(KERN_WARNING
"pcibr cannot allocate interrupt for error handler\n");
@@ -142,9 +144,12 @@
j++, sn_flush_device_list++) {
if (sn_flush_device_list->sfdl_slot == -1)
continue;
- if (sn_flush_device_list->
- sfdl_persistent_busnum ==
- soft->pbi_buscommon.bs_persist_busnum)
+ if ((sn_flush_device_list->
+ sfdl_persistent_segment ==
+ soft->pbi_buscommon.bs_persist_segment) &&
+ (sn_flush_device_list->
+ sfdl_persistent_busnum ==
+ soft->pbi_buscommon.bs_persist_busnum))
sn_flush_device_list->sfdl_pcibus_info =
soft;
}
@@ -158,12 +163,18 @@
memset(soft->pbi_int_ate_resource.ate, 0,
(soft->pbi_int_ate_size * sizeof(uint64_t)));
- if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP)
- /*
- * TIO PCI Bridge with no closest node information.
- * FIXME: Find another way to determine the closest node
- */
- controller->node = -1;
+ if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP) {
+ /* TIO PCI Bridge: find nearest node with CPUs */
+ int e = sn_hwperf_get_nearest_node(cnode, NULL, &near_cnode);
+
+ if (e < 0) {
+ near_cnode = (cnodeid_t)-1; /* use any node */
+ printk(KERN_WARNING "pcibr_bus_fixup: failed to find "
+ "near node with CPUs to TIO node %d, err=%d\n",
+ cnode, e);
+ }
+ controller->node = near_cnode;
+ }
else
controller->node = cnode;
return soft;
@@ -175,6 +186,9 @@
struct pcibus_info *pcibus_info;
int bit = sn_irq_info->irq_int_bit;
+ if (! sn_irq_info->irq_bridge)
+ return;
+
pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
if (pcidev_info) {
pcibus_info =
@@ -184,7 +198,7 @@
}
}
-void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info)
+void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info)
{
struct pcidev_info *pcidev_info;
struct pcibus_info *pcibus_info;
@@ -219,6 +233,8 @@
.dma_map_consistent = pcibr_dma_map_consistent,
.dma_unmap = pcibr_dma_unmap,
.bus_fixup = pcibr_bus_fixup,
+ .force_interrupt = pcibr_force_interrupt,
+ .target_interrupt = pcibr_target_interrupt
};
int
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index 5d76a75..19bced3 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -148,7 +148,7 @@
tioca_kern->ca_pcigart_entries =
tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize;
tioca_kern->ca_pcigart_pagemap =
- kcalloc(1, tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL);
+ kzalloc(tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL);
if (!tioca_kern->ca_pcigart_pagemap) {
free_pages((unsigned long)tioca_kern->ca_gart,
get_order(tioca_kern->ca_gart_size));
@@ -392,7 +392,7 @@
* allocate a map struct
*/
- ca_dmamap = kcalloc(1, sizeof(struct tioca_dmamap), GFP_ATOMIC);
+ ca_dmamap = kzalloc(sizeof(struct tioca_dmamap), GFP_ATOMIC);
if (!ca_dmamap)
goto map_return;
@@ -559,7 +559,7 @@
ret_stuff.status = 0;
ret_stuff.v0 = 0;
- segment = 0;
+ segment = soft->ca_common.bs_persist_segment;
busnum = soft->ca_common.bs_persist_busnum;
SAL_CALL_NOLOCK(ret_stuff,
@@ -600,7 +600,7 @@
* Allocate kernel bus soft and copy from prom.
*/
- tioca_common = kcalloc(1, sizeof(struct tioca_common), GFP_KERNEL);
+ tioca_common = kzalloc(sizeof(struct tioca_common), GFP_KERNEL);
if (!tioca_common)
return NULL;
@@ -609,7 +609,7 @@
/* init kernel-private area */
- tioca_kern = kcalloc(1, sizeof(struct tioca_kernel), GFP_KERNEL);
+ tioca_kern = kzalloc(sizeof(struct tioca_kernel), GFP_KERNEL);
if (!tioca_kern) {
kfree(tioca_common);
return NULL;
@@ -622,7 +622,8 @@
nasid_to_cnodeid(tioca_common->ca_closest_nasid);
tioca_common->ca_kernel_private = (uint64_t) tioca_kern;
- bus = pci_find_bus(0, tioca_common->ca_common.bs_persist_busnum);
+ bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment,
+ tioca_common->ca_common.bs_persist_busnum);
BUG_ON(!bus);
tioca_kern->ca_devices = &bus->devices;
@@ -656,6 +657,8 @@
.dma_map_consistent = tioca_dma_map,
.dma_unmap = tioca_dma_unmap,
.bus_fixup = tioca_bus_fixup,
+ .force_interrupt = NULL,
+ .target_interrupt = NULL
};
/**
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
new file mode 100644
index 0000000..8e75db2
--- /dev/null
+++ b/arch/ia64/sn/pci/tioce_provider.c
@@ -0,0 +1,771 @@
+/*
+ * 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) 2003-2005 Silicon Graphics, Inc. All Rights Reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioce_provider.h>
+
+/**
+ * Bus address ranges for the 5 flavors of TIOCE DMA
+ */
+
+#define TIOCE_D64_MIN 0x8000000000000000UL
+#define TIOCE_D64_MAX 0xffffffffffffffffUL
+#define TIOCE_D64_ADDR(a) ((a) >= TIOCE_D64_MIN)
+
+#define TIOCE_D32_MIN 0x0000000080000000UL
+#define TIOCE_D32_MAX 0x00000000ffffffffUL
+#define TIOCE_D32_ADDR(a) ((a) >= TIOCE_D32_MIN && (a) <= TIOCE_D32_MAX)
+
+#define TIOCE_M32_MIN 0x0000000000000000UL
+#define TIOCE_M32_MAX 0x000000007fffffffUL
+#define TIOCE_M32_ADDR(a) ((a) >= TIOCE_M32_MIN && (a) <= TIOCE_M32_MAX)
+
+#define TIOCE_M40_MIN 0x0000004000000000UL
+#define TIOCE_M40_MAX 0x0000007fffffffffUL
+#define TIOCE_M40_ADDR(a) ((a) >= TIOCE_M40_MIN && (a) <= TIOCE_M40_MAX)
+
+#define TIOCE_M40S_MIN 0x0000008000000000UL
+#define TIOCE_M40S_MAX 0x000000ffffffffffUL
+#define TIOCE_M40S_ADDR(a) ((a) >= TIOCE_M40S_MIN && (a) <= TIOCE_M40S_MAX)
+
+/*
+ * ATE manipulation macros.
+ */
+
+#define ATE_PAGESHIFT(ps) (__ffs(ps))
+#define ATE_PAGEMASK(ps) ((ps)-1)
+
+#define ATE_PAGE(x, ps) ((x) >> ATE_PAGESHIFT(ps))
+#define ATE_NPAGES(start, len, pagesize) \
+ (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
+
+#define ATE_VALID(ate) ((ate) & (1UL << 63))
+#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63))
+
+/*
+ * Flavors of ate-based mapping supported by tioce_alloc_map()
+ */
+
+#define TIOCE_ATE_M32 1
+#define TIOCE_ATE_M40 2
+#define TIOCE_ATE_M40S 3
+
+#define KB(x) ((x) << 10)
+#define MB(x) ((x) << 20)
+#define GB(x) ((x) << 30)
+
+/**
+ * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode
+ * @ct_addr: system coretalk address
+ *
+ * Map @ct_addr into 64-bit CE bus space. No device context is necessary
+ * and no CE mapping are consumed.
+ *
+ * Bits 53:0 come from the coretalk address. The remaining bits are set as
+ * follows:
+ *
+ * 63 - must be 1 to indicate d64 mode to CE hardware
+ * 62 - barrier bit ... controlled with tioce_dma_barrier()
+ * 61 - 0 since this is not an MSI transaction
+ * 60:54 - reserved, MBZ
+ */
+static uint64_t
+tioce_dma_d64(unsigned long ct_addr)
+{
+ uint64_t bus_addr;
+
+ bus_addr = ct_addr | (1UL << 63);
+
+ return bus_addr;
+}
+
+/**
+ * pcidev_to_tioce - return misc ce related pointers given a pci_dev
+ * @pci_dev: pci device context
+ * @base: ptr to store struct tioce_mmr * for the CE holding this device
+ * @kernel: ptr to store struct tioce_kernel * for the CE holding this device
+ * @port: ptr to store the CE port number that this device is on
+ *
+ * Return pointers to various CE-related structures for the CE upstream of
+ * @pci_dev.
+ */
+static inline void
+pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
+ struct tioce_kernel **kernel, int *port)
+{
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce_kernel *ce_kernel;
+
+ pcidev_info = SN_PCIDEV_INFO(pdev);
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+ ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private;
+
+ if (base)
+ *base = (struct tioce *)ce_common->ce_pcibus.bs_base;
+ if (kernel)
+ *kernel = ce_kernel;
+
+ /*
+ * we use port as a zero-based value internally, even though the
+ * documentation is 1-based.
+ */
+ if (port)
+ *port =
+ (pdev->bus->number < ce_kernel->ce_port1_secondary) ? 0 : 1;
+}
+
+/**
+ * tioce_alloc_map - Given a coretalk address, map it to pcie bus address
+ * space using one of the various ATE-based address modes.
+ * @ce_kern: tioce context
+ * @type: map mode to use
+ * @port: 0-based port that the requesting device is downstream of
+ * @ct_addr: the coretalk address to map
+ * @len: number of bytes to map
+ *
+ * Given the addressing type, set up various paramaters that define the
+ * ATE pool to use. Search for a contiguous block of entries to cover the
+ * length, and if enough resources exist, fill in the ATE's and construct a
+ * tioce_dmamap struct to track the mapping.
+ */
+static uint64_t
+tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
+ uint64_t ct_addr, int len)
+{
+ int i;
+ int j;
+ int first;
+ int last;
+ int entries;
+ int nates;
+ int pagesize;
+ uint64_t *ate_shadow;
+ uint64_t *ate_reg;
+ uint64_t addr;
+ struct tioce *ce_mmr;
+ uint64_t bus_base;
+ struct tioce_dmamap *map;
+
+ ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
+
+ switch (type) {
+ case TIOCE_ATE_M32:
+ /*
+ * The first 64 entries of the ate3240 pool are dedicated to
+ * super-page (TIOCE_ATE_M40S) mode.
+ */
+ first = 64;
+ entries = TIOCE_NUM_M3240_ATES - 64;
+ ate_shadow = ce_kern->ce_ate3240_shadow;
+ ate_reg = ce_mmr->ce_ure_ate3240;
+ pagesize = ce_kern->ce_ate3240_pagesize;
+ bus_base = TIOCE_M32_MIN;
+ break;
+ case TIOCE_ATE_M40:
+ first = 0;
+ entries = TIOCE_NUM_M40_ATES;
+ ate_shadow = ce_kern->ce_ate40_shadow;
+ ate_reg = ce_mmr->ce_ure_ate40;
+ pagesize = MB(64);
+ bus_base = TIOCE_M40_MIN;
+ break;
+ case TIOCE_ATE_M40S:
+ /*
+ * ate3240 entries 0-31 are dedicated to port1 super-page
+ * mappings. ate3240 entries 32-63 are dedicated to port2.
+ */
+ first = port * 32;
+ entries = 32;
+ ate_shadow = ce_kern->ce_ate3240_shadow;
+ ate_reg = ce_mmr->ce_ure_ate3240;
+ pagesize = GB(16);
+ bus_base = TIOCE_M40S_MIN;
+ break;
+ default:
+ return 0;
+ }
+
+ nates = ATE_NPAGES(ct_addr, len, pagesize);
+ if (nates > entries)
+ return 0;
+
+ last = first + entries - nates;
+ for (i = first; i <= last; i++) {
+ if (ATE_VALID(ate_shadow[i]))
+ continue;
+
+ for (j = i; j < i + nates; j++)
+ if (ATE_VALID(ate_shadow[j]))
+ break;
+
+ if (j >= i + nates)
+ break;
+ }
+
+ if (i > last)
+ return 0;
+
+ map = kcalloc(1, sizeof(struct tioce_dmamap), GFP_ATOMIC);
+ if (!map)
+ return 0;
+
+ addr = ct_addr;
+ for (j = 0; j < nates; j++) {
+ uint64_t ate;
+
+ ate = ATE_MAKE(addr, pagesize);
+ ate_shadow[i + j] = ate;
+ ate_reg[i + j] = ate;
+ addr += pagesize;
+ }
+
+ map->refcnt = 1;
+ map->nbytes = nates * pagesize;
+ map->ct_start = ct_addr & ~ATE_PAGEMASK(pagesize);
+ map->pci_start = bus_base + (i * pagesize);
+ map->ate_hw = &ate_reg[i];
+ map->ate_shadow = &ate_shadow[i];
+ map->ate_count = nates;
+
+ list_add(&map->ce_dmamap_list, &ce_kern->ce_dmamap_list);
+
+ return (map->pci_start + (ct_addr - map->ct_start));
+}
+
+/**
+ * tioce_dma_d32 - create a DMA mapping using 32-bit direct mode
+ * @pdev: linux pci_dev representing the function
+ * @paddr: system physical address
+ *
+ * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
+ */
+static uint64_t
+tioce_dma_d32(struct pci_dev *pdev, uint64_t ct_addr)
+{
+ int dma_ok;
+ int port;
+ struct tioce *ce_mmr;
+ struct tioce_kernel *ce_kern;
+ uint64_t ct_upper;
+ uint64_t ct_lower;
+ dma_addr_t bus_addr;
+
+ ct_upper = ct_addr & ~0x3fffffffUL;
+ ct_lower = ct_addr & 0x3fffffffUL;
+
+ pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
+
+ if (ce_kern->ce_port[port].dirmap_refcnt == 0) {
+ volatile uint64_t tmp;
+
+ ce_kern->ce_port[port].dirmap_shadow = ct_upper;
+ ce_mmr->ce_ure_dir_map[port] = ct_upper;
+ tmp = ce_mmr->ce_ure_dir_map[port];
+ dma_ok = 1;
+ } else
+ dma_ok = (ce_kern->ce_port[port].dirmap_shadow == ct_upper);
+
+ if (dma_ok) {
+ ce_kern->ce_port[port].dirmap_refcnt++;
+ bus_addr = TIOCE_D32_MIN + ct_lower;
+ } else
+ bus_addr = 0;
+
+ return bus_addr;
+}
+
+/**
+ * tioce_dma_barrier - swizzle a TIOCE bus address to include or exclude
+ * the barrier bit.
+ * @bus_addr: bus address to swizzle
+ *
+ * Given a TIOCE bus address, set the appropriate bit to indicate barrier
+ * attributes.
+ */
+static uint64_t
+tioce_dma_barrier(uint64_t bus_addr, int on)
+{
+ uint64_t barrier_bit;
+
+ /* barrier not supported in M40/M40S mode */
+ if (TIOCE_M40_ADDR(bus_addr) || TIOCE_M40S_ADDR(bus_addr))
+ return bus_addr;
+
+ if (TIOCE_D64_ADDR(bus_addr))
+ barrier_bit = (1UL << 62);
+ else /* must be m32 or d32 */
+ barrier_bit = (1UL << 30);
+
+ return (on) ? (bus_addr | barrier_bit) : (bus_addr & ~barrier_bit);
+}
+
+/**
+ * tioce_dma_unmap - release CE mapping resources
+ * @pdev: linux pci_dev representing the function
+ * @bus_addr: bus address returned by an earlier tioce_dma_map
+ * @dir: mapping direction (unused)
+ *
+ * Locate mapping resources associated with @bus_addr and release them.
+ * For mappings created using the direct modes there are no resources
+ * to release.
+ */
+void
+tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
+{
+ int i;
+ int port;
+ struct tioce_kernel *ce_kern;
+ struct tioce *ce_mmr;
+ unsigned long flags;
+
+ bus_addr = tioce_dma_barrier(bus_addr, 0);
+ pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
+
+ /* nothing to do for D64 */
+
+ if (TIOCE_D64_ADDR(bus_addr))
+ return;
+
+ spin_lock_irqsave(&ce_kern->ce_lock, flags);
+
+ if (TIOCE_D32_ADDR(bus_addr)) {
+ if (--ce_kern->ce_port[port].dirmap_refcnt == 0) {
+ ce_kern->ce_port[port].dirmap_shadow = 0;
+ ce_mmr->ce_ure_dir_map[port] = 0;
+ }
+ } else {
+ struct tioce_dmamap *map;
+
+ list_for_each_entry(map, &ce_kern->ce_dmamap_list,
+ ce_dmamap_list) {
+ uint64_t last;
+
+ last = map->pci_start + map->nbytes - 1;
+ if (bus_addr >= map->pci_start && bus_addr <= last)
+ break;
+ }
+
+ if (&map->ce_dmamap_list == &ce_kern->ce_dmamap_list) {
+ printk(KERN_WARNING
+ "%s: %s - no map found for bus_addr 0x%lx\n",
+ __FUNCTION__, pci_name(pdev), bus_addr);
+ } else if (--map->refcnt == 0) {
+ for (i = 0; i < map->ate_count; i++) {
+ map->ate_shadow[i] = 0;
+ map->ate_hw[i] = 0;
+ }
+
+ list_del(&map->ce_dmamap_list);
+ kfree(map);
+ }
+ }
+
+ spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+}
+
+/**
+ * tioce_do_dma_map - map pages for PCI DMA
+ * @pdev: linux pci_dev representing the function
+ * @paddr: host physical address to map
+ * @byte_count: bytes to map
+ *
+ * This is the main wrapper for mapping host physical pages to CE PCI space.
+ * The mapping mode used is based on the device's dma_mask.
+ */
+static uint64_t
+tioce_do_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count,
+ int barrier)
+{
+ unsigned long flags;
+ uint64_t ct_addr;
+ uint64_t mapaddr = 0;
+ struct tioce_kernel *ce_kern;
+ struct tioce_dmamap *map;
+ int port;
+ uint64_t dma_mask;
+
+ dma_mask = (barrier) ? pdev->dev.coherent_dma_mask : pdev->dma_mask;
+
+ /* cards must be able to address at least 31 bits */
+ if (dma_mask < 0x7fffffffUL)
+ return 0;
+
+ ct_addr = PHYS_TO_TIODMA(paddr);
+
+ /*
+ * If the device can generate 64 bit addresses, create a D64 map.
+ * Since this should never fail, bypass the rest of the checks.
+ */
+ if (dma_mask == ~0UL) {
+ mapaddr = tioce_dma_d64(ct_addr);
+ goto dma_map_done;
+ }
+
+ pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
+
+ spin_lock_irqsave(&ce_kern->ce_lock, flags);
+
+ /*
+ * D64 didn't work ... See if we have an existing map that covers
+ * this address range. Must account for devices dma_mask here since
+ * an existing map might have been done in a mode using more pci
+ * address bits than this device can support.
+ */
+ list_for_each_entry(map, &ce_kern->ce_dmamap_list, ce_dmamap_list) {
+ uint64_t last;
+
+ last = map->ct_start + map->nbytes - 1;
+ if (ct_addr >= map->ct_start &&
+ ct_addr + byte_count - 1 <= last &&
+ map->pci_start <= dma_mask) {
+ map->refcnt++;
+ mapaddr = map->pci_start + (ct_addr - map->ct_start);
+ break;
+ }
+ }
+
+ /*
+ * If we don't have a map yet, and the card can generate 40
+ * bit addresses, try the M40/M40S modes. Note these modes do not
+ * support a barrier bit, so if we need a consistent map these
+ * won't work.
+ */
+ if (!mapaddr && !barrier && dma_mask >= 0xffffffffffUL) {
+ /*
+ * We have two options for 40-bit mappings: 16GB "super" ATE's
+ * and 64MB "regular" ATE's. We'll try both if needed for a
+ * given mapping but which one we try first depends on the
+ * size. For requests >64MB, prefer to use a super page with
+ * regular as the fallback. Otherwise, try in the reverse order.
+ */
+
+ if (byte_count > MB(64)) {
+ mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+ port, ct_addr, byte_count);
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+ ct_addr, byte_count);
+ } else {
+ mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+ ct_addr, byte_count);
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+ port, ct_addr, byte_count);
+ }
+ }
+
+ /*
+ * 32-bit direct is the next mode to try
+ */
+ if (!mapaddr && dma_mask >= 0xffffffffUL)
+ mapaddr = tioce_dma_d32(pdev, ct_addr);
+
+ /*
+ * Last resort, try 32-bit ATE-based map.
+ */
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
+ byte_count);
+
+ spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+
+dma_map_done:
+ if (mapaddr & barrier)
+ mapaddr = tioce_dma_barrier(mapaddr, 1);
+
+ return mapaddr;
+}
+
+/**
+ * tioce_dma - standard pci dma map interface
+ * @pdev: pci device requesting the map
+ * @paddr: system physical address to map into pci space
+ * @byte_count: # bytes to map
+ *
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit clear
+ * in the address.
+ */
+static uint64_t
+tioce_dma(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+ return tioce_do_dma_map(pdev, paddr, byte_count, 0);
+}
+
+/**
+ * tioce_dma_consistent - consistent pci dma map interface
+ * @pdev: pci device requesting the map
+ * @paddr: system physical address to map into pci space
+ * @byte_count: # bytes to map
+ *
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit set
+ * in the address.
+ */ static uint64_t
+tioce_dma_consistent(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+ return tioce_do_dma_map(pdev, paddr, byte_count, 1);
+}
+
+/**
+ * tioce_error_intr_handler - SGI TIO CE error interrupt handler
+ * @irq: unused
+ * @arg: pointer to tioce_common struct for the given CE
+ * @pt: unused
+ *
+ * Handle a CE error interrupt. Simply a wrapper around a SAL call which
+ * defers processing to the SGI prom.
+ */ static irqreturn_t
+tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
+{
+ struct tioce_common *soft = arg;
+ struct ia64_sal_retval ret_stuff;
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+
+ SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
+ soft->ce_pcibus.bs_persist_segment,
+ soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * tioce_kern_init - init kernel structures related to a given TIOCE
+ * @tioce_common: ptr to a cached tioce_common struct that originated in prom
+ */ static struct tioce_kernel *
+tioce_kern_init(struct tioce_common *tioce_common)
+{
+ int i;
+ uint32_t tmp;
+ struct tioce *tioce_mmr;
+ struct tioce_kernel *tioce_kern;
+
+ tioce_kern = kcalloc(1, sizeof(struct tioce_kernel), GFP_KERNEL);
+ if (!tioce_kern) {
+ return NULL;
+ }
+
+ tioce_kern->ce_common = tioce_common;
+ spin_lock_init(&tioce_kern->ce_lock);
+ INIT_LIST_HEAD(&tioce_kern->ce_dmamap_list);
+ tioce_common->ce_kernel_private = (uint64_t) tioce_kern;
+
+ /*
+ * Determine the secondary bus number of the port2 logical PPB.
+ * This is used to decide whether a given pci device resides on
+ * port1 or port2. Note: We don't have enough plumbing set up
+ * here to use pci_read_config_xxx() so use the raw_pci_ops vector.
+ */
+
+ raw_pci_ops->read(tioce_common->ce_pcibus.bs_persist_segment,
+ tioce_common->ce_pcibus.bs_persist_busnum,
+ PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1, &tmp);
+ tioce_kern->ce_port1_secondary = (uint8_t) tmp;
+
+ /*
+ * Set PMU pagesize to the largest size available, and zero out
+ * the ate's.
+ */
+
+ tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
+ tioce_mmr->ce_ure_page_map &= ~CE_URE_PAGESIZE_MASK;
+ tioce_mmr->ce_ure_page_map |= CE_URE_256K_PAGESIZE;
+ tioce_kern->ce_ate3240_pagesize = KB(256);
+
+ for (i = 0; i < TIOCE_NUM_M40_ATES; i++) {
+ tioce_kern->ce_ate40_shadow[i] = 0;
+ tioce_mmr->ce_ure_ate40[i] = 0;
+ }
+
+ for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) {
+ tioce_kern->ce_ate3240_shadow[i] = 0;
+ tioce_mmr->ce_ure_ate3240[i] = 0;
+ }
+
+ return tioce_kern;
+}
+
+/**
+ * tioce_force_interrupt - implement altix force_interrupt() backend for CE
+ * @sn_irq_info: sn asic irq that we need an interrupt generated for
+ *
+ * Given an sn_irq_info struct, set the proper bit in ce_adm_force_int to
+ * force a secondary interrupt to be generated. This is to work around an
+ * asic issue where there is a small window of opportunity for a legacy device
+ * interrupt to be lost.
+ */
+static void
+tioce_force_interrupt(struct sn_irq_info *sn_irq_info)
+{
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce *ce_mmr;
+ uint64_t force_int_val;
+
+ if (!sn_irq_info->irq_bridge)
+ return;
+
+ if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_TIOCE)
+ return;
+
+ pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+ if (!pcidev_info)
+ return;
+
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+ ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+
+ /*
+ * irq_int_bit is originally set up by prom, and holds the interrupt
+ * bit shift (not mask) as defined by the bit definitions in the
+ * ce_adm_int mmr. These shifts are not the same for the
+ * ce_adm_force_int register, so do an explicit mapping here to make
+ * things clearer.
+ */
+
+ switch (sn_irq_info->irq_int_bit) {
+ case CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT;
+ break;
+ default:
+ return;
+ }
+ ce_mmr->ce_adm_force_int = force_int_val;
+}
+
+/**
+ * tioce_target_interrupt - implement set_irq_affinity for tioce resident
+ * functions. Note: only applies to line interrupts, not MSI's.
+ *
+ * @sn_irq_info: SN IRQ context
+ *
+ * Given an sn_irq_info, set the associated CE device's interrupt destination
+ * register. Since the interrupt destination registers are on a per-ce-slot
+ * basis, this will retarget line interrupts for all functions downstream of
+ * the slot.
+ */
+static void
+tioce_target_interrupt(struct sn_irq_info *sn_irq_info)
+{
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce *ce_mmr;
+ int bit;
+
+ pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+ if (!pcidev_info)
+ return;
+
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+ ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+
+ bit = sn_irq_info->irq_int_bit;
+
+ ce_mmr->ce_adm_int_mask |= (1UL << bit);
+ ce_mmr->ce_adm_int_dest[bit] =
+ ((uint64_t)sn_irq_info->irq_irq << INTR_VECTOR_SHFT) |
+ sn_irq_info->irq_xtalkaddr;
+ ce_mmr->ce_adm_int_mask &= ~(1UL << bit);
+
+ tioce_force_interrupt(sn_irq_info);
+}
+
+/**
+ * tioce_bus_fixup - perform final PCI fixup for a TIO CE bus
+ * @prom_bussoft: Common prom/kernel struct representing the bus
+ *
+ * Replicates the tioce_common pointed to by @prom_bussoft in kernel
+ * space. Allocates and initializes a kernel-only area for a given CE,
+ * and sets up an irq for handling CE error interrupts.
+ *
+ * On successful setup, returns the kernel version of tioce_common back to
+ * the caller.
+ */
+static void *
+tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
+{
+ struct tioce_common *tioce_common;
+
+ /*
+ * Allocate kernel bus soft and copy from prom.
+ */
+
+ tioce_common = kcalloc(1, sizeof(struct tioce_common), GFP_KERNEL);
+ if (!tioce_common)
+ return NULL;
+
+ memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common));
+ tioce_common->ce_pcibus.bs_base |= __IA64_UNCACHED_OFFSET;
+
+ if (tioce_kern_init(tioce_common) == NULL) {
+ kfree(tioce_common);
+ return NULL;
+ }
+
+ if (request_irq(SGI_PCIASIC_ERROR,
+ tioce_error_intr_handler,
+ SA_SHIRQ, "TIOCE error", (void *)tioce_common))
+ printk(KERN_WARNING
+ "%s: Unable to get irq %d. "
+ "Error interrupts won't be routed for "
+ "TIOCE bus %04x:%02x\n",
+ __FUNCTION__, SGI_PCIASIC_ERROR,
+ tioce_common->ce_pcibus.bs_persist_segment,
+ tioce_common->ce_pcibus.bs_persist_busnum);
+
+ return tioce_common;
+}
+
+static struct sn_pcibus_provider tioce_pci_interfaces = {
+ .dma_map = tioce_dma,
+ .dma_map_consistent = tioce_dma_consistent,
+ .dma_unmap = tioce_dma_unmap,
+ .bus_fixup = tioce_bus_fixup,
+ .force_interrupt = tioce_force_interrupt,
+ .target_interrupt = tioce_target_interrupt
+};
+
+/**
+ * tioce_init_provider - init SN PCI provider ops for TIO CE
+ */
+int
+tioce_init_provider(void)
+{
+ sn_pci_provider[PCIIO_ASIC_TYPE_TIOCE] = &tioce_pci_interfaces;
+ return 0;
+}
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c
index 8a2b77b..539c562 100644
--- a/arch/m32r/kernel/time.c
+++ b/arch/m32r/kernel/time.c
@@ -171,10 +171,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
@@ -221,7 +218,7 @@
* called as close as possible to 500 ms before the new second starts.
*/
write_seqlock(&xtime_lock);
- if ((time_status & STA_UNSYNC) == 0
+ if (ntp_synced()
&& xtime.tv_sec > last_rtc_update + 660
&& (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2
&& (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2)
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 178c4a3..ba960bb 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -25,6 +25,11 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ depends on Q40 || (BROKEN && SUN3X)
+ default y
+
mainmenu "Linux/68k Kernel Configuration"
source "init/Kconfig"
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
index c6b2a41..eb63ca6 100644
--- a/arch/m68k/bvme6000/rtc.c
+++ b/arch/m68k/bvme6000/rtc.c
@@ -14,6 +14,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
+#include <linux/module.h>
#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
#include <linux/smp_lock.h>
#include <asm/bvme6000hw.h>
@@ -171,7 +172,7 @@
.fops = &rtc_fops
};
-int __init rtc_DP8570A_init(void)
+static int __init rtc_DP8570A_init(void)
{
if (!MACH_IS_BVME6000)
return -ENODEV;
@@ -179,4 +180,4 @@
printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
return misc_register(&rtc_dev);
}
-
+module_init(rtc_DP8570A_init);
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index fe837e3..73e2f5e 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -74,10 +74,6 @@
EXPORT_SYMBOL(__ashldi3);
EXPORT_SYMBOL(__ashrdi3);
EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(__muldi3);
EXPORT_SYMBOL(__down_failed);
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index f4e1e5e..8ed1b01 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -95,7 +95,7 @@
if (regno == PT_USP)
addr = &task->thread.usp;
else if (regno < sizeof(regoff)/sizeof(regoff[0]))
- addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
+ addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
else
return -1;
*addr = data;
@@ -103,48 +103,56 @@
}
/*
- * Called by kernel/ptrace.c when detaching..
- *
* Make sure the single step bit is not set.
*/
+static inline void singlestep_disable(struct task_struct *child)
+{
+ unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+ put_reg(child, PT_SR, tmp);
+ child->thread.work.delayed_trace = 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
void ptrace_disable(struct task_struct *child)
{
- unsigned long tmp;
- /* make sure the single step bit is not set. */
- tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
- put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 0;
+ singlestep_disable(child);
child->thread.work.syscall_trace = 0;
}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
- int ret;
+ unsigned long tmp;
+ int i, ret = 0;
lock_kernel();
- ret = -EPERM;
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
- if (current->ptrace & PT_PTRACED)
+ if (current->ptrace & PT_PTRACED) {
+ ret = -EPERM;
goto out;
+ }
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
- ret = 0;
goto out;
}
- ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
- if (!child)
+ if (unlikely(!child)) {
+ ret = -ESRCH;
goto out;
+ }
- ret = -EPERM;
- if (pid == 1) /* you may not mess with init */
+ /* you may not mess with init */
+ if (unlikely(pid == 1)) {
+ ret = -EPERM;
goto out_tsk;
+ }
if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child);
@@ -152,227 +160,171 @@
}
ret = ptrace_check_attach(child, request == PTRACE_KILL);
- if (ret < 0)
+ if (ret)
goto out_tsk;
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long *) data);
- break;
- }
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA:
+ i = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ if (i != sizeof(tmp))
+ goto out_eio;
+ ret = put_user(tmp, (unsigned long *)data);
+ break;
/* read the word at location addr in the USER area. */
- case PTRACE_PEEKUSR: {
- unsigned long tmp;
+ case PTRACE_PEEKUSR:
+ if (addr & 3)
+ goto out_eio;
+ addr >>= 2; /* temporary hack. */
- ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
- break;
-
- tmp = 0; /* Default return condition */
- addr = addr >> 2; /* temporary hack. */
- ret = -EIO;
- if (addr < 19) {
- tmp = get_reg(child, addr);
- if (addr == PT_SR)
- tmp >>= 16;
- } else if (addr >= 21 && addr < 49) {
- tmp = child->thread.fp[addr - 21];
-#ifdef CONFIG_M68KFPU_EMU
- /* Convert internal fpu reg representation
- * into long double format
- */
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
- tmp = ((tmp & 0xffff0000) << 15) |
- ((tmp & 0x0000ffff) << 16);
-#endif
- } else
- break;
- ret = put_user(tmp,(unsigned long *) data);
- break;
- }
-
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
- break;
-
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
- break;
-
- addr = addr >> 2; /* temporary hack. */
-
- if (addr == PT_SR) {
- data &= SR_MASK;
- data <<= 16;
- data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
- }
- if (addr < 19) {
- if (put_reg(child, addr, data))
- break;
- ret = 0;
- break;
- }
- if (addr >= 21 && addr < 48)
- {
-#ifdef CONFIG_M68KFPU_EMU
- /* Convert long double format
- * into internal fpu reg representation
- */
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
- data = (unsigned long)data << 15;
- data = (data & 0xffff0000) |
- ((data & 0x0000ffff) >> 1);
- }
-#endif
- child->thread.fp[addr - 21] = data;
- ret = 0;
- }
- break;
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- long tmp;
-
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL) {
- child->thread.work.syscall_trace = ~0;
- } else {
- child->thread.work.syscall_trace = 0;
- }
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
- put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 0;
- wake_up_process(child);
- ret = 0;
- break;
- }
-
-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- long tmp;
-
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
- put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 0;
- wake_up_process(child);
- break;
- }
-
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- long tmp;
-
- ret = -EIO;
- if (!valid_signal(data))
- break;
- child->thread.work.syscall_trace = 0;
- tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
- put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 1;
-
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
- break;
- }
-
- case PTRACE_DETACH: /* detach a process that was attached. */
- ret = ptrace_detach(child, data);
- break;
-
- case PTRACE_GETREGS: { /* Get all gp regs from the child. */
- int i;
- unsigned long tmp;
- for (i = 0; i < 19; i++) {
- tmp = get_reg(child, i);
- if (i == PT_SR)
+ if (addr >= 0 && addr < 19) {
+ tmp = get_reg(child, addr);
+ if (addr == PT_SR)
tmp >>= 16;
- if (put_user(tmp, (unsigned long *) data)) {
- ret = -EFAULT;
- break;
- }
- data += sizeof(long);
- }
- ret = 0;
+ } else if (addr >= 21 && addr < 49) {
+ tmp = child->thread.fp[addr - 21];
+ /* Convert internal fpu reg representation
+ * into long double format
+ */
+ if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
+ tmp = ((tmp & 0xffff0000) << 15) |
+ ((tmp & 0x0000ffff) << 16);
+ } else
break;
- }
+ ret = put_user(tmp, (unsigned long *)data);
+ break;
- case PTRACE_SETREGS: { /* Set all gp regs in the child. */
- int i;
- unsigned long tmp;
- for (i = 0; i < 19; i++) {
- if (get_user(tmp, (unsigned long *) data)) {
- ret = -EFAULT;
+ /* when I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data))
+ goto out_eio;
+ break;
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ if (addr & 3)
+ goto out_eio;
+ addr >>= 2; /* temporary hack. */
+
+ if (addr == PT_SR) {
+ data &= SR_MASK;
+ data <<= 16;
+ data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+ } else if (addr >= 0 && addr < 19) {
+ if (put_reg(child, addr, data))
+ goto out_eio;
+ } else if (addr >= 21 && addr < 48) {
+ /* Convert long double format
+ * into internal fpu reg representation
+ */
+ if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
+ data = (unsigned long)data << 15;
+ data = (data & 0xffff0000) |
+ ((data & 0x0000ffff) >> 1);
+ }
+ child->thread.fp[addr - 21] = data;
+ } else
+ goto out_eio;
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ if (!valid_signal(data))
+ goto out_eio;
+
+ if (request == PTRACE_SYSCALL)
+ child->thread.work.syscall_trace = ~0;
+ else
+ child->thread.work.syscall_trace = 0;
+ child->exit_code = data;
+ singlestep_disable(child);
+ wake_up_process(child);
+ break;
+
+ /*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL:
+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ singlestep_disable(child);
+ wake_up_process(child);
+ break;
+
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ if (!valid_signal(data))
+ goto out_eio;
+
+ child->thread.work.syscall_trace = 0;
+ tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
+ put_reg(child, PT_SR, tmp);
+ child->thread.work.delayed_trace = 1;
+
+ child->exit_code = data;
+ /* give it a chance to run. */
+ wake_up_process(child);
+ break;
+
+ case PTRACE_DETACH: /* detach a process that was attached. */
+ ret = ptrace_detach(child, data);
+ break;
+
+ case PTRACE_GETREGS: /* Get all gp regs from the child. */
+ for (i = 0; i < 19; i++) {
+ tmp = get_reg(child, i);
+ if (i == PT_SR)
+ tmp >>= 16;
+ ret = put_user(tmp, (unsigned long *)data);
+ if (ret)
break;
- }
- if (i == PT_SR) {
+ data += sizeof(long);
+ }
+ break;
+
+ case PTRACE_SETREGS: /* Set all gp regs in the child. */
+ for (i = 0; i < 19; i++) {
+ ret = get_user(tmp, (unsigned long *)data);
+ if (ret)
+ break;
+ if (i == PT_SR) {
tmp &= SR_MASK;
tmp <<= 16;
tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
- }
- put_reg(child, i, tmp);
- data += sizeof(long);
}
- ret = 0;
- break;
+ put_reg(child, i, tmp);
+ data += sizeof(long);
}
+ break;
- case PTRACE_GETFPREGS: { /* Get the child FPU state. */
- ret = 0;
- if (copy_to_user((void *)data, &child->thread.fp,
- sizeof(struct user_m68kfp_struct)))
- ret = -EFAULT;
- break;
- }
+ case PTRACE_GETFPREGS: /* Get the child FPU state. */
+ if (copy_to_user((void *)data, &child->thread.fp,
+ sizeof(struct user_m68kfp_struct)))
+ ret = -EFAULT;
+ break;
- case PTRACE_SETFPREGS: { /* Set the child FPU state. */
- ret = 0;
- if (copy_from_user(&child->thread.fp, (void *)data,
- sizeof(struct user_m68kfp_struct)))
- ret = -EFAULT;
- break;
- }
+ case PTRACE_SETFPREGS: /* Set the child FPU state. */
+ if (copy_from_user(&child->thread.fp, (void *)data,
+ sizeof(struct user_m68kfp_struct)))
+ ret = -EFAULT;
+ break;
- default:
- ret = ptrace_request(child, request, addr, data);
- break;
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
}
out_tsk:
put_task_struct(child);
out:
unlock_kernel();
return ret;
+out_eio:
+ ret = -EIO;
+ goto out_tsk;
}
asmlinkage void syscall_trace(void)
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index e47e195..4ec95e3 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -166,10 +166,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index 34b6dbc..ebe51a5 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -5,4 +5,4 @@
EXTRA_AFLAGS := -traditional
lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
- checksum.o memcmp.o memcpy.o memset.o semaphore.o
+ checksum.o string.o semaphore.o
diff --git a/arch/m68k/lib/memcmp.c b/arch/m68k/lib/memcmp.c
deleted file mode 100644
index f4796fe..0000000
--- a/arch/m68k/lib/memcmp.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <linux/types.h>
-
-int memcmp(const void * cs,const void * ct,size_t count)
-{
- const unsigned char *su1, *su2;
-
- for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
- if (*su1 != *su2)
- return((*su1 < *su2) ? -1 : +1);
- return(0);
-}
diff --git a/arch/m68k/lib/memcpy.c b/arch/m68k/lib/memcpy.c
deleted file mode 100644
index 73e1818..0000000
--- a/arch/m68k/lib/memcpy.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <linux/types.h>
-
-void * memcpy(void * to, const void * from, size_t n)
-{
- void *xto = to;
- size_t temp, temp1;
-
- if (!n)
- return xto;
- if ((long) to & 1)
- {
- char *cto = to;
- const char *cfrom = from;
- *cto++ = *cfrom++;
- to = cto;
- from = cfrom;
- n--;
- }
- if (n > 2 && (long) to & 2)
- {
- short *sto = to;
- const short *sfrom = from;
- *sto++ = *sfrom++;
- to = sto;
- from = sfrom;
- n -= 2;
- }
- temp = n >> 2;
- if (temp)
- {
- long *lto = to;
- const long *lfrom = from;
-
- __asm__ __volatile__("movel %2,%3\n\t"
- "andw #7,%3\n\t"
- "lsrl #3,%2\n\t"
- "negw %3\n\t"
- "jmp %%pc@(1f,%3:w:2)\n\t"
- "4:\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "movel %0@+,%1@+\n\t"
- "1:\t"
- "dbra %2,4b\n\t"
- "clrw %2\n\t"
- "subql #1,%2\n\t"
- "jpl 4b\n\t"
- : "=a" (lfrom), "=a" (lto), "=d" (temp),
- "=&d" (temp1)
- : "0" (lfrom), "1" (lto), "2" (temp)
- );
- to = lto;
- from = lfrom;
- }
- if (n & 2)
- {
- short *sto = to;
- const short *sfrom = from;
- *sto++ = *sfrom++;
- to = sto;
- from = sfrom;
- }
- if (n & 1)
- {
- char *cto = to;
- const char *cfrom = from;
- *cto = *cfrom;
- }
- return xto;
-}
diff --git a/arch/m68k/lib/memset.c b/arch/m68k/lib/memset.c
deleted file mode 100644
index d55fdb2..0000000
--- a/arch/m68k/lib/memset.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <linux/types.h>
-
-void * memset(void * s, int c, size_t count)
-{
- void *xs = s;
- size_t temp, temp1;
-
- if (!count)
- return xs;
- c &= 0xff;
- c |= c << 8;
- c |= c << 16;
- if ((long) s & 1)
- {
- char *cs = s;
- *cs++ = c;
- s = cs;
- count--;
- }
- if (count > 2 && (long) s & 2)
- {
- short *ss = s;
- *ss++ = c;
- s = ss;
- count -= 2;
- }
- temp = count >> 2;
- if (temp)
- {
- long *ls = s;
-
- __asm__ __volatile__("movel %1,%2\n\t"
- "andw #7,%2\n\t"
- "lsrl #3,%1\n\t"
- "negw %2\n\t"
- "jmp %%pc@(2f,%2:w:2)\n\t"
- "1:\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "movel %3,%0@+\n\t"
- "2:\t"
- "dbra %1,1b\n\t"
- "clrw %1\n\t"
- "subql #1,%1\n\t"
- "jpl 1b\n\t"
- : "=a" (ls), "=d" (temp), "=&d" (temp1)
- : "d" (c), "0" (ls), "1" (temp)
- );
- s = ls;
- }
- if (count & 2)
- {
- short *ss = s;
- *ss++ = c;
- s = ss;
- }
- if (count & 1)
- {
- char *cs = s;
- *cs = c;
- }
- return xs;
-}
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
new file mode 100644
index 0000000..b92b89e
--- /dev/null
+++ b/arch/m68k/lib/string.c
@@ -0,0 +1,237 @@
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+void *memset(void *s, int c, size_t count)
+{
+ void *xs = s;
+ size_t temp, temp1;
+
+ if (!count)
+ return xs;
+ c &= 0xff;
+ c |= c << 8;
+ c |= c << 16;
+ if ((long)s & 1) {
+ char *cs = s;
+ *cs++ = c;
+ s = cs;
+ count--;
+ }
+ if (count > 2 && (long)s & 2) {
+ short *ss = s;
+ *ss++ = c;
+ s = ss;
+ count -= 2;
+ }
+ temp = count >> 2;
+ if (temp) {
+ long *ls = s;
+
+ asm volatile (
+ " movel %1,%2\n"
+ " andw #7,%2\n"
+ " lsrl #3,%1\n"
+ " negw %2\n"
+ " jmp %%pc@(2f,%2:w:2)\n"
+ "1: movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ "2: dbra %1,1b\n"
+ " clrw %1\n"
+ " subql #1,%1\n"
+ " jpl 1b"
+ : "=a" (ls), "=d" (temp), "=&d" (temp1)
+ : "d" (c), "0" (ls), "1" (temp));
+ s = ls;
+ }
+ if (count & 2) {
+ short *ss = s;
+ *ss++ = c;
+ s = ss;
+ }
+ if (count & 1) {
+ char *cs = s;
+ *cs = c;
+ }
+ return xs;
+}
+EXPORT_SYMBOL(memset);
+
+void *memcpy(void *to, const void *from, size_t n)
+{
+ void *xto = to;
+ size_t temp, temp1;
+
+ if (!n)
+ return xto;
+ if ((long)to & 1) {
+ char *cto = to;
+ const char *cfrom = from;
+ *cto++ = *cfrom++;
+ to = cto;
+ from = cfrom;
+ n--;
+ }
+ if (n > 2 && (long)to & 2) {
+ short *sto = to;
+ const short *sfrom = from;
+ *sto++ = *sfrom++;
+ to = sto;
+ from = sfrom;
+ n -= 2;
+ }
+ temp = n >> 2;
+ if (temp) {
+ long *lto = to;
+ const long *lfrom = from;
+
+ asm volatile (
+ " movel %2,%3\n"
+ " andw #7,%3\n"
+ " lsrl #3,%2\n"
+ " negw %3\n"
+ " jmp %%pc@(1f,%3:w:2)\n"
+ "4: movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ "1: dbra %2,4b\n"
+ " clrw %2\n"
+ " subql #1,%2\n"
+ " jpl 4b"
+ : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
+ : "0" (lfrom), "1" (lto), "2" (temp));
+ to = lto;
+ from = lfrom;
+ }
+ if (n & 2) {
+ short *sto = to;
+ const short *sfrom = from;
+ *sto++ = *sfrom++;
+ to = sto;
+ from = sfrom;
+ }
+ if (n & 1) {
+ char *cto = to;
+ const char *cfrom = from;
+ *cto = *cfrom;
+ }
+ return xto;
+}
+EXPORT_SYMBOL(memcpy);
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ void *xdest = dest;
+ size_t temp;
+
+ if (!n)
+ return xdest;
+
+ if (dest < src) {
+ if ((long)dest & 1) {
+ char *cdest = dest;
+ const char *csrc = src;
+ *cdest++ = *csrc++;
+ dest = cdest;
+ src = csrc;
+ n--;
+ }
+ if (n > 2 && (long)dest & 2) {
+ short *sdest = dest;
+ const short *ssrc = src;
+ *sdest++ = *ssrc++;
+ dest = sdest;
+ src = ssrc;
+ n -= 2;
+ }
+ temp = n >> 2;
+ if (temp) {
+ long *ldest = dest;
+ const long *lsrc = src;
+ temp--;
+ do
+ *ldest++ = *lsrc++;
+ while (temp--);
+ dest = ldest;
+ src = lsrc;
+ }
+ if (n & 2) {
+ short *sdest = dest;
+ const short *ssrc = src;
+ *sdest++ = *ssrc++;
+ dest = sdest;
+ src = ssrc;
+ }
+ if (n & 1) {
+ char *cdest = dest;
+ const char *csrc = src;
+ *cdest = *csrc;
+ }
+ } else {
+ dest = (char *)dest + n;
+ src = (const char *)src + n;
+ if ((long)dest & 1) {
+ char *cdest = dest;
+ const char *csrc = src;
+ *--cdest = *--csrc;
+ dest = cdest;
+ src = csrc;
+ n--;
+ }
+ if (n > 2 && (long)dest & 2) {
+ short *sdest = dest;
+ const short *ssrc = src;
+ *--sdest = *--ssrc;
+ dest = sdest;
+ src = ssrc;
+ n -= 2;
+ }
+ temp = n >> 2;
+ if (temp) {
+ long *ldest = dest;
+ const long *lsrc = src;
+ temp--;
+ do
+ *--ldest = *--lsrc;
+ while (temp--);
+ dest = ldest;
+ src = lsrc;
+ }
+ if (n & 2) {
+ short *sdest = dest;
+ const short *ssrc = src;
+ *--sdest = *--ssrc;
+ dest = sdest;
+ src = ssrc;
+ }
+ if (n & 1) {
+ char *cdest = dest;
+ const char *csrc = src;
+ *--cdest = *--csrc;
+ }
+ }
+ return xdest;
+}
+EXPORT_SYMBOL(memmove);
+
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+ const unsigned char *su1, *su2;
+
+ for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--)
+ if (*su1 != *su2)
+ return *su1 < *su2 ? -1 : +1;
+ return 0;
+}
+EXPORT_SYMBOL(memcmp);
diff --git a/arch/m68k/mm/Makefile b/arch/m68k/mm/Makefile
index 90f1c73..5eaa43c 100644
--- a/arch/m68k/mm/Makefile
+++ b/arch/m68k/mm/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux m68k-specific parts of the memory manager.
#
-obj-y := init.o fault.o hwtest.o
+obj-y := cache.o init.o fault.o hwtest.o
obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o
obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c
new file mode 100644
index 0000000..5437fff
--- /dev/null
+++ b/arch/m68k/mm/cache.c
@@ -0,0 +1,118 @@
+/*
+ * linux/arch/m68k/mm/cache.c
+ *
+ * Instruction cache handling
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#include <linux/module.h>
+#include <asm/pgalloc.h>
+#include <asm/traps.h>
+
+
+static unsigned long virt_to_phys_slow(unsigned long vaddr)
+{
+ if (CPU_IS_060) {
+ unsigned long paddr;
+
+ /* The PLPAR instruction causes an access error if the translation
+ * is not possible. To catch this we use the same exception mechanism
+ * as for user space accesses in <asm/uaccess.h>. */
+ asm volatile (".chip 68060\n"
+ "1: plpar (%0)\n"
+ ".chip 68k\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ " .even\n"
+ "3: sub.l %0,%0\n"
+ " jra 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,3b\n"
+ ".previous"
+ : "=a" (paddr)
+ : "0" (vaddr));
+ return paddr;
+ } else if (CPU_IS_040) {
+ unsigned long mmusr;
+
+ asm volatile (".chip 68040\n\t"
+ "ptestr (%1)\n\t"
+ "movec %%mmusr, %0\n\t"
+ ".chip 68k"
+ : "=r" (mmusr)
+ : "a" (vaddr));
+
+ if (mmusr & MMU_R_040)
+ return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+ } else {
+ unsigned short mmusr;
+ unsigned long *descaddr;
+
+ asm volatile ("ptestr %3,%2@,#7,%0\n\t"
+ "pmove %%psr,%1@"
+ : "=a&" (descaddr)
+ : "a" (&mmusr), "a" (vaddr), "d" (get_fs().seg));
+ if (mmusr & (MMU_I|MMU_B|MMU_L))
+ return 0;
+ descaddr = phys_to_virt((unsigned long)descaddr);
+ switch (mmusr & MMU_NUM) {
+ case 1:
+ return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+ case 2:
+ return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+ case 3:
+ return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+ }
+ }
+ return 0;
+}
+
+/* Push n pages at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
+void flush_icache_range(unsigned long address, unsigned long endaddr)
+{
+
+ if (CPU_IS_040_OR_060) {
+ address &= PAGE_MASK;
+
+ do {
+ asm volatile ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (virt_to_phys_slow(address)));
+ address += PAGE_SIZE;
+ } while (address < endaddr);
+ } else {
+ unsigned long tmp;
+ asm volatile ("movec %%cacr,%0\n\t"
+ "orw %1,%0\n\t"
+ "movec %0,%%cacr"
+ : "=&d" (tmp)
+ : "di" (FLUSH_I));
+ }
+}
+EXPORT_SYMBOL(flush_icache_range);
+
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+ unsigned long addr, int len)
+{
+ if (CPU_IS_040_OR_060) {
+ asm volatile ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (page_to_phys(page)));
+ } else {
+ unsigned long tmp;
+ asm volatile ("movec %%cacr,%0\n\t"
+ "orw %1,%0\n\t"
+ "movec %0,%%cacr"
+ : "=&d" (tmp)
+ : "di" (FLUSH_I));
+ }
+}
+
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 1453a60..559942c 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -354,110 +354,6 @@
#endif
}
-static unsigned long virt_to_phys_slow(unsigned long vaddr)
-{
- if (CPU_IS_060) {
- mm_segment_t fs = get_fs();
- unsigned long paddr;
-
- set_fs(get_ds());
-
- /* The PLPAR instruction causes an access error if the translation
- * is not possible. To catch this we use the same exception mechanism
- * as for user space accesses in <asm/uaccess.h>. */
- asm volatile (".chip 68060\n"
- "1: plpar (%0)\n"
- ".chip 68k\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- " .even\n"
- "3: sub.l %0,%0\n"
- " jra 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,3b\n"
- ".previous"
- : "=a" (paddr)
- : "0" (vaddr));
- set_fs(fs);
- return paddr;
- } else if (CPU_IS_040) {
- mm_segment_t fs = get_fs();
- unsigned long mmusr;
-
- set_fs(get_ds());
-
- asm volatile (".chip 68040\n\t"
- "ptestr (%1)\n\t"
- "movec %%mmusr, %0\n\t"
- ".chip 68k"
- : "=r" (mmusr)
- : "a" (vaddr));
- set_fs(fs);
-
- if (mmusr & MMU_R_040)
- return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
- } else {
- unsigned short mmusr;
- unsigned long *descaddr;
-
- asm volatile ("ptestr #5,%2@,#7,%0\n\t"
- "pmove %%psr,%1@"
- : "=a&" (descaddr)
- : "a" (&mmusr), "a" (vaddr));
- if (mmusr & (MMU_I|MMU_B|MMU_L))
- return 0;
- descaddr = phys_to_virt((unsigned long)descaddr);
- switch (mmusr & MMU_NUM) {
- case 1:
- return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
- case 2:
- return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
- case 3:
- return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
- }
- }
- return 0;
-}
-
-/* Push n pages at kernel virtual address and clear the icache */
-/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-void flush_icache_range(unsigned long address, unsigned long endaddr)
-{
- if (CPU_IS_040_OR_060) {
- address &= PAGE_MASK;
-
- if (address >= PAGE_OFFSET && address < (unsigned long)high_memory) {
- do {
- asm volatile ("nop\n\t"
- ".chip 68040\n\t"
- "cpushp %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (virt_to_phys((void *)address)));
- address += PAGE_SIZE;
- } while (address < endaddr);
- } else {
- do {
- asm volatile ("nop\n\t"
- ".chip 68040\n\t"
- "cpushp %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (virt_to_phys_slow(address)));
- address += PAGE_SIZE;
- } while (address < endaddr);
- }
- } else {
- unsigned long tmp;
- asm volatile ("movec %%cacr,%0\n\t"
- "orw %1,%0\n\t"
- "movec %0,%%cacr"
- : "=&d" (tmp)
- : "di" (FLUSH_I));
- }
-}
-
-
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int mm_end_of_chunk (unsigned long addr, int len)
{
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 8a24250..7977eae 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -161,7 +161,7 @@
.fops = &rtc_fops
};
-int __init rtc_MK48T08_init(void)
+static int __init rtc_MK48T08_init(void)
{
if (!MACH_IS_MVME16x)
return -ENODEV;
@@ -169,4 +169,4 @@
printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
return misc_register(&rtc_dev);
}
-
+module_init(rtc_MK48T08_init);
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 117f183..8520df9 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -71,21 +71,31 @@
help
Motorola ColdFire 5206e processor support.
+config M523x
+ bool "MCF523x"
+ help
+ Freescale Coldfire 5230/1/2/4/5 processor support
+
config M5249
bool "MCF5249"
help
Motorola ColdFire 5249 processor support.
-config M527x
- bool "MCF527x"
+config M5271
+ bool "MCF5271"
help
- Freescale (Motorola) ColdFire 5270/5271/5274/5275 processor support.
+ Freescale (Motorola) ColdFire 5270/5271 processor support.
config M5272
bool "MCF5272"
help
Motorola ColdFire 5272 processor support.
+config M5275
+ bool "MCF5275"
+ help
+ Freescale (Motorola) ColdFire 5274/5275 processor support.
+
config M528x
bool "MCF528x"
help
@@ -103,9 +113,14 @@
endchoice
+config M527x
+ bool
+ depends on (M5271 || M5275)
+ default y
+
config COLDFIRE
bool
- depends on (M5206 || M5206e || M5249 || M527x || M5272 || M528x || M5307 || M5407)
+ depends on (M5206 || M5206e || M523x || M5249 || M527x || M5272 || M528x || M5307 || M5407)
default y
choice
@@ -183,6 +198,11 @@
help
Select a 60MHz CPU clock frequency.
+config CLOCK_62_5MHz
+ bool "62.5MHz"
+ help
+ Select a 62.5MHz CPU clock frequency.
+
config CLOCK_64MHz
bool "64MHz"
help
@@ -302,6 +322,12 @@
help
Support for the Motorola M5206eLITE board.
+config M5235EVB
+ bool "Freescale M5235EVB support"
+ depends on M523x
+ help
+ Support for the Freescale M5235EVB board.
+
config M5249C3
bool "Motorola M5249C3 board support"
depends on M5249
@@ -310,13 +336,13 @@
config M5271EVB
bool "Freescale (Motorola) M5271EVB board support"
- depends on M527x
+ depends on M5271
help
Support for the Freescale (Motorola) M5271EVB board.
config M5275EVB
bool "Freescale (Motorola) M5275EVB board support"
- depends on M527x
+ depends on M5275
help
Support for the Freescale (Motorola) M5275EVB board.
@@ -343,6 +369,12 @@
depends on M528x
help
Support for the senTec COBRA5282 board.
+
+config SOM5282EM
+ bool "EMAC.Inc SOM5282EM board support"
+ depends on M528x
+ help
+ Support for the EMAC.Inc SOM5282EM module.
config ARN5307
bool "Arnewsh 5307 board support"
@@ -410,6 +442,12 @@
help
Support for the SNEHA CPU16B board.
+config MOD5272
+ bool "Netburner MOD-5272 board support"
+ depends on M5272
+ help
+ Support for the Netburner MOD-5272 board.
+
config ROMFS_FROM_ROM
bool " ROMFS image not RAM resident"
depends on (NETtel || SNAPGEAR)
@@ -430,7 +468,7 @@
config MOTOROLA
bool
default y
- depends on (M5206eC3 || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
+ depends on (M5206eC3 || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
config HW_FEITH
bool
@@ -441,6 +479,11 @@
bool
default y
depends on (COBRA5272 || COBRA5282)
+
+config EMAC_INC
+ bool
+ default y
+ depends on (SOM5282EM)
config SNEHA
bool
@@ -455,6 +498,15 @@
a lot of RAM, and you need to able to allocate very large
contiguous chunks. If unsure, say N.
+config 4KSTACKS
+ bool "Use 4Kb for kernel stacks instead of 8Kb"
+ default y
+ help
+ If you say Y here the kernel will use a 4Kb stacksize for the
+ kernel stack attached to each process/thread. This facilitates
+ running more threads on a system and also reduces the pressure
+ on the VM subsystem for higher order allocations.
+
choice
prompt "RAM size"
default AUTO
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
index a254aa9..7ce5e55 100644
--- a/arch/m68knommu/Makefile
+++ b/arch/m68knommu/Makefile
@@ -14,6 +14,7 @@
platform-$(CONFIG_M68360) := 68360
platform-$(CONFIG_M5206) := 5206
platform-$(CONFIG_M5206e) := 5206e
+platform-$(CONFIG_M523x) := 523x
platform-$(CONFIG_M5249) := 5249
platform-$(CONFIG_M527x) := 527x
platform-$(CONFIG_M5272) := 5272
@@ -29,6 +30,7 @@
board-$(CONFIG_DRAGEN2) := de2
board-$(CONFIG_ARNEWSH) := ARNEWSH
board-$(CONFIG_MOTOROLA) := MOTOROLA
+board-$(CONFIG_M5235EVB) := M5235EVB
board-$(CONFIG_M5271EVB) := M5271EVB
board-$(CONFIG_M5275EVB) := M5275EVB
board-$(CONFIG_M5282EVB) := M5282EVB
@@ -39,6 +41,7 @@
board-$(CONFIG_CLEOPATRA) := CLEOPATRA
board-$(CONFIG_senTec) := senTec
board-$(CONFIG_SNEHA) := SNEHA
+board-$(CONFIG_MOD5272) := MOD5272
BOARD := $(board-y)
model-$(CONFIG_RAMKERNEL) := ram
@@ -53,6 +56,7 @@
#
cpuclass-$(CONFIG_M5206) := 5307
cpuclass-$(CONFIG_M5206e) := 5307
+cpuclass-$(CONFIG_M523x) := 5307
cpuclass-$(CONFIG_M5249) := 5307
cpuclass-$(CONFIG_M527x) := 5307
cpuclass-$(CONFIG_M5272) := 5307
@@ -76,6 +80,7 @@
#
cflags-$(CONFIG_M5206) := -m5200 -Wa,-S -Wa,-m5200
cflags-$(CONFIG_M5206e) := -m5200 -Wa,-S -Wa,-m5200
+cflags-$(CONFIG_M523x) := -m5307 -Wa,-S -Wa,-m5307
cflags-$(CONFIG_M5249) := -m5200 -Wa,-S -Wa,-m5200
cflags-$(CONFIG_M527x) := -m5307 -Wa,-S -Wa,-m5307
cflags-$(CONFIG_M5272) := -m5307 -Wa,-S -Wa,-m5307
@@ -109,7 +114,7 @@
prepare: include/asm-$(ARCH)/asm-offsets.h
archclean:
- $(call descend arch/$(ARCH)/boot, subdirclean)
+ $(Q)$(MAKE) $(clean)=arch/m68knommu/boot
include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \
include/asm include/linux/version.h \
diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig
index e4bd31b..87f2d65 100644
--- a/arch/m68knommu/defconfig
+++ b/arch/m68knommu/defconfig
@@ -1,24 +1,48 @@
#
# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-uc0
+# Wed Aug 31 15:03:26 2005
#
+CONFIG_M68KNOMMU=y
# CONFIG_MMU is not set
# CONFIG_FPU is not set
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
-# CONFIG_SYSVIPC is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -34,9 +58,11 @@
# CONFIG_M68360 is not set
# CONFIG_M5206 is not set
# CONFIG_M5206e is not set
+# CONFIG_M523x is not set
# CONFIG_M5249 is not set
-# CONFIG_M527x is not set
+# CONFIG_M5271 is not set
CONFIG_M5272=y
+# CONFIG_M5275 is not set
# CONFIG_M528x is not set
# CONFIG_M5307 is not set
# CONFIG_M5407 is not set
@@ -54,6 +80,8 @@
# CONFIG_CLOCK_50MHz is not set
# CONFIG_CLOCK_54MHz is not set
# CONFIG_CLOCK_60MHz is not set
+# CONFIG_CLOCK_62_5MHz is not set
+# CONFIG_CLOCK_64MHz is not set
CONFIG_CLOCK_66MHz=y
# CONFIG_CLOCK_70MHz is not set
# CONFIG_CLOCK_100MHz is not set
@@ -65,13 +93,19 @@
# Platform
#
CONFIG_M5272C3=y
+# CONFIG_COBRA5272 is not set
+# CONFIG_CANCam is not set
+# CONFIG_SCALES is not set
# CONFIG_NETtel is not set
+# CONFIG_CPU16B is not set
+# CONFIG_MOD5272 is not set
CONFIG_MOTOROLA=y
# CONFIG_LARGE_ALLOCS is not set
-# CONFIG_RAMAUTO is not set
+CONFIG_4KSTACKS=y
+CONFIG_RAMAUTO=y
# CONFIG_RAM4MB is not set
# CONFIG_RAM8MB is not set
-CONFIG_RAM16MB=y
+# CONFIG_RAM16MB is not set
# CONFIG_RAM32MB is not set
CONFIG_RAMAUTOBIT=y
# CONFIG_RAM8BIT is not set
@@ -79,20 +113,34 @@
# CONFIG_RAM32BIT is not set
CONFIG_RAMKERNEL=y
# CONFIG_ROMKERNEL is not set
-# CONFIG_HIMEMKERNEL 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
#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
#
# CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
#
# Executable file formats
#
-CONFIG_KCORE_AOUT=y
CONFIG_BINFMT_FLAT=y
# CONFIG_BINFMT_ZFLAT is not set
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
#
# Power management options
@@ -100,12 +148,82 @@
# CONFIG_PM is not set
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE 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
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
# Memory Technology Devices (MTD)
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
@@ -116,35 +234,50 @@
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
#
# RAM/ROM/Flash chip drivers
#
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
CONFIG_MTD_RAM=y
# 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_UCLINUX=y
+# CONFIG_MTD_SNAPGEARuC is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
#
# Disk-On-Chip Device Drivers
#
-# CONFIG_MTD_DOC1000 is not set
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
#
# NAND Flash Device Drivers
@@ -159,21 +292,32 @@
#
# Plug and Play support
#
-# CONFIG_PNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_BLKMEM is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
#
-# ATA/IDE/MFM/RLL support
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -190,91 +334,47 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
#
# I2O device support
#
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_XFRM_USER is not set
-# CONFIG_IPV6 is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NET_PCI is not set
CONFIG_FEC=y
+# CONFIG_FEC2 is not set
#
# Ethernet (1000 Mbit)
#
-CONFIG_PPP=y
-# CONFIG_PPP_MULTILINK 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_PPPOE is not set
-# CONFIG_SLIP is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
#
# Wireless LAN (non-hamradio)
@@ -282,29 +382,27 @@
# CONFIG_NET_RADIO is not set
#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
# Wan interfaces
#
# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
+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_PPPOE 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_BOOL is not set
+# CONFIG_ISDN is not set
#
# Telephony Support
@@ -314,50 +412,20 @@
#
# Input device support
#
-CONFIG_INPUT=y
+# CONFIG_INPUT is not set
#
-# Userland interfaces
+# Hardware I/O ports
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
+# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
#
# Character devices
#
# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_LEDMAN is not set
# CONFIG_RESETSWITCH is not set
#
@@ -370,25 +438,8 @@
#
CONFIG_SERIAL_COLDFIRE=y
# CONFIG_UNIX98_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
#
# IPMI
@@ -399,21 +450,42 @@
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
+# CONFIG_MCFWATCHDOG is not set
# CONFIG_RTC is not set
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_MCF_QSPI is not set
+# CONFIG_M41T11M6 is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
#
# Multimedia devices
@@ -421,18 +493,71 @@
# CONFIG_VIDEO_DEV is not set
#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
+#
+
+#
# 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_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+CONFIG_MAGIC_ROM_PTR=y
+# CONFIG_INOTIFY is not set
# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -445,15 +570,17 @@
#
# DOS/FAT/NT Filesystems
#
-# CONFIG_FAT_FS is not set
+# 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_DEVFS_FS is not set
+CONFIG_SYSFS=y
# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
@@ -462,6 +589,7 @@
# 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
@@ -479,12 +607,10 @@
#
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
@@ -494,30 +620,19 @@
CONFIG_MSDOS_PARTITION=y
#
-# Graphics support
+# Native Language Support
#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_NLS is not set
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_FULLDEBUG is not set
-# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_HIGHPROFILE is not set
+# CONFIG_BOOTPARAM is not set
# CONFIG_DUMPTOFLASH is not set
# CONFIG_NO_KERNEL_MSG is not set
# CONFIG_BDM_DISABLE is not set
@@ -525,6 +640,7 @@
#
# Security options
#
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
@@ -533,6 +649,12 @@
# CONFIG_CRYPTO is not set
#
+# Hardware crypto devices
+#
+
+#
# Library routines
#
+# CONFIG_CRC_CCITT is not set
# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 5572385..a220345 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -6,7 +6,7 @@
* Copyleft ()) 2000 James D. Schettine {james@telos-systems.com}
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
* Copyright (C) 1995 Hamish Macdonald
- * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
+ * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
* Copyright (C) 2001 Lineo, Inc. <www.lineo.com>
*
* 68VZ328 Fixes/support Evan Stawnyczy <e@lineo.ca>
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/fb.h>
+#include <linux/module.h>
#include <linux/console.h>
#include <linux/genhd.h>
#include <linux/errno.h>
@@ -45,6 +46,9 @@
unsigned long memory_start;
unsigned long memory_end;
+EXPORT_SYMBOL(memory_start);
+EXPORT_SYMBOL(memory_end);
+
char command_line[COMMAND_LINE_SIZE];
/* setup some dummy routines */
@@ -103,15 +107,21 @@
#if defined(CONFIG_M5206e)
#define CPU "COLDFIRE(m5206e)"
#endif
+#if defined(CONFIG_M523x)
+ #define CPU "COLDFIRE(m523x)"
+#endif
#if defined(CONFIG_M5249)
#define CPU "COLDFIRE(m5249)"
#endif
-#if defined(CONFIG_M527x)
- #define CPU "COLDFIRE(m5270/5271/5274/5275)"
+#if defined(CONFIG_M5271)
+ #define CPU "COLDFIRE(m5270/5271)"
#endif
#if defined(CONFIG_M5272)
#define CPU "COLDFIRE(m5272)"
#endif
+#if defined(CONFIG_M5275)
+ #define CPU "COLDFIRE(m5274/5275)"
+#endif
#if defined(CONFIG_M528x)
#define CPU "COLDFIRE(m5280/5282)"
#endif
@@ -152,7 +162,7 @@
init_mm.start_code = (unsigned long) &_stext;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
- init_mm.brk = (unsigned long) 0;
+ init_mm.brk = (unsigned long) 0;
config_BSP(&command_line[0], sizeof(command_line));
@@ -171,7 +181,7 @@
#endif
#ifdef CONFIG_ELITE
printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
-#endif
+#endif
#ifdef CONFIG_TELOS
printk(KERN_INFO "Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n");
#endif
@@ -200,6 +210,9 @@
#ifdef CONFIG_DRAGEN2
printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
#endif
+#ifdef CONFIG_M5235EVB
+ printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)");
+#endif
#ifdef DEBUG
printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
@@ -223,7 +236,7 @@
saved_command_line[COMMAND_LINE_SIZE-1] = 0;
#ifdef DEBUG
- if (strlen(*cmdline_p))
+ if (strlen(*cmdline_p))
printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
#endif
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 5c3ca67..b17c1ec 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -68,7 +68,7 @@
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -178,10 +178,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index ad7dc63..5bc0684 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -21,6 +21,7 @@
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/a.out.h>
#include <linux/user.h>
@@ -38,7 +39,7 @@
#include <asm/machdep.h>
#include <asm/siginfo.h>
-static char *vec_names[] = {
+static char const * const vec_names[] = {
"RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
"ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
"PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
@@ -106,17 +107,20 @@
int kstack_depth_to_print = 48;
-void show_stack(struct task_struct *task, unsigned long *esp)
+void show_stack(struct task_struct *task, unsigned long *stack)
{
- unsigned long *stack, *endstack, addr;
+ unsigned long *endstack, addr;
extern char _start, _etext;
int i;
- if (esp == NULL)
- esp = (unsigned long *) &esp;
+ if (!stack) {
+ if (task)
+ stack = (unsigned long *)task->thread.ksp;
+ else
+ stack = (unsigned long *)&stack;
+ }
- stack = esp;
- addr = (unsigned long) esp;
+ addr = (unsigned long) stack;
endstack = (unsigned long *) PAGE_ALIGN(addr);
printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
@@ -306,6 +310,8 @@
show_stack(current, &stack);
}
+EXPORT_SYMBOL(dump_stack);
+
#ifdef CONFIG_M68KFPU_EMU
asmlinkage void fpemu_signal(int signal, int code, void *addr)
{
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 31cb128..47f0678 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -107,7 +107,7 @@
*/
#if defined(CONFIG_ELITE)
#define RAM_START 0x30020000
-#define RAM_END 0xe0000
+#define RAM_LENGTH 0xe0000
#endif
/*
@@ -118,7 +118,8 @@
#if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \
defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \
defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \
- defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB)
+ defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB) || \
+ defined(CONFIG_M5235EVB)
#define RAM_START 0x20000
#define RAM_LENGTH 0x3e0000
#endif
@@ -145,6 +146,16 @@
#define RAM_LENGTH 0x3f0000
#endif
+
+/*
+ * The EMAC SoM-5282EM module.
+ */
+#if defined(CONFIG_SOM5282EM)
+#define RAM_START 0x10000
+#define RAM_LENGTH 0xff0000
+#endif
+
+
/*
* These flash boot boards use all of ram for operation. Again the
* actual memory size is not important here, assume at least 4MiB.
@@ -158,7 +169,7 @@
#endif
/*
- * Sneha Boards mimimun memmory
+ * Sneha Boards mimimun memory
* The end of RAM will vary depending on how much ram is fitted,
* but this isn't important here, we assume at least 4MiB.
*/
@@ -167,6 +178,12 @@
#define RAM_LENGTH 0x3e0000
#endif
+#if defined(CONFIG_MOD5272)
+#define RAM_START 0x02000000
+#define RAM_LENGTH 0x00800000
+#define RAMVEC_START 0x20000000
+#define RAMVEC_LENGTH 0x00000400
+#endif
#if defined(CONFIG_RAMKERNEL)
#define TEXT ram
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
new file mode 100644
index 0000000..22767ce
--- /dev/null
+++ b/arch/m68knommu/platform/523x/config.c
@@ -0,0 +1,82 @@
+/***************************************************************************/
+
+/*
+ * linux/arch/m68knommu/platform/523x/config.c
+ *
+ * Sub-architcture dependant initialization code for the Freescale
+ * 523x CPUs.
+ *
+ * Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+void coldfire_pit_tick(void);
+void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+unsigned long coldfire_pit_offset(void);
+void coldfire_trap_init(void);
+void coldfire_reset(void);
+
+/***************************************************************************/
+
+/*
+ * DMA channel base address table.
+ */
+unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+ MCF_MBAR + MCFDMA_BASE0,
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
+
+void mcf_disableall(void)
+{
+ *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
+ *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
+}
+
+/***************************************************************************/
+
+void mcf_autovector(unsigned int vec)
+{
+ /* Everything is auto-vectored on the 5272 */
+}
+
+/***************************************************************************/
+
+void config_BSP(char *commandp, int size)
+{
+ mcf_disableall();
+
+#ifdef CONFIG_BOOTPARAM
+ strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+ commandp[size-1] = 0;
+#else
+ memset(commandp, 0, size);
+#endif
+
+ mach_sched_init = coldfire_pit_init;
+ mach_tick = coldfire_pit_tick;
+ mach_gettimeoffset = coldfire_pit_offset;
+ mach_trap_init = coldfire_trap_init;
+ mach_reset = coldfire_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S
index c7d7a39..7f4ba83 100644
--- a/arch/m68knommu/platform/5307/head.S
+++ b/arch/m68knommu/platform/5307/head.S
@@ -39,14 +39,18 @@
* Memory size exceptions for special cases. Some boards may be set
* for auto memory sizing, but we can't do it that way for some reason.
* For example the 5206eLITE board has static RAM, and auto-detecting
- * the SDRAM will do you no good at all.
+ * the SDRAM will do you no good at all. Same goes for the MOD5272.
*/
#ifdef CONFIG_RAMAUTO
#if defined(CONFIG_M5206eLITE)
-#define MEM_SIZE 0x00100000 /* 1MiB default memory */
+#define MEM_SIZE 0x00100000 /* 1MiB default memory */
+#endif
+#if defined(CONFIG_MOD5272)
+#define MEM_SIZE 0x00800000 /* 8MiB default memory */
#endif
#endif /* CONFIG_RAMAUTO */
+
/*
* If we don't have a fixed memory size now, then lets build in code
* to auto detect the DRAM size. Obviously this is the prefered
@@ -100,11 +104,15 @@
/*
* Most ColdFire boards have their DRAM starting at address 0.
- * Notable exception is the 5206eLITE board.
+ * Notable exception is the 5206eLITE board, another is the MOD5272.
*/
#if defined(CONFIG_M5206eLITE)
#define MEM_BASE 0x30000000
#endif
+#if defined(CONFIG_MOD5272)
+#define MEM_BASE 0x02000000
+#define VBR_BASE 0x20000000 /* vectors in SRAM */
+#endif
#ifndef MEM_BASE
#define MEM_BASE 0x00000000 /* memory base at address 0 */
@@ -188,6 +196,7 @@
movel %a7,_rambase
GET_MEM_SIZE /* macro code determines size */
+ addl %a7,%d0
movel %d0,_ramend /* set end ram addr */
/*
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index 0f5d1fe..7d8990d 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -79,7 +79,7 @@
movel %sp@(PT_ORIG_D0),%d0
movel %sp,%d1 /* get thread_info pointer */
- andl #0xffffe000,%d1
+ andl #-THREAD_SIZE,%d1
movel %d1,%a2
btst #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
jne do_trace
@@ -105,7 +105,7 @@
andw #ALLOWINT,%sr
movel %sp,%d1 /* get thread_info pointer */
- andl #0xffffe000,%d1
+ andl #-THREAD_SIZE,%d1
movel %d1,%a2
move %a2@(TI_FLAGS),%d1 /* thread_info->flags */
andl #_TIF_WORK_MASK,%d1
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
index f7bc80a..8ff48ad 100644
--- a/arch/m68knommu/platform/68360/entry.S
+++ b/arch/m68knommu/platform/68360/entry.S
@@ -96,7 +96,7 @@
andw #ALLOWINT,%sr
movel %sp,%d1 /* get thread_info pointer */
- andl #0xffffe000,%d1
+ andl #-THREAD_SIZE,%d1
movel %d1,%a2
move %a2@(TI_FLAGS),%d1 /* thread_info->flags */
andl #_TIF_WORK_MASK,%d1
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 898de2d..8d76eb1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -4,27 +4,52 @@
# Horrible source of confusion. Die, die, die ...
select EMBEDDED
-config MIPS64
- bool "64-bit kernel"
- help
- Select this option if you want to build a 64-bit kernel. You should
- only select this option if you have hardware that actually has a
- 64-bit processor and if your application will actually benefit from
- 64-bit processing, otherwise say N. You must say Y for kernels for
- SGI IP27 (Origin 200 and 2000) and SGI IP32 (O2). If in doubt say N.
-
-config 64BIT
- def_bool MIPS64
-
-config MIPS32
+# shouldn't it be per-subarchitecture?
+config ARCH_MAY_HAVE_PC_FDC
bool
- depends on MIPS64 = 'n'
default y
mainmenu "Linux/MIPS Kernel Configuration"
source "init/Kconfig"
+config SYS_SUPPORTS_32BIT_KERNEL
+ bool
+config SYS_SUPPORTS_64BIT_KERNEL
+ bool
+config CPU_SUPPORTS_32BIT_KERNEL
+ bool
+config CPU_SUPPORTS_64BIT_KERNEL
+ bool
+
+menu "Kernel type"
+
+choice
+
+ prompt "Kernel code model"
+ help
+ You should only select this option if you have a workload that
+ actually benefits from 64-bit processing or if your machine has
+ large memory. You will only be presented a single option in this
+ menu if your system does not support both 32-bit and 64-bit kernels.
+
+config 32BIT
+ bool "32-bit kernel"
+ depends on CPU_SUPPORTS_32BIT_KERNEL && SYS_SUPPORTS_32BIT_KERNEL
+ select TRAD_SIGNALS
+ help
+ Select this option if you want to build a 32-bit kernel.
+
+config 64BIT
+ bool "64-bit kernel"
+ depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL
+ help
+ Select this option if you want to build a 64-bit kernel.
+
+endchoice
+
+endmenu
+
menu "Machine selection"
config MACH_JAZZ
@@ -34,6 +59,8 @@
select GENERIC_ISA_DMA
select I8259
select ISA
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
help
This a family of machines based on the MIPS R4030 chipset which was
used by several vendors to build RISC/os and Windows NT workstations.
@@ -71,7 +98,9 @@
<http://www.linux-mips.org/>.
config MACH_VR41XX
- bool "Support for NEC VR41XX-based machines"
+ bool "Support for NEC VR4100 series based machines"
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
config NEC_CMBVR4133
bool "Support for NEC CMB-VR4133"
@@ -80,7 +109,6 @@
select DMA_NONCOHERENT
select IRQ_CPU
select HW_HAS_PCI
- select PCI_VR41XX
config ROCKHOPPER
bool "Support for Rockhopper baseboard"
@@ -91,6 +119,7 @@
config CASIO_E55
bool "Support for CASIO CASSIOPEIA E-10/15/55/65"
depends on MACH_VR41XX
+ select CPU_LITTLE_ENDIAN
select DMA_NONCOHERENT
select IRQ_CPU
select ISA
@@ -98,53 +127,54 @@
config IBM_WORKPAD
bool "Support for IBM WorkPad z50"
depends on MACH_VR41XX
+ select CPU_LITTLE_ENDIAN
select DMA_NONCOHERENT
select IRQ_CPU
select ISA
-config TANBAC_TB0226
- bool "Support for TANBAC TB0226 (Mbase)"
+config TANBAC_TB022X
+ bool "Support for TANBAC VR4131 multichip module and TANBAC VR4131DIMM"
depends on MACH_VR41XX
+ select CPU_LITTLE_ENDIAN
select DMA_NONCOHERENT
- select HW_HAS_PCI
select IRQ_CPU
+ select HW_HAS_PCI
help
- The TANBAC TB0226 (Mbase) is a MIPS-based platform manufactured by TANBAC.
- Please refer to <http://www.tanbac.co.jp/> about Mbase.
+ The TANBAC VR4131 multichip module(TB0225) and
+ the TANBAC VR4131DIMM(TB0229) are MIPS-based platforms
+ manufactured by TANBAC.
+ Please refer to <http://www.tanbac.co.jp/>
+ about VR4131 multichip module and VR4131DIMM.
-config TANBAC_TB0229
- bool "Support for TANBAC TB0229 (VR4131DIMM)"
- depends on MACH_VR41XX
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select IRQ_CPU
+config TANBAC_TB0226
+ bool "Support for TANBAC Mbase(TB0226)"
+ depends on TANBAC_TB022X
+ select GPIO_VR41XX
help
- The TANBAC TB0229 (VR4131DIMM) is a MIPS-based platform manufactured by TANBAC.
- Please refer to <http://www.tanbac.co.jp/> about VR4131DIMM.
+ The TANBAC Mbase(TB0226) is a MIPS-based platform manufactured by TANBAC.
+ Please refer to <http://www.tanbac.co.jp/> about Mbase.
config VICTOR_MPC30X
bool "Support for Victor MP-C303/304"
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select IRQ_CPU
depends on MACH_VR41XX
+ select CPU_LITTLE_ENDIAN
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select HW_HAS_PCI
config ZAO_CAPCELLA
bool "Support for ZAO Networks Capcella"
depends on MACH_VR41XX
+ select CPU_LITTLE_ENDIAN
select DMA_NONCOHERENT
- select HW_HAS_PCI
select IRQ_CPU
+ select HW_HAS_PCI
config PCI_VR41XX
bool "Add PCI control unit support of NEC VR4100 series"
- depends on MACH_VR41XX && PCI
-
-config VRC4171
- tristate "Add NEC VRC4171 companion chip support"
- depends on MACH_VR41XX && ISA
- ---help---
- The NEC VRC4171/4171A is a companion chip for NEC VR4111/VR4121.
+ depends on MACH_VR41XX && HW_HAS_PCI
+ default y
+ select PCI
config VRC4173
tristate "Add NEC VRC4173 companion chip support"
@@ -154,25 +184,28 @@
config TOSHIBA_JMR3927
bool "Support for Toshiba JMR-TX3927 board"
- depends on MIPS32
select DMA_NONCOHERENT
select HW_HAS_PCI
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
config MIPS_COBALT
- bool "Support for Cobalt Server (EXPERIMENTAL)"
+ bool "Support for Cobalt Server"
depends on EXPERIMENTAL
select DMA_NONCOHERENT
select HW_HAS_PCI
select I8259
select IRQ_CPU
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
config MACH_DECSTATION
bool "Support for DECstations"
select BOOT_ELF32
select DMA_NONCOHERENT
select IRQ_CPU
- depends on MIPS32 || EXPERIMENTAL
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
---help---
This enables support for DEC's MIPS based workstations. For details
see the Linux/MIPS FAQ on <http://www.linux-mips.org/> and the
@@ -194,6 +227,8 @@
select DMA_NONCOHERENT
select HW_HAS_PCI
select MIPS_GT64120
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This is an evaluation board based on the Galileo GT-64120
single-chip system controller that contains a MIPS R5000 compatible
@@ -214,6 +249,8 @@
select MIPS_GT96100
select RM7000_CPU_SCACHE
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This is an evaluation board based on the Galileo GT-96100 LAN/WAN
communications controllers containing a MIPS R5000 compatible core
@@ -224,6 +261,8 @@
bool "Support for Globespan IVR board"
select DMA_NONCOHERENT
select HW_HAS_PCI
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
help
This is an evaluation board built by Globespan to showcase thir
iVR (Internet Video Recorder) design. It utilizes a QED RM5231
@@ -237,6 +276,8 @@
select HW_HAS_PCI
select MIPS_GT64120
select R5000_CPU_SCACHE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
config PICVUE
tristate "PICVUE LCD display driver"
@@ -258,6 +299,8 @@
bool "Support for ITE 8172G board"
select DMA_NONCOHERENT
select HW_HAS_PCI
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
help
Ths is an evaluation board made by ITE <http://www.ite.com.tw/>
with ATX form factor that utilizes a MIPS R5000 to work with its
@@ -281,6 +324,8 @@
select HW_HAS_PCI
select MIPS_GT64120
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This enables support for the QED R5231-based MIPS Atlas evaluation
board.
@@ -295,6 +340,8 @@
select I8259
select MIPS_GT64120
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This enables support for the VR5000-based MIPS Malta evaluation
board.
@@ -304,6 +351,8 @@
depends on EXPERIMENTAL
select IRQ_CPU
select DMA_NONCOHERENT
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
config MOMENCO_OCELOT
bool "Support for Momentum Ocelot board"
@@ -314,6 +363,8 @@
select MIPS_GT64120
select RM7000_CPU_SCACHE
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
The Ocelot is a MIPS-based Single Board Computer (SBC) made by
Momentum Computer <http://www.momenco.com/>.
@@ -327,6 +378,8 @@
select PCI_MARVELL
select RM7000_CPU_SCACHE
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
The Ocelot is a MIPS-based Single Board Computer (SBC) made by
Momentum Computer <http://www.momenco.com/>.
@@ -340,6 +393,8 @@
select PCI_MARVELL
select RM7000_CPU_SCACHE
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
The Ocelot is a MIPS-based Single Board Computer (SBC) made by
Momentum Computer <http://www.momenco.com/>.
@@ -355,6 +410,8 @@
select PCI_MARVELL
select RM7000_CPU_SCACHE
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
The Ocelot-3 is based off Discovery III System Controller and
PMC-Sierra Rm79000 core.
@@ -371,6 +428,8 @@
select PCI_MARVELL
select RM7000_CPU_SCACHE
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
The Jaguar ATX is a MIPS-based Single Board Computer (SBC) made by
Momentum Computer <http://www.momenco.com/>.
@@ -390,6 +449,8 @@
select IRQ_CPU_RM7K
select IRQ_CPU_RM9K
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
Yosemite is an evaluation board for the RM9000x2 processor
manufactured by PMC-Sierra
@@ -407,6 +468,8 @@
select IRQ_CPU
select I8259
select ISA
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This enables support for the VR5000-based NEC DDB Vrc-5074
evaluation board.
@@ -419,6 +482,8 @@
select IRQ_CPU
select I8259
select ISA
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
help
This enables support for the R5432-based NEC DDB Vrc-5476
evaluation board.
@@ -433,6 +498,8 @@
select HW_HAS_PCI
select I8259
select IRQ_CPU
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
help
This enables support for the R5432-based NEC DDB Vrc-5477,
or Rockhopper/SolutionGear boards with R5432/R5500 CPUs.
@@ -445,10 +512,23 @@
depends on DDB5477
default 0
-config NEC_OSPREY
- bool "Support for NEC Osprey board"
- select DMA_NONCOHERENT
- select IRQ_CPU
+config QEMU
+ bool "Support for Qemu"
+ select DMA_COHERENT
+ select GENERIC_ISA_DMA
+ select HAVE_STD_PC_SERIAL_PORT
+ select I8259
+ select ISA
+ select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ help
+ Qemu is a software emulator which among other architectures also
+ can simulate a MIPS32 4Kc system. This patch adds support for the
+ system architecture that currently is being simulated by Qemu. It
+ will eventually be removed again when Qemu has the capability to
+ simulate actual MIPS hardware platforms. More information on Qemu
+ can be found at http://www.linux-mips.org/wiki/Qemu.
config SGI_IP22
bool "Support for SGI IP22 (Indy/Indigo2)"
@@ -459,6 +539,8 @@
select IP22_CPU_SCACHE
select IRQ_CPU
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This are the SGI Indy, Challenge S and Indigo2, as well as certain
OEM variants like the Tandem CMN B006S. To compile a Linux kernel
@@ -466,12 +548,12 @@
config SGI_IP27
bool "Support for SGI IP27 (Origin200/2000)"
- depends on MIPS64
select ARC
select ARC64
select DMA_IP27
select HW_HAS_PCI
select PCI_DOMAINS
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
workstations. To compile a Linux kernel that runs on these, say Y
@@ -534,7 +616,7 @@
config SGI_IP32
bool "Support for SGI IP32 (O2) (EXPERIMENTAL)"
- depends on MIPS64 && EXPERIMENTAL
+ depends on EXPERIMENTAL
select ARC
select ARC32
select BOOT_ELF32
@@ -544,12 +626,13 @@
select HW_HAS_PCI
select R5000_CPU_SCACHE
select RM7000_CPU_SCACHE
+ select SYS_SUPPORTS_64BIT_KERNEL
help
If you want this kernel to run on SGI O2 workstation, say Y here.
config SOC_AU1X00
- depends on MIPS32
bool "Support for AMD/Alchemy Au1X00 SOCs"
+ select SYS_SUPPORTS_32BIT_KERNEL
choice
prompt "Au1X00 SOC Type"
@@ -661,6 +744,8 @@
select BOOT_ELF32
select DMA_COHERENT
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
choice
prompt "BCM1xxx SOC-based board"
@@ -880,6 +965,8 @@
select HW_HAS_PCI
select I8259
select ISA
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
help
The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens
Nixdorf Informationssysteme (SNI), parent company of Pyramid
@@ -888,13 +975,14 @@
config TOSHIBA_RBTX4927
bool "Support for Toshiba TBTX49[23]7 board"
- depends on MIPS32
select DMA_NONCOHERENT
select HAS_TXX9_SERIAL
select HW_HAS_PCI
select I8259
select ISA
select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
help
This Toshiba board is based on the TX4927 processor. Say Y here to
support this machine type
@@ -926,13 +1014,21 @@
depends on SNI_RM200_PCI || SGI_IP32 || SGI_IP27 || SGI_IP22 || MIPS_MAGNUM_4000 || OLIVETTI_M700 || ACER_PICA_61
default y
-config DMA_COHERENT
+config DMA_COHERENT
bool
-config DMA_IP27
+config DMA_IP27
bool
-config DMA_NONCOHERENT
+config DMA_IP32
+ bool
+ select DMA_NEED_PCI_MAP_STATE
+
+config DMA_NONCOHERENT
+ bool
+ select DMA_NEED_PCI_MAP_STATE
+
+config DMA_NEED_PCI_MAP_STATE
bool
config EARLY_PRINTK
@@ -974,7 +1070,7 @@
config CPU_LITTLE_ENDIAN
bool "Generate little endian code"
- default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA
+ default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA
default n if MIPS_EV64120 || MIPS_EV96100 || MOMENCO_OCELOT || MOMENCO_OCELOT_G || SGI_IP22 || SGI_IP27 || SGI_IP32 || TOSHIBA_JMR3927
help
Some MIPS machines can be configured for either little or big endian
@@ -1091,11 +1187,6 @@
config HAVE_STD_PC_SERIAL_PORT
bool
-config VR4181
- bool
- depends on NEC_OSPREY
- default y
-
config ARC_CONSOLE
bool "ARC console support"
depends on SGI_IP22 || SNI_RM200_PCI
@@ -1145,13 +1236,16 @@
config CPU_MIPS32
bool "MIPS32"
+ select CPU_SUPPORTS_32BIT_KERNEL
config CPU_MIPS64
bool "MIPS64"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
config CPU_R3000
bool "R3000"
- depends on MIPS32
+ select CPU_SUPPORTS_32BIT_KERNEL
help
Please make sure to pick the right CPU type. Linux/MIPS is not
designed to be generic, i.e. Kernels compiled for R3000 CPUs will
@@ -1162,10 +1256,12 @@
config CPU_TX39XX
bool "R39XX"
- depends on MIPS32
+ select CPU_SUPPORTS_32BIT_KERNEL
config CPU_VR41XX
bool "R41xx"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
The options selects support for the NEC VR41xx series of processors.
Only choose this option if you have one of these processors as a
@@ -1174,20 +1270,28 @@
config CPU_R4300
bool "R4300"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
MIPS Technologies R4300-series processors.
config CPU_R4X00
bool "R4x00"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
MIPS Technologies R4000-series processors other than 4300, including
the R4000, R4400, R4600, and 4700.
config CPU_TX49XX
bool "R49XX"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
config CPU_R5000
bool "R5000"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
MIPS Technologies R5000-series processors other than the Nevada.
@@ -1196,36 +1300,48 @@
config CPU_R6000
bool "R6000"
- depends on MIPS32 && EXPERIMENTAL
+ depends on EXPERIMENTAL
+ select CPU_SUPPORTS_32BIT_KERNEL
help
MIPS Technologies R6000 and R6000A series processors. Note these
processors are extremly rare and the support for them is incomplete.
config CPU_NEVADA
bool "RM52xx"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
QED / PMC-Sierra RM52xx-series ("Nevada") processors.
config CPU_R8000
bool "R8000"
- depends on MIPS64 && EXPERIMENTAL
+ depends on EXPERIMENTAL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
MIPS Technologies R8000 processors. Note these processors are
uncommon and the support for them is incomplete.
config CPU_R10000
bool "R10000"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
help
MIPS Technologies R10000-series processors.
config CPU_RM7000
bool "RM7000"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
config CPU_RM9000
bool "RM9000"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
config CPU_SB1
bool "SB1"
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
endchoice
@@ -1321,11 +1437,11 @@
config 64BIT_PHYS_ADDR
bool "Support for 64-bit physical address space"
- depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && MIPS32
+ depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && 32BIT
config CPU_ADVANCED
bool "Override CPU Options"
- depends on MIPS32
+ depends on 32BIT
help
Saying yes here allows you to select support for various features
your CPU may or may not have. Most people should say N here.
@@ -1379,7 +1495,7 @@
#
config HIGHMEM
bool "High Memory Support"
- depends on MIPS32 && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX)
+ depends on 32BIT && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX)
config ARCH_FLATMEM_ENABLE
def_bool y
@@ -1439,7 +1555,7 @@
config MIPS_INSANE_LARGE
bool "Support for large 64-bit configurations"
- depends on CPU_R10000 && MIPS64
+ depends on CPU_R10000 && 64BIT
help
MIPS R10000 does support a 44 bit / 16TB address space as opposed to
previous 64-bit processors which only supported 40 bit / 1TB. If you
@@ -1540,11 +1656,11 @@
config TRAD_SIGNALS
bool
- default y if MIPS32
+ default y if 32BIT
config BUILD_ELF64
bool "Use 64-bit ELF format for building"
- depends on MIPS64
+ depends on 64BIT
help
A 64-bit kernel is usually built using the 64-bit ELF binary object
format as it's one that allows arbitrary 64-bit constructs. For
@@ -1559,11 +1675,11 @@
config BINFMT_IRIX
bool "Include IRIX binary compatibility"
- depends on !CPU_LITTLE_ENDIAN && MIPS32 && BROKEN
+ depends on !CPU_LITTLE_ENDIAN && 32BIT && BROKEN
config MIPS32_COMPAT
bool "Kernel support for Linux/MIPS 32-bit binary compatibility"
- depends on MIPS64
+ depends on 64BIT
help
Select this option if you want Linux/MIPS 32-bit binary
compatibility. Since all software available for Linux/MIPS is
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index bc1c442..b0fdaee 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -37,12 +37,12 @@
64bit-emul = elf64btsmip
endif
-ifdef CONFIG_MIPS32
+ifdef CONFIG_32BIT
gcc-abi = 32
tool-prefix = $(32bit-tool-prefix)
UTS_MACHINE := mips
endif
-ifdef CONFIG_MIPS64
+ifdef CONFIG_64BIT
gcc-abi = 64
tool-prefix = $(64bit-tool-prefix)
UTS_MACHINE := mips64
@@ -63,7 +63,7 @@
vmlinux-32 = vmlinux
vmlinux-64 = vmlinux.64
-cflags-$(CONFIG_MIPS64) += $(call cc-option,-mno-explicit-relocs)
+cflags-$(CONFIG_64BIT) += $(call cc-option,-mno-explicit-relocs)
endif
#
@@ -177,7 +177,7 @@
cflags-$(CONFIG_CPU_R5000) += \
$(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \
- -Wa,--trap
+ -Wa,--trap
cflags-$(CONFIG_CPU_R5432) += \
$(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \
@@ -423,6 +423,12 @@
cflags-$(CONFIG_PMC_YOSEMITE) += -Iinclude/asm-mips/mach-yosemite
load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000
+# Qemu simulating MIPS32 4Kc
+#
+core-$(CONFIG_QEMU) += arch/mips/qemu/
+cflags-$(CONFIG_QEMU) += -Iinclude/asm-mips/mach-qemu
+load-$(CONFIG_QEMU) += 0xffffffff80010000
+
#
# Momentum Ocelot-3
#
@@ -469,13 +475,6 @@
load-$(CONFIG_LASAT) += 0xffffffff80000000
#
-# NEC Osprey (vr4181) board
-#
-core-$(CONFIG_NEC_OSPREY) += arch/mips/vr4181/common/ \
- arch/mips/vr4181/osprey/
-load-$(CONFIG_NEC_OSPREY) += 0xffffffff80002000
-
-#
# Common VR41xx
#
core-$(CONFIG_MACH_VR41XX) += arch/mips/vr41xx/common/
@@ -490,13 +489,11 @@
#
# ZAO Networks Capcella (VR4131)
#
-core-$(CONFIG_ZAO_CAPCELLA) += arch/mips/vr41xx/zao-capcella/
load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000
#
# Victor MP-C303/304 (VR4122)
#
-core-$(CONFIG_VICTOR_MPC30X) += arch/mips/vr41xx/victor-mpc30x/
load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000
#
@@ -512,16 +509,9 @@
load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
#
-# TANBAC TB0226 Mbase (VR4131)
+# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
#
-core-$(CONFIG_TANBAC_TB0226) += arch/mips/vr41xx/tanbac-tb0226/
-load-$(CONFIG_TANBAC_TB0226) += 0xffffffff80000000
-
-#
-# TANBAC TB0229 VR4131DIMM (VR4131)
-#
-core-$(CONFIG_TANBAC_TB0229) += arch/mips/vr41xx/tanbac-tb0229/
-load-$(CONFIG_TANBAC_TB0229) += 0xffffffff80000000
+load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
#
# SGI IP22 (Indy/Indigo2)
@@ -534,10 +524,10 @@
#
core-$(CONFIG_SGI_IP22) += arch/mips/sgi-ip22/
cflags-$(CONFIG_SGI_IP22) += -Iinclude/asm-mips/mach-ip22
-ifdef CONFIG_MIPS32
+ifdef CONFIG_32BIT
load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
endif
-ifdef CONFIG_MIPS64
+ifdef CONFIG_64BIT
load-$(CONFIG_SGI_IP22) += 0xffffffff88004000
endif
@@ -642,7 +632,7 @@
cflags-y += -Iinclude/asm-mips/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/
-ifdef CONFIG_MIPS32
+ifdef CONFIG_32BIT
ifdef CONFIG_CPU_LITTLE_ENDIAN
JIFFIES = jiffies_64
else
@@ -674,8 +664,8 @@
head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
libs-y += arch/mips/lib/
-libs-$(CONFIG_MIPS32) += arch/mips/lib-32/
-libs-$(CONFIG_MIPS64) += arch/mips/lib-64/
+libs-$(CONFIG_32BIT) += arch/mips/lib-32/
+libs-$(CONFIG_64BIT) += arch/mips/lib-64/
core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/
@@ -683,7 +673,7 @@
ifdef CONFIG_LASAT
rom.bin rom.sw: vmlinux
- $(call descend,arch/mips/lasat/image,$@)
+ $(Q)$(MAKE) $(build)=arch/mips/lasat/image $@
endif
#
@@ -730,7 +720,7 @@
@$(MAKE) $(clean)=arch/mips/boot
@$(MAKE) $(clean)=arch/mips/lasat
-# Generate <asm/offset.h
+# Generate <asm/offset.h
#
# The default rule is suffering from funny problems on MIPS so we using our
# own ...
diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c
index 533721e..4e5a6e1 100644
--- a/arch/mips/au1000/common/pci.c
+++ b/arch/mips/au1000/common/pci.c
@@ -40,14 +40,14 @@
/* TBD */
static struct resource pci_io_resource = {
- "pci IO space",
+ "pci IO space",
(u32)PCI_IO_START,
(u32)PCI_IO_END,
IORESOURCE_IO
};
static struct resource pci_mem_resource = {
- "pci memory space",
+ "pci memory space",
(u32)PCI_MEM_START,
(u32)PCI_MEM_END,
IORESOURCE_MEM
@@ -68,7 +68,7 @@
static int __init au1x_pci_setup(void)
{
#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
- virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START,
+ virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START,
Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1);
if (!virt_io_addr) {
@@ -77,7 +77,7 @@
}
#ifdef CONFIG_DMA_NONCOHERENT
- /*
+ /*
* Set the NC bit in controller for Au1500 pre-AC silicon
*/
u32 prid = read_c0_prid();
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index dbc8b1b..eff89e1 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -97,7 +97,7 @@
argptr = prom_getcmdline();
strcat(argptr, " console=ttyS0,115200");
}
-#endif
+#endif
#ifdef CONFIG_FB_AU1100
if ((argptr = strstr(argptr, "video=")) == NULL) {
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index fe418f1..57675b4 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -281,7 +281,7 @@
cpu_speed = count * 2;
}
#else
- cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
+ cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
AU1000_SRC_CLK;
count = cpu_speed / 2;
#endif
@@ -356,7 +356,7 @@
: "hi", "lo", GCC_REG_ACCUM);
/*
- * Due to possible jiffies inconsistencies, we need to check
+ * Due to possible jiffies inconsistencies, we need to check
* the result so that we'll get a timer that is monotonic.
*/
if (res >= USECS_PER_JIFFY)
@@ -375,8 +375,8 @@
au_sync();
offset = pc0 - last_pc0;
if (offset > 2*MATCH20_INC) {
- printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
- (unsigned)offset, (unsigned)last_pc0,
+ printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
+ (unsigned)offset, (unsigned)last_pc0,
(unsigned)last_match20, (unsigned)pc0);
}
offset = (unsigned long)((offset * 305) / 10);
@@ -394,11 +394,11 @@
r4k_offset = cal_r4koff();
printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
- //est_freq = 2*r4k_offset*HZ;
- est_freq = r4k_offset*HZ;
+ //est_freq = 2*r4k_offset*HZ;
+ est_freq = r4k_offset*HZ;
est_freq += 5000; /* round */
est_freq -= est_freq%10000;
- printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+ printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
(est_freq%1000000)*100/1000000);
set_au1x00_speed(est_freq);
set_au1x00_lcd_clock(); // program the LCD clock
diff --git a/arch/mips/au1000/csb250/board_setup.c b/arch/mips/au1000/csb250/board_setup.c
index 90426ea..1c55c5f 100644
--- a/arch/mips/au1000/csb250/board_setup.c
+++ b/arch/mips/au1000/csb250/board_setup.c
@@ -182,7 +182,7 @@
au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV);
au_writel(0, Au1500_PCI_MWBASE_REV_CCL);
au_writel(0x02a00356, Au1500_PCI_STATCMD);
- au_writel(0x00003c04, Au1500_PCI_HDRTYPE);
+ au_writel(0x00003c04, Au1500_PCI_HDRTYPE);
au_writel(0x00000008, Au1500_PCI_MBAR);
au_sync();
@@ -216,7 +216,7 @@
unsigned int gpio2_pins;
retval = 1;
-
+
/* First, disable both selects, then assert the one requested.
*/
au_writel(0xc000c000, GPIO2_OUTPUT);
diff --git a/arch/mips/au1000/csb250/init.c b/arch/mips/au1000/csb250/init.c
index 4320057..bd99733 100644
--- a/arch/mips/au1000/csb250/init.c
+++ b/arch/mips/au1000/csb250/init.c
@@ -81,7 +81,7 @@
csb_env[0] = env1;
mips_machgroup = MACH_GROUP_ALCHEMY;
- mips_machtype = MACH_CSB250;
+ mips_machtype = MACH_CSB250;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c
index 51eee94..4b9d5e4 100644
--- a/arch/mips/au1000/db1x00/init.c
+++ b/arch/mips/au1000/db1x00/init.c
@@ -61,7 +61,7 @@
prom_envp = (char **) fw_arg2;
mips_machgroup = MACH_GROUP_ALCHEMY;
- mips_machtype = MACH_DB1000; /* set the platform # */
+ mips_machtype = MACH_DB1000; /* set the platform # */
prom_init_cmdline();
diff --git a/arch/mips/au1000/hydrogen3/init.c b/arch/mips/au1000/hydrogen3/init.c
index eee4adf..8cc9879 100644
--- a/arch/mips/au1000/hydrogen3/init.c
+++ b/arch/mips/au1000/hydrogen3/init.c
@@ -63,7 +63,7 @@
prom_envp = envp;
mips_machgroup = MACH_GROUP_ALCHEMY;
- mips_machtype = MACH_DB1000; /* set the platform # */
+ mips_machtype = MACH_DB1000; /* set the platform # */
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c
index 2fa211b..0b4807d 100644
--- a/arch/mips/au1000/pb1000/board_setup.c
+++ b/arch/mips/au1000/pb1000/board_setup.c
@@ -174,7 +174,7 @@
case 0x02: /* HB */
break;
default: /* HC and newer */
- /* Enable sys bus clock divider when IDLE state or no bus
+ /* Enable sys bus clock divider when IDLE state or no bus
activity. */
au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
break;
diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/au1000/xxs1500/board_setup.c
index 9dadc82..1e59433 100644
--- a/arch/mips/au1000/xxs1500/board_setup.c
+++ b/arch/mips/au1000/xxs1500/board_setup.c
@@ -49,7 +49,7 @@
void __init board_setup(void)
{
u32 pin_func;
-
+
// set multiple use pins (UART3/GPIO) to UART (it's used as UART too)
pin_func = au_readl(SYS_PINFUNC) & (u32)(~SYS_PF_UR3);
pin_func |= SYS_PF_UR3;
@@ -75,11 +75,11 @@
au_writel(1, GPIO2_ENABLE);
/* gpio2 208/9/10/11 are inputs */
au_writel((1<<8) | (1<<9) | (1<<10) | (1<<11), GPIO2_DIR);
-
+
/* turn off power */
au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30), GPIO2_OUTPUT);
#endif
-
+
#ifdef CONFIG_PCI
#if defined(__MIPSEB__)
diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c
index 03f7552..f1c7653 100644
--- a/arch/mips/au1000/xxs1500/init.c
+++ b/arch/mips/au1000/xxs1500/init.c
@@ -55,7 +55,7 @@
prom_envp = (char **) fw_arg2;
mips_machgroup = MACH_GROUP_ALCHEMY;
- mips_machtype = MACH_XXS1500; /* set the platform # */
+ mips_machtype = MACH_XXS1500; /* set the platform # */
prom_init_cmdline();
diff --git a/arch/mips/au1000/xxs1500/irqmap.c b/arch/mips/au1000/xxs1500/irqmap.c
index 954800a..52f2f7d 100644
--- a/arch/mips/au1000/xxs1500/irqmap.c
+++ b/arch/mips/au1000/xxs1500/irqmap.c
@@ -56,7 +56,7 @@
{ AU1500_GPIO_207, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 },
- { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 },
+ { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_GPIO_2, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_GPIO_4, INTC_INT_LOW_LEVEL, 0 }, /* CF interrupt */
diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig
index caad7ca..3120a02 100644
--- a/arch/mips/configs/atlas_defconfig
+++ b/arch/mips/configs/atlas_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:00 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -88,6 +88,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_MIPS_BONITO64=y
CONFIG_MIPS_MSC=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
index 1b7f8a7..158e716 100644
--- a/arch/mips/configs/capcella_defconfig
+++ b/arch/mips/configs/capcella_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:00 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -97,6 +97,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
index 8861854..4302c6f 100644
--- a/arch/mips/configs/cobalt_defconfig
+++ b/arch/mips/configs/cobalt_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:00 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -82,6 +82,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_I8259=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index 19cac1b..962fc14 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:01 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -104,6 +104,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index 035ac95..6a528d4 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:01 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -104,6 +104,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index c38c4ed..fed6f2f 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:01 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index ee81309..178c0ad 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:02 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
diff --git a/arch/mips/configs/ddb5476_defconfig b/arch/mips/configs/ddb5476_defconfig
index d43ed57..70addc7 100644
--- a/arch/mips/configs/ddb5476_defconfig
+++ b/arch/mips/configs/ddb5476_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:02 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -82,6 +82,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_I8259=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig
index 5a032cd..6029280 100644
--- a/arch/mips/configs/ddb5477_defconfig
+++ b/arch/mips/configs/ddb5477_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:02 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -83,6 +83,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_I8259=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
index 32ada79..66ec1f4 100644
--- a/arch/mips/configs/decstation_defconfig
+++ b/arch/mips/configs/decstation_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:03 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -88,6 +88,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
index 52074a20..ba2ec01 100644
--- a/arch/mips/configs/e55_defconfig
+++ b/arch/mips/configs/e55_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:03 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -96,6 +96,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig
index 360e842..17e87f7 100644
--- a/arch/mips/configs/ev64120_defconfig
+++ b/arch/mips/configs/ev64120_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:03 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -89,6 +89,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_MIPS_GT64120=y
# CONFIG_SYSCLK_75 is not set
diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig
index 657a950..9da4140 100644
--- a/arch/mips/configs/ev96100_defconfig
+++ b/arch/mips/configs/ev96100_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:03 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -88,6 +88,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_MIPS_GT64120=y
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index 3fb102e..17fa5c4 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:04 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -90,6 +90,7 @@
CONFIG_HAVE_DEC_LOCK=y
CONFIG_ARC=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_SWAP_IO_SPACE=y
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index b5bab3a..b2a67da 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -4,7 +4,7 @@
# Wed Jan 26 02:49:04 2005
#
CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
CONFIG_64BIT=y
#
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index bdf1415..b26e117 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -4,7 +4,7 @@
# Wed Jan 26 02:49:04 2005
#
CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
CONFIG_64BIT=y
#
@@ -84,6 +84,7 @@
CONFIG_DMA_IP32=y
CONFIG_OWN_DMA=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_ARC32=y
CONFIG_BOOT_ELF32=y
diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig
index 1ca7746..08bd3ad 100644
--- a/arch/mips/configs/it8172_defconfig
+++ b/arch/mips/configs/it8172_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:05 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -90,6 +90,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_ITE_BOARD_GEN=y
CONFIG_IT8172_CIR=y
diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig
index c6eef70..583ef5c 100644
--- a/arch/mips/configs/ivr_defconfig
+++ b/arch/mips/configs/ivr_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:05 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -89,6 +89,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_ITE_BOARD_GEN=y
CONFIG_IT8172_CIR=y
diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig
index 757c4e8..8abb5a0 100644
--- a/arch/mips/configs/jaguar-atx_defconfig
+++ b/arch/mips/configs/jaguar-atx_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:05 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -81,6 +81,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_LIMITED_DMA=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index e5a6139..da5d9ee 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:06 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -82,6 +82,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_MIPS_TX3927=y
CONFIG_SWAP_IO_SPACE=y
diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig
index 1e76978..8d600ae 100644
--- a/arch/mips/configs/lasat200_defconfig
+++ b/arch/mips/configs/lasat200_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:06 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -92,6 +92,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_MIPS_NILE4=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_MIPS_GT64120=y
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 61fb9fb..79519ac 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:53:14 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -88,6 +88,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_I8259=y
CONFIG_MIPS_BONITO64=y
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
index 31b8f2a..0fea57e 100644
--- a/arch/mips/configs/mpc30x_defconfig
+++ b/arch/mips/configs/mpc30x_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:07 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -97,6 +97,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
index 2cce682..b4cf97a 100644
--- a/arch/mips/configs/ocelot_3_defconfig
+++ b/arch/mips/configs/ocelot_3_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:07 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -89,6 +89,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_IRQ_CPU_RM7K=y
diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig
index 0cbf48a..a38903d 100644
--- a/arch/mips/configs/ocelot_c_defconfig
+++ b/arch/mips/configs/ocelot_c_defconfig
@@ -4,7 +4,7 @@
# Wed Jan 26 02:49:07 2005
#
CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
CONFIG_64BIT=y
#
@@ -80,6 +80,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_IRQ_MV64340=y
diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig
index 4043950..920d59b 100644
--- a/arch/mips/configs/ocelot_defconfig
+++ b/arch/mips/configs/ocelot_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:08 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -82,6 +82,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_IRQ_CPU_RM7K=y
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig
index 3870af4..ef5ea50 100644
--- a/arch/mips/configs/ocelot_g_defconfig
+++ b/arch/mips/configs/ocelot_g_defconfig
@@ -4,7 +4,7 @@
# Wed Jan 26 02:49:08 2005
#
CONFIG_MIPS=y
-CONFIG_MIPS64=y
+CONFIG_64BIT=y
CONFIG_64BIT=y
#
@@ -80,6 +80,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_IRQ_CPU_RM7K=y
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 6cdabd5..813e3a8 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:08 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -104,6 +104,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SWAP_IO_SPACE=y
# CONFIG_AU1X00_USB_DEVICE is not set
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index 2aebbd2..49e52834 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:09 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index 9e21edc..8e42677 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:09 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
diff --git a/arch/mips/configs/osprey_defconfig b/arch/mips/configs/qemu_defconfig
similarity index 66%
rename from arch/mips/configs/osprey_defconfig
rename to arch/mips/configs/qemu_defconfig
index 989cb9e..b6568e42 100644
--- a/arch/mips/configs/osprey_defconfig
+++ b/arch/mips/configs/qemu_defconfig
@@ -1,108 +1,133 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Wed Jan 26 02:49:08 2005
+# Linux kernel version: 2.6.13-rc6
+# Mon Aug 8 11:49:54 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
-# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
#
# Code maturity level options
#
-CONFIG_EXPERIMENTAL=y
+# CONFIG_EXPERIMENTAL is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_SYSCTL is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
+# CONFIG_SHMEM is not set
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
#
# Loadable module support
#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
+# CONFIG_MODULES is not set
#
# Machine selection
#
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_MACH_VR41XX is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
-# CONFIG_LASAT is not set
# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
# CONFIG_DDB5074 is not set
# CONFIG_DDB5476 is not set
# CONFIG_DDB5477 is not set
-CONFIG_NEC_OSPREY=y
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+CONFIG_QEMU=y
# CONFIG_SGI_IP22 is not set
-# CONFIG_SOC_AU1X00 is not set
-# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_IRQ_CPU=y
+CONFIG_DMA_COHERENT=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_I8259=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
-CONFIG_VR4181=y
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
#
# CPU selection
#
-# CONFIG_CPU_MIPS32 is not set
-# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
+CONFIG_CPU_R4X00=y
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
@@ -113,17 +138,36 @@
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_LLDSCD=y
CONFIG_CPU_HAS_SYNC=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
+CONFIG_ISA=y
CONFIG_MMU=y
#
@@ -132,10 +176,6 @@
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# PCI Hotplug Support
#
@@ -147,6 +187,56 @@
CONFIG_TRAD_SIGNALS=y
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER 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_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
# Device Drivers
#
@@ -154,7 +244,7 @@
# Generic Driver Options
#
CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
#
@@ -170,6 +260,7 @@
#
# Plug and Play support
#
+# CONFIG_PNP is not set
#
# Block devices
@@ -181,19 +272,16 @@
# CONFIG_BLK_DEV_RAM is not set
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_CDROM_PKTCDVD is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_ATA_OVER_ETH=m
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -206,6 +294,11 @@
# CONFIG_SCSI is not set
#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -213,6 +306,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -223,84 +317,41 @@
#
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER 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_TUNNEL=m
-CONFIG_IP_TCPDIAG=m
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=y
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
@@ -313,6 +364,7 @@
#
# Token Ring devices
#
+# CONFIG_TR is not set
#
# Wireless LAN (non-hamradio)
@@ -325,8 +377,8 @@
# 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
@@ -346,28 +398,13 @@
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_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 I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-CONFIG_SERIO_RAW=m
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -377,6 +414,12 @@
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
@@ -397,9 +440,8 @@
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
#
# IPMI
@@ -418,13 +460,17 @@
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+
+#
# I2C support
#
# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
#
# Dallas's 1-wire bus
@@ -432,6 +478,11 @@
# CONFIG_W1 is not set
#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+
+#
# Misc devices
#
@@ -453,9 +504,9 @@
#
# Console display driver support
#
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -469,10 +520,6 @@
# CONFIG_USB_ARCH_HAS_OHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -488,19 +535,28 @@
# CONFIG_INFINIBAND is not set
#
+# SN Devices
+#
+
+#
# File systems
#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -520,12 +576,8 @@
#
# Pseudo filesystems
#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS_XATTR=y
-CONFIG_DEVPTS_FS_SECURITY=y
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -533,13 +585,7 @@
#
# 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
@@ -551,23 +597,18 @@
# 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=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
#
# Partition Types
@@ -581,22 +622,18 @@
# CONFIG_NLS is not set
#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="ip=bootp ether=46,0x03fe0300,eth0"
+CONFIG_CMDLINE="console=ttyS0 debug ip=172.20.0.2:172.20.0.1::255.255.0.0"
#
# Security options
#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
@@ -612,7 +649,7 @@
# Library routines
#
# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
-CONFIG_LIBCRC32C=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index d0c85a4..17d4fce 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:09 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -91,6 +91,7 @@
CONFIG_HAVE_DEC_LOCK=y
CONFIG_ARC=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_I8259=y
CONFIG_CPU_LITTLE_ENDIAN=y
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
index 84978b7..1dc935f3 100644
--- a/arch/mips/configs/sb1250-swarm_defconfig
+++ b/arch/mips/configs/sb1250-swarm_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:10 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig
index 7c718a4..dd07e86 100644
--- a/arch/mips/configs/sead_defconfig
+++ b/arch/mips/configs/sead_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:10 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -80,6 +80,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_BOARDS_GEN=y
diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
index e01727c..c9d3f83 100644
--- a/arch/mips/configs/tb0226_defconfig
+++ b/arch/mips/configs/tb0226_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:12 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -95,6 +95,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig
index c6ba3de2..2cb6691 100644
--- a/arch/mips/configs/tb0229_defconfig
+++ b/arch/mips/configs/tb0229_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:12 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -98,6 +98,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
index 915c43b..16e07fc 100644
--- a/arch/mips/configs/workpad_defconfig
+++ b/arch/mips/configs/workpad_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:12 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -96,6 +96,7 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
index 562f2b8..6d22907 100644
--- a/arch/mips/configs/yosemite_defconfig
+++ b/arch/mips/configs/yosemite_defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:49:13 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
index 5f027bf..9ffe1a91 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq.c
@@ -76,7 +76,7 @@
extern void vrc5477_irq_init(u32 base);
extern void mips_cpu_irq_init(u32 base);
extern asmlinkage void ddb5477_handle_int(void);
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
+extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
void __init arch_init_irq(void)
@@ -94,7 +94,7 @@
/* setup PCI interrupt attributes */
set_pci_int_attr(PCI0, INTA, ACTIVE_LOW, LEVEL_SENSE);
set_pci_int_attr(PCI0, INTB, ACTIVE_LOW, LEVEL_SENSE);
- if (mips_machtype == MACH_NEC_ROCKHOPPERII)
+ if (mips_machtype == MACH_NEC_ROCKHOPPERII)
set_pci_int_attr(PCI0, INTC, ACTIVE_HIGH, LEVEL_SENSE);
else
set_pci_int_attr(PCI0, INTC, ACTIVE_LOW, LEVEL_SENSE);
@@ -134,7 +134,7 @@
/* setup cascade interrupts */
setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
- setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
+ setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
/* hook up the first-level interrupt handler */
set_except_vector(0, ddb5477_handle_int);
diff --git a/arch/mips/ddb5xxx/ddb5477/setup.c b/arch/mips/ddb5xxx/ddb5477/setup.c
index 15c6e54..d62f5a7 100644
--- a/arch/mips/ddb5xxx/ddb5477/setup.c
+++ b/arch/mips/ddb5xxx/ddb5477/setup.c
@@ -141,7 +141,7 @@
/* mips_hpt_frequency is 1/2 of the cpu core freq */
i = (read_c0_config() >> 28 ) & 7;
- if ((current_cpu_data.cputype == CPU_R5432) && (i == 3))
+ if ((current_cpu_data.cputype == CPU_R5432) && (i == 3))
i = 4;
mips_hpt_frequency = bus_frequency*(i+4)/4;
}
@@ -298,11 +298,11 @@
if (mips_machtype == MACH_NEC_ROCKHOPPER
|| mips_machtype == MACH_NEC_ROCKHOPPERII) {
- /* Disable bus diagnostics. */
+ /* Disable bus diagnostics. */
ddb_out32(DDB_PCICTL0_L, 0);
ddb_out32(DDB_PCICTL0_H, 0);
ddb_out32(DDB_PCICTL1_L, 0);
- ddb_out32(DDB_PCICTL1_H, 0);
+ ddb_out32(DDB_PCICTL1_H, 0);
}
if (mips_machtype == MACH_NEC_ROCKHOPPER) {
@@ -354,7 +354,7 @@
*/
pci_write_config_byte(&dev_m1533, 0x58, 0x74);
- /*
+ /*
* positive decode (bit6 -0)
* enable IDE controler interrupt (bit 4 -1)
* setup SIRQ to point to IRQ 14 (bit 3:0 - 1101)
@@ -364,31 +364,31 @@
/* Setup M5229 registers */
dev_m5229.bus = &bus;
dev_m5229.sysdata = NULL;
- dev_m5229.devfn = 4*8; // slot 4 (AD15): M5229 IDE
+ dev_m5229.devfn = 4*8; // slot 4 (AD15): M5229 IDE
/*
* enable IDE in the M5229 config register 0x50 (bit 0 - 1)
- * M5229 IDSEL is addr:15; see above setting
+ * M5229 IDSEL is addr:15; see above setting
*/
pci_read_config_byte(&dev_m5229, 0x50, &temp8);
pci_write_config_byte(&dev_m5229, 0x50, temp8 | 0x1);
- /*
- * enable bus master (bit 2) and IO decoding (bit 0)
+ /*
+ * enable bus master (bit 2) and IO decoding (bit 0)
*/
pci_read_config_byte(&dev_m5229, 0x04, &temp8);
pci_write_config_byte(&dev_m5229, 0x04, temp8 | 0x5);
/*
* enable native, copied from arch/ppc/k2boot/head.S
- * TODO - need volatile, need to be portable
+ * TODO - need volatile, need to be portable
*/
pci_write_config_byte(&dev_m5229, 0x09, 0xef);
- /* Set Primary Channel Command Block Timing */
+ /* Set Primary Channel Command Block Timing */
pci_write_config_byte(&dev_m5229, 0x59, 0x31);
- /*
+ /*
* Enable primary channel 40-pin cable
* M5229 register 0x4a (bit 0)
*/
diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c
index 133fb7c..6dbce92 100644
--- a/arch/mips/dec/ecc-berr.c
+++ b/arch/mips/dec/ecc-berr.c
@@ -253,7 +253,7 @@
kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR);
kn0x_chksyn = (void *)(KN03_SLOT_BASE + IOASIC_CHKSYN);
-
+
/*
* Set normal ECC detection and generation, enable ECC correction.
* For KN05 we also need to make sure EE (?) is enabled in the MB.
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 3b37909..c89768d 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -133,7 +133,7 @@
*/
mfc0 t0,CP0_CAUSE # get pending interrupts
mfc0 t1,CP0_STATUS
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
lw t2,cpu_fpu_mask
#endif
andi t0,ST0_IM # CAUSE.CE may be non-zero!
@@ -141,7 +141,7 @@
beqz t0,spurious
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
and t2,t0
bnez t2,fpu # handle FPU immediately
#endif
@@ -271,7 +271,7 @@
j ret_from_irq
nop
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
fpu:
j handle_fpe_int
nop
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
index 373822e..bcd0247 100644
--- a/arch/mips/dec/prom/Makefile
+++ b/arch/mips/dec/prom/Makefile
@@ -5,7 +5,7 @@
lib-y += init.o memory.o cmdline.o identify.o console.o
-lib-$(CONFIG_MIPS32) += locore.o
-lib-$(CONFIG_MIPS64) += call_o32.o
+lib-$(CONFIG_32BIT) += locore.o
+lib-$(CONFIG_64BIT) += call_o32.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index d55fe66..20f84b1 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -4,9 +4,9 @@
# Wed Jan 26 02:48:59 2005
#
CONFIG_MIPS=y
-# CONFIG_MIPS64 is not set
# CONFIG_64BIT is not set
-CONFIG_MIPS32=y
+# CONFIG_64BIT is not set
+CONFIG_32BIT=y
#
# Code maturity level options
@@ -90,6 +90,7 @@
CONFIG_HAVE_DEC_LOCK=y
CONFIG_ARC=y
CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_IRQ_CPU=y
CONFIG_SWAP_IO_SPACE=y
diff --git a/arch/mips/ite-boards/generic/it8172_setup.c b/arch/mips/ite-boards/generic/it8172_setup.c
index d808a67..a5f6d84 100644
--- a/arch/mips/ite-boards/generic/it8172_setup.c
+++ b/arch/mips/ite-boards/generic/it8172_setup.c
@@ -129,7 +129,7 @@
/*
* IO/MEM resources.
- *
+ *
* revisit this area.
*/
set_io_port_base(KSEG1);
diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c
index 30a6c0d..f5d67ee 100644
--- a/arch/mips/ite-boards/generic/time.c
+++ b/arch/mips/ite-boards/generic/time.c
@@ -72,7 +72,7 @@
static inline unsigned char
bin_to_hw(unsigned char c)
{
- if (rtc_dm_binary())
+ if (rtc_dm_binary())
return c;
else
return ((c/10) << 4) + (c%10);
@@ -91,9 +91,9 @@
static inline unsigned char
hour_bin_to_hw(unsigned char c)
{
- if (rtc_24h())
+ if (rtc_24h())
return bin_to_hw(c);
- if (c >= 12)
+ if (c >= 12)
return 0x80 | bin_to_hw((c==12)?12:c-12); /* 12 is 12pm */
else
return bin_to_hw((c==0)?12:c); /* 0 is 12 AM, not 0 am */
@@ -105,9 +105,9 @@
unsigned char tmp = hw_to_bin(c&0x3f);
if (rtc_24h())
return tmp;
- if (c & 0x80)
+ if (c & 0x80)
return (tmp==12)?12:tmp+12; /* 12pm is 12, not 24 */
- else
+ else
return (tmp==12)?0:tmp; /* 12am is 0 */
}
@@ -145,7 +145,7 @@
return (mips_hpt_frequency / HZ);
}
-static unsigned long
+static unsigned long
it8172_rtc_get_time(void)
{
unsigned int year, mon, day, hour, min, sec;
@@ -166,12 +166,12 @@
hour = hour_hw_to_bin(CMOS_READ(RTC_HOURS));
day = hw_to_bin(CMOS_READ(RTC_DAY_OF_MONTH));
mon = hw_to_bin(CMOS_READ(RTC_MONTH));
- year = hw_to_bin(CMOS_READ(RTC_YEAR)) +
+ year = hw_to_bin(CMOS_READ(RTC_YEAR)) +
hw_to_bin(*rtc_century_reg) * 100;
/* restore interrupts */
local_irq_restore(flags);
-
+
return mktime(year, mon, day, hour, min, sec);
}
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index a0230ee..d330358 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -13,8 +13,8 @@
ifdef CONFIG_MODULES
obj-y += mips_ksyms.o module.o
-obj-$(CONFIG_MIPS32) += module-elf32.o
-obj-$(CONFIG_MIPS64) += module-elf64.o
+obj-$(CONFIG_32BIT) += module-elf32.o
+obj-$(CONFIG_64BIT) += module-elf64.o
endif
obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o
@@ -45,8 +45,8 @@
obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o
obj-$(CONFIG_IRQ_MV64340) += irq-mv6434x.o
-obj-$(CONFIG_MIPS32) += scall32-o32.o
-obj-$(CONFIG_MIPS64) += scall64-64.o
+obj-$(CONFIG_32BIT) += scall32-o32.o
+obj-$(CONFIG_64BIT) += scall64-64.o
obj-$(CONFIG_BINFMT_IRIX) += binfmt_irix.o
obj-$(CONFIG_MIPS32_COMPAT) += ioctl32.o linux32.o signal32.o
obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o
@@ -55,7 +55,7 @@
obj-$(CONFIG_KGDB) += gdb-low.o gdb-stub.o
obj-$(CONFIG_PROC_FS) += proc.o
-obj-$(CONFIG_MIPS64) += cpu-bugs64.o
+obj-$(CONFIG_64BIT) += cpu-bugs64.o
obj-$(CONFIG_GEN_RTC) += genrtc.o
diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
index ed47041..6b645fb 100644
--- a/arch/mips/kernel/binfmt_elfn32.c
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -103,7 +103,7 @@
* Convert jiffies to nanoseconds and seperate with
* one divide.
*/
- u64 nsec = (u64)jiffies * TICK_NSEC;
+ u64 nsec = (u64)jiffies * TICK_NSEC;
value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
value->tv_usec /= NSEC_PER_USEC;
}
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index ee21b18..b4075e9 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -105,7 +105,7 @@
* Convert jiffies to nanoseconds and seperate with
* one divide.
*/
- u64 nsec = (u64)jiffies * TICK_NSEC;
+ u64 nsec = (u64)jiffies * TICK_NSEC;
value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
value->tv_usec /= NSEC_PER_USEC;
}
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index 11ebe5d..47a087b 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -137,7 +137,7 @@
for (i = 0; i < 8; i++)
if (v1[i] != w[i])
bug = 1;
-
+
if (bug == 0) {
printk("no.\n");
return;
@@ -149,7 +149,7 @@
for (i = 0; i < 8; i++)
if (v2[i] != w[i])
fix = 0;
-
+
if (fix == 1) {
printk("yes.\n");
return;
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 4bb8495..7685f8b 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -229,15 +229,9 @@
break;
case PRID_IMP_VR41XX:
switch (c->processor_id & 0xf0) {
-#ifndef CONFIG_VR4181
case PRID_REV_VR4111:
c->cputype = CPU_VR4111;
break;
-#else
- case PRID_REV_VR4181:
- c->cputype = CPU_VR4181;
- break;
-#endif
case PRID_REV_VR4121:
c->cputype = CPU_VR4121;
break;
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S
index ece6dda..512bedb 100644
--- a/arch/mips/kernel/gdb-low.S
+++ b/arch/mips/kernel/gdb-low.S
@@ -13,13 +13,13 @@
#include <asm/stackframe.h>
#include <asm/gdb-stub.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define DMFC0 mfc0
#define DMTC0 mtc0
#define LDC1 lwc1
#define SDC1 lwc1
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define DMFC0 dmfc0
#define DMTC0 dmtc0
#define LDC1 ldc1
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
index 2698893..d3fd1ab 100644
--- a/arch/mips/kernel/gdb-stub.c
+++ b/arch/mips/kernel/gdb-stub.c
@@ -687,8 +687,8 @@
* acquire the big kgdb spinlock
*/
if (!spin_trylock(&kgdb_lock)) {
- /*
- * some other CPU has the lock, we should go back to
+ /*
+ * some other CPU has the lock, we should go back to
* receive the gdb_wait IPC
*/
return;
@@ -703,7 +703,7 @@
async_bp.addr = 0;
}
- /*
+ /*
* acquire the CPU spinlocks
*/
for (i = num_online_cpus()-1; i >= 0; i--)
@@ -894,7 +894,7 @@
ptr = &input_buffer[1];
if (hexToLong(&ptr, &addr))
regs->cp0_epc = addr;
-
+
goto exit_kgdb_exception;
break;
@@ -1001,7 +1001,7 @@
return;
__asm__ __volatile__(
- ".globl breakinst\n\t"
+ ".globl breakinst\n\t"
".set\tnoreorder\n\t"
"nop\n"
"breakinst:\tbreak\n\t"
@@ -1014,7 +1014,7 @@
void async_breakpoint(void)
{
__asm__ __volatile__(
- ".globl async_breakinst\n\t"
+ ".globl async_breakinst\n\t"
".set\tnoreorder\n\t"
"nop\n"
"async_breakinst:\tbreak\n\t"
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index a5b0a38..e7f6c1b 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -54,7 +54,7 @@
#endif
mfc0 k1, CP0_CAUSE
andi k1, k1, 0x7c
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
dsll k1, k1, 1
#endif
PTR_L k0, exception_handlers(k1)
@@ -81,7 +81,7 @@
beq k1, k0, handle_vced
li k0, 14<<2
beq k1, k0, handle_vcei
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
dsll k1, k1, 1
#endif
.set pop
@@ -244,12 +244,12 @@
start with an n and gas will believe \n is ok ... */
.macro __BUILD_verbose nexception
LONG_L a1, PT_EPC(sp)
-#if CONFIG_MIPS32
+#ifdef CONFIG_32BIT
PRINT("Got \nexception at %08lx\012")
-#endif
-#if CONFIG_MIPS64
+#endif
+#ifdef CONFIG_64BIT
PRINT("Got \nexception at %016lx\012")
-#endif
+#endif
.endm
.macro __BUILD_count exception
@@ -293,7 +293,7 @@
BUILD_HANDLER mcheck mcheck cli verbose /* #24 */
BUILD_HANDLER reserved reserved sti verbose /* others */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/* A temporary overflow handler used by check_daddi(). */
__INIT
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index a64e87d2..2a1b45d 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -107,7 +107,7 @@
.endm
.macro setup_c0_status_pri
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
setup_c0_status ST0_KX 0
#else
setup_c0_status 0 0
@@ -115,7 +115,7 @@
.endm
.macro setup_c0_status_sec
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
setup_c0_status ST0_KX ST0_BEV
#else
setup_c0_status 0 ST0_BEV
@@ -215,7 +215,7 @@
* slightly different layout ...
*/
page swapper_pg_dir, _PGD_ORDER
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
page invalid_pmd_table, _PMD_ORDER
#endif
page invalid_pte_table, _PTE_ORDER
diff --git a/arch/mips/kernel/ioctl32.c b/arch/mips/kernel/ioctl32.c
index 519cd5d..c069719 100644
--- a/arch/mips/kernel/ioctl32.c
+++ b/arch/mips/kernel/ioctl32.c
@@ -27,7 +27,7 @@
#include "compat_ioctl.c"
typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
+
#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl)
#define HANDLE_IOCTL(cmd,handler) { (cmd), (ioctl32_handler_t)(handler), NULL },
#define IOCTL_TABLE_START \
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 441157a..7d93992 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -77,7 +77,7 @@
if (i < NR_IRQS) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
- if (!action)
+ if (!action)
goto skip;
seq_printf(p, "%3d: ",i);
#ifndef CONFIG_SMP
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 993abc8..ece4564 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -313,7 +313,7 @@
struct sysinfo s;
int ret, err;
mm_segment_t old_fs = get_fs ();
-
+
set_fs (KERNEL_DS);
ret = sys_sysinfo(&s);
set_fs (old_fs);
@@ -546,21 +546,21 @@
struct ipc_perm32
{
key_t key;
- compat_uid_t uid;
- compat_gid_t gid;
- compat_uid_t cuid;
- compat_gid_t cgid;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
+ __compat_uid_t cuid;
+ __compat_gid_t cgid;
compat_mode_t mode;
unsigned short seq;
};
struct ipc64_perm32 {
key_t key;
- compat_uid_t uid;
- compat_gid_t gid;
- compat_uid_t cuid;
- compat_gid_t cgid;
- compat_mode_t mode;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
+ __compat_uid_t cuid;
+ __compat_gid_t cgid;
+ compat_mode_t mode;
unsigned short seq;
unsigned short __pad1;
unsigned int __unused1;
@@ -1334,17 +1334,17 @@
mm_segment_t old_fs = get_fs();
int ret;
off_t of;
-
+
if (offset && get_user(of, offset))
return -EFAULT;
-
+
set_fs(KERNEL_DS);
ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
set_fs(old_fs);
-
+
if (offset && put_user(of, offset))
return -EFAULT;
-
+
return ret;
}
@@ -1362,11 +1362,11 @@
#undef AL
/*
- * System call vectors.
+ * System call vectors.
*
* Argument checking cleaned up. Saved 20% in size.
* This function doesn't need to set the kernel lock because
- * it is set by the callees.
+ * it is set by the callees.
*/
asmlinkage long sys32_socketcall(int call, unsigned int *args32)
@@ -1402,11 +1402,11 @@
/* copy_from_user should be SMP safe. */
if (copy_from_user(a, args32, socketcall_nargs[call]))
return -EFAULT;
-
+
a0=a[0];
a1=a[1];
-
- switch(call)
+
+ switch(call)
{
case SYS_SOCKET:
err = sys_socket(a0,a1,a[2]);
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index eed29fc..86e42c6 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -35,7 +35,7 @@
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strchr);
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
EXPORT_SYMBOL(strncmp);
#endif
EXPORT_SYMBOL(strlen);
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6e70c42..e4f2f80 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -70,7 +70,7 @@
/* New thread loses kernel privileges. */
status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|KU_MASK);
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
status &= ~ST0_FR;
status |= (current->thread.mflags & MF_32BIT_REGS) ? 0 : ST0_FR;
#endif
@@ -236,10 +236,10 @@
break;
if (
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
ip->i_format.opcode == sw_op &&
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
ip->i_format.opcode == sd_op &&
#endif
ip->i_format.rs == 29)
@@ -353,7 +353,7 @@
out:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
if (current->thread.mflags & MF_32BIT_REGS) /* Kludge for 32-bit ps */
pc &= 0xffffffffUL;
#endif
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 92e70ca..0b571a5 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -124,7 +124,7 @@
if (tsk_used_math(child)) {
fpureg_t *fregs = get_fpu_regs(child);
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
/*
* The odd registers are actually the high
* order bits of the values stored in the even
@@ -135,7 +135,7 @@
else
tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
tmp = fregs[addr - FPR_BASE];
#endif
} else {
@@ -213,7 +213,7 @@
sizeof(child->thread.fpu.hard));
child->thread.fpu.hard.fcr31 = 0;
}
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
/*
* The odd registers are actually the high order bits
* of the values stored in the even registers - unless
@@ -227,7 +227,7 @@
fregs[addr - FPR_BASE] |= data;
}
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
fregs[addr - FPR_BASE] = data;
#endif
break;
@@ -304,14 +304,14 @@
static inline int audit_arch(void)
{
#ifdef CONFIG_CPU_LITTLE_ENDIAN
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
if (!(current->thread.mflags & MF_32BIT_REGS))
return AUDIT_ARCH_MIPSEL64;
#endif /* MIPS64 */
return AUDIT_ARCH_MIPSEL;
#else /* big endian... */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
if (!(current->thread.mflags & MF_32BIT_REGS))
return AUDIT_ARCH_MIPS64;
#endif /* MIPS64 */
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 243e7b6..f100196 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -35,7 +35,7 @@
/*
* FPU context is saved iff the process has used it's FPU in the current
* time slice as indicated by TIF_USEDFPU. In any case, the CU1 bit for user
- * space STATUS register should be 0, so that a process *always* starts its
+ * space STATUS register should be 0, so that a process *always* starts its
* userland with FPU disabled after each context switch.
*
* FPU will be enabled as soon as the process accesses FPU again, through
@@ -55,7 +55,7 @@
cpu_save_nonscratch a0
sw ra, THREAD_REG31(a0)
- /*
+ /*
* check if we need to save FPU registers
*/
lw t3, TASK_THREAD_INFO(a0)
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index ebb643d..aba665b 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -36,7 +36,7 @@
LEAF(_save_fp_context)
cfc1 t1, fcr31
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/* Store the 16 odd double precision registers */
EX sdc1 $f1, SC_FPREGS+8(a0)
EX sdc1 $f3, SC_FPREGS+24(a0)
@@ -118,7 +118,7 @@
*/
LEAF(_restore_fp_context)
EX lw t0, SC_FPC_CSR(a0)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
EX ldc1 $f1, SC_FPREGS+8(a0)
EX ldc1 $f3, SC_FPREGS+24(a0)
EX ldc1 $f5, SC_FPREGS+40(a0)
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 1fc3b2e..e02b772 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -33,7 +33,7 @@
/*
* FPU context is saved iff the process has used it's FPU in the current
* time slice as indicated by _TIF_USEDFPU. In any case, the CU1 bit for user
- * space STATUS register should be 0, so that a process *always* starts its
+ * space STATUS register should be 0, so that a process *always* starts its
* userland with FPU disabled after each context switch.
*
* FPU will be enabled as soon as the process accesses FPU again, through
@@ -105,7 +105,7 @@
* Save a thread's fp context.
*/
LEAF(_save_fp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
mfc0 t1, CP0_STATUS
#endif
fpu_save_double a0 t1 t0 t2 # clobbers t1
@@ -142,7 +142,7 @@
li t1, -1 # SNaN
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
sll t0, t0, 5
bgez t0, 1f # 16 / 32 register mode?
@@ -164,7 +164,7 @@
dmtc1 t1, $f31
1:
#endif
-
+
#ifdef CONFIG_CPU_MIPS32
mtc1 t1, $f0
mtc1 t1, $f1
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 3a240e3..12b531c 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -241,7 +241,7 @@
if (*tmp)
strcat(command_line, tmp);
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/* HACK: Guess if the sign extension was forgotten */
if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
start |= 0xffffffff00000000;
@@ -446,7 +446,7 @@
{
int i;
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
/*
* The 64bit code in 32bit object format trick can't represent
* 64bit wide relocations for linker script symbols.
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index f6875f0..8ddfbd8 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -558,7 +558,7 @@
if (!used_math())
goto out;
- /*
+ /*
* Save FPU state to signal context. Signal handler will "inherit"
* current FPU state.
*/
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index f3bf0e4..b465954 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -632,10 +632,7 @@
write_seqlock_irq(&xtime_lock);
xtime.tv_sec = value;
xtime.tv_nsec = 0;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
return 0;
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 648c822..0dd0df7a 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -223,10 +223,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
@@ -442,7 +439,7 @@
* called as close as possible to 500 ms before the new second starts.
*/
write_seqlock(&xtime_lock);
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 56c36e4..a53b1ed 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -924,7 +924,7 @@
* flag that some firmware may have left set and the TS bit (for
* IP27). Set XX for ISA IV code to work.
*/
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
#endif
if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 3f24a1d..36c5212 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -240,7 +240,7 @@
break;
case lwu_op:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
@@ -278,13 +278,13 @@
*newvalue = value;
*regptr = ®s->regs[insn.i_format.rt];
break;
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
case ld_op:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
@@ -320,7 +320,7 @@
*newvalue = value;
*regptr = ®s->regs[insn.i_format.rt];
break;
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
@@ -392,7 +392,7 @@
break;
case sd_op:
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
@@ -428,7 +428,7 @@
if (res)
goto fault;
break;
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index e830d78..482ac31 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -15,7 +15,7 @@
/* This is the value for an Origin kernel, taken from an IRIX kernel. */
/* . = 0xc00000000001c000; */
- /* Set the vaddr for the text segment to a value
+ /* Set the vaddr for the text segment to a value
>= 0xa800 0000 0001 9000 if no symmon is going to configured
>= 0xa800 0000 0030 0000 otherwise */
diff --git a/arch/mips/lasat/at93c.c b/arch/mips/lasat/at93c.c
index f6add04..ca26e55 100644
--- a/arch/mips/lasat/at93c.c
+++ b/arch/mips/lasat/at93c.c
@@ -1,7 +1,7 @@
-/*
+/*
* Atmel AT93C46 serial eeprom driver
*
- * Brian Murphy <brian.murphy@eicon.com>
+ * Brian Murphy <brian.murphy@eicon.com>
*
*/
#include <linux/kernel.h>
@@ -21,12 +21,12 @@
struct at93c_defs *at93c;
-static void at93c_reg_write(u32 val)
+static void at93c_reg_write(u32 val)
{
*at93c->reg = val;
}
-static u32 at93c_reg_read(void)
+static u32 at93c_reg_read(void)
{
u32 tmp = *at93c->reg;
return tmp;
@@ -81,7 +81,7 @@
}
static void at93c_write_bits(u32 data, int size)
-{
+{
int i;
int shift = size - 1;
u32 mask = (1 << shift);
@@ -90,7 +90,7 @@
at93c_write_databit((data & mask) >> shift);
data <<= 1;
}
-}
+}
static void at93c_init_op(void)
{
@@ -104,8 +104,8 @@
lasat_ndelay(250);
}
-static void at93c_wait(void)
-{
+static void at93c_wait(void)
+{
at93c_init_op();
while (!at93c_read_databit())
;
diff --git a/arch/mips/lasat/at93c.h b/arch/mips/lasat/at93c.h
index a912ac2..cfe2f99 100644
--- a/arch/mips/lasat/at93c.h
+++ b/arch/mips/lasat/at93c.h
@@ -1,7 +1,7 @@
-/*
+/*
* Atmel AT93C46 serial eeprom driver
*
- * Brian Murphy <brian.murphy@eicon.com>
+ * Brian Murphy <brian.murphy@eicon.com>
*
*/
diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c
index 7bbf6cf..9d7812e 100644
--- a/arch/mips/lasat/ds1603.c
+++ b/arch/mips/lasat/ds1603.c
@@ -1,7 +1,7 @@
-/*
- * Dallas Semiconductors 1603 RTC driver
+/*
+ * Dallas Semiconductors 1603 RTC driver
*
- * Brian Murphy <brian@murphy.dk>
+ * Brian Murphy <brian@murphy.dk>
*
*/
#include <linux/kernel.h>
@@ -20,12 +20,12 @@
struct ds_defs *ds1603 = NULL;
/* HW specific register functions */
-static void rtc_reg_write(unsigned long val)
+static void rtc_reg_write(unsigned long val)
{
*ds1603->reg = val;
}
-static unsigned long rtc_reg_read(void)
+static unsigned long rtc_reg_read(void)
{
unsigned long tmp = *ds1603->reg;
return tmp;
@@ -80,7 +80,7 @@
{
unsigned int data;
- data = (rtc_datareg_read() & (1 << ds1603->data_read_shift))
+ data = (rtc_datareg_read() & (1 << ds1603->data_read_shift))
>> ds1603->data_read_shift;
rtc_cycle_clock(rtc_reg_read());
return data;
diff --git a/arch/mips/lasat/ds1603.h b/arch/mips/lasat/ds1603.h
index 55f3b04..c2e5c76 100644
--- a/arch/mips/lasat/ds1603.h
+++ b/arch/mips/lasat/ds1603.h
@@ -1,7 +1,7 @@
-/*
- * Dallas Semiconductors 1603 RTC driver
+/*
+ * Dallas Semiconductors 1603 RTC driver
*
- * Brian Murphy <brian@murphy.dk>
+ * Brian Murphy <brian@murphy.dk>
*
*/
#ifndef __DS1603_H
diff --git a/arch/mips/lasat/image/Makefile b/arch/mips/lasat/image/Makefile
index 18b6430..35ecd64 100644
--- a/arch/mips/lasat/image/Makefile
+++ b/arch/mips/lasat/image/Makefile
@@ -21,7 +21,7 @@
HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \
-D_kernel_entry=0x$(KERNEL_ENTRY) \
-D VERSION="\"$(Version)\"" \
- -D TIMESTAMP=$(shell date +%s)
+ -D TIMESTAMP=$(shell date +%s)
$(obj)/head.o: $(obj)/head.S $(KERNEL_IMAGE)
$(CC) -fno-pic $(HEAD_DEFINES) -I$(TOPDIR)/include -c -o $@ $<
diff --git a/arch/mips/lasat/image/head.S b/arch/mips/lasat/image/head.S
index 426bd7d..efb95f2 100644
--- a/arch/mips/lasat/image/head.S
+++ b/arch/mips/lasat/image/head.S
@@ -27,5 +27,5 @@
.word TIMESTAMP
.org 0x50
-release:
+release:
.string VERSION
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index 1148a2d..c90da16 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
- * Routines for generic manipulation of the interrupts found on the
+ * Routines for generic manipulation of the interrupts found on the
* Lasat boards.
*/
#include <linux/init.h>
@@ -101,7 +101,7 @@
return *lasat_int_status & *lasat_int_mask;
}
-static unsigned long get_int_status_200(void)
+static unsigned long get_int_status_200(void)
{
unsigned long int_status;
diff --git a/arch/mips/lasat/lasat_board.c b/arch/mips/lasat/lasat_board.c
index 8c784bc..fc9b0e2 100644
--- a/arch/mips/lasat/lasat_board.c
+++ b/arch/mips/lasat/lasat_board.c
@@ -67,7 +67,7 @@
if (mips_machtype == MACH_LASAT_100) {
lasat_board_info.li_flash_base = 0x1e000000;
-
+
lb[LASAT_MTD_BOOTLOADER] = 0x1e400000;
if (lasat_board_info.li_flash_size > 0x200000) {
@@ -103,7 +103,7 @@
memset(&lasat_board_info, 0, sizeof(lasat_board_info));
/* First read the EEPROM info */
- EEPROMRead(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
+ EEPROMRead(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
sizeof(struct lasat_eeprom_struct));
/* Check the CRC */
@@ -188,7 +188,7 @@
case 0x1:
lasat_board_info.li_cpu_hz =
lasat_board_info.li_bus_hz +
- (lasat_board_info.li_bus_hz >> 1);
+ (lasat_board_info.li_bus_hz >> 1);
break;
case 0x2:
lasat_board_info.li_cpu_hz =
@@ -271,7 +271,7 @@
lasat_board_info.li_eeprom_info.crc32 = crc;
/* Write the EEPROM info */
- EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
+ EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
sizeof(struct lasat_eeprom_struct));
}
diff --git a/arch/mips/lasat/picvue.c b/arch/mips/lasat/picvue.c
index 5637cd1..9ae82c3 100644
--- a/arch/mips/lasat/picvue.c
+++ b/arch/mips/lasat/picvue.c
@@ -1,7 +1,7 @@
-/*
+/*
* Picvue PVC160206 display driver
*
- * Brian Murphy <brian@murphy.dk>
+ * Brian Murphy <brian@murphy.dk>
*
*/
#include <linux/kernel.h>
@@ -24,12 +24,12 @@
DECLARE_MUTEX(pvc_sem);
-static void pvc_reg_write(u32 val)
+static void pvc_reg_write(u32 val)
{
*picvue->reg = val;
}
-static u32 pvc_reg_read(void)
+static u32 pvc_reg_read(void)
{
u32 tmp = *picvue->reg;
return tmp;
@@ -65,12 +65,12 @@
{
u32 data = pvc_reg_read();
u8 byte;
- data |= picvue->rw;
+ data |= picvue->rw;
data &= ~picvue->rs;
pvc_reg_write(data);
ndelay(40);
byte = pvc_read_byte(data);
- data |= picvue->rs;
+ data |= picvue->rs;
pvc_reg_write(data);
return byte;
}
diff --git a/arch/mips/lasat/picvue.h b/arch/mips/lasat/picvue.h
index 74a3903..2a96bf9 100644
--- a/arch/mips/lasat/picvue.h
+++ b/arch/mips/lasat/picvue.h
@@ -1,7 +1,7 @@
-/*
+/*
* Picvue PVC160206 display driver
*
- * Brian Murphy <brian.murphy@eicon.com>
+ * Brian Murphy <brian.murphy@eicon.com>
*
*/
#include <asm/semaphore.h>
diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c
index eaa2b46..cce7cdd 100644
--- a/arch/mips/lasat/picvue_proc.c
+++ b/arch/mips/lasat/picvue_proc.c
@@ -1,7 +1,7 @@
-/*
+/*
* Picvue PVC160206 display driver
*
- * Brian Murphy <brian.murphy@eicon.com>
+ * Brian Murphy <brian.murphy@eicon.com>
*
*/
#include <linux/kernel.h>
@@ -51,10 +51,10 @@
page += sprintf(page, "%s\n", pvc_lines[lineno]);
up(&pvc_sem);
- return page - origpage;
+ return page - origpage;
}
-static int pvc_proc_write_line(struct file *file, const char *buffer,
+static int pvc_proc_write_line(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int origcount = count;
@@ -119,7 +119,7 @@
page += sprintf(page, "%d\n", scroll_dir * scroll_interval);
up(&pvc_sem);
- return page - origpage;
+ return page - origpage;
}
diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c
index ca62881..88c7ab8 100644
--- a/arch/mips/lasat/prom.c
+++ b/arch/mips/lasat/prom.c
@@ -42,7 +42,7 @@
/* these are functions provided by the bootloader */
static void (* prom_putc)(char c) = null_prom_putc;
void (* prom_printf)(const char * fmt, ...) = null_prom_printf;
-void (* prom_display)(const char *string, int pos, int clear) =
+void (* prom_display)(const char *string, int pos, int clear) =
null_prom_display;
void (* prom_monitor)(void) = null_prom_monitor;
diff --git a/arch/mips/lasat/reset.c b/arch/mips/lasat/reset.c
index 37e4912..8d7d7a4 100644
--- a/arch/mips/lasat/reset.c
+++ b/arch/mips/lasat/reset.c
@@ -1,4 +1,4 @@
-/*
+/*
* Thomas Horsten <thh@lasat.com>
* Copyright (C) 2000 LASAT Networks A/S.
*
diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
index e371ed5..f2604fa 100644
--- a/arch/mips/lasat/setup.c
+++ b/arch/mips/lasat/setup.c
@@ -105,7 +105,7 @@
return NOTIFY_DONE;
}
-static struct notifier_block lasat_panic_block[] =
+static struct notifier_block lasat_panic_block[] =
{
{ lasat_panic_display, NULL, INT_MAX },
{ lasat_panic_prom_monitor, NULL, INT_MIN }
@@ -120,7 +120,7 @@
{
write_c0_compare(
- read_c0_count() +
+ read_c0_count() +
mips_hpt_frequency / HZ);
change_c0_status(ST0_IM, IE_IRQ0 | IE_IRQ5);
}
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c
index 1c0cc62..8ff43a1 100644
--- a/arch/mips/lasat/sysctl.c
+++ b/arch/mips/lasat/sysctl.c
@@ -37,14 +37,14 @@
static DECLARE_MUTEX(lasat_info_sem);
-/* Strategy function to write EEPROM after changing string entry */
+/* Strategy function to write EEPROM after changing string entry */
int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen, void **context)
{
int r;
down(&lasat_info_sem);
- r = sysctl_string(table, name,
+ r = sysctl_string(table, name,
nlen, oldval, oldlenp, newval, newlen, context);
if (r < 0) {
up(&lasat_info_sem);
@@ -74,7 +74,7 @@
return 0;
}
-/* proc function to write EEPROM after changing int entry */
+/* proc function to write EEPROM after changing int entry */
int proc_dolasatint(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp, loff_t *ppos)
{
@@ -93,7 +93,7 @@
static int rtctmp;
#ifdef CONFIG_DS1603
-/* proc function to read/write RealTime Clock */
+/* proc function to read/write RealTime Clock */
int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp, loff_t *ppos)
{
@@ -165,9 +165,9 @@
void update_bcastaddr(void)
{
unsigned int ip;
-
- ip = (lasat_board_info.li_eeprom_info.ipaddr &
- lasat_board_info.li_eeprom_info.netmask) |
+
+ ip = (lasat_board_info.li_eeprom_info.ipaddr &
+ lasat_board_info.li_eeprom_info.netmask) |
~lasat_board_info.li_eeprom_info.netmask;
sprintf(lasat_bcastaddr, "%d.%d.%d.%d",
@@ -205,7 +205,7 @@
break;
len++;
}
- if (len >= sizeof(proc_lasat_ipbuf)-1)
+ if (len >= sizeof(proc_lasat_ipbuf)-1)
len = sizeof(proc_lasat_ipbuf) - 1;
if (copy_from_user(proc_lasat_ipbuf, buffer, len))
{
@@ -249,8 +249,8 @@
}
#endif /* defined(CONFIG_INET) */
-static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
- void *oldval, size_t *oldlenp,
+static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
void *newval, size_t newlen,
void **context)
{
@@ -293,7 +293,7 @@
if (!strcmp(filp->f_dentry->d_name.name, "debugaccess"))
lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
}
- lasat_write_eeprom_info();
+ lasat_write_eeprom_info();
up(&lasat_info_sem);
return 0;
}
@@ -316,8 +316,8 @@
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,
+ {LASAT_BCAST, "bcastaddr", &lasat_bcastaddr,
+ sizeof(lasat_bcastaddr), 0600, NULL,
&proc_dostring, &sysctl_string},
#endif
{LASAT_PASSWORD, "passwd_hash", &lasat_board_info.li_eeprom_info.passwd_hash, sizeof(lasat_board_info.li_eeprom_info.passwd_hash),
diff --git a/arch/mips/lib-32/Makefile b/arch/mips/lib-32/Makefile
index fd6a2ba..ad28578 100644
--- a/arch/mips/lib-32/Makefile
+++ b/arch/mips/lib-32/Makefile
@@ -2,7 +2,7 @@
# Makefile for MIPS-specific library files..
#
-lib-y += csum_partial.o memset.o watch.o
+lib-y += csum_partial.o memset.o watch.o
obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o
obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o
diff --git a/arch/mips/lib-64/Makefile b/arch/mips/lib-64/Makefile
index fd6a2ba..ad28578 100644
--- a/arch/mips/lib-64/Makefile
+++ b/arch/mips/lib-64/Makefile
@@ -2,7 +2,7 @@
# Makefile for MIPS-specific library files..
#
-lib-y += csum_partial.o memset.o watch.o
+lib-y += csum_partial.o memset.o watch.o
obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o
obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o
diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S
index afa8eae..90ee8d4 100644
--- a/arch/mips/lib/memcpy.S
+++ b/arch/mips/lib/memcpy.S
@@ -79,7 +79,7 @@
/*
* Only on the 64-bit kernel we can made use of 64-bit registers.
*/
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define USE_DOUBLE
#endif
@@ -101,7 +101,7 @@
#define NBYTES 8
#define LOG_NBYTES 3
-/*
+/*
* As we are sharing code base with the mips32 tree (which use the o32 ABI
* register definitions). We need to redefine the register definitions from
* the n64 ABI register naming to the o32 ABI register naming.
@@ -118,7 +118,7 @@
#define t5 $13
#define t6 $14
#define t7 $15
-
+
#else
#define LOAD lw
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 20a552b..99c5506 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -320,7 +320,7 @@
case cop1_op:
switch (MIPSInst_RS(ir)) {
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
case dmfc_op:
/* copregister fs -> gpr[rt] */
if (MIPSInst_RT(ir) != 0) {
@@ -805,7 +805,7 @@
ieee754dp d;
ieee754sp s;
int w;
-#if __mips64
+#ifdef __mips64
s64 l;
#endif
} rv; /* resulting value */
@@ -950,7 +950,7 @@
}
#endif /* __mips >= 2 */
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
case fcvtl_op:{
ieee754sp fs;
@@ -1125,7 +1125,7 @@
}
#endif
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
case fcvtl_op:{
ieee754dp fs;
@@ -1203,7 +1203,7 @@
break;
}
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
case l_fmt:{
switch (MIPSInst_FUNC(ir)) {
case fcvts_op:
@@ -1267,7 +1267,7 @@
case w_fmt:
SITOREG(rv.w, MIPSInst_FD(ir));
break;
-#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
case l_fmt:
DITOREG(rv.l, MIPSInst_FD(ir));
break;
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
index 04397fec..4002f0c 100644
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -86,7 +86,7 @@
return err;
}
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* This is the o32 version
*/
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
index 8f1d875..19d4b07 100644
--- a/arch/mips/mips-boards/atlas/atlas_int.c
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -122,7 +122,7 @@
int i;
atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *));
-
+
/*
* Mask out all interrupt by writing "1" to all bit position in
* the interrupt reset reg.
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
index 31caf06..311155d 100644
--- a/arch/mips/mips-boards/generic/init.c
+++ b/arch/mips/mips-boards/generic/init.c
@@ -200,7 +200,7 @@
generic_putDebugChar = saa9730_putDebugChar;
generic_getDebugChar = saa9730_getDebugChar;
}
- else
+ else
#endif
{
speed = rs_kgdb_hook(line, speed);
@@ -243,7 +243,7 @@
mips_revision_corid = MIPS_REVISION_CORID;
if (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL) {
- if (BONITO_PCIDID == 0x0001df53 ||
+ if (BONITO_PCIDID == 0x0001df53 ||
BONITO_PCIDID == 0x0003df53)
mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_BON;
else
@@ -310,7 +310,7 @@
case MIPS_REVISION_CORID_CORE_MSC:
case MIPS_REVISION_CORID_CORE_FPGA2:
case MIPS_REVISION_CORID_CORE_EMUL_MSC:
- _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000);
+ _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000);
#ifdef CONFIG_CPU_LITTLE_ENDIAN
MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP);
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index fe7fc17..1631544 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -89,7 +89,7 @@
* really calculate the timer frequency
* For now we hardwire the SEAD board frequency to 12MHz.
*/
-
+
if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
(prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
count = 12000000;
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 3377e66..df6db64 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -149,15 +149,15 @@
argptr = prom_getcmdline();
if (strstr(argptr, "iobcuncached")) {
BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
- BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
+ BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
printk("Disabled Bonito IOBC coherency\n");
}
else {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
- BONITO_PCIMEMBASECFG |=
- (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
+ BONITO_PCIMEMBASECFG |=
+ (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
printk("Disabled Bonito IOBC coherency\n");
}
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index f61e038..b56a0ab 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -5,8 +5,8 @@
obj-y += cache.o extable.o fault.o init.o pgtable.o \
tlbex.o tlbex-fault.o
-obj-$(CONFIG_MIPS32) += ioremap.o pgtable-32.o
-obj-$(CONFIG_MIPS64) += pgtable-64.o
+obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
+obj-$(CONFIG_64BIT) += pgtable-64.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index a03ebb2..5ea84bc 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -126,13 +126,13 @@
CACHE32_UNROLL32_ALIGN2;
/* I'm in even chunk. blast odd chunks */
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
cache32_unroll32(addr|ws,Index_Invalidate_I);
CACHE32_UNROLL32_ALIGN;
/* I'm in odd chunk. blast even chunks */
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400 * 2)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400 * 2)
cache32_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -156,13 +156,13 @@
CACHE32_UNROLL32_ALIGN2;
/* I'm in even chunk. blast odd chunks */
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start + 0x400; addr < end; addr += 0x400 * 2)
cache32_unroll32(addr|ws,Index_Invalidate_I);
CACHE32_UNROLL32_ALIGN;
/* I'm in odd chunk. blast even chunks */
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400 * 2)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400 * 2)
cache32_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -723,10 +723,10 @@
".set push\n\t"
".set noat\n\t"
".set mips3\n\t"
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
"la $at,1f\n\t"
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
"dla $at,1f\n\t"
#endif
"cache %0,($at)\n\t"
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
index ab30afd..502f68c 100644
--- a/arch/mips/mm/c-sb1.c
+++ b/arch/mips/mm/c-sb1.c
@@ -270,7 +270,7 @@
__sb1_writeback_inv_dcache_all();
else
__sb1_writeback_inv_dcache_range(start, end);
-
+
/* Just flush the whole icache if the range is big enough */
if ((end - start) > icache_range_cutoff)
__sb1_flush_icache_all();
diff --git a/arch/mips/mm/cerr-sb1.c b/arch/mips/mm/cerr-sb1.c
index 13d96d6..7166ffe 100644
--- a/arch/mips/mm/cerr-sb1.c
+++ b/arch/mips/mm/cerr-sb1.c
@@ -25,7 +25,7 @@
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_scd.h>
#endif
-
+
/* SB1 definitions */
/* XXX should come from config1 XXX */
@@ -136,14 +136,14 @@
#ifndef CONFIG_SIBYTE_BUS_WATCHER
-static void check_bus_watcher(void)
-{
+static void check_bus_watcher(void)
+{
uint32_t status, l2_err, memio_err;
/* Destructive read, clears register and interrupt */
status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
/* Bit 31 is always on, but there's no #define for that */
- if (status & ~(1UL << 31)) {
+ if (status & ~(1UL << 31)) {
l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
prom_printf("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
@@ -153,14 +153,14 @@
(int)(G_SCD_BERR_TID(status) >> 6),
(int)G_SCD_BERR_RID(status),
(int)G_SCD_BERR_DCODE(status));
- } else {
- prom_printf("Bus watcher indicates no error\n");
- }
-}
-#else
-extern void check_bus_watcher(void);
-#endif
-
+ } else {
+ prom_printf("Bus watcher indicates no error\n");
+ }
+}
+#else
+extern void check_bus_watcher(void);
+#endif
+
asmlinkage void sb1_cache_error(void)
{
uint64_t cerr_dpa;
diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c
index 9895e32..59e54f1 100644
--- a/arch/mips/mm/dma-noncoherent.c
+++ b/arch/mips/mm/dma-noncoherent.c
@@ -162,7 +162,7 @@
for (i = 0; i < nents; i++, sg++) {
unsigned long addr;
-
+
addr = (unsigned long) page_address(sg->page);
if (addr)
__dma_sync(addr + sg->offset, sg->length, direction);
@@ -230,9 +230,9 @@
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);
}
@@ -282,9 +282,9 @@
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),
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 9c9a271..dc6830b 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -96,7 +96,7 @@
kmap_prot = PAGE_KERNEL;
}
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
static void __init fixrange_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
@@ -125,7 +125,7 @@
j = 0;
}
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
#endif /* CONFIG_HIGHMEM */
#ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -258,7 +258,7 @@
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/* Switch from KSEG0 to XKPHYS addresses */
start = (unsigned long)phys_to_virt(CPHYSADDR(start));
end = (unsigned long)phys_to_virt(CPHYSADDR(end));
@@ -286,7 +286,7 @@
addr = (unsigned long) &__init_begin;
while (addr < (unsigned long) &__init_end) {
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
page = PAGE_OFFSET | CPHYSADDR(addr);
#else
page = addr;
diff --git a/arch/mips/mm/pg-sb1.c b/arch/mips/mm/pg-sb1.c
index 59d131b..1b6df71 100644
--- a/arch/mips/mm/pg-sb1.c
+++ b/arch/mips/mm/pg-sb1.c
@@ -114,7 +114,7 @@
" pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%1)\n"
" pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n"
"1: pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%1)\n"
-# ifdef CONFIG_MIPS64
+# ifdef CONFIG_64BIT
" ld $8, -128(%0) \n" /* Block copy a cacheline */
" ld $9, -120(%0) \n"
" ld $10, -112(%0) \n"
@@ -148,7 +148,7 @@
" daddiu %0, %0, -128 \n"
" daddiu %1, %1, -128 \n"
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
" ld $8, 0(%0) \n" /* Block copy a cacheline */
"1: ld $9, 8(%0) \n"
" ld $10, 16(%0) \n"
@@ -178,7 +178,7 @@
" daddiu %0, %0, 32 \n"
" daddiu %1, %1, 32 \n"
" bnel %0, %2, 1b \n"
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
" ld $8, 0(%0) \n"
#else
" lw $2, 0(%0) \n"
@@ -186,7 +186,7 @@
" .set pop \n"
: "+r" (src), "+r" (dst)
: "r" (end)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
: "$8","$9","$10","$11","memory");
#else
: "$2","$3","$6","$7","$8","$9","$10","$11","memory");
@@ -198,7 +198,7 @@
/*
* Pad descriptors to cacheline, since each is exclusively owned by a
- * particular CPU.
+ * particular CPU.
*/
typedef struct dmadscr_s {
u64 dscr_a;
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 87e229f..6569be3 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -448,7 +448,7 @@
L_LA(_r3000_write_probe_ok)
/* convenience macros for instructions */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
# define i_LW(buf, rs, rt, off) i_ld(buf, rs, rt, off)
# define i_SW(buf, rs, rt, off) i_sd(buf, rs, rt, off)
# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
@@ -486,7 +486,7 @@
#define i_ssnop(buf) i_sll(buf, 0, 0, 1)
#define i_ehb(buf) i_sll(buf, 0, 0, 3)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
static __init int __attribute__((unused)) in_compat_space_p(long addr)
{
/* Is this address in 32bit compat space? */
@@ -516,7 +516,7 @@
static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
{
-#if CONFIG_MIPS64
+#ifdef CONFIG_64BIT
if (!in_compat_space_p(addr)) {
i_lui(buf, rs, rel_highest(addr));
if (rel_higher(addr))
@@ -682,7 +682,7 @@
#define C0_EPC 14
#define C0_XCONTEXT 20
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
#else
# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_CONTEXT)
@@ -923,7 +923,7 @@
}
}
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* TMP and PTR are scratch.
* TMP will be clobbered, PTR will hold the pmd entry.
@@ -1010,7 +1010,7 @@
}
}
-#else /* !CONFIG_MIPS64 */
+#else /* !CONFIG_64BIT */
/*
* TMP and PTR are scratch.
@@ -1038,7 +1038,7 @@
i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
}
-#endif /* !CONFIG_MIPS64 */
+#endif /* !CONFIG_64BIT */
static __init void build_adjust_context(u32 **p, unsigned int ctx)
{
@@ -1159,7 +1159,7 @@
/* No need for i_nop */
}
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
#else
build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
@@ -1171,7 +1171,7 @@
l_leave(&l, p);
i_eret(&p); /* return from trap */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
build_get_pgd_vmalloc64(&p, &l, &r, K0, K1);
#endif
@@ -1182,7 +1182,7 @@
* need three, with the the second nop'ed and the third being
* unused.
*/
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
if ((p - tlb_handler) > 64)
panic("TLB refill handler space exceeded");
#else
@@ -1195,12 +1195,12 @@
/*
* Now fold the handler in the TLB refill handler space.
*/
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
f = final_handler;
/* Simplest case, just copy the handler. */
copy_handler(relocs, labels, tlb_handler, p, f);
final_len = p - tlb_handler;
-#else /* CONFIG_MIPS64 */
+#else /* CONFIG_64BIT */
f = final_handler + 32;
if ((p - tlb_handler) <= 32) {
/* Just copy the handler. */
@@ -1235,7 +1235,7 @@
copy_handler(relocs, labels, split, p, final_handler);
final_len = (f - (final_handler + 32)) + (p - split);
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
resolve_relocs(relocs, labels);
printk("Synthesized TLB refill handler (%u instructions).\n",
@@ -1605,7 +1605,7 @@
struct reloc **r, unsigned int pte,
unsigned int ptr)
{
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
#else
build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
@@ -1636,7 +1636,7 @@
l_leave(l, *p);
i_eret(p); /* return from trap */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
build_get_pgd_vmalloc64(p, l, r, tmp, ptr);
#endif
}
diff --git a/arch/mips/momentum/jaguar_atx/int-handler.S b/arch/mips/momentum/jaguar_atx/int-handler.S
index 43fd5a5..55bc789 100644
--- a/arch/mips/momentum/jaguar_atx/int-handler.S
+++ b/arch/mips/momentum/jaguar_atx/int-handler.S
@@ -27,11 +27,11 @@
SAVE_ALL
CLI
.set at
- mfc0 t0, CP0_CAUSE
+ mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
-
+
andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
bnez t1, ll_sw0_irq
andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
@@ -103,25 +103,25 @@
move a1, sp
jal do_IRQ
j ret_from_irq
-
+
ll_pcib_irq:
li a0, 5
move a1, sp
jal do_IRQ
j ret_from_irq
-
+
ll_uart_irq:
li a0, 6
move a1, sp
jal do_IRQ
j ret_from_irq
-
+
ll_cputimer_irq:
li a0, 7
move a1, sp
jal ll_timer_interrupt
j ret_from_irq
-
+
ll_mv64340_decode_irq:
move a0, sp
jal ll_mv64340_irq
diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c
index fa5982a..14ae2e7 100644
--- a/arch/mips/momentum/jaguar_atx/prom.c
+++ b/arch/mips/momentum/jaguar_atx/prom.c
@@ -64,7 +64,7 @@
/* turn the clock off and read-strobe */
JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-
+
/* return the data */
return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
}
@@ -90,7 +90,7 @@
}
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
unsigned long signext(unsigned long addr)
{
@@ -143,7 +143,7 @@
return p;
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/* PMON passes arguments in C main() style */
void __init prom_init(void)
@@ -158,7 +158,7 @@
// ja_setup_console(); /* The very first thing. */
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
char *ptr;
printk("Mips64 Jaguar-ATX\n");
@@ -201,7 +201,7 @@
}
printk("arcs_cmdline: %s\n", arcs_cmdline);
-#else /* CONFIG_MIPS64 */
+#else /* CONFIG_64BIT */
/* save the PROM vectors for debugging use */
debug_vectors = cv;
@@ -226,7 +226,7 @@
}
env++;
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
mips_machgroup = MACH_GROUP_MOMENCO;
mips_machtype = MACH_MOMENCO_JAGUAR_ATX;
diff --git a/arch/mips/momentum/jaguar_atx/reset.c b/arch/mips/momentum/jaguar_atx/reset.c
index 4803948..c4236b1 100644
--- a/arch/mips/momentum/jaguar_atx/reset.c
+++ b/arch/mips/momentum/jaguar_atx/reset.c
@@ -27,7 +27,7 @@
void momenco_jaguar_restart(char *command)
{
/* base address of timekeeper portion of part */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
void *nvram = (void*) 0xfffffffffc807000;
#else
void *nvram = (void*) 0xfc807000;
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
index 30462e7..90288cf 100644
--- a/arch/mips/momentum/jaguar_atx/setup.c
+++ b/arch/mips/momentum/jaguar_atx/setup.c
@@ -105,7 +105,7 @@
static __init void wire_stupidity_into_tlb(void)
{
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
write_c0_wired(0);
local_flush_tlb_all();
@@ -451,7 +451,7 @@
#ifdef GEMDEBUG_TRACEBUFFER
{
unsigned int tbControl;
- tbControl =
+ tbControl =
0 << 26 | /* post trigger delay 0 */
0x2 << 16 | /* sequential trace mode */
// 0x0 << 16 | /* non-sequential trace mode */
diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c
index 89c17a0..c4fa9c5 100644
--- a/arch/mips/momentum/ocelot_3/prom.c
+++ b/arch/mips/momentum/ocelot_3/prom.c
@@ -93,7 +93,7 @@
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
unsigned long signext(unsigned long addr)
{
@@ -145,7 +145,7 @@
return p;
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
void __init prom_init(void)
{
@@ -155,7 +155,7 @@
struct callvectors *cv = (struct callvectors *) fw_arg3;
int i;
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
char *ptr;
printk("prom_init - MIPS64\n");
@@ -198,7 +198,7 @@
}
printk("arcs_cmdline: %s\n", arcs_cmdline);
-#else /* CONFIG_MIPS64 */
+#else /* CONFIG_64BIT */
/* save the PROM vectors for debugging use */
debug_vectors = cv;
@@ -224,7 +224,7 @@
}
env++;
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
mips_machgroup = MACH_GROUP_MOMENCO;
mips_machtype = MACH_MOMENCO_OCELOT_3;
@@ -234,7 +234,7 @@
get_mac(prom_mac_addr_base);
#endif
-#ifndef CONFIG_MIPS64
+#ifndef CONFIG_64BIT
debug_vectors->printf("Booting Linux kernel...\n");
#endif
}
diff --git a/arch/mips/momentum/ocelot_c/int-handler.S b/arch/mips/momentum/ocelot_c/int-handler.S
index 2f24306..52349d9 100644
--- a/arch/mips/momentum/ocelot_c/int-handler.S
+++ b/arch/mips/momentum/ocelot_c/int-handler.S
@@ -27,11 +27,11 @@
SAVE_ALL
CLI
.set at
- mfc0 t0, CP0_CAUSE
+ mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
-
+
andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
bnez t1, ll_sw0_irq
andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
@@ -83,7 +83,7 @@
move a1, sp
jal do_IRQ
j ret_from_irq
-
+
ll_cpci_decode_irq:
move a0, sp
jal ll_cpci_irq
@@ -99,4 +99,4 @@
move a1, sp
jal do_IRQ
j ret_from_irq
-
+
diff --git a/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h b/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
index a6cf7a7..97fb77da 100644
--- a/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
+++ b/arch/mips/momentum/ocelot_c/ocelot_c_fpga.h
@@ -32,7 +32,7 @@
#include <linux/config.h>
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define OCELOT_C_CS0_ADDR (0xfffffffffc000000)
#else
#define OCELOT_C_CS0_ADDR (0xfc000000)
diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c
index 49ac302..5b68097 100644
--- a/arch/mips/momentum/ocelot_c/prom.c
+++ b/arch/mips/momentum/ocelot_c/prom.c
@@ -67,7 +67,7 @@
/* turn the clock off and read-strobe */
OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-
+
/* return the data */
return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
}
@@ -94,7 +94,7 @@
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
unsigned long signext(unsigned long addr)
{
@@ -144,7 +144,7 @@
p = (char *)get_arg(args, arg_index);
return p;
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
void __init prom_init(void)
@@ -155,7 +155,7 @@
struct callvectors *cv = (struct callvectors *) fw_arg3;
int i;
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
char *ptr;
printk("prom_init - MIPS64\n");
@@ -197,7 +197,7 @@
}
printk("arcs_cmdline: %s\n", arcs_cmdline);
-#else /* CONFIG_MIPS64 */
+#else /* CONFIG_64BIT */
/* save the PROM vectors for debugging use */
debug_vectors = cv;
@@ -222,7 +222,7 @@
}
env++;
}
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
mips_machgroup = MACH_GROUP_MOMENCO;
mips_machtype = MACH_MOMENCO_OCELOT_C;
@@ -232,7 +232,7 @@
get_mac(prom_mac_addr_base);
#endif
-#ifndef CONFIG_MIPS64
+#ifndef CONFIG_64BIT
debug_vectors->printf("Booting Linux kernel...\n");
#endif
}
diff --git a/arch/mips/momentum/ocelot_c/reset.c b/arch/mips/momentum/ocelot_c/reset.c
index 1f2b426..6a2489f 100644
--- a/arch/mips/momentum/ocelot_c/reset.c
+++ b/arch/mips/momentum/ocelot_c/reset.c
@@ -28,7 +28,7 @@
{
/* base address of timekeeper portion of part */
void *nvram = (void *)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
0xfffffffffc807000;
#else
0xfc807000;
diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c
index 021c00e..844ddd0 100644
--- a/arch/mips/momentum/ocelot_c/setup.c
+++ b/arch/mips/momentum/ocelot_c/setup.c
@@ -109,7 +109,7 @@
*/
printk("PMON_v2_setup\n");
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/* marvell and extra space */
add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), 0xfffffffff4000000, PM_64K);
/* fpga, rtc, and uart */
@@ -134,7 +134,7 @@
unsigned long m48t37y_get_time(void)
{
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
unsigned char *rtc_base = (unsigned char*)0xfffffffffc800000;
#else
unsigned char* rtc_base = (unsigned char*)0xfc800000;
@@ -163,7 +163,7 @@
int m48t37y_set_time(unsigned long sec)
{
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
unsigned char* rtc_base = (unsigned char*)0xfffffffffc800000;
#else
unsigned char* rtc_base = (unsigned char*)0xfc800000;
@@ -342,7 +342,7 @@
early_initcall(momenco_ocelot_c_setup);
-#ifndef CONFIG_MIPS64
+#ifndef CONFIG_64BIT
/* This needs to be one of the first initcalls, because no I/O port access
can work before this */
static int io_base_ioremap(void)
diff --git a/arch/mips/pci/fixup-ddb5074.c b/arch/mips/pci/fixup-ddb5074.c
index b345e52..5a4a7c2 100644
--- a/arch/mips/pci/fixup-ddb5074.c
+++ b/arch/mips/pci/fixup-ddb5074.c
@@ -5,7 +5,7 @@
{
extern struct pci_dev *pci_pmu;
u8 t8;
-
+
pci_pmu = dev; /* for LEDs D2 and D3 */
/* Program the lines for LEDs D2 and D3 to output */
pci_read_config_byte(dev, 0x7d, &t8);
diff --git a/arch/mips/pci/fixup-ddb5477.c b/arch/mips/pci/fixup-ddb5477.c
index 6abdc88..2f1444e 100644
--- a/arch/mips/pci/fixup-ddb5477.c
+++ b/arch/mips/pci/fixup-ddb5477.c
@@ -65,7 +65,7 @@
ioaddr = pci_resource_start(dev, 0);
inw(ioaddr + PCNET32_WIO_RESET); /* reset chip */
-
+
/* bcr_18 |= 0x0800 */
outw(18, ioaddr + PCNET32_WIO_RAP);
temp = inw(ioaddr + PCNET32_WIO_BDP);
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
index b9296d9..bf2c41d 100644
--- a/arch/mips/pci/fixup-malta.c
+++ b/arch/mips/pci/fixup-malta.c
@@ -56,7 +56,7 @@
0, 0, 0, 3,
4, 5, 6, 7,
0, 9, 10, 11,
- 12, 0, 14, 15
+ 12, 0, 14, 15
};
int i;
diff --git a/arch/mips/pci/fixup-rbtx4927.c b/arch/mips/pci/fixup-rbtx4927.c
index de4e443..ceeb186 100644
--- a/arch/mips/pci/fixup-rbtx4927.c
+++ b/arch/mips/pci/fixup-rbtx4927.c
@@ -7,7 +7,7 @@
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
- * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2000-2001 Toshiba Corporation
*
* Copyright (C) 2004 MontaVista Software Inc.
* Author: Manish Lachwani (mlachwani@mvista.com)
diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c
index c8ef01a..a176f2c 100644
--- a/arch/mips/pci/fixup-sni.c
+++ b/arch/mips/pci/fixup-sni.c
@@ -32,7 +32,7 @@
* Device 4: Unused
* Device 5: Slot 2
* Device 6: Slot 3
- * Device 7: Slot 4
+ * Device 7: Slot 4
*
* Documentation says the VGA is device 5 and device 3 is unused but that
* seem to be a documentation error. At least on my RM200C the Cirrus
diff --git a/arch/mips/pci/fixup-tb0219.c b/arch/mips/pci/fixup-tb0219.c
index 850a900..bc55b06 100644
--- a/arch/mips/pci/fixup-tb0219.c
+++ b/arch/mips/pci/fixup-tb0219.c
@@ -29,27 +29,12 @@
switch (slot) {
case 12:
- vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN,
- TRIGGER_LEVEL,
- SIGNAL_THROUGH);
- vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN,
- LEVEL_LOW);
irq = TB0219_PCI_SLOT1_IRQ;
break;
case 13:
- vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN,
- TRIGGER_LEVEL,
- SIGNAL_THROUGH);
- vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN,
- LEVEL_LOW);
irq = TB0219_PCI_SLOT2_IRQ;
break;
case 14:
- vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN,
- TRIGGER_LEVEL,
- SIGNAL_THROUGH);
- vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN,
- LEVEL_LOW);
irq = TB0219_PCI_SLOT3_IRQ;
break;
default:
diff --git a/arch/mips/pci/ops-ddb5477.c b/arch/mips/pci/ops-ddb5477.c
index e955443..0406b50 100644
--- a/arch/mips/pci/ops-ddb5477.c
+++ b/arch/mips/pci/ops-ddb5477.c
@@ -127,7 +127,7 @@
}
static int read_config_dword(struct pci_config_swap *swap,
- struct pci_bus *bus, u32 devfn, u32 where,
+ struct pci_bus *bus, u32 devfn, u32 where,
u32 * val)
{
u32 bus_num, slot_num, func_num;
@@ -153,7 +153,7 @@
}
static int read_config_word(struct pci_config_swap *swap,
- struct pci_bus *bus, u32 devfn, u32 where,
+ struct pci_bus *bus, u32 devfn, u32 where,
u16 * val)
{
int status;
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c
index 2a9d722..7688b77 100644
--- a/arch/mips/pci/ops-tx4927.c
+++ b/arch/mips/pci/ops-tx4927.c
@@ -1,16 +1,16 @@
/*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
- * ahennessy@mvista.com
+ * ahennessy@mvista.com
*
- * Copyright (C) 2000-2001 Toshiba Corporation
+ * Copyright (C) 2000-2001 Toshiba Corporation
* Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
*
* Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
*
* Define the pci_ops for the Toshiba rbtx4927
*
- * Much of the code is derived from the original DDB5074 port by
+ * Much of the code is derived from the original DDB5074 port by
* Geert Uytterhoeven <geert@sonycom.com>
*
* Copyright 2004 MontaVista Software Inc.
diff --git a/arch/mips/pci/pci-ddb5477.c b/arch/mips/pci/pci-ddb5477.c
index 4ddd53e..826d653 100644
--- a/arch/mips/pci/pci-ddb5477.c
+++ b/arch/mips/pci/pci-ddb5477.c
@@ -76,7 +76,7 @@
*/
/*
- * irq mapping : device -> pci int # -> vrc4377 irq# ,
+ * irq mapping : device -> pci int # -> vrc4377 irq# ,
* ddb5477 board manual page 4 and vrc5477 manual page 46
*/
@@ -137,9 +137,9 @@
unsigned char *slot_irq_map;
unsigned char irq;
- /*
+ /*
* We ignore the swizzled slot and pin values. The original
- * pci_fixup_irq() codes largely base irq number on the dev slot
+ * pci_fixup_irq() codes largely base irq number on the dev slot
* numbers because except for one case they are unique even
* though there are multiple pci buses.
*/
@@ -160,7 +160,7 @@
if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
/* hack to distinquish overlapping slot 20s, one
- * on bus 0 (ALI USB on the M1535 on the backplane),
+ * on bus 0 (ALI USB on the M1535 on the backplane),
* and one on bus 2 (NEC USB controller on the CPU board)
* Make the M1535 USB - ISA IRQ number 9.
*/
diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c
index 1faeb03..000dc6a 100644
--- a/arch/mips/pci/pci-ip32.c
+++ b/arch/mips/pci/pci-ip32.c
@@ -84,7 +84,7 @@
extern struct pci_ops mace_pci_ops;
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
static struct resource mace_pci_mem_resource = {
.name = "SGI O2 PCI MEM",
.start = MACEPCI_HI_MEMORY,
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 8141dff..a8d499b 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -132,7 +132,7 @@
hose->need_domain_info = need_domain_info;
next_busno = bus->subordinate + 1;
/* Don't allow 8-bit bus number overflow inside the hose -
- reserve some space for bridges. */
+ reserve some space for bridges. */
if (next_busno > 224) {
next_busno = 0;
need_domain_info = 1;
@@ -260,7 +260,7 @@
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_read_bridge_bases(bus);
pcibios_fixup_device_resources(dev, bus);
- }
+ }
for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
struct pci_dev *dev = pci_dev_b(ln);
@@ -292,8 +292,25 @@
region->end = res->end - offset;
}
+void __devinit
+pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
+{
+ struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
+ unsigned long offset = 0;
+
+ if (res->flags & IORESOURCE_IO)
+ offset = hose->io_offset;
+ else if (res->flags & IORESOURCE_MEM)
+ offset = hose->mem_offset;
+
+ res->start = region->start + offset;
+ res->end = region->end + offset;
+}
+
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pcibios_resource_to_bus);
+EXPORT_SYMBOL(pcibios_bus_to_resource);
EXPORT_SYMBOL(PCIBIOS_MIN_IO);
EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
#endif
diff --git a/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.c b/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.c
index b067988..97862f4 100644
--- a/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.c
+++ b/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.c
@@ -30,7 +30,7 @@
*
* This code reads the ATMEL 24CXX EEPROM. The PMC-Sierra Yosemite board uses the ATMEL
* 24C32/24C64 which uses two byte addressing as compared to 24C16. Note that this program
- * uses the serial port like /dev/ttyS0, to communicate with the EEPROM. Hence, you are
+ * uses the serial port like /dev/ttyS0, to communicate with the EEPROM. Hence, you are
* expected to have a connectivity from the EEPROM to the serial port. This program does
* __not__ communicate using the I2C protocol
*/
@@ -64,14 +64,14 @@
static void send_byte(unsigned char byte)
{
int i = 0;
-
- for (i = 7; i >= 0; i--)
+
+ for (i = 7; i >= 0; i--)
send_bit((byte >> i) & 0x01);
}
-
+
static void send_start(void)
{
- sda_hi;
+ sda_hi;
delay(TXX);
scl_hi;
delay(TXX);
@@ -114,9 +114,9 @@
int i;
unsigned char byte=0;
- for (i=7;i>=0;i--)
+ for (i=7;i>=0;i--)
byte |= (recv_bit() << i);
-
+
return byte;
}
diff --git a/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.h b/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.h
index d27566d..c19f01a 100644
--- a/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.h
+++ b/arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.h
@@ -27,7 +27,7 @@
*/
/*
- * Header file for atmel_read_eeprom.c
+ * Header file for atmel_read_eeprom.c
*/
#include <linux/types.h>
@@ -46,7 +46,7 @@
#define DEFAULT_PORT "/dev/ttyS0" /* Port to open */
#define TXX 0 /* Dummy loop for spinning */
-#define BLOCK_SEL 0x00
+#define BLOCK_SEL 0x00
#define SLAVE_ADDR 0xa0
#define READ_BIT 0x01
#define WRITE_BIT 0x00
diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile
new file mode 100644
index 0000000..934944a
--- /dev/null
+++ b/arch/mips/qemu/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Qemu specific kernel interface routines under Linux.
+#
+
+obj-y = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o
diff --git a/arch/mips/qemu/q-firmware.c b/arch/mips/qemu/q-firmware.c
new file mode 100644
index 0000000..5980f02b
--- /dev/null
+++ b/arch/mips/qemu/q-firmware.c
@@ -0,0 +1,7 @@
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+
+void __init prom_init(void)
+{
+ add_memory_region(0x0<<20, 0x10<<20, BOOT_MEM_RAM);
+}
diff --git a/arch/mips/qemu/q-int.S b/arch/mips/qemu/q-int.S
new file mode 100644
index 0000000..6e3dfe5
--- /dev/null
+++ b/arch/mips/qemu/q-int.S
@@ -0,0 +1,17 @@
+/*
+ * Qemu interrupt handler code.
+ *
+ * Copyright (C) 2005 by Ralf Baechle
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ .align 5
+ NESTED(qemu_handle_int, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ move a0, sp
+ PTR_LA ra, ret_from_irq
+ j do_qemu_int
+ END(qemu_handle_int)
diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
new file mode 100644
index 0000000..2c4e070
--- /dev/null
+++ b/arch/mips/qemu/q-irq.c
@@ -0,0 +1,37 @@
+#include <linux/init.h>
+#include <linux/linkage.h>
+
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+#include <asm/qemu.h>
+#include <asm/system.h>
+#include <asm/time.h>
+
+extern asmlinkage void qemu_handle_int(void);
+
+asmlinkage void do_qemu_int(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & 0x8000) {
+ ll_timer_interrupt(Q_COUNT_COMPARE_IRQ, regs);
+ return;
+ }
+ if (pending & 0x0400) {
+ int irq = i8259_irq();
+
+ if (likely(irq >= 0))
+ do_IRQ(irq, regs);
+
+ return;
+ }
+}
+
+void __init arch_init_irq(void)
+{
+ set_except_vector(0, qemu_handle_int);
+ mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */
+
+ init_i8259_irqs();
+ set_c0_status(0x8400);
+}
diff --git a/arch/mips/qemu/q-mem.c b/arch/mips/qemu/q-mem.c
new file mode 100644
index 0000000..d174fac
--- /dev/null
+++ b/arch/mips/qemu/q-mem.c
@@ -0,0 +1,6 @@
+#include <linux/init.h>
+
+unsigned long __init prom_free_prom_memory(void)
+{
+ return 0UL;
+}
diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c
new file mode 100644
index 0000000..1a80eee
--- /dev/null
+++ b/arch/mips/qemu/q-setup.c
@@ -0,0 +1,20 @@
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/time.h>
+
+#define QEMU_PORT_BASE 0xb4000000
+
+static void __init qemu_timer_setup(struct irqaction *irq)
+{
+ /* set the clock to 100 Hz */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+ setup_irq(0, irq);
+}
+
+void __init plat_setup(void)
+{
+ set_io_port_base(QEMU_PORT_BASE);
+ board_timer_setup = qemu_timer_setup;
+}
diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c
index 0ab4abf..fa0e719 100644
--- a/arch/mips/sgi-ip22/ip22-eisa.c
+++ b/arch/mips/sgi-ip22/ip22-eisa.c
@@ -242,7 +242,7 @@
int i, c;
char *str;
u8 *slot_addr;
-
+
if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
printk(KERN_INFO "EISA: bus not present.\n");
return 1;
diff --git a/arch/mips/sgi-ip22/ip22-hpc.c b/arch/mips/sgi-ip22/ip22-hpc.c
index c0afecc..5c00cdd 100644
--- a/arch/mips/sgi-ip22/ip22-hpc.c
+++ b/arch/mips/sgi-ip22/ip22-hpc.c
@@ -49,7 +49,7 @@
sgint = &sgioc->int3;
system_type = "SGI Indy";
}
-
+
sgi_ioc_reset = (SGIOC_RESET_PPORT | SGIOC_RESET_KBDMOUSE |
SGIOC_RESET_EISA | SGIOC_RESET_ISDN |
SGIOC_RESET_LC0OFF);
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index ea2844d..d16fb43 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -28,7 +28,7 @@
/* #define DEBUG_SGINT */
/* So far nothing hangs here */
-#undef USE_LIO3_IRQ
+#undef USE_LIO3_IRQ
struct sgint_regs *sgint;
@@ -272,32 +272,32 @@
irq_exit();
}
-static struct irqaction local0_cascade = {
+static struct irqaction local0_cascade = {
.handler = no_action,
.flags = SA_INTERRUPT,
.name = "local0 cascade",
};
-static struct irqaction local1_cascade = {
+static struct irqaction local1_cascade = {
.handler = no_action,
.flags = SA_INTERRUPT,
.name = "local1 cascade",
};
-static struct irqaction buserr = {
+static struct irqaction buserr = {
.handler = no_action,
.flags = SA_INTERRUPT,
.name = "Bus Error",
};
-static struct irqaction map0_cascade = {
+static struct irqaction map0_cascade = {
.handler = no_action,
.flags = SA_INTERRUPT,
.name = "mapable0 cascade",
};
#ifdef USE_LIO3_IRQ
-static struct irqaction map1_cascade = {
+static struct irqaction map1_cascade = {
.handler = no_action,
.flags = SA_INTERRUPT,
.name = "mapable1 cascade",
diff --git a/arch/mips/sgi-ip22/ip22-nvram.c b/arch/mips/sgi-ip22/ip22-nvram.c
index de43e86..fd29fd4 100644
--- a/arch/mips/sgi-ip22/ip22-nvram.c
+++ b/arch/mips/sgi-ip22/ip22-nvram.c
@@ -39,7 +39,7 @@
*ptr |= EEPROM_CSEL; \
*ptr |= EEPROM_ECLK; })
-
+
#define eeprom_cs_off(ptr) ({ \
*ptr &= ~EEPROM_ECLK; \
*ptr &= ~EEPROM_CSEL; \
@@ -50,7 +50,7 @@
/*
* clock in the nvram command and the register number. For the
* national semiconductor nv ram chip the op code is 3 bits and
- * the address is 6/8 bits.
+ * the address is 6/8 bits.
*/
static inline void eeprom_cmd(volatile unsigned int *ctrl, unsigned cmd,
unsigned reg)
@@ -90,7 +90,7 @@
if (*ctrl & EEPROM_DATI)
res |= 1;
}
-
+
eeprom_cs_off(ctrl);
return res;
@@ -113,7 +113,7 @@
reg <<= 1;
tmp = hpc3c0->bbram[reg++] & 0xff;
return (tmp << 8) | (hpc3c0->bbram[reg] & 0xff);
- }
+ }
}
EXPORT_SYMBOL(ip22_nvram_read);
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
index ed5c60a..214ffd2 100644
--- a/arch/mips/sgi-ip22/ip22-reset.c
+++ b/arch/mips/sgi-ip22/ip22-reset.c
@@ -185,7 +185,7 @@
add_timer(&debounce_timer);
}
- /* Power button was pressed
+ /* Power button was pressed
* ioc.ps page 22: "The Panel Register is called Power Control by Full
* House. Only lowest 2 bits are used. Guiness uses upper four bits
* for volume control". This is not true, all bits are pulled high
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 173f768..df9b569 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -126,7 +126,7 @@
unsigned long r4k_ticks[3];
unsigned long r4k_tick;
- /*
+ /*
* Figure out the r4k offset, the algorithm is very simple and works in
* _all_ cases as long as the 8254 counter register itself works ok (as
* an interrupt driving timer it does not because of bug, this is why
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index a160d04..ef20d9a 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -538,7 +538,7 @@
for_each_online_node(node) {
unsigned slot, numslots;
struct page *end, *p;
-
+
/*
* This will free up the bootmem, ie, slot 0 memory.
*/
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 8c1b96f..cddf1ce 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -118,7 +118,7 @@
* RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to when a second starts.
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
index 281f090..88e1f52 100644
--- a/arch/mips/sgi-ip32/ip32-reset.c
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -140,7 +140,7 @@
reg_c = CMOS_READ(RTC_INTR_FLAGS);
if (!(reg_c & RTC_IRQF)) {
- printk(KERN_WARNING
+ printk(KERN_WARNING
"%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__);
}
/* Wait until interrupt goes away */
diff --git a/arch/mips/sibyte/cfe/cfe_error.h b/arch/mips/sibyte/cfe/cfe_error.h
index 77eb493..975f000 100644
--- a/arch/mips/sibyte/cfe/cfe_error.h
+++ b/arch/mips/sibyte/cfe/cfe_error.h
@@ -17,15 +17,15 @@
*/
/* *********************************************************************
- *
+ *
* Broadcom Common Firmware Environment (CFE)
- *
+ *
* Error codes File: cfe_error.h
- *
+ *
* CFE's global error code list is here.
- *
+ *
* Author: Mitch Lichtenberg
- *
+ *
********************************************************************* */
diff --git a/arch/mips/sibyte/cfe/console.c b/arch/mips/sibyte/cfe/console.c
index 53a5c1e..7721100 100644
--- a/arch/mips/sibyte/cfe/console.c
+++ b/arch/mips/sibyte/cfe/console.c
@@ -38,7 +38,7 @@
last += written;
} while (last < count);
}
-
+
}
static int cfe_console_setup(struct console *cons, char *str)
diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c
index d6d0364..7a2c7a8 100644
--- a/arch/mips/sibyte/cfe/setup.c
+++ b/arch/mips/sibyte/cfe/setup.c
@@ -33,7 +33,7 @@
#include "cfe_error.h"
/* Max ram addressable in 32-bit segments */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define MAX_RAM_SIZE (~0ULL)
#else
#ifdef CONFIG_HIGHMEM
@@ -285,7 +285,7 @@
while (1) ;
}
cfe_init(cfe_handle, cfe_ept);
- /*
+ /*
* Get the handle for (at least) prom_putchar, possibly for
* boot console
*/
diff --git a/arch/mips/sibyte/cfe/smp.c b/arch/mips/sibyte/cfe/smp.c
index 7339219..e44ce1a 100644
--- a/arch/mips/sibyte/cfe/smp.c
+++ b/arch/mips/sibyte/cfe/smp.c
@@ -57,7 +57,7 @@
void prom_boot_secondary(int cpu, struct task_struct *idle)
{
int retval;
-
+
retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
__KSTK_TOS(idle),
(unsigned long)idle->thread_info, 0);
diff --git a/arch/mips/sibyte/sb1250/bus_watcher.c b/arch/mips/sibyte/sb1250/bus_watcher.c
index 182a16f..1a97e31 100644
--- a/arch/mips/sibyte/sb1250/bus_watcher.c
+++ b/arch/mips/sibyte/sb1250/bus_watcher.c
@@ -10,13 +10,13 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*
+/*
* The Bus Watcher monitors internal bus transactions and maintains
* counts of transactions with error status, logging details and
* causing one of several interrupts. This driver provides a handler
@@ -155,7 +155,7 @@
static void create_proc_decoder(struct bw_stats_struct *stats)
{
struct proc_dir_entry *ent;
-
+
ent = create_proc_read_entry("bus_watcher", S_IWUSR | S_IRUGO, NULL,
bw_read_proc, stats);
if (!ent) {
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 2728abb..2725b26 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -377,7 +377,7 @@
/*
* Note that the timer interrupts are also mapped, but this is
- * done in sb1250_time_init(). Also, the profiling driver
+ * done in sb1250_time_init(). Also, the profiling driver
* does its own management of IP7.
*/
@@ -392,7 +392,7 @@
if (kgdb_flag) {
kgdb_irq = K_INT_UART_0 + kgdb_port;
-#ifdef CONFIG_SIBYTE_SB1250_DUART
+#ifdef CONFIG_SIBYTE_SB1250_DUART
sb1250_duart_present[kgdb_port] = 0;
#endif
/* Setup uart 1 settings, mapper */
diff --git a/arch/mips/sibyte/swarm/rtc_m41t81.c b/arch/mips/sibyte/swarm/rtc_m41t81.c
index 0e633ee..a686bb7 100644
--- a/arch/mips/sibyte/swarm/rtc_m41t81.c
+++ b/arch/mips/sibyte/swarm/rtc_m41t81.c
@@ -128,7 +128,7 @@
/* Clear error bit by writing a 1 */
bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
return -1;
- }
+ }
/* read the same byte again to make sure it is written */
bus_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
@@ -136,7 +136,7 @@
while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
;
-
+
return 0;
}
@@ -148,13 +148,13 @@
/*
* Note the write order matters as it ensures the correctness.
- * When we write sec, 10th sec is clear. It is reasonable to
+ * When we write sec, 10th sec is clear. It is reasonable to
* believe we should finish writing min within a second.
*/
tm.tm_sec = BIN2BCD(tm.tm_sec);
m41t81_write(M41T81REG_SC, tm.tm_sec);
-
+
tm.tm_min = BIN2BCD(tm.tm_min);
m41t81_write(M41T81REG_MN, tm.tm_min);
@@ -187,7 +187,7 @@
{
unsigned int year, mon, day, hour, min, sec;
- /*
+ /*
* min is valid if two reads of sec are the same.
*/
for (;;) {
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c
index 457aeb7..4daeaa41 100644
--- a/arch/mips/sibyte/swarm/setup.c
+++ b/arch/mips/sibyte/swarm/setup.c
@@ -73,7 +73,7 @@
{
if (!is_fixup && (regs->cp0_cause & 4)) {
/* Data bus error - print PA */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
printk("DBE physical address: %010lx\n",
__read_64bit_c0_register($26, 1));
#else
@@ -98,7 +98,7 @@
rtc_get_time = xicor_get_time;
rtc_set_time = xicor_set_time;
}
-
+
if (m41t81_probe()) {
printk("swarm setup: M41T81 RTC detected.\n");
rtc_get_time = m41t81_get_time;
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 62c760f..141a310 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -103,7 +103,7 @@
/*
* hwint 1 deals with EISA and SCSI interrupts,
- *
+ *
* The EISA_INT bit in CSITPEND is high active, all others are low active.
*/
void pciasic_hwint1(struct pt_regs *regs)
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index 8f67cee..1b3f8a0 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -111,7 +111,7 @@
* The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
* for other purposes. Be paranoid and allocate all of the before the PCI
* code gets a chance to to map anything else there ...
- *
+ *
* This leaves the following areas available:
*
* 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
diff --git a/arch/mips/tx4927/common/tx4927_irq_handler.S b/arch/mips/tx4927/common/tx4927_irq_handler.S
index ca123e2..dd3ceda 100644
--- a/arch/mips/tx4927/common/tx4927_irq_handler.S
+++ b/arch/mips/tx4927/common/tx4927_irq_handler.S
@@ -42,13 +42,13 @@
CLI
.set at
- mfc0 t0, CP0_CAUSE
+ mfc0 t0, CP0_CAUSE
mfc0 t1, CP0_STATUS
and t0, t1
-
+
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_ip7
-
+
/* IP6..IP3 multiplexed -- do not use */
andi t1, t0, STATUSF_IP2 /* tx4927 pic */
diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c
index 16bcbdc..26d7c53 100644
--- a/arch/mips/tx4927/common/tx4927_setup.c
+++ b/arch/mips/tx4927/common/tx4927_setup.c
@@ -152,7 +152,7 @@
print_cp0(key, 16, "CONFIG ", read_c0_config());
return;
}
-
+
void print_pic(char *key, u32 reg, char *name)
{
printk("%s pic:0x%08x:%s=0x%08x\n", key, reg, name,
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/Makefile b/arch/mips/tx4927/toshiba_rbtx4927/Makefile
index 86ca4cf..c1a377a 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/Makefile
+++ b/arch/mips/tx4927/toshiba_rbtx4927/Makefile
@@ -1,5 +1,5 @@
-obj-y += toshiba_rbtx4927_prom.o
-obj-y += toshiba_rbtx4927_setup.o
-obj-y += toshiba_rbtx4927_irq.o
+obj-y += toshiba_rbtx4927_prom.o
+obj-y += toshiba_rbtx4927_setup.o
+obj-y += toshiba_rbtx4927_irq.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
index fd5b433..aee07ff 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
@@ -31,7 +31,7 @@
/*
-IRQ Device
+IRQ Device
00 RBTX4927-ISA/00
01 RBTX4927-ISA/01 PS2/Keyboard
02 RBTX4927-ISA/02 Cascade RBTX4927-ISA (irqs 8-15)
@@ -52,15 +52,15 @@
16 TX4927-CP0/00 Software 0
17 TX4927-CP0/01 Software 1
18 TX4927-CP0/02 Cascade TX4927-CP0
-19 TX4927-CP0/03 Multiplexed -- do not use
-20 TX4927-CP0/04 Multiplexed -- do not use
-21 TX4927-CP0/05 Multiplexed -- do not use
-22 TX4927-CP0/06 Multiplexed -- do not use
+19 TX4927-CP0/03 Multiplexed -- do not use
+20 TX4927-CP0/04 Multiplexed -- do not use
+21 TX4927-CP0/05 Multiplexed -- do not use
+22 TX4927-CP0/06 Multiplexed -- do not use
23 TX4927-CP0/07 CPU TIMER
24 TX4927-PIC/00
25 TX4927-PIC/01
-26 TX4927-PIC/02
+26 TX4927-PIC/02
27 TX4927-PIC/03 Cascade RBTX4927-IOC
28 TX4927-PIC/04
29 TX4927-PIC/05 RBTX4927 RTL-8019AS ethernet
@@ -80,7 +80,7 @@
43 TX4927-PIC/19
44 TX4927-PIC/20
45 TX4927-PIC/21
-46 TX4927-PIC/22 TX4927 PCI PCI-ERR
+46 TX4927-PIC/22 TX4927 PCI PCI-ERR
47 TX4927-PIC/23 TX4927 PCI PCI-PMA (not used)
48 TX4927-PIC/24
49 TX4927-PIC/25
@@ -100,7 +100,7 @@
62 RBTX4927-IOC/06
63 RBTX4927-IOC/07
-NOTES:
+NOTES:
SouthBridge/INTR is mapped to SouthBridge/A=PCI-B/#58
SouthBridge/ISA/pin=0 no pci irq used by this device
SouthBridge/IDE/pin=1 no pci irq used by this device, using INTR via ISA IRQ14
@@ -175,19 +175,19 @@
static const u32 toshiba_rbtx4927_irq_debug_flag =
(TOSHIBA_RBTX4927_IRQ_NONE | TOSHIBA_RBTX4927_IRQ_INFO |
TOSHIBA_RBTX4927_IRQ_WARN | TOSHIBA_RBTX4927_IRQ_EROR
-// | TOSHIBA_RBTX4927_IRQ_IOC_INIT
-// | TOSHIBA_RBTX4927_IRQ_IOC_STARTUP
-// | TOSHIBA_RBTX4927_IRQ_IOC_SHUTDOWN
-// | TOSHIBA_RBTX4927_IRQ_IOC_ENABLE
-// | TOSHIBA_RBTX4927_IRQ_IOC_DISABLE
-// | TOSHIBA_RBTX4927_IRQ_IOC_MASK
-// | TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ
-// | TOSHIBA_RBTX4927_IRQ_ISA_INIT
-// | TOSHIBA_RBTX4927_IRQ_ISA_STARTUP
-// | TOSHIBA_RBTX4927_IRQ_ISA_SHUTDOWN
-// | TOSHIBA_RBTX4927_IRQ_ISA_ENABLE
-// | TOSHIBA_RBTX4927_IRQ_ISA_DISABLE
-// | TOSHIBA_RBTX4927_IRQ_ISA_MASK
+// | TOSHIBA_RBTX4927_IRQ_IOC_INIT
+// | TOSHIBA_RBTX4927_IRQ_IOC_STARTUP
+// | TOSHIBA_RBTX4927_IRQ_IOC_SHUTDOWN
+// | TOSHIBA_RBTX4927_IRQ_IOC_ENABLE
+// | TOSHIBA_RBTX4927_IRQ_IOC_DISABLE
+// | TOSHIBA_RBTX4927_IRQ_IOC_MASK
+// | TOSHIBA_RBTX4927_IRQ_IOC_ENDIRQ
+// | TOSHIBA_RBTX4927_IRQ_ISA_INIT
+// | TOSHIBA_RBTX4927_IRQ_ISA_STARTUP
+// | TOSHIBA_RBTX4927_IRQ_ISA_SHUTDOWN
+// | TOSHIBA_RBTX4927_IRQ_ISA_ENABLE
+// | TOSHIBA_RBTX4927_IRQ_ISA_DISABLE
+// | TOSHIBA_RBTX4927_IRQ_ISA_MASK
// | TOSHIBA_RBTX4927_IRQ_ISA_ENDIRQ
);
#endif
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index 8724ea3..fc07205 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -395,7 +395,7 @@
/* enable secondary ide */
v08_43 |= 0x80;
- /*
+ /*
* !!! DO NOT REMOVE THIS COMMENT IT IS REQUIRED BY SMSC !!!
*
* This line of code is intended to provide the user with a work
diff --git a/arch/mips/vr4181/common/Makefile b/arch/mips/vr4181/common/Makefile
deleted file mode 100644
index f7587ca..0000000
--- a/arch/mips/vr4181/common/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for common code of NEC vr4181 based boards
-#
-
-obj-y := irq.o int_handler.o serial.o time.o
-
-EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr4181/common/int_handler.S b/arch/mips/vr4181/common/int_handler.S
deleted file mode 100644
index 2c041b8..0000000
--- a/arch/mips/vr4181/common/int_handler.S
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * arch/mips/vr4181/common/int_handler.S
- *
- * Adapted to the VR4181 and almost entirely rewritten:
- * Copyright (C) 1999 Bradley D. LaRonde and Michael Klar
- *
- * Clean up to conform to the new IRQ
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * 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 <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
-
-#include <asm/vr4181/vr4181.h>
-
-/*
- * [jsun]
- * See include/asm/vr4181/irq.h for IRQ assignment and strategy.
- */
-
- .text
- .set noreorder
-
- .align 5
- NESTED(vr4181_handle_irq, PT_SIZE, ra)
-
- .set noat
- SAVE_ALL
- CLI
-
- .set at
- .set noreorder
-
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- /* we check IP3 first; it happens most frequently */
- andi t1, t0, STATUSF_IP3
- bnez t1, ll_cpu_ip3
- andi t1, t0, STATUSF_IP2
- bnez t1, ll_cpu_ip2
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cputimer_irq
- andi t1, t0, STATUSF_IP4
- bnez t1, ll_cpu_ip4
- andi t1, t0, STATUSF_IP5
- bnez t1, ll_cpu_ip5
- andi t1, t0, STATUSF_IP6
- bnez t1, ll_cpu_ip6
- andi t1, t0, STATUSF_IP0 /* software int 0 */
- bnez t1, ll_cpu_ip0
- andi t1, t0, STATUSF_IP1 /* software int 1 */
- bnez t1, ll_cpu_ip1
- nop
-
- .set reorder
-do_spurious:
- j spurious_interrupt
-
-/*
- * regular CPU irqs
- */
-ll_cputimer_irq:
- li a0, VR4181_IRQ_TIMER
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-
-ll_cpu_ip0:
- li a0, VR4181_IRQ_SW1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip1:
- li a0, VR4181_IRQ_SW2
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip3:
- li a0, VR4181_IRQ_INT1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip4:
- li a0, VR4181_IRQ_INT2
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip5:
- li a0, VR4181_IRQ_INT3
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip6:
- li a0, VR4181_IRQ_INT4
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-/*
- * One of the sys irq has happend.
- *
- * In the interest of speed, we first determine in the following order
- * which 16-irq block have pending interrupts:
- * sysint1 (16 sources, including cascading intrs from GPIO)
- * sysint2
- * gpio (16 intr sources)
- *
- * Then we do binary search to find the exact interrupt source.
- */
-ll_cpu_ip2:
-
- lui t3,%hi(VR4181_SYSINT1REG)
- lhu t0,%lo(VR4181_SYSINT1REG)(t3)
- lhu t2,%lo(VR4181_MSYSINT1REG)(t3)
- and t0, 0xfffb /* hack - remove RTC Long 1 intr */
- and t0, t2
- beqz t0, check_sysint2
-
- /* check for GPIO interrupts */
- andi t1, t0, 0x0100
- bnez t1, check_gpio_int
-
- /* so we have an interrupt in sysint1 which is not gpio int */
- li a0, VR4181_SYS_IRQ_BASE - 1
- j check_16
-
-check_sysint2:
-
- lhu t0,%lo(VR4181_SYSINT2REG)(t3)
- lhu t2,%lo(VR4181_MSYSINT2REG)(t3)
- and t0, 0xfffe /* hack - remove RTC Long 2 intr */
- and t0, t2
- li a0, VR4181_SYS_IRQ_BASE + 16 - 1
- j check_16
-
-check_gpio_int:
- lui t3,%hi(VR4181_GPINTMSK)
- lhu t0,%lo(VR4181_GPINTMSK)(t3)
- lhu t2,%lo(VR4181_GPINTSTAT)(t3)
- xori t0, 0xffff /* why? reverse logic? */
- and t0, t2
- li a0, VR4181_GPIO_IRQ_BASE - 1
- j check_16
-
-/*
- * When we reach check_16, we have 16-bit status in t0 and base irq number
- * in a0.
- */
-check_16:
- andi t1, t0, 0xff
- bnez t1, check_8
-
- srl t0, 8
- addi a0, 8
- j check_8
-
-/*
- * When we reach check_8, we have 8-bit status in t0 and base irq number
- * in a0.
- */
-check_8:
- andi t1, t0, 0xf
- bnez t1, check_4
-
- srl t0, 4
- addi a0, 4
- j check_4
-
-/*
- * When we reach check_4, we have 4-bit status in t0 and base irq number
- * in a0.
- */
-check_4:
- andi t0, t0, 0xf
- beqz t0, do_spurious
-
-loop:
- andi t2, t0, 0x1
- srl t0, 1
- addi a0, 1
- beqz t2, loop
-
-found_it:
- move a1, sp
- jal do_IRQ
-
- j ret_from_irq
-
- END(vr4181_handle_irq)
diff --git a/arch/mips/vr4181/common/irq.c b/arch/mips/vr4181/common/irq.c
deleted file mode 100644
index 2cdf77c..0000000
--- a/arch/mips/vr4181/common/irq.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * linux/arch/mips/vr4181/common/irq.c
- * Completely re-written to use the new irq.c
- *
- * Credits to Bradley D. LaRonde and Michael Klar for writing the original
- * irq.c file which was derived from the common irq.c file.
- *
- * 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/types.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/gdb-stub.h>
-
-#include <asm/vr4181/vr4181.h>
-
-/*
- * Strategy:
- *
- * We essentially have three irq controllers, CPU, system, and gpio.
- *
- * CPU irq controller is taken care by arch/mips/kernel/irq_cpu.c and
- * CONFIG_IRQ_CPU config option.
- *
- * We here provide sys_irq and gpio_irq controller code.
- */
-
-static int sys_irq_base;
-static int gpio_irq_base;
-
-/* ---------------------- sys irq ------------------------ */
-static void
-sys_irq_enable(unsigned int irq)
-{
- irq -= sys_irq_base;
- if (irq < 16) {
- *VR4181_MSYSINT1REG |= (u16)(1 << irq);
- } else {
- irq -= 16;
- *VR4181_MSYSINT2REG |= (u16)(1 << irq);
- }
-}
-
-static void
-sys_irq_disable(unsigned int irq)
-{
- irq -= sys_irq_base;
- if (irq < 16) {
- *VR4181_MSYSINT1REG &= ~((u16)(1 << irq));
- } else {
- irq -= 16;
- *VR4181_MSYSINT2REG &= ~((u16)(1 << irq));
- }
-
-}
-
-static unsigned int
-sys_irq_startup(unsigned int irq)
-{
- sys_irq_enable(irq);
- return 0;
-}
-
-#define sys_irq_shutdown sys_irq_disable
-#define sys_irq_ack sys_irq_disable
-
-static void
-sys_irq_end(unsigned int irq)
-{
- if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- sys_irq_enable(irq);
-}
-
-static hw_irq_controller sys_irq_controller = {
- "vr4181_sys_irq",
- sys_irq_startup,
- sys_irq_shutdown,
- sys_irq_enable,
- sys_irq_disable,
- sys_irq_ack,
- sys_irq_end,
- NULL /* no affinity stuff for UP */
-};
-
-/* ---------------------- gpio irq ------------------------ */
-/* gpio irq lines use reverse logic */
-static void
-gpio_irq_enable(unsigned int irq)
-{
- irq -= gpio_irq_base;
- *VR4181_GPINTMSK &= ~((u16)(1 << irq));
-}
-
-static void
-gpio_irq_disable(unsigned int irq)
-{
- irq -= gpio_irq_base;
- *VR4181_GPINTMSK |= (u16)(1 << irq);
-}
-
-static unsigned int
-gpio_irq_startup(unsigned int irq)
-{
- gpio_irq_enable(irq);
-
- irq -= gpio_irq_base;
- *VR4181_GPINTEN |= (u16)(1 << irq );
-
- return 0;
-}
-
-static void
-gpio_irq_shutdown(unsigned int irq)
-{
- gpio_irq_disable(irq);
-
- irq -= gpio_irq_base;
- *VR4181_GPINTEN &= ~((u16)(1 << irq ));
-}
-
-static void
-gpio_irq_ack(unsigned int irq)
-{
- u16 irqtype;
- u16 irqshift;
-
- gpio_irq_disable(irq);
-
- /* we clear interrupt if it is edge triggered */
- irq -= gpio_irq_base;
- if (irq < 8) {
- irqtype = *VR4181_GPINTTYPL;
- irqshift = 2 << (irq*2);
- } else {
- irqtype = *VR4181_GPINTTYPH;
- irqshift = 2 << ((irq-8)*2);
- }
- if ( ! (irqtype & irqshift) ) {
- *VR4181_GPINTSTAT = (u16) (1 << irq);
- }
-}
-
-static void
-gpio_irq_end(unsigned int irq)
-{
- if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- gpio_irq_enable(irq);
-}
-
-static hw_irq_controller gpio_irq_controller = {
- "vr4181_gpio_irq",
- gpio_irq_startup,
- gpio_irq_shutdown,
- gpio_irq_enable,
- gpio_irq_disable,
- gpio_irq_ack,
- gpio_irq_end,
- NULL /* no affinity stuff for UP */
-};
-
-/* --------------------- IRQ init stuff ---------------------- */
-
-extern asmlinkage void vr4181_handle_irq(void);
-extern void breakpoint(void);
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
-extern void mips_cpu_irq_init(u32 irq_base);
-
-static struct irqaction cascade =
- { no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade", NULL, NULL };
-static struct irqaction reserved =
- { no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade", NULL, NULL };
-
-void __init arch_init_irq(void)
-{
- int i;
-
- set_except_vector(0, vr4181_handle_irq);
-
- /* init CPU irqs */
- mips_cpu_irq_init(VR4181_CPU_IRQ_BASE);
-
- /* init sys irqs */
- sys_irq_base = VR4181_SYS_IRQ_BASE;
- for (i=sys_irq_base; i < sys_irq_base + VR4181_NUM_SYS_IRQ; i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].handler = &sys_irq_controller;
- }
-
- /* init gpio irqs */
- gpio_irq_base = VR4181_GPIO_IRQ_BASE;
- for (i=gpio_irq_base; i < gpio_irq_base + VR4181_NUM_GPIO_IRQ; i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].handler = &gpio_irq_controller;
- }
-
- /* Default all ICU IRQs to off ... */
- *VR4181_MSYSINT1REG = 0;
- *VR4181_MSYSINT2REG = 0;
-
- /* We initialize the level 2 ICU registers to all bits disabled. */
- *VR4181_MPIUINTREG = 0;
- *VR4181_MAIUINTREG = 0;
- *VR4181_MKIUINTREG = 0;
-
- /* disable all GPIO intrs */
- *VR4181_GPINTMSK = 0xffff;
-
- /* vector handler. What these do is register the IRQ as non-sharable */
- setup_irq(VR4181_IRQ_INT0, &cascade);
- setup_irq(VR4181_IRQ_GIU, &cascade);
-
- /*
- * RTC interrupts are interesting. They have two destinations.
- * One is at sys irq controller, and the other is at CPU IP3 and IP4.
- * RTC timer is used as system timer.
- * We enable them here, but timer routine will register later
- * with CPU IP3/IP4.
- */
- setup_irq(VR4181_IRQ_RTCL1, &reserved);
- setup_irq(VR4181_IRQ_RTCL2, &reserved);
-}
diff --git a/arch/mips/vr4181/common/serial.c b/arch/mips/vr4181/common/serial.c
deleted file mode 100644
index 3f62c62..0000000
--- a/arch/mips/vr4181/common/serial.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * arch/mips/vr4181/common/serial.c
- * initialize serial port on vr4181.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-/*
- * [jsun, 010925]
- * You need to make sure rs_table has at least one element in
- * drivers/char/serial.c file. There is no good way to do it right
- * now. A workaround is to include CONFIG_SERIAL_MANY_PORTS in your
- * configure file, which would gives you 64 ports and wastes 11K ram.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-
-#include <asm/vr4181/vr4181.h>
-
-void __init vr4181_init_serial(void)
-{
- struct serial_struct s;
-
- /* turn on UART clock */
- *VR4181_CMUCLKMSK |= VR4181_CMUCLKMSK_MSKSIU;
-
- /* clear memory */
- memset(&s, 0, sizeof(s));
-
- s.line = 0; /* we set the first one */
- s.baud_base = 1152000;
- s.irq = VR4181_IRQ_SIU;
- s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; /* STD_COM_FLAGS */
- s.iomem_base = (u8*)VR4181_SIURB;
- s.iomem_reg_shift = 0;
- s.io_type = SERIAL_IO_MEM;
- if (early_serial_setup(&s) != 0) {
- panic("vr4181_init_serial() failed!");
- }
-}
-
diff --git a/arch/mips/vr4181/common/time.c b/arch/mips/vr4181/common/time.c
deleted file mode 100644
index 1781407..0000000
--- a/arch/mips/vr4181/common/time.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * rtc and time ops for vr4181. Part of code is drived from
- * linux-vr, originally written by Bradley D. LaRonde & Michael Klar.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the 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/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/param.h> /* for HZ */
-#include <linux/time.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/time.h>
-
-#include <asm/vr4181/vr4181.h>
-
-#define COUNTS_PER_JIFFY ((32768 + HZ/2) / HZ)
-
-/*
- * RTC ops
- */
-
-DEFINE_SPINLOCK(rtc_lock);
-
-/* per VR41xx docs, bad data can be read if between 2 counts */
-static inline unsigned short
-read_time_reg(volatile unsigned short *reg)
-{
- unsigned short value;
- do {
- value = *reg;
- barrier();
- } while (value != *reg);
- return value;
-}
-
-static unsigned long
-vr4181_rtc_get_time(void)
-{
- unsigned short regh, regm, regl;
-
- // why this crazy order, you ask? to guarantee that neither m
- // nor l wrap before all 3 read
- do {
- regm = read_time_reg(VR4181_ETIMEMREG);
- barrier();
- regh = read_time_reg(VR4181_ETIMEHREG);
- barrier();
- regl = read_time_reg(VR4181_ETIMELREG);
- } while (regm != read_time_reg(VR4181_ETIMEMREG));
- return ((regh << 17) | (regm << 1) | (regl >> 15));
-}
-
-static int
-vr4181_rtc_set_time(unsigned long timeval)
-{
- unsigned short intreg;
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
- intreg = *VR4181_RTCINTREG & 0x05;
- barrier();
- *VR4181_ETIMELREG = timeval << 15;
- *VR4181_ETIMEMREG = timeval >> 1;
- *VR4181_ETIMEHREG = timeval >> 17;
- barrier();
- // assume that any ints that just triggered are invalid, since the
- // time value is written non-atomically in 3 separate regs
- *VR4181_RTCINTREG = 0x05 ^ intreg;
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return 0;
-}
-
-
-/*
- * timer interrupt routine (wrapper)
- *
- * we need our own interrupt routine because we need to clear
- * RTC1 interrupt.
- */
-static void
-vr4181_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* Clear the interrupt. */
- *VR4181_RTCINTREG = 0x2;
-
- /* call the generic one */
- timer_interrupt(irq, dev_id, regs);
-}
-
-
-/*
- * vr4181_time_init:
- *
- * We pick the following choices:
- * . we use elapsed timer as the RTC. We set some reasonable init data since
- * it does not persist across reset
- * . we use RTC1 as the system timer interrupt source.
- * . we use CPU counter for fast_gettimeoffset and we calivrate the cpu
- * frequency. In other words, we use calibrate_div64_gettimeoffset().
- * . we use our own timer interrupt routine which clears the interrupt
- * and then calls the generic high-level timer interrupt routine.
- *
- */
-
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
-
-static void
-vr4181_timer_setup(struct irqaction *irq)
-{
- /* over-write the handler to be our own one */
- irq->handler = vr4181_timer_interrupt;
-
- /* sets up the frequency */
- *VR4181_RTCL1LREG = COUNTS_PER_JIFFY;
- *VR4181_RTCL1HREG = 0;
-
- /* and ack any pending ints */
- *VR4181_RTCINTREG = 0x2;
-
- /* setup irqaction */
- setup_irq(VR4181_IRQ_INT1, irq);
-
-}
-
-void
-vr4181_init_time(void)
-{
- /* setup hookup functions */
- rtc_get_time = vr4181_rtc_get_time;
- rtc_set_time = vr4181_rtc_set_time;
-
- board_timer_setup = vr4181_timer_setup;
-}
-
diff --git a/arch/mips/vr4181/osprey/Makefile b/arch/mips/vr4181/osprey/Makefile
deleted file mode 100644
index 34be057..0000000
--- a/arch/mips/vr4181/osprey/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for common code of NEC Osprey board
-#
-
-obj-y := setup.o prom.o reset.o
-
-obj-$(CONFIG_KGDB) += dbg_io.o
diff --git a/arch/mips/vr4181/osprey/dbg_io.c b/arch/mips/vr4181/osprey/dbg_io.c
deleted file mode 100644
index 5e8a840..0000000
--- a/arch/mips/vr4181/osprey/dbg_io.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * kgdb io functions for osprey. We use the serial port on debug board.
- *
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-/* ======================= CONFIG ======================== */
-
-/* [jsun] we use the second serial port for kdb */
-#define BASE 0xb7fffff0
-#define MAX_BAUD 115200
-
-/* distance in bytes between two serial registers */
-#define REG_OFFSET 1
-
-/*
- * 0 - kgdb does serial init
- * 1 - kgdb skip serial init
- */
-static int remoteDebugInitialized = 1;
-
-/*
- * the default baud rate *if* kgdb does serial init
- */
-#define BAUD_DEFAULT UART16550_BAUD_38400
-
-/* ======================= END OF CONFIG ======================== */
-
-typedef unsigned char uint8;
-typedef unsigned int uint32;
-
-#define UART16550_BAUD_2400 2400
-#define UART16550_BAUD_4800 4800
-#define UART16550_BAUD_9600 9600
-#define UART16550_BAUD_19200 19200
-#define UART16550_BAUD_38400 38400
-#define UART16550_BAUD_57600 57600
-#define UART16550_BAUD_115200 115200
-
-#define UART16550_PARITY_NONE 0
-#define UART16550_PARITY_ODD 0x08
-#define UART16550_PARITY_EVEN 0x18
-#define UART16550_PARITY_MARK 0x28
-#define UART16550_PARITY_SPACE 0x38
-
-#define UART16550_DATA_5BIT 0x0
-#define UART16550_DATA_6BIT 0x1
-#define UART16550_DATA_7BIT 0x2
-#define UART16550_DATA_8BIT 0x3
-
-#define UART16550_STOP_1BIT 0x0
-#define UART16550_STOP_2BIT 0x4
-
-/* register offset */
-#define OFS_RCV_BUFFER 0
-#define OFS_TRANS_HOLD 0
-#define OFS_SEND_BUFFER 0
-#define OFS_INTR_ENABLE (1*REG_OFFSET)
-#define OFS_INTR_ID (2*REG_OFFSET)
-#define OFS_DATA_FORMAT (3*REG_OFFSET)
-#define OFS_LINE_CONTROL (3*REG_OFFSET)
-#define OFS_MODEM_CONTROL (4*REG_OFFSET)
-#define OFS_RS232_OUTPUT (4*REG_OFFSET)
-#define OFS_LINE_STATUS (5*REG_OFFSET)
-#define OFS_MODEM_STATUS (6*REG_OFFSET)
-#define OFS_RS232_INPUT (6*REG_OFFSET)
-#define OFS_SCRATCH_PAD (7*REG_OFFSET)
-
-#define OFS_DIVISOR_LSB (0*REG_OFFSET)
-#define OFS_DIVISOR_MSB (1*REG_OFFSET)
-
-
-/* memory-mapped read/write of the port */
-#define UART16550_READ(y) (*((volatile uint8*)(BASE + y)))
-#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z)
-
-void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
-{
- /* disable interrupts */
- UART16550_WRITE(OFS_INTR_ENABLE, 0);
-
- /* set up buad rate */
- {
- uint32 divisor;
-
- /* set DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
-
- /* set divisor */
- divisor = MAX_BAUD / baud;
- UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
- UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
-
- /* clear DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
- }
-
- /* set data format */
- UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
-}
-
-
-uint8 getDebugChar(void)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(BAUD_DEFAULT,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
- return UART16550_READ(OFS_RCV_BUFFER);
-}
-
-
-int putDebugChar(uint8 byte)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(BAUD_DEFAULT,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
- UART16550_WRITE(OFS_SEND_BUFFER, byte);
- return 1;
-}
diff --git a/arch/mips/vr4181/osprey/prom.c b/arch/mips/vr4181/osprey/prom.c
deleted file mode 100644
index af0d145..0000000
--- a/arch/mips/vr4181/osprey/prom.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * arch/mips/vr4181/osprey/prom.c
- * prom code for osprey.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the 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/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <asm/bootinfo.h>
-#include <asm/addrspace.h>
-
-const char *get_system_type(void)
-{
- return "NEC_Vr41xx Osprey";
-}
-
-/*
- * [jsun] right now we assume it is the nec debug monitor, which does
- * not pass any arguments.
- */
-void __init prom_init(void)
-{
- // cmdline is now set in default config
- // strcpy(arcs_cmdline, "ip=bootp ");
- // strcat(arcs_cmdline, "ether=46,0x03fe0300,eth0 ");
- // strcpy(arcs_cmdline, "ether=0,0x0300,eth0 "
- // strcat(arcs_cmdline, "video=vr4181fb:xres:240,yres:320,bpp:8 ");
-
- mips_machgroup = MACH_GROUP_NEC_VR41XX;
- mips_machtype = MACH_NEC_OSPREY;
-
- /* 16MB fixed */
- add_memory_region(0, 16 << 20, BOOT_MEM_RAM);
-}
-
-unsigned long __init prom_free_prom_memory(void)
-{
- return 0;
-}
diff --git a/arch/mips/vr4181/osprey/reset.c b/arch/mips/vr4181/osprey/reset.c
deleted file mode 100644
index 036ae83..0000000
--- a/arch/mips/vr4181/osprey/reset.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Copyright (C) 1997, 2001 Ralf Baechle
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/cacheflush.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-
-void nec_osprey_restart(char *command)
-{
- set_c0_status(ST0_ERL);
- change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
- flush_cache_all();
- write_c0_wired(0);
- __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
-}
-
-void nec_osprey_halt(void)
-{
- printk(KERN_NOTICE "\n** You can safely turn off the power\n");
- while (1)
- __asm__(".set\tmips3\n\t"
- "wait\n\t"
- ".set\tmips0");
-}
-
-void nec_osprey_power_off(void)
-{
- nec_osprey_halt();
-}
diff --git a/arch/mips/vr4181/osprey/setup.c b/arch/mips/vr4181/osprey/setup.c
deleted file mode 100644
index 2ff7140..0000000
--- a/arch/mips/vr4181/osprey/setup.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * linux/arch/mips/vr4181/setup.c
- *
- * VR41xx setup routines
- *
- * Copyright (C) 1999 Bradley D. LaRonde
- * Copyright (C) 1999, 2000 Michael Klar
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/reboot.h>
-#include <asm/vr4181/vr4181.h>
-#include <asm/io.h>
-
-
-extern void nec_osprey_restart(char* c);
-extern void nec_osprey_halt(void);
-extern void nec_osprey_power_off(void);
-
-extern void vr4181_init_serial(void);
-extern void vr4181_init_time(void);
-
-static void __init nec_osprey_setup(void)
-{
- set_io_port_base(VR4181_PORT_BASE);
- isa_slot_offset = VR4181_ISAMEM_BASE;
-
- vr4181_init_serial();
- vr4181_init_time();
-
- _machine_restart = nec_osprey_restart;
- _machine_halt = nec_osprey_halt;
- _machine_power_off = nec_osprey_power_off;
-
- /* setup resource limit */
- ioport_resource.end = 0xffffffff;
- iomem_resource.end = 0xffffffff;
-
- /* [jsun] hack */
- /*
- printk("[jsun] hack to change external ISA control register, %x -> %x\n",
- (*VR4181_XISACTL),
- (*VR4181_XISACTL) | 0x2);
- *VR4181_XISACTL |= 0x2;
- */
-
- // *VR4181_GPHIBSTH = 0x2000;
- // *VR4181_GPMD0REG = 0x00c0;
- // *VR4181_GPINTEN = 1<<6;
-
- /* [jsun] I believe this will get the interrupt type right
- * for the ether port.
- */
- *VR4181_GPINTTYPL = 0x3000;
-}
-
-early_initcall(nec_osprey_setup);
diff --git a/arch/mips/vr41xx/casio-e55/setup.c b/arch/mips/vr41xx/casio-e55/setup.c
index aa8605a..d29201a 100644
--- a/arch/mips/vr41xx/casio-e55/setup.c
+++ b/arch/mips/vr41xx/casio-e55/setup.c
@@ -23,11 +23,6 @@
#include <asm/io.h>
#include <asm/vr41xx/e55.h>
-const char *get_system_type(void)
-{
- return "CASIO CASSIOPEIA E-11/15/55/65";
-}
-
static int __init casio_e55_setup(void)
{
set_io_port_base(IO_PORT_BASE);
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index fa98ef3..9096302 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -2,7 +2,7 @@
# Makefile for common code of the NEC VR4100 series.
#
-obj-y += bcu.o cmu.o icu.o init.o int-handler.o pmu.o
+obj-y += bcu.o cmu.o icu.o init.o int-handler.o irq.o pmu.o type.o
obj-$(CONFIG_VRC4173) += vrc4173.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c
index c842661..0b73c5a 100644
--- a/arch/mips/vr41xx/common/icu.c
+++ b/arch/mips/vr41xx/common/icu.c
@@ -3,8 +3,7 @@
*
* Copyright (C) 2001-2002 MontaVista Software Inc.
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,7 +30,7 @@
*/
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
+#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/smp.h>
@@ -39,34 +38,24 @@
#include <asm/cpu.h>
#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/irq_cpu.h>
#include <asm/vr41xx/vr41xx.h>
-extern asmlinkage void vr41xx_handle_interrupt(void);
-
-extern void init_vr41xx_giuint_irq(void);
-extern void giuint_irq_dispatch(struct pt_regs *regs);
-
-static uint32_t icu1_base;
-static uint32_t icu2_base;
-
-static struct irqaction icu_cascade = {
- .handler = no_action,
- .mask = CPU_MASK_NONE,
- .name = "cascade",
-};
+static void __iomem *icu1_base;
+static void __iomem *icu2_base;
static unsigned char sysint1_assign[16] = {
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char sysint2_assign[16] = {
- 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-#define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080)
-#define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200)
+#define ICU1_TYPE1_BASE 0x0b000080UL
+#define ICU2_TYPE1_BASE 0x0b000200UL
-#define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080)
-#define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0)
+#define ICU1_TYPE2_BASE 0x0f000080UL
+#define ICU2_TYPE2_BASE 0x0f0000a0UL
+
+#define ICU1_SIZE 0x20
+#define ICU2_SIZE 0x1c
#define SYSINT1REG 0x00
#define PIUINTREG 0x02
@@ -106,61 +95,61 @@
#define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */
#define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */
-#define read_icu1(offset) readw(icu1_base + (offset))
-#define write_icu1(val, offset) writew((val), icu1_base + (offset))
+#define INT_TO_IRQ(x) ((x) + 2) /* Int0-4 -> IRQ2-6 */
-#define read_icu2(offset) readw(icu2_base + (offset))
-#define write_icu2(val, offset) writew((val), icu2_base + (offset))
+#define icu1_read(offset) readw(icu1_base + (offset))
+#define icu1_write(offset, value) writew((value), icu1_base + (offset))
+
+#define icu2_read(offset) readw(icu2_base + (offset))
+#define icu2_write(offset, value) writew((value), icu2_base + (offset))
#define INTASSIGN_MAX 4
#define INTASSIGN_MASK 0x0007
-static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
+static inline uint16_t icu1_set(uint8_t offset, uint16_t set)
{
- uint16_t res;
+ uint16_t data;
- res = read_icu1(offset);
- res |= set;
- write_icu1(res, offset);
+ data = icu1_read(offset);
+ data |= set;
+ icu1_write(offset, data);
- return res;
+ return data;
}
-static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
+static inline uint16_t icu1_clear(uint8_t offset, uint16_t clear)
{
- uint16_t res;
+ uint16_t data;
- res = read_icu1(offset);
- res &= ~clear;
- write_icu1(res, offset);
+ data = icu1_read(offset);
+ data &= ~clear;
+ icu1_write(offset, data);
- return res;
+ return data;
}
-static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
+static inline uint16_t icu2_set(uint8_t offset, uint16_t set)
{
- uint16_t res;
+ uint16_t data;
- res = read_icu2(offset);
- res |= set;
- write_icu2(res, offset);
+ data = icu2_read(offset);
+ data |= set;
+ icu2_write(offset, data);
- return res;
+ return data;
}
-static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
+static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear)
{
- uint16_t res;
+ uint16_t data;
- res = read_icu2(offset);
- res &= ~clear;
- write_icu2(res, offset);
+ data = icu2_read(offset);
+ data &= ~clear;
+ icu2_write(offset, data);
- return res;
+ return data;
}
-/*=======================================================================*/
-
void vr41xx_enable_piuint(uint16_t mask)
{
irq_desc_t *desc = irq_desc + PIU_IRQ;
@@ -169,7 +158,7 @@
if (current_cpu_data.cputype == CPU_VR4111 ||
current_cpu_data.cputype == CPU_VR4121) {
spin_lock_irqsave(&desc->lock, flags);
- set_icu1(MPIUINTREG, mask);
+ icu1_set(MPIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -184,7 +173,7 @@
if (current_cpu_data.cputype == CPU_VR4111 ||
current_cpu_data.cputype == CPU_VR4121) {
spin_lock_irqsave(&desc->lock, flags);
- clear_icu1(MPIUINTREG, mask);
+ icu1_clear(MPIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -199,7 +188,7 @@
if (current_cpu_data.cputype == CPU_VR4111 ||
current_cpu_data.cputype == CPU_VR4121) {
spin_lock_irqsave(&desc->lock, flags);
- set_icu1(MAIUINTREG, mask);
+ icu1_set(MAIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -214,7 +203,7 @@
if (current_cpu_data.cputype == CPU_VR4111 ||
current_cpu_data.cputype == CPU_VR4121) {
spin_lock_irqsave(&desc->lock, flags);
- clear_icu1(MAIUINTREG, mask);
+ icu1_clear(MAIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -229,7 +218,7 @@
if (current_cpu_data.cputype == CPU_VR4111 ||
current_cpu_data.cputype == CPU_VR4121) {
spin_lock_irqsave(&desc->lock, flags);
- set_icu1(MKIUINTREG, mask);
+ icu1_set(MKIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -244,7 +233,7 @@
if (current_cpu_data.cputype == CPU_VR4111 ||
current_cpu_data.cputype == CPU_VR4121) {
spin_lock_irqsave(&desc->lock, flags);
- clear_icu1(MKIUINTREG, mask);
+ icu1_clear(MKIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -257,7 +246,7 @@
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
- set_icu1(MDSIUINTREG, mask);
+ icu1_set(MDSIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
@@ -269,7 +258,7 @@
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
- clear_icu1(MDSIUINTREG, mask);
+ icu1_clear(MDSIUINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
@@ -281,7 +270,7 @@
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
- set_icu2(MFIRINTREG, mask);
+ icu2_set(MFIRINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
@@ -293,7 +282,7 @@
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
- clear_icu2(MFIRINTREG, mask);
+ icu2_clear(MFIRINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
@@ -308,7 +297,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- write_icu2(PCIINT0, MPCIINTREG);
+ icu2_write(MPCIINTREG, PCIINT0);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -324,7 +313,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- write_icu2(0, MPCIINTREG);
+ icu2_write(MPCIINTREG, 0);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -340,7 +329,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- write_icu2(SCUINT0, MSCUINTREG);
+ icu2_write(MSCUINTREG, SCUINT0);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -356,7 +345,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- write_icu2(0, MSCUINTREG);
+ icu2_write(MSCUINTREG, 0);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -372,7 +361,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- set_icu2(MCSIINTREG, mask);
+ icu2_set(MCSIINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -388,7 +377,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- clear_icu2(MCSIINTREG, mask);
+ icu2_clear(MCSIINTREG, mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -404,7 +393,7 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- write_icu2(BCUINTR, MBCUINTREG);
+ icu2_write(MBCUINTREG, BCUINTR);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
@@ -420,30 +409,28 @@
current_cpu_data.cputype == CPU_VR4131 ||
current_cpu_data.cputype == CPU_VR4133) {
spin_lock_irqsave(&desc->lock, flags);
- write_icu2(0, MBCUINTREG);
+ icu2_write(MBCUINTREG, 0);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
EXPORT_SYMBOL(vr41xx_disable_bcuint);
-/*=======================================================================*/
-
static unsigned int startup_sysint1_irq(unsigned int irq)
{
- set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+ icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
return 0; /* never anything pending */
}
static void shutdown_sysint1_irq(unsigned int irq)
{
- clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+ icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
}
static void enable_sysint1_irq(unsigned int irq)
{
- set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+ icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
}
#define disable_sysint1_irq shutdown_sysint1_irq
@@ -452,7 +439,7 @@
static void end_sysint1_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
+ icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
}
static struct hw_interrupt_type sysint1_irq_type = {
@@ -465,23 +452,21 @@
.end = end_sysint1_irq,
};
-/*=======================================================================*/
-
static unsigned int startup_sysint2_irq(unsigned int irq)
{
- set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+ icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
return 0; /* never anything pending */
}
static void shutdown_sysint2_irq(unsigned int irq)
{
- clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+ icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
}
static void enable_sysint2_irq(unsigned int irq)
{
- set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+ icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
}
#define disable_sysint2_irq shutdown_sysint2_irq
@@ -490,7 +475,7 @@
static void end_sysint2_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
+ icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
}
static struct hw_interrupt_type sysint2_irq_type = {
@@ -503,8 +488,6 @@
.end = end_sysint2_irq,
};
-/*=======================================================================*/
-
static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
{
irq_desc_t *desc = irq_desc + irq;
@@ -515,8 +498,8 @@
spin_lock_irq(&desc->lock);
- intassign0 = read_icu1(INTASSIGN0);
- intassign1 = read_icu1(INTASSIGN1);
+ intassign0 = icu1_read(INTASSIGN0);
+ intassign1 = icu1_read(INTASSIGN1);
switch (pin) {
case 0:
@@ -556,8 +539,8 @@
}
sysint1_assign[pin] = assign;
- write_icu1(intassign0, INTASSIGN0);
- write_icu1(intassign1, INTASSIGN1);
+ icu1_write(INTASSIGN0, intassign0);
+ icu1_write(INTASSIGN1, intassign1);
spin_unlock_irq(&desc->lock);
@@ -574,8 +557,8 @@
spin_lock_irq(&desc->lock);
- intassign2 = read_icu1(INTASSIGN2);
- intassign3 = read_icu1(INTASSIGN3);
+ intassign2 = icu1_read(INTASSIGN2);
+ intassign3 = icu1_read(INTASSIGN3);
switch (pin) {
case 0:
@@ -623,8 +606,8 @@
}
sysint2_assign[pin] = assign;
- write_icu1(intassign2, INTASSIGN2);
- write_icu1(intassign3, INTASSIGN3);
+ icu1_write(INTASSIGN2, intassign2);
+ icu1_write(INTASSIGN3, intassign3);
spin_unlock_irq(&desc->lock);
@@ -651,88 +634,92 @@
EXPORT_SYMBOL(vr41xx_set_intassign);
-/*=======================================================================*/
-
-asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
+static int icu_get_irq(unsigned int irq, struct pt_regs *regs)
{
uint16_t pend1, pend2;
uint16_t mask1, mask2;
int i;
- pend1 = read_icu1(SYSINT1REG);
- mask1 = read_icu1(MSYSINT1REG);
+ pend1 = icu1_read(SYSINT1REG);
+ mask1 = icu1_read(MSYSINT1REG);
- pend2 = read_icu2(SYSINT2REG);
- mask2 = read_icu2(MSYSINT2REG);
+ pend2 = icu2_read(SYSINT2REG);
+ mask2 = icu2_read(MSYSINT2REG);
mask1 &= pend1;
mask2 &= pend2;
if (mask1) {
for (i = 0; i < 16; i++) {
- if (intnum == sysint1_assign[i] &&
- (mask1 & ((uint16_t)1 << i))) {
- if (i == 8)
- giuint_irq_dispatch(regs);
- else
- do_IRQ(SYSINT1_IRQ(i), regs);
- return;
- }
+ if (irq == INT_TO_IRQ(sysint1_assign[i]) && (mask1 & (1 << i)))
+ return SYSINT1_IRQ(i);
}
}
if (mask2) {
for (i = 0; i < 16; i++) {
- if (intnum == sysint2_assign[i] &&
- (mask2 & ((uint16_t)1 << i))) {
- do_IRQ(SYSINT2_IRQ(i), regs);
- return;
- }
+ if (irq == INT_TO_IRQ(sysint2_assign[i]) && (mask2 & (1 << i)))
+ return SYSINT2_IRQ(i);
}
}
printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2);
atomic_inc(&irq_err_count);
-}
-/*=======================================================================*/
+ return -1;
+}
static int __init vr41xx_icu_init(void)
{
+ unsigned long icu1_start, icu2_start;
+ int i;
+
switch (current_cpu_data.cputype) {
case CPU_VR4111:
case CPU_VR4121:
- icu1_base = SYSINT1REG_TYPE1;
- icu2_base = SYSINT2REG_TYPE1;
+ icu1_start = ICU1_TYPE1_BASE;
+ icu2_start = ICU2_TYPE1_BASE;
break;
case CPU_VR4122:
case CPU_VR4131:
case CPU_VR4133:
- icu1_base = SYSINT1REG_TYPE2;
- icu2_base = SYSINT2REG_TYPE2;
+ icu1_start = ICU1_TYPE2_BASE;
+ icu2_start = ICU2_TYPE2_BASE;
break;
default:
printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n");
- return -EINVAL;
+ return -ENODEV;
}
- write_icu1(0, MSYSINT1REG);
- write_icu1(0xffff, MGIUINTLREG);
+ if (request_mem_region(icu1_start, ICU1_SIZE, "ICU") == NULL)
+ return -EBUSY;
- write_icu2(0, MSYSINT2REG);
- write_icu2(0xffff, MGIUINTHREG);
+ if (request_mem_region(icu2_start, ICU2_SIZE, "ICU") == NULL) {
+ release_mem_region(icu1_start, ICU1_SIZE);
+ return -EBUSY;
+ }
- return 0;
-}
+ icu1_base = ioremap(icu1_start, ICU1_SIZE);
+ if (icu1_base == NULL) {
+ release_mem_region(icu1_start, ICU1_SIZE);
+ release_mem_region(icu2_start, ICU2_SIZE);
+ return -ENOMEM;
+ }
-early_initcall(vr41xx_icu_init);
+ icu2_base = ioremap(icu2_start, ICU2_SIZE);
+ if (icu2_base == NULL) {
+ iounmap(icu1_base);
+ release_mem_region(icu1_start, ICU1_SIZE);
+ release_mem_region(icu2_start, ICU2_SIZE);
+ return -ENOMEM;
+ }
-/*=======================================================================*/
+ icu1_write(MSYSINT1REG, 0);
+ icu1_write(MGIUINTLREG, 0xffff);
-static inline void init_vr41xx_icu_irq(void)
-{
- int i;
+ icu2_write(MSYSINT2REG, 0);
+ icu2_write(MGIUINTHREG, 0xffff);
for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++)
irq_desc[i].handler = &sysint1_irq_type;
@@ -740,18 +727,13 @@
for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++)
irq_desc[i].handler = &sysint2_irq_type;
- setup_irq(INT0_CASCADE_IRQ, &icu_cascade);
- setup_irq(INT1_CASCADE_IRQ, &icu_cascade);
- setup_irq(INT2_CASCADE_IRQ, &icu_cascade);
- setup_irq(INT3_CASCADE_IRQ, &icu_cascade);
- setup_irq(INT4_CASCADE_IRQ, &icu_cascade);
+ cascade_irq(INT0_IRQ, icu_get_irq);
+ cascade_irq(INT1_IRQ, icu_get_irq);
+ cascade_irq(INT2_IRQ, icu_get_irq);
+ cascade_irq(INT3_IRQ, icu_get_irq);
+ cascade_irq(INT4_IRQ, icu_get_irq);
+
+ return 0;
}
-void __init arch_init_irq(void)
-{
- mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
- init_vr41xx_icu_irq();
- init_vr41xx_giuint_irq();
-
- set_except_vector(0, vr41xx_handle_interrupt);
-}
+core_initcall(vr41xx_icu_init);
diff --git a/arch/mips/vr41xx/common/int-handler.S b/arch/mips/vr41xx/common/int-handler.S
index 38ff89b..272c13a 100644
--- a/arch/mips/vr41xx/common/int-handler.S
+++ b/arch/mips/vr41xx/common/int-handler.S
@@ -71,24 +71,24 @@
andi t1, t0, CAUSEF_IP3 # check for Int1
bnez t1, handle_int
- li a0, 1
+ li a0, 3
andi t1, t0, CAUSEF_IP4 # check for Int2
bnez t1, handle_int
- li a0, 2
+ li a0, 4
andi t1, t0, CAUSEF_IP5 # check for Int3
bnez t1, handle_int
- li a0, 3
+ li a0, 5
andi t1, t0, CAUSEF_IP6 # check for Int4
bnez t1, handle_int
- li a0, 4
+ li a0, 6
1:
andi t1, t0, CAUSEF_IP2 # check for Int0
bnez t1, handle_int
- li a0, 0
+ li a0, 2
andi t1, t0, CAUSEF_IP0 # check for IP0
bnez t1, handle_irq
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
new file mode 100644
index 0000000..43b214d
--- /dev/null
+++ b/arch/mips/vr41xx/common/irq.c
@@ -0,0 +1,94 @@
+/*
+ * Interrupt handing routines for NEC VR4100 series.
+ *
+ * Copyright (C) 2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/system.h>
+#include <asm/vr41xx/vr41xx.h>
+
+typedef struct irq_cascade {
+ int (*get_irq)(unsigned int, struct pt_regs *);
+} irq_cascade_t;
+
+static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
+
+static struct irqaction cascade_irqaction = {
+ .handler = no_action,
+ .mask = CPU_MASK_NONE,
+ .name = "cascade",
+};
+
+int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *))
+{
+ int retval = 0;
+
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ if (irq_cascade[irq].get_irq != NULL)
+ free_irq(irq, NULL);
+
+ irq_cascade[irq].get_irq = get_irq;
+
+ if (get_irq != NULL) {
+ retval = setup_irq(irq, &cascade_irqaction);
+ if (retval < 0)
+ irq_cascade[irq].get_irq = NULL;
+ }
+
+ return retval;
+}
+
+EXPORT_SYMBOL_GPL(cascade_irq);
+
+asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs)
+{
+ irq_cascade_t *cascade;
+ irq_desc_t *desc;
+
+ if (irq >= NR_IRQS) {
+ atomic_inc(&irq_err_count);
+ return;
+ }
+
+ cascade = irq_cascade + irq;
+ if (cascade->get_irq != NULL) {
+ unsigned int source_irq = irq;
+ desc = irq_desc + source_irq;
+ desc->handler->ack(source_irq);
+ irq = cascade->get_irq(irq, regs);
+ if (irq < 0)
+ atomic_inc(&irq_err_count);
+ else
+ irq_dispatch(irq, regs);
+ desc->handler->end(source_irq);
+ } else
+ do_IRQ(irq, regs);
+}
+
+extern asmlinkage void vr41xx_handle_interrupt(void);
+
+void __init arch_init_irq(void)
+{
+ mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
+
+ set_except_vector(0, vr41xx_handle_interrupt);
+}
diff --git a/arch/mips/vr41xx/tanbac-tb0226/setup.c b/arch/mips/vr41xx/common/type.c
similarity index 84%
rename from arch/mips/vr41xx/tanbac-tb0226/setup.c
rename to arch/mips/vr41xx/common/type.c
index 60027e5..bcb5f71 100644
--- a/arch/mips/vr41xx/tanbac-tb0226/setup.c
+++ b/arch/mips/vr41xx/common/type.c
@@ -1,7 +1,7 @@
/*
- * setup.c, Setup for the TANBAC TB0226.
+ * type.c, System type for NEC VR4100 series.
*
- * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ * Copyright (C) 2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,5 +20,5 @@
const char *get_system_type(void)
{
- return "TANBAC TB0226";
+ return "NEC VR4100 series";
}
diff --git a/arch/mips/vr41xx/common/vrc4173.c b/arch/mips/vr41xx/common/vrc4173.c
index 5475dd7..ba58764 100644
--- a/arch/mips/vr41xx/common/vrc4173.c
+++ b/arch/mips/vr41xx/common/vrc4173.c
@@ -476,7 +476,7 @@
if (cascade_irq < GIU_IRQ(0) || cascade_irq > GIU_IRQ(15))
return -EINVAL;
-
+
vrc4173_outw(0, VRC4173_MSYSINT1REG);
vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq), TRIGGER_LEVEL, SIGNAL_THROUGH);
diff --git a/arch/mips/vr41xx/ibm-workpad/setup.c b/arch/mips/vr41xx/ibm-workpad/setup.c
index cff4460..e4b34ad 100644
--- a/arch/mips/vr41xx/ibm-workpad/setup.c
+++ b/arch/mips/vr41xx/ibm-workpad/setup.c
@@ -23,11 +23,6 @@
#include <asm/io.h>
#include <asm/vr41xx/workpad.h>
-const char *get_system_type(void)
-{
- return "IBM WorkPad z50";
-}
-
static int __init ibm_workpad_setup(void)
{
set_io_port_base(IO_PORT_BASE);
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/init.c b/arch/mips/vr41xx/nec-cmbvr4133/init.c
index 87f06b3..be590ed 100644
--- a/arch/mips/vr41xx/nec-cmbvr4133/init.c
+++ b/arch/mips/vr41xx/nec-cmbvr4133/init.c
@@ -16,11 +16,6 @@
* Manish Lachwani (mlachwani@mvista.com)
*/
#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/bootinfo.h>
#ifdef CONFIG_ROCKHOPPER
#include <asm/io.h>
@@ -28,14 +23,7 @@
#define PCICONFDREG 0xaf000c14
#define PCICONFAREG 0xaf000c18
-#endif
-const char *get_system_type(void)
-{
- return "NEC CMB-VR4133";
-}
-
-#ifdef CONFIG_ROCKHOPPER
void disable_pcnet(void)
{
u32 data;
diff --git a/arch/mips/vr41xx/tanbac-tb0226/Makefile b/arch/mips/vr41xx/tanbac-tb0226/Makefile
deleted file mode 100644
index 372f953..0000000
--- a/arch/mips/vr41xx/tanbac-tb0226/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the TANBAC TB0226 specific parts of the kernel
-#
-
-obj-y += setup.o
diff --git a/arch/mips/vr41xx/tanbac-tb0229/Makefile b/arch/mips/vr41xx/tanbac-tb0229/Makefile
deleted file mode 100644
index 9c6b864..0000000
--- a/arch/mips/vr41xx/tanbac-tb0229/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the TANBAC TB0229(VR4131DIMM) specific parts of the kernel
-#
-
-obj-y := setup.o
diff --git a/arch/mips/vr41xx/tanbac-tb0229/setup.c b/arch/mips/vr41xx/tanbac-tb0229/setup.c
deleted file mode 100644
index 5c1b757..0000000
--- a/arch/mips/vr41xx/tanbac-tb0229/setup.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * setup.c, Setup for the TANBAC TB0229 (VR4131DIMM)
- *
- * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- * Modified for TANBAC TB0229:
- * Copyright (C) 2003 Megasolution Inc. <matsu@megasolution.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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
- */
-
-const char *get_system_type(void)
-{
- return "TANBAC TB0229";
-}
diff --git a/arch/mips/vr41xx/victor-mpc30x/Makefile b/arch/mips/vr41xx/victor-mpc30x/Makefile
deleted file mode 100644
index a2e8086..0000000
--- a/arch/mips/vr41xx/victor-mpc30x/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Victor MP-C303/304 specific parts of the kernel
-#
-
-obj-y += setup.o
diff --git a/arch/mips/vr41xx/victor-mpc30x/setup.c b/arch/mips/vr41xx/victor-mpc30x/setup.c
deleted file mode 100644
index f591e36..0000000
--- a/arch/mips/vr41xx/victor-mpc30x/setup.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * setup.c, Setup for the Victor MP-C303/304.
- *
- * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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
- */
-
-const char *get_system_type(void)
-{
- return "Victor MP-C303/304";
-}
diff --git a/arch/mips/vr41xx/zao-capcella/Makefile b/arch/mips/vr41xx/zao-capcella/Makefile
deleted file mode 100644
index cf42019..0000000
--- a/arch/mips/vr41xx/zao-capcella/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the ZAO Networks Capcella specific parts of the kernel
-#
-
-obj-y += setup.o
diff --git a/arch/mips/vr41xx/zao-capcella/setup.c b/arch/mips/vr41xx/zao-capcella/setup.c
deleted file mode 100644
index 17bade2..0000000
--- a/arch/mips/vr41xx/zao-capcella/setup.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * setup.c, Setup for the ZAO Networks Capcella.
- *
- * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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
- */
-
-const char *get_system_type(void)
-{
- return "ZAO Networks Capcella";
-}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 1c2d874..0b07922 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -49,6 +49,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
source "init/Kconfig"
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 6cf7407..7ff67f8 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -188,10 +188,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
}
write_sequnlock_irq(&xtime_lock);
clock_was_set();
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index e6fa1d1..6ab7e5e 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -47,6 +47,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
source "init/Kconfig"
menu "Processor"
@@ -330,14 +334,6 @@
End of life: end 2000 ?
URL: see TQM850L
- SPD823TS:
- MPC823 based board used in the "Tele Server" product
- Manufacturer: Speech Design, <http://www.speech-design.de/>
- Date of Release: Mid 2000 (?)
- End of life: -
- URL: <http://www.speech-design.de/>
- select "English", then "Teleteam Solutions", then "TeleServer"
-
IVMS8:
MPC860 based board used in the "Integrated Voice Mail System",
Small Version (8 voice channels)
@@ -354,13 +350,6 @@
End of life: -
URL: <http://www.speech-design.de/>
- SM850:
- Service Module (based on TQM850L)
- Manufacturer: Dependable Computer Systems, <http://www.decomsys.com/>
- Date of Release: end 2000 (?)
- End of life: mid 2001 (?)
- URL: <http://www.tz-mikroelektronik.de/ServiceModule/index.html>
-
HERMES:
Hermes-Pro ISDN/LAN router with integrated 8 x hub
Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik
@@ -464,13 +453,6 @@
config FPS850L
bool "FPS850L"
-config SPD823TS
- bool "SPD823TS"
- help
- Say Y here to support the Speech Design 823 Tele-Server from Speech
- Design, released in 2000. The manufacturer's website is at
- <http://www.speech-design.de/>.
-
config IVMS8
bool "IVMS8"
help
@@ -485,14 +467,6 @@
from Speech Design, released March 2001. The manufacturer's website
is at <http://www.speech-design.de/>.
-config SM850
- bool "SM850"
- help
- Say Y here to support the Service Module 850 from Dependable
- Computer Systems, an SBC based on the TQM850L module by TQ
- Components. This board is no longer in production. The
- manufacturer's website is at <http://www.decomsys.com/>.
-
config HERMES_PRO
bool "HERMES"
@@ -525,6 +499,11 @@
MPC821 PowerPC, introduced in 1998 and designed to be used in
thin-client machines. Say Y to support it directly.
+ Be aware that PCI buses can only function when SYS 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
+ responsiblilty.
+
endchoice
choice
@@ -578,9 +557,6 @@
help
Select CPCI690 if configuring a Force CPCI690 cPCI board.
-config PCORE
- bool "Force-PowerCore"
-
config POWERPMC250
bool "Force-PowerPMC250"
@@ -613,9 +589,6 @@
config LOPEC
bool "Motorola-LoPEC"
-config MCPN765
- bool "Motorola-MCPN765"
-
config MVME5100
bool "Motorola-MVME5100"
@@ -637,12 +610,6 @@
config RADSTONE_PPC7D
bool "Radstone Technology PPC7D board"
-config ADIR
- bool "SBS-Adirondack"
-
-config K2
- bool "SBS-K2"
-
config PAL4
bool "SBS-Palomar4"
@@ -713,6 +680,11 @@
help
This option enables support for the MPC 834x SYS evaluation board.
+config EV64360
+ bool "Marvell-EV64360BP"
+ help
+ Select EV64360 if configuring a Marvell EV64360BP Evaluation
+ platform.
endchoice
config PQ2ADS
@@ -722,7 +694,7 @@
config TQM8xxL
bool
- depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L || SM850)
+ depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L)
default y
config EMBEDDEDBOOT
@@ -796,15 +768,15 @@
config PPC_GEN550
bool
- depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || \
- PRPMC750 || K2 || PRPMC800 || LOPEC || \
+ depends on SANDPOINT || SPRUCE || PPLUS || \
+ PRPMC750 || PRPMC800 || LOPEC || \
(EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
83xx
default y
config FORCE
bool
- depends on 6xx && (PCORE || POWERPMC250)
+ depends on 6xx && POWERPMC250
default y
config GT64260
@@ -814,7 +786,7 @@
config MV64360 # Really MV64360 & MV64460
bool
- depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU
+ depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360
default y
config MV64X60
@@ -867,7 +839,7 @@
config MPC10X_BRIDGE
bool
- depends on PCORE || POWERPMC250 || LOPEC || SANDPOINT
+ depends on POWERPMC250 || LOPEC || SANDPOINT
default y
config MPC10X_OPENPIC
@@ -886,10 +858,6 @@
If this option is enabled then the MPC824x processor will run
in DUART mode instead of UART mode.
-config CPC710_DATA_GATHERING
- bool "Enable CPC710 data gathering"
- depends on K2
-
config HARRIER_STORE_GATHERING
bool "Enable Harrier store gathering"
depends on HARRIER
@@ -1194,6 +1162,11 @@
bool
default PCI
+config MPC83xx_PCI2
+ bool " Supprt for 2nd PCI host controller"
+ depends on PCI && MPC834x
+ default y if MPC834x_SYS
+
config PCI_QSPAN
bool "QSpan PCI"
depends on !4xx && !CPM2 && 8xx
diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug
index e16c771..61653cb 100644
--- a/arch/ppc/Kconfig.debug
+++ b/arch/ppc/Kconfig.debug
@@ -62,7 +62,8 @@
config SERIAL_TEXT_DEBUG
bool "Support for early boot texts over serial port"
- depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx
+ depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
+ PPC_GEN550 || PPC_MPC52xx
config PPC_OCP
bool
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
index d4dc4fa..b7bd8f6 100644
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -96,10 +96,6 @@
zimageinitrd-$(CONFIG_GEMINI) := zImage.initrd-STRIPELF
end-$(CONFIG_GEMINI) := gemini
- extra.o-$(CONFIG_K2) := prepmap.o
- end-$(CONFIG_K2) := k2
- cacheflag-$(CONFIG_K2) := -include $(clear_L2_L3)
-
extra.o-$(CONFIG_KATANA) := misc-katana.o
end-$(CONFIG_KATANA) := katana
cacheflag-$(CONFIG_KATANA) := -include $(clear_L2_L3)
@@ -108,12 +104,15 @@
end-$(CONFIG_RADSTONE_PPC7D) := radstone_ppc7d
cacheflag-$(CONFIG_RADSTONE_PPC7D) := -include $(clear_L2_L3)
+ extra.o-$(CONFIG_EV64360) := misc-ev64360.o
+ end-$(CONFIG_EV64360) := ev64360
+ cacheflag-$(CONFIG_EV64360) := -include $(clear_L2_L3)
+
# kconfig 'feature', only one of these will ever be 'y' at a time.
# The rest will be unset.
-motorola := $(CONFIG_MCPN765)$(CONFIG_MVME5100)$(CONFIG_PRPMC750) \
+motorola := $(CONFIG_MVME5100)$(CONFIG_PRPMC750) \
$(CONFIG_PRPMC800)$(CONFIG_LOPEC)$(CONFIG_PPLUS)
motorola := $(strip $(motorola))
-pcore := $(CONFIG_PCORE)$(CONFIG_POWERPMC250)
zimage-$(motorola) := zImage-PPLUS
zimageinitrd-$(motorola) := zImage.initrd-PPLUS
@@ -123,12 +122,6 @@
extra.o-$(CONFIG_PPLUS) := prepmap.o
extra.o-$(CONFIG_LOPEC) := mpc10x_memory.o
- zimage-$(pcore) := zImage-STRIPELF
-zimageinitrd-$(pcore) := zImage.initrd-STRIPELF
- extra.o-$(pcore) := chrpmap.o
- end-$(pcore) := pcore
- cacheflag-$(pcore) := -include $(clear_L2_L3)
-
# Really only valid if CONFIG_6xx=y
zimage-$(CONFIG_PPC_PREP) := zImage-PPLUS
zimageinitrd-$(CONFIG_PPC_PREP) := zImage.initrd-PPLUS
@@ -158,8 +151,6 @@
# This is a treeboot that needs init functions until the
# boot rom is sorted out (i.e. this is short lived)
-extra-aflags-$(CONFIG_REDWOOD_4) := -Wa,-m405
-extra.o-$(CONFIG_REDWOOD_4) := rw4/rw4_init.o rw4/rw4_init_brd.o
EXTRA_AFLAGS := $(extra-aflags-y)
# head.o needs to get the cacheflags defined.
AFLAGS_head.o += $(cacheflag-y)
diff --git a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c
index c342b47..491a691 100644
--- a/arch/ppc/boot/simple/embed_config.c
+++ b/arch/ppc/boot/simple/embed_config.c
@@ -784,28 +784,12 @@
#ifdef CONFIG_IBM_OPENBIOS
/* This could possibly work for all treeboot roms.
*/
-#if defined(CONFIG_ASH) || defined(CONFIG_BEECH) || defined(CONFIG_BUBINGA)
+#if defined(CONFIG_BUBINGA)
#define BOARD_INFO_VECTOR 0xFFF80B50 /* openbios 1.19 moved this vector down - armin */
#else
#define BOARD_INFO_VECTOR 0xFFFE0B50
#endif
-#ifdef CONFIG_BEECH
-static void
-get_board_info(bd_t **bdp)
-{
- typedef void (*PFV)(bd_t *bd);
- ((PFV)(*(unsigned long *)BOARD_INFO_VECTOR))(*bdp);
- return;
-}
-
-void
-embed_config(bd_t **bdp)
-{
- *bdp = &bdinfo;
- get_board_info(bdp);
-}
-#else /* !CONFIG_BEECH */
void
embed_config(bd_t **bdp)
{
@@ -860,7 +844,6 @@
#endif
timebase_period_ns = 1000000000 / bd->bi_tbfreq;
}
-#endif /* CONFIG_BEECH */
#endif /* CONFIG_IBM_OPENBIOS */
#ifdef CONFIG_EP405
@@ -943,39 +926,3 @@
#endif
}
#endif
-
-#ifdef CONFIG_RAINIER
-/* Rainier uses vxworks bootrom */
-void
-embed_config(bd_t **bdp)
-{
- u_char *cp;
- int i;
- bd_t *bd;
-
- bd = &bdinfo;
- *bdp = bd;
-
- for(i=0;i<8192;i+=32) {
- __asm__("dccci 0,%0" :: "r" (i));
- }
- __asm__("iccci 0,0");
- __asm__("sync;isync");
-
- /* init ram for parity */
- memset(0, 0,0x400000); /* Lo memory */
-
-
- bd->bi_memsize = (32 * 1024 * 1024) ;
- bd->bi_intfreq = 133000000; //the internal clock is 133 MHz
- bd->bi_busfreq = 100000000;
- bd->bi_pci_busfreq= 33000000;
-
- cp = (u_char *)def_enet_addr;
- for (i=0; i<6; i++) {
- bd->bi_enetaddr[i] = *cp++;
- }
-
-}
-#endif
-
diff --git a/arch/ppc/boot/simple/head.S b/arch/ppc/boot/simple/head.S
index 5240532..5e4adc2 100644
--- a/arch/ppc/boot/simple/head.S
+++ b/arch/ppc/boot/simple/head.S
@@ -120,15 +120,6 @@
mtspr SPRN_DER,r4
#endif
-#ifdef CONFIG_REDWOOD_4
- /* All of this Redwood 4 stuff will soon disappear when the
- * boot rom is straightened out.
- */
- mr r29, r3 /* Easier than changing the other code */
- bl HdwInit
- mr r3, r29
-#endif
-
#if defined(CONFIG_MBX) || defined(CONFIG_RPX8260) || defined(CONFIG_PPC_PREP)
mr r4,r29 /* put the board info pointer where the relocate
* routine will find it
diff --git a/arch/ppc/boot/simple/misc-cpci690.c b/arch/ppc/boot/simple/misc-cpci690.c
index ef08e86..2686030 100644
--- a/arch/ppc/boot/simple/misc-cpci690.c
+++ b/arch/ppc/boot/simple/misc-cpci690.c
@@ -12,16 +12,56 @@
*/
#include <linux/types.h>
+#include <asm/io.h>
#include <platforms/cpci690.h>
+#define KB (1024UL)
+#define MB (1024UL*KB)
+#define GB (1024UL*MB)
+
extern u32 mv64x60_console_baud;
extern u32 mv64x60_mpsc_clk_src;
extern u32 mv64x60_mpsc_clk_freq;
+u32 mag = 0xffff;
+
+unsigned long
+get_mem_size(void)
+{
+ u32 size;
+
+ switch (in_8(((void __iomem *)CPCI690_BR_BASE + CPCI690_BR_MEM_CTLR))
+ & 0x07) {
+ case 0x01:
+ size = 256*MB;
+ break;
+ case 0x02:
+ size = 512*MB;
+ break;
+ case 0x03:
+ size = 768*MB;
+ break;
+ case 0x04:
+ size = 1*GB;
+ break;
+ case 0x05:
+ size = 1*GB + 512*MB;
+ break;
+ case 0x06:
+ size = 2*GB;
+ break;
+ default:
+ size = 0;
+ }
+
+ return size;
+}
+
void
mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
{
mv64x60_console_baud = CPCI690_MPSC_BAUD;
mv64x60_mpsc_clk_src = CPCI690_MPSC_CLK_SRC;
- mv64x60_mpsc_clk_freq = CPCI690_BUS_FREQ;
+ mv64x60_mpsc_clk_freq =
+ (get_mem_size() >= (1*GB)) ? 100000000 : 133333333;
}
diff --git a/arch/ppc/boot/simple/misc-ev64360.c b/arch/ppc/boot/simple/misc-ev64360.c
new file mode 100644
index 0000000..cd1ccf2
--- /dev/null
+++ b/arch/ppc/boot/simple/misc-ev64360.c
@@ -0,0 +1,44 @@
+/*
+ * arch/ppc/boot/simple/misc-ev64360.c
+ * Copyright (C) 2005 Lee Nicks <allinux@gmail.com>
+ *
+ * Based on arch/ppc/boot/simple/misc-katana.c from:
+ * Mark A. Greer <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/mv64x60_defs.h>
+#include <platforms/ev64360.h>
+
+extern u32 mv64x60_console_baud;
+extern u32 mv64x60_mpsc_clk_src;
+extern u32 mv64x60_mpsc_clk_freq;
+
+/* Not in the kernel so won't include kernel.h to get its 'min' definition */
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
+{
+ mv64x60_console_baud = EV64360_DEFAULT_BAUD;
+ mv64x60_mpsc_clk_src = EV64360_MPSC_CLK_SRC;
+ mv64x60_mpsc_clk_freq = EV64360_MPSC_CLK_FREQ;
+}
diff --git a/arch/ppc/boot/simple/misc-katana.c b/arch/ppc/boot/simple/misc-katana.c
index b6e1bb8..ec94a11 100644
--- a/arch/ppc/boot/simple/misc-katana.c
+++ b/arch/ppc/boot/simple/misc-katana.c
@@ -26,6 +26,8 @@
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
+unsigned long mv64360_get_mem_size(void);
+
void
mv64x60_board_init(void __iomem *old_base, void __iomem *new_base)
{
@@ -35,3 +37,9 @@
min(katana_bus_freq((void __iomem *)KATANA_CPLD_BASE),
MV64x60_TCLK_FREQ_MAX);
}
+
+unsigned long
+get_mem_size(void)
+{
+ return mv64360_get_mem_size();
+}
diff --git a/arch/ppc/boot/simple/misc-mv64x60.c b/arch/ppc/boot/simple/misc-mv64x60.c
index 7e88fc6..258d459 100644
--- a/arch/ppc/boot/simple/misc-mv64x60.c
+++ b/arch/ppc/boot/simple/misc-mv64x60.c
@@ -19,6 +19,33 @@
extern struct bi_record *decompress_kernel(unsigned long load_addr,
int num_words, unsigned long cksum);
+
+u32 size_reg[MV64x60_CPU2MEM_WINDOWS] = {
+ MV64x60_CPU2MEM_0_SIZE, MV64x60_CPU2MEM_1_SIZE,
+ MV64x60_CPU2MEM_2_SIZE, MV64x60_CPU2MEM_3_SIZE
+};
+
+/* Read mem ctlr to get the amount of mem in system */
+unsigned long
+mv64360_get_mem_size(void)
+{
+ u32 enables, i, v;
+ u32 mem = 0;
+
+ enables = in_le32((void __iomem *)CONFIG_MV64X60_NEW_BASE +
+ MV64360_CPU_BAR_ENABLE) & 0xf;
+
+ for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++)
+ if (!(enables & (1<<i))) {
+ v = in_le32((void __iomem *)CONFIG_MV64X60_NEW_BASE
+ + size_reg[i]) & 0xffff;
+ v = (v + 1) << 16;
+ mem += v;
+ }
+
+ return mem;
+}
+
void
mv64x60_move_base(void __iomem *old_base, void __iomem *new_base)
{
diff --git a/arch/ppc/boot/simple/mv64x60_tty.c b/arch/ppc/boot/simple/mv64x60_tty.c
index 5b45eb4..b9c24d4 100644
--- a/arch/ppc/boot/simple/mv64x60_tty.c
+++ b/arch/ppc/boot/simple/mv64x60_tty.c
@@ -22,9 +22,16 @@
#include <asm/mv64x60_defs.h>
#include <mpsc_defs.h>
+#ifdef CONFIG_EV64360
+#include <platforms/ev64360.h>
+u32 mv64x60_console_baud = EV64360_DEFAULT_BAUD;
+u32 mv64x60_mpsc_clk_src = EV64360_MPSC_CLK_SRC; /* TCLK */
+u32 mv64x60_mpsc_clk_freq = EV64360_MPSC_CLK_FREQ;
+#else
u32 mv64x60_console_baud = 9600;
u32 mv64x60_mpsc_clk_src = 8; /* TCLK */
u32 mv64x60_mpsc_clk_freq = 100000000;
+#endif
extern void udelay(long);
static void stop_dma(int chan);
diff --git a/arch/ppc/configs/SM850_defconfig b/arch/ppc/configs/SM850_defconfig
deleted file mode 100644
index 021884b..0000000
--- a/arch/ppc/configs/SM850_defconfig
+++ /dev/null
@@ -1,522 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-CONFIG_8xx=y
-
-#
-# IBM 4xx options
-#
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_RPXLITE is not set
-# CONFIG_RPXCLASSIC is not set
-# CONFIG_BSEIP is not set
-# CONFIG_FADS is not set
-# CONFIG_TQM823L is not set
-# CONFIG_TQM850L is not set
-# CONFIG_TQM855L is not set
-# CONFIG_TQM860L is not set
-# CONFIG_FPS850L is not set
-# CONFIG_SPD823TS is not set
-# CONFIG_IVMS8 is not set
-# CONFIG_IVML24 is not set
-CONFIG_SM850=y
-# CONFIG_HERMES_PRO is not set
-# CONFIG_IP860 is not set
-# CONFIG_LWMON is not set
-# CONFIG_PCU_E is not set
-# CONFIG_CCM is not set
-# CONFIG_LANTEC is not set
-# CONFIG_MBX is not set
-# CONFIG_WINCEPT is not set
-CONFIG_TQM8xxL=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_MATH_EMULATION=y
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyCPM1"
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_SERIAL_CPM_SCC1 is not set
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-# CONFIG_SERIAL_CPM_SCC4 is not set
-CONFIG_SERIAL_CPM_SMC1=y
-CONFIG_SERIAL_CPM_SMC2=y
-CONFIG_SERIAL_CPM_ALT_SMC2=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# MPC8xx CPM Options
-#
-CONFIG_SCC_ENET=y
-# CONFIG_SCC1_ENET is not set
-# CONFIG_SCC2_ENET is not set
-CONFIG_SCC3_ENET=y
-# CONFIG_FEC_ENET is not set
-CONFIG_ENET_BIG_BUFFERS=y
-
-#
-# Generic MPC8xx Options
-#
-CONFIG_8xx_COPYBACK=y
-CONFIG_8xx_CPU6=y
-# CONFIG_UCODE_PATCH is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/SPD823TS_defconfig b/arch/ppc/configs/SPD823TS_defconfig
deleted file mode 100644
index ba60fea..0000000
--- a/arch/ppc/configs/SPD823TS_defconfig
+++ /dev/null
@@ -1,520 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-CONFIG_8xx=y
-
-#
-# IBM 4xx options
-#
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_RPXLITE is not set
-# CONFIG_RPXCLASSIC is not set
-# CONFIG_BSEIP is not set
-# CONFIG_FADS is not set
-# CONFIG_TQM823L is not set
-# CONFIG_TQM850L is not set
-# CONFIG_TQM855L is not set
-# CONFIG_TQM860L is not set
-# CONFIG_FPS850L is not set
-CONFIG_SPD823TS=y
-# CONFIG_IVMS8 is not set
-# CONFIG_IVML24 is not set
-# CONFIG_SM850 is not set
-# CONFIG_HERMES_PRO is not set
-# CONFIG_IP860 is not set
-# CONFIG_LWMON is not set
-# CONFIG_PCU_E is not set
-# CONFIG_CCM is not set
-# CONFIG_LANTEC is not set
-# CONFIG_MBX is not set
-# CONFIG_WINCEPT is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_MATH_EMULATION=y
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_SERIAL_CPM_SCC1 is not set
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-# CONFIG_SERIAL_CPM_SCC4 is not set
-CONFIG_SERIAL_CPM_SMC1=y
-# CONFIG_SERIAL_CPM_SMC2 is not set
-CONFIG_SERIAL_CPM_ALT_SMC2=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# MPC8xx CPM Options
-#
-CONFIG_SCC_ENET=y
-# CONFIG_SCC1_ENET is not set
-CONFIG_SCC2_ENET=y
-# CONFIG_SCC3_ENET is not set
-# CONFIG_FEC_ENET is not set
-CONFIG_ENET_BIG_BUFFERS=y
-
-#
-# Generic MPC8xx Options
-#
-CONFIG_8xx_COPYBACK=y
-# CONFIG_8xx_CPU6 is not set
-# CONFIG_UCODE_PATCH is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/adir_defconfig b/arch/ppc/configs/adir_defconfig
deleted file mode 100644
index f20e653..0000000
--- a/arch/ppc/configs/adir_defconfig
+++ /dev/null
@@ -1,805 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-
-#
-# IBM 4xx options
-#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-CONFIG_ADIR=y
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_PCI_LEGACY_PROC=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
-# CONFIG_PARPORT_SERIAL is not set
-CONFIG_PARPORT_PC_FIFO=y
-CONFIG_PARPORT_PC_SUPERIO=y
-# CONFIG_PARPORT_OTHER is not set
-CONFIG_PARPORT_1284=y
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-# CONFIG_IP_NF_TARGET_ULOG is not set
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_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_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
-# CONFIG_TIPAR is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-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=y
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_UHCI_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_BLUETOOTH_TTY is not set
-CONFIG_USB_ACM=m
-# CONFIG_USB_PRINTER is not set
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-CONFIG_USB_STORAGE_FREECOM=y
-# CONFIG_USB_STORAGE_ISD200 is not set
-CONFIG_USB_STORAGE_DPCM=y
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-CONFIG_USB_HID=m
-
-#
-# Input core support is needed for USB HID input layer or HIDBP support
-#
-CONFIG_USB_HIDDEV=y
-
-#
-# USB HID Boot Protocol drivers
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# 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 is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-CONFIG_USB_SERIAL=m
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-CONFIG_USB_SERIAL_VISOR=m
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-CONFIG_USB_SERIAL_KEYSPAN=m
-# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_SAFE is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-CONFIG_USB_EZUSB=y
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_TIGL is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/ash_defconfig b/arch/ppc/configs/ash_defconfig
deleted file mode 100644
index c4a73cc..0000000
--- a/arch/ppc/configs/ash_defconfig
+++ /dev/null
@@ -1,666 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-CONFIG_ASH=y
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_EVB405EP is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_WALNUT is not set
-CONFIG_NP405H=y
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_PPC_OCP=y
-CONFIG_IBM_OPENBIOS=y
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_LEGACY_PROC=y
-# CONFIG_PCI_NAMES 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=0x00400000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_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_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_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# 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_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-CONFIG_IBM_EMAC=y
-# CONFIG_IBM_EMAC_ERRMSG is not set
-CONFIG_IBM_EMAC_RXB=64
-CONFIG_IBM_EMAC_TXB=8
-CONFIG_IBM_EMAC_FGAP=8
-CONFIG_IBM_EMAC_SKBRES=0
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# 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_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ALI1535 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_IBM_IIC is not set
-# CONFIG_I2C_ISA is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-
-#
-# Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 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_LM90 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM 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
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_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_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# IBM 40x options
-#
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/beech_defconfig b/arch/ppc/configs/beech_defconfig
deleted file mode 100644
index 0bd671b..0000000
--- a/arch/ppc/configs/beech_defconfig
+++ /dev/null
@@ -1,615 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-CONFIG_BEECH=y
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_IBM_OPENBIOS=y
-CONFIG_405_DMA=y
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT 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=0x00400000
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL 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 is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CFI_AMDSTD=y
-# CONFIG_MTD_CFI_STAA is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_BEECH=y
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD 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
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-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_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN 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_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_CT65550 is not set
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# 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 I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 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
-
-#
-# Macintosh device drivers
-#
-
-#
-# 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_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-CONFIG_I2C_IBM_IIC=y
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/cedar_defconfig b/arch/ppc/configs/cedar_defconfig
deleted file mode 100644
index 5de8288..0000000
--- a/arch/ppc/configs/cedar_defconfig
+++ /dev/null
@@ -1,534 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-CONFIG_CEDAR=y
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_NP405L=y
-CONFIG_BIOS_FIXUP=y
-CONFIG_IBM_OPENBIOS=y
-# CONFIG_405_DMA is not set
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN 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_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_IBM_OCP_ALGO=y
-CONFIG_I2C_IBM_OCP_ADAP=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_SC520_WDT is not set
-# CONFIG_AMD7XX_TCO is not set
-# CONFIG_ALIM7101_WDT is not set
-# CONFIG_SC1200_WDT is not set
-# CONFIG_WAFER_WDT is not set
-# CONFIG_CPU5_WDT is not set
-# 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
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/cpci690_defconfig b/arch/ppc/configs/cpci690_defconfig
index 5394879..ff3f7e0 100644
--- a/arch/ppc/configs/cpci690_defconfig
+++ b/arch/ppc/configs/cpci690_defconfig
@@ -1,15 +1,17 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Fri Dec 3 15:56:10 2004
+# Linux kernel version: 2.6.13-mm1
+# Thu Sep 1 17:10:37 2005
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
#
# Code maturity level options
@@ -17,33 +19,38 @@
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -65,38 +72,42 @@
# CONFIG_POWER3 is not set
# CONFIG_POWER4 is not set
# CONFIG_8xx is not set
+# CONFIG_E200 is not set
# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
CONFIG_ALTIVEC=y
# CONFIG_TAU is not set
+# CONFIG_KEXEC is not set
# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
CONFIG_PPC_STD_MMU=y
# CONFIG_NOT_COHERENT_CACHE is not set
#
+# Performance-monitoring counters support
+#
+# CONFIG_PERFCTR is not set
+
+#
# Platform options
#
# CONFIG_PPC_MULTIPLATFORM is not set
# CONFIG_APUS is not set
# CONFIG_KATANA is not set
-# CONFIG_DMV182 is not set
# CONFIG_WILLOW is not set
CONFIG_CPCI690=y
-# CONFIG_PCORE is not set
# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_DB64360 is not set
# CONFIG_CHESTNUT is not set
# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
# CONFIG_MVME5100 is not set
# CONFIG_PPLUS is not set
# CONFIG_PRPMC750 is not set
# CONFIG_PRPMC800 is not set
-# CONFIG_PRPMC880 is not set
# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
+# CONFIG_RADSTONE_PPC7D is not set
# CONFIG_PAL4 is not set
# CONFIG_GEMINI is not set
# CONFIG_EST8260 is not set
@@ -105,22 +116,41 @@
# CONFIG_RPX8260 is not set
# CONFIG_TQM8260 is not set
# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_EV64360 is not set
+CONFIG_GT64260=y
+CONFIG_MV64X60=y
#
# Set bridge options
#
CONFIG_MV64X60_BASE=0xf1000000
CONFIG_MV64X60_NEW_BASE=0xf1000000
-CONFIG_GT64260=y
-CONFIG_MV64X60=y
# CONFIG_SMP is not set
+CONFIG_HIGHMEM=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM 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_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyMM0,9600 ip=on"
+CONFIG_CMDLINE="console=ttyMM0 ip=on"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
#
# Bus options
@@ -129,7 +159,11 @@
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
#
# Advanced setup
@@ -146,6 +180,76 @@
CONFIG_BOOT_LOAD=0x00800000
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK 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
#
@@ -154,6 +258,7 @@
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
#
# Memory Technology Devices (MTD)
@@ -177,6 +282,7 @@
# 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
@@ -185,7 +291,6 @@
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
@@ -196,6 +301,7 @@
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -205,6 +311,7 @@
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
#
@@ -215,6 +322,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -231,71 +339,8 @@
#
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_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_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -308,6 +353,11 @@
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -328,6 +378,7 @@
# 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=y
# CONFIG_PCNET32 is not set
@@ -337,7 +388,6 @@
# CONFIG_FORCEDETH is not set
# CONFIG_DGRS is not set
CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
@@ -360,13 +410,18 @@
# 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
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
@@ -390,6 +445,11 @@
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -419,14 +479,6 @@
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -436,6 +488,12 @@
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
@@ -455,6 +513,7 @@
CONFIG_SERIAL_MPSC_CONSOLE=y
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
@@ -483,6 +542,11 @@
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
@@ -493,10 +557,21 @@
# CONFIG_W1 is not set
#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
# Misc devices
#
#
+# Multimedia Capabilities Port drivers
+#
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -518,6 +593,11 @@
CONFIG_DUMMY_CONSOLE=y
#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+
+#
# Sound
#
# CONFIG_SOUND is not set
@@ -525,13 +605,9 @@
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
#
# USB Gadget Support
@@ -539,21 +615,49 @@
# CONFIG_USB_GADGET is not set
#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# 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_JBD is not set
+# CONFIG_REISER4_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_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_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
@@ -574,20 +678,18 @@
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -605,13 +707,14 @@
#
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_EXPORTFS is not set
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
CONFIG_RPCSEC_GSS_KRB5=y
@@ -621,6 +724,7 @@
# 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
@@ -637,6 +741,7 @@
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
@@ -648,7 +753,9 @@
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_SERIAL_TEXT_DEBUG is not set
#
@@ -669,6 +776,7 @@
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
@@ -684,3 +792,7 @@
# 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/ppc/configs/ev64360_defconfig b/arch/ppc/configs/ev64360_defconfig
new file mode 100644
index 0000000..de9bbb7
--- /dev/null
+++ b/arch/ppc/configs/ev64360_defconfig
@@ -0,0 +1,784 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-rc5
+# Fri Aug 5 15:18:23 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_EV64360=y
+CONFIG_MV64360=y
+CONFIG_MV64X60=y
+
+#
+# Set bridge options
+#
+CONFIG_MV64X60_BASE=0xf1000000
+CONFIG_MV64X60_NEW_BASE=0xf1000000
+# CONFIG_SMP is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=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_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyMM0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2"
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+# CONFIG_KERNEL_START_BOOL is not set
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_CONSISTENT_START_BOOL is not set
+CONFIG_CONSISTENT_START=0xff100000
+# CONFIG_CONSISTENT_SIZE_BOOL is not set
+CONFIG_CONSISTENT_SIZE=0x00200000
+# CONFIG_BOOT_LOAD_BOOL is not set
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE 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
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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 is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL 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=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=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+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 is not set
+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=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xff000000
+CONFIG_MTD_PHYSMAP_LEN=0x01000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+# 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=y
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD 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
+
+#
+# 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_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# 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
+
+#
+# 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_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+# CONFIG_MV643XX_ETH_1 is not set
+# CONFIG_MV643XX_ETH_2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO 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_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
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_MPSC=y
+CONFIG_SERIAL_MPSC_CONSOLE=y
+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_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_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 is not set
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# 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=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/k2_defconfig b/arch/ppc/configs/k2_defconfig
deleted file mode 100644
index f10f5a6..0000000
--- a/arch/ppc/configs/k2_defconfig
+++ /dev/null
@@ -1,680 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-CONFIG_K2=y
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_GEN550=y
-# CONFIG_CPC710_DATA_GATHERING is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES 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
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE 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_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-CONFIG_BLK_DEV_ALI15X3=y
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-# CONFIG_IP_NF_IRC is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-# CONFIG_IP_NF_MATCH_IPRANGE is not set
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-# CONFIG_IP_NF_MATCH_RECENT is not set
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-# CONFIG_IP_NF_MATCH_LENGTH is not set
-# CONFIG_IP_NF_MATCH_TTL is not set
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_SAME is not set
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-# CONFIG_IP_NF_ARP_MANGLE is not set
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IP_NF_RAW is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_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_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO 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_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE 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
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# 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=2
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_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_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/katana_defconfig b/arch/ppc/configs/katana_defconfig
index f0b0d57..0f3bb9a 100644
--- a/arch/ppc/configs/katana_defconfig
+++ b/arch/ppc/configs/katana_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11
-# Tue Mar 8 17:31:00 2005
+# Linux kernel version: 2.6.13-mm1
+# Thu Sep 1 17:16:03 2005
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
#
# Code maturity level options
@@ -18,28 +19,31 @@
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=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_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
@@ -68,15 +72,23 @@
# CONFIG_POWER3 is not set
# CONFIG_POWER4 is not set
# CONFIG_8xx is not set
+# CONFIG_E200 is not set
# CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
CONFIG_ALTIVEC=y
# CONFIG_TAU is not set
+# CONFIG_KEXEC is not set
# CONFIG_CPU_FREQ is not set
-# CONFIG_83xx is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
CONFIG_PPC_STD_MMU=y
CONFIG_NOT_COHERENT_CACHE=y
#
+# Performance-monitoring counters support
+#
+# CONFIG_PERFCTR is not set
+
+#
# Platform options
#
# CONFIG_PPC_MULTIPLATFORM is not set
@@ -84,21 +96,18 @@
CONFIG_KATANA=y
# CONFIG_WILLOW is not set
# CONFIG_CPCI690 is not set
-# CONFIG_PCORE is not set
# CONFIG_POWERPMC250 is not set
# CONFIG_CHESTNUT is not set
# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
# CONFIG_EV64260 is not set
# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
# CONFIG_MVME5100 is not set
# CONFIG_PPLUS is not set
# CONFIG_PRPMC750 is not set
# CONFIG_PRPMC800 is not set
# CONFIG_SANDPOINT is not set
# CONFIG_RADSTONE_PPC7D is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
# CONFIG_PAL4 is not set
# CONFIG_GEMINI is not set
# CONFIG_EST8260 is not set
@@ -109,6 +118,8 @@
# CONFIG_ADS8272 is not set
# CONFIG_PQ2FADS is not set
# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_EV64360 is not set
CONFIG_MV64360=y
CONFIG_MV64X60=y
@@ -118,12 +129,28 @@
CONFIG_MV64X60_BASE=0xf8100000
CONFIG_MV64X60_NEW_BASE=0xf8100000
# CONFIG_SMP is not set
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM 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_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyMM0,9600 ip=on"
+CONFIG_CMDLINE="console=ttyMM0 ip=on"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
#
# Bus options
@@ -132,7 +159,6 @@
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
#
# PCCARD (PCMCIA/CardBus) support
@@ -140,13 +166,10 @@
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# Advanced setup
#
CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_HIGHMEM_START_BOOL is not set
CONFIG_HIGHMEM_START=0xfe000000
# CONFIG_LOWMEM_SIZE_BOOL is not set
CONFIG_LOWMEM_SIZE=0x30000000
@@ -162,6 +185,76 @@
CONFIG_BOOT_LOAD=0x00800000
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK 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
#
@@ -177,8 +270,8 @@
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
@@ -212,6 +305,7 @@
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=y
# CONFIG_MTD_CFI_AMDSTD is not set
# CONFIG_MTD_CFI_STAA is not set
@@ -219,7 +313,6 @@
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
#
# Mapping drivers for chip access
@@ -229,6 +322,7 @@
CONFIG_MTD_PHYSMAP_START=0xe0000000
CONFIG_MTD_PHYSMAP_LEN=0x0
CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -278,7 +372,6 @@
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
@@ -299,6 +392,7 @@
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
#
@@ -309,6 +403,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -325,71 +420,8 @@
#
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_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_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -402,6 +434,11 @@
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -422,6 +459,7 @@
# 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=y
# CONFIG_PCNET32 is not set
@@ -448,14 +486,19 @@
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI 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_MV643XX_ETH=y
CONFIG_MV643XX_ETH_0=y
CONFIG_MV643XX_ETH_1=y
@@ -464,6 +507,7 @@
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
@@ -487,6 +531,11 @@
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -516,14 +565,6 @@
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -533,6 +574,12 @@
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
@@ -552,6 +599,7 @@
CONFIG_SERIAL_MPSC_CONSOLE=y
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
@@ -580,6 +628,11 @@
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
# I2C support
#
CONFIG_I2C=y
@@ -602,11 +655,10 @@
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
@@ -621,14 +673,39 @@
CONFIG_I2C_MV64XXX=y
#
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
#
-# CONFIG_I2C_SENSOR is not set
+# 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_RTC8564 is not set
+CONFIG_SENSORS_M41T00=y
+# 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID 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_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -644,39 +721,29 @@
# 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_SMSC47B397 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-CONFIG_SENSORS_M41T00=y
-# 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
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
#
#
+# Multimedia Capabilities Port drivers
+#
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -698,6 +765,11 @@
CONFIG_DUMMY_CONSOLE=y
#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+
+#
# Sound
#
# CONFIG_SOUND is not set
@@ -705,13 +777,9 @@
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
#
# USB Gadget Support
@@ -729,25 +797,39 @@
# CONFIG_INFINIBAND is not set
#
+# SN Devices
+#
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# 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_JBD is not set
+# CONFIG_REISER4_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
#
# CONFIG_XFS_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_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
@@ -768,20 +850,18 @@
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_ASFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -801,12 +881,14 @@
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -815,6 +897,7 @@
# 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
@@ -831,6 +914,7 @@
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
@@ -842,8 +926,10 @@
#
# Kernel hacking
#
-# CONFIG_DEBUG_KERNEL is not set
# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG is not set
#
# Security options
diff --git a/arch/ppc/configs/mcpn765_defconfig b/arch/ppc/configs/mcpn765_defconfig
deleted file mode 100644
index 899e89a..0000000
--- a/arch/ppc/configs/mcpn765_defconfig
+++ /dev/null
@@ -1,579 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_KMOD is not set
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-CONFIG_ALTIVEC=y
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-CONFIG_MCPN765=y
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_GEN550=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_HIGHMEM=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES 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
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-CONFIG_BLK_DEV_VIA82CXXX=y
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-CONFIG_TULIP=y
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT 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
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# 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_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/menf1_defconfig b/arch/ppc/configs/menf1_defconfig
deleted file mode 100644
index 321659b..0000000
--- a/arch/ppc/configs/menf1_defconfig
+++ /dev/null
@@ -1,621 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-
-#
-# IBM 4xx options
-#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-CONFIG_MENF1=y
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-CONFIG_MPC10X_STORE_GATHERING=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_IDEPCI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_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_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/mpc8560_ads_defconfig b/arch/ppc/configs/mpc8560_ads_defconfig
index 38a343c..f834fb5 100644
--- a/arch/ppc/configs/mpc8560_ads_defconfig
+++ b/arch/ppc/configs/mpc8560_ads_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc1
-# Thu Jan 20 01:24:56 2005
+# Linux kernel version: 2.6.13-rc6
+# Thu Aug 11 18:14:45 2005
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
#
# Code maturity level options
@@ -18,6 +19,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -29,12 +31,14 @@
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -44,6 +48,7 @@
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -59,12 +64,16 @@
# CONFIG_POWER3 is not set
# CONFIG_POWER4 is not set
# CONFIG_8xx is not set
+# CONFIG_E200 is not set
CONFIG_E500=y
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
CONFIG_SPE=y
CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
CONFIG_85xx=y
CONFIG_PPC_INDIRECT_PCI_BE=y
@@ -72,9 +81,11 @@
# Freescale 85xx options
#
# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8548_CDS is not set
# CONFIG_MPC8555_CDS is not set
CONFIG_MPC8560_ADS=y
# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
CONFIG_MPC8560=y
#
@@ -83,11 +94,25 @@
CONFIG_CPM2=y
# CONFIG_PC_KEYBOARD is not set
# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_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_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_CMDLINE_BOOL is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
#
# Bus options
@@ -103,10 +128,6 @@
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# Advanced setup
#
# CONFIG_ADVANCED_OPTIONS is not set
@@ -121,6 +142,69 @@
CONFIG_BOOT_LOAD=0x00800000
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=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_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE 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
+
+#
# Device Drivers
#
@@ -193,6 +277,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -209,71 +294,8 @@
#
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_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_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -311,8 +333,10 @@
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE 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
@@ -342,6 +366,8 @@
# 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
@@ -368,14 +394,6 @@
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -385,6 +403,12 @@
# 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
@@ -403,11 +427,12 @@
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
CONFIG_SERIAL_CPM_SCC1=y
-# CONFIG_SERIAL_CPM_SCC2 is not set
+CONFIG_SERIAL_CPM_SCC2=y
# CONFIG_SERIAL_CPM_SCC3 is not set
-CONFIG_SERIAL_CPM_SCC4=y
+# CONFIG_SERIAL_CPM_SCC4 is not set
# CONFIG_SERIAL_CPM_SMC1 is not set
# CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -436,6 +461,11 @@
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
# I2C support
#
CONFIG_I2C=y
@@ -458,11 +488,11 @@
# 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_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
@@ -473,19 +503,46 @@
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_SENSOR is not set
#
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
#
-# CONFIG_I2C_SENSOR is not set
+# 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_RTC8564 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
# 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_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
@@ -496,31 +553,18 @@
# 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_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 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
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -540,7 +584,6 @@
# Graphics support
#
# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -550,13 +593,9 @@
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
#
# USB Gadget Support
@@ -574,10 +613,15 @@
# CONFIG_INFINIBAND is not set
#
+# SN Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -587,9 +631,15 @@
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -614,7 +664,6 @@
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
@@ -648,7 +697,7 @@
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -700,7 +749,9 @@
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_KGDB_CONSOLE is not set
#
diff --git a/arch/ppc/configs/oak_defconfig b/arch/ppc/configs/oak_defconfig
deleted file mode 100644
index 366cc48..0000000
--- a/arch/ppc/configs/oak_defconfig
+++ /dev/null
@@ -1,485 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-CONFIG_OAK=y
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR51=y
-CONFIG_403GCX=y
-# CONFIG_405_DMA is not set
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN 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_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-CONFIG_OAKNET=y
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/pcore_defconfig b/arch/ppc/configs/pcore_defconfig
deleted file mode 100644
index ed34405..0000000
--- a/arch/ppc/configs/pcore_defconfig
+++ /dev/null
@@ -1,716 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-CONFIG_ALTIVEC=y
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-CONFIG_PCORE=y
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX6 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_PPC_GEN550=y
-CONFIG_FORCE=y
-# CONFIG_MPC10X_STORE_GATHERING is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
-
-#
-# Bus options
-#
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES 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
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-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=y
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INIA100 is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 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
-
-#
-# 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
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE 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
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-# CONFIG_IP_NF_MATCH_IPRANGE is not set
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-# CONFIG_IP_NF_MATCH_RECENT is not set
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_SAME is not set
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-# CONFIG_IP_NF_ARP_MANGLE is not set
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 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=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_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_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT 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
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# 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=2
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_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_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/rainier_defconfig b/arch/ppc/configs/rainier_defconfig
deleted file mode 100644
index 4d4fcdc..0000000
--- a/arch/ppc/configs/rainier_defconfig
+++ /dev/null
@@ -1,599 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-CONFIG_WALNUT=y
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_BIOS_FIXUP=y
-CONFIG_405GP=y
-CONFIG_IBM_OPENBIOS=y
-CONFIG_405_DMA=y
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_NOT_COHERENT_CACHE=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN 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_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_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_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_PPP=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_PPPOE is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_IBM_OCP_ALGO is not set
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-# 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_PIIX4 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-CONFIG_BUSMOUSE=y
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_SCx200_WDT is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-# CONFIG_SC520_WDT is not set
-# CONFIG_AMD7XX_TCO is not set
-# CONFIG_ALIM7101_WDT is not set
-# CONFIG_SC1200_WDT is not set
-# CONFIG_WAFER_WDT is not set
-# CONFIG_CPU5_WDT is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/redwood_defconfig b/arch/ppc/configs/redwood_defconfig
deleted file mode 100644
index 4aa348d..0000000
--- a/arch/ppc/configs/redwood_defconfig
+++ /dev/null
@@ -1,540 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-CONFIG_40x=y
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-# CONFIG_8xx is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_4xx=y
-
-#
-# IBM 4xx options
-#
-# CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-CONFIG_REDWOOD_4=y
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_REDWOOD_6 is not set
-# CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM405_ERR51=y
-CONFIG_IBM_OCP=y
-CONFIG_STB03xxx=y
-CONFIG_IBM_OPENBIOS=y
-# CONFIG_405_DMA is not set
-# CONFIG_PM is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-# CONFIG_SERIAL_SICC is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT 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=0x00400000
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-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_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN 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_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_OAKNET=y
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# 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 I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 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
-
-#
-# Macintosh device drivers
-#
-
-#
-# 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_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-CONFIG_I2C_IBM_IIC=y
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# IBM 40x options
-#
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_SERIAL_TEXT_DEBUG=y
-CONFIG_OCP=y
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S
index 468721d..bd037ca 100644
--- a/arch/ppc/kernel/cpu_setup_6xx.S
+++ b/arch/ppc/kernel/cpu_setup_6xx.S
@@ -249,8 +249,11 @@
sync
isync
- /* Enable L2 HW prefetch
+ /* Enable L2 HW prefetch, if L2 is enabled
*/
+ mfspr r3,SPRN_L2CR
+ andis. r3,r3,L2CR_L2E@h
+ beqlr
mfspr r3,SPRN_MSSCR0
ori r3,r3,3
sync
@@ -324,6 +327,7 @@
cmplwi cr4,r3,0x8002 /* 7457 */
cmplwi cr5,r3,0x8003 /* 7447A */
cmplwi cr6,r3,0x7000 /* 750FX */
+ cmplwi cr7,r3,0x8004 /* 7448 */
/* cr1 is 7400 || 7410 */
cror 4*cr1+eq,4*cr1+eq,4*cr2+eq
/* cr0 is 74xx */
@@ -331,6 +335,7 @@
cror 4*cr0+eq,4*cr0+eq,4*cr4+eq
cror 4*cr0+eq,4*cr0+eq,4*cr1+eq
cror 4*cr0+eq,4*cr0+eq,4*cr5+eq
+ cror 4*cr0+eq,4*cr0+eq,4*cr7+eq
bne 1f
/* Backup 74xx specific regs */
mfspr r4,SPRN_MSSCR0
@@ -393,6 +398,7 @@
cmplwi cr4,r3,0x8002 /* 7457 */
cmplwi cr5,r3,0x8003 /* 7447A */
cmplwi cr6,r3,0x7000 /* 750FX */
+ cmplwi cr7,r3,0x8004 /* 7448 */
/* cr1 is 7400 || 7410 */
cror 4*cr1+eq,4*cr1+eq,4*cr2+eq
/* cr0 is 74xx */
@@ -400,6 +406,7 @@
cror 4*cr0+eq,4*cr0+eq,4*cr4+eq
cror 4*cr0+eq,4*cr0+eq,4*cr1+eq
cror 4*cr0+eq,4*cr0+eq,4*cr5+eq
+ cror 4*cr0+eq,4*cr0+eq,4*cr7+eq
bne 2f
/* Restore 74xx specific regs */
lwz r4,CS_MSSCR0(r5)
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
index 8a3d74f..546e1ea 100644
--- a/arch/ppc/kernel/cputable.c
+++ b/arch/ppc/kernel/cputable.c
@@ -198,20 +198,6 @@
.num_pmcs = 4,
.cpu_setup = __setup_cpu_750
},
- { /* 745/755 */
- .pvr_mask = 0xfffff000,
- .pvr_value = 0x00083000,
- .cpu_name = "745/755",
- .cpu_features = CPU_FTR_COMMON |
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
- CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
- CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
- .cpu_user_features = COMMON_PPC,
- .icache_bsize = 32,
- .dcache_bsize = 32,
- .num_pmcs = 4,
- .cpu_setup = __setup_cpu_750
- },
{ /* 750CX (80100 and 8010x?) */
.pvr_mask = 0xfffffff0,
.pvr_value = 0x00080100,
@@ -254,6 +240,34 @@
.num_pmcs = 4,
.cpu_setup = __setup_cpu_750cx
},
+ { /* 750CXe "Gekko" (83214) */
+ .pvr_mask = 0xffffffff,
+ .pvr_value = 0x00083214,
+ .cpu_name = "750CXe",
+ .cpu_features = CPU_FTR_COMMON |
+ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
+ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
+ CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
+ .cpu_user_features = COMMON_PPC,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750cx
+ },
+ { /* 745/755 */
+ .pvr_mask = 0xfffff000,
+ .pvr_value = 0x00083000,
+ .cpu_name = "745/755",
+ .cpu_features = CPU_FTR_COMMON |
+ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
+ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
+ CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
+ .cpu_user_features = COMMON_PPC,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750
+ },
{ /* 750FX rev 1.x */
.pvr_mask = 0xffffff00,
.pvr_value = 0x70000100,
@@ -536,6 +550,22 @@
.num_pmcs = 6,
.cpu_setup = __setup_cpu_745x
},
+ { /* 7448 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x80040000,
+ .cpu_name = "7448",
+ .cpu_features = CPU_FTR_COMMON |
+ CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR |
+ CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
+ CPU_FTR_HAS_HIGH_BATS | CPU_FTR_NEED_COHERENT,
+ .cpu_user_features = COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 6,
+ .cpu_setup = __setup_cpu_745x
+ },
{ /* 82xx (8240, 8245, 8260 are all 603e cores) */
.pvr_mask = 0x7fff0000,
.pvr_value = 0x00810000,
@@ -922,6 +952,26 @@
.icache_bsize = 32,
.dcache_bsize = 32,
},
+ { /* 440GX Rev. F */
+ .pvr_mask = 0xf0000fff,
+ .pvr_value = 0x50000894,
+ .cpu_name = "440GX Rev. F",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB,
+ .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ },
+ { /* 440SP Rev. A */
+ .pvr_mask = 0xff000fff,
+ .pvr_value = 0x53000891,
+ .cpu_name = "440SP Rev. A",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB,
+ .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ },
#endif /* CONFIG_44x */
#ifdef CONFIG_FSL_BOOKE
{ /* e200z5 */
diff --git a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c
deleted file mode 100644
index 3c0fa8e..0000000
--- a/arch/ppc/kernel/find_name.c
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <stdio.h>
-#include <asm/page.h>
-#include <sys/mman.h>
-#include <strings.h>
-/*
- * Finds a given address in the System.map and prints it out
- * with its neighbors. -- Cort
- */
-
-int main(int argc, char **argv)
-{
- unsigned long addr, cmp, i;
- FILE *f;
- char s[256], last[256];
-
- if ( argc < 2 )
- {
- fprintf(stderr, "Usage: %s <address>\n", argv[0]);
- return -1;
- }
-
- for ( i = 1 ; argv[i] ; i++ )
- {
- sscanf( argv[i], "%0lx", &addr );
- /* adjust if addr is relative to kernelbase */
- if ( addr < PAGE_OFFSET )
- addr += PAGE_OFFSET;
-
- if ( (f = fopen( "System.map", "r" )) == NULL )
- {
- perror("fopen()\n");
- exit(-1);
- }
-
- while ( !feof(f) )
- {
- fgets(s, 255 , f);
- sscanf( s, "%0lx", &cmp );
- if ( addr < cmp )
- break;
- strcpy( last, s);
- }
-
- printf( "%s%s", last, s );
- }
- fclose(f);
- return 0;
-}
diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
index 69ff3a9..9e68e32 100644
--- a/arch/ppc/kernel/head_44x.S
+++ b/arch/ppc/kernel/head_44x.S
@@ -462,7 +462,11 @@
/* Watchdog Timer Interrupt */
/* TODO: Add watchdog support */
+#ifdef CONFIG_BOOKE_WDT
+ CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException)
+#else
CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException)
+#endif
/* Data TLB Error Interrupt */
START_EXCEPTION(DataTLBError)
diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
index 23fb518..0a5e723 100644
--- a/arch/ppc/kernel/head_4xx.S
+++ b/arch/ppc/kernel/head_4xx.S
@@ -448,7 +448,9 @@
/* 0x1020 - Watchdog Timer (WDT) Exception
*/
-
+#ifdef CONFIG_BOOKE_WDT
+ CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException)
+#else
CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException)
#endif
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index eb804b7..4028f4c 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -564,8 +564,11 @@
EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
/* Watchdog Timer Interrupt */
- /* TODO: Add watchdog support */
+#ifdef CONFIG_BOOKE_WDT
+ CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException)
+#else
CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
+#endif
/* Data TLB Error Interrupt */
START_EXCEPTION(DataTLBError)
diff --git a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S
index c394410..8611152 100644
--- a/arch/ppc/kernel/l2cr.S
+++ b/arch/ppc/kernel/l2cr.S
@@ -156,6 +156,26 @@
The bit moved on the 7450.....
****/
+BEGIN_FTR_SECTION
+ /* Disable L2 prefetch on some 745x and try to ensure
+ * L2 prefetch engines are idle. As explained by errata
+ * text, we can't be sure they are, we just hope very hard
+ * that well be enough (sic !). At least I noticed Apple
+ * doesn't even bother doing the dcbf's here...
+ */
+ mfspr r4,SPRN_MSSCR0
+ rlwinm r4,r4,0,0,29
+ sync
+ mtspr SPRN_MSSCR0,r4
+ sync
+ isync
+ lis r4,KERNELBASE@h
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+
/* TODO: use HW flush assist when available */
lis r4,0x0002
@@ -230,7 +250,16 @@
oris r3,r3,0x8000
mtspr SPRN_L2CR,r3
sync
-
+
+ /* Enable L2 HW prefetch on 744x/745x */
+BEGIN_FTR_SECTION
+ mfspr r3,SPRN_MSSCR0
+ ori r3,r3,3
+ sync
+ mtspr SPRN_MSSCR0,r3
+ sync
+ isync
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
4:
/* Restore HID0[DPM] to whatever it was before */
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index e7d40cc..88f6bb7 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -51,9 +51,6 @@
#include <asm/commproc.h>
#endif
-/* Tell string.h we don't want memcpy etc. as cpp defines */
-#define EXPORT_SYMTAB_STROPS
-
extern void transfer_to_handler(void);
extern void do_IRQ(struct pt_regs *regs);
extern void MachineCheckException(struct pt_regs *regs);
@@ -263,6 +260,7 @@
EXPORT_SYMBOL(__ashldi3);
EXPORT_SYMBOL(__lshrdi3);
EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(cacheable_memcpy);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memscan);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 929e5d1..545cfd0 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -41,7 +41,11 @@
#include <asm/xmon.h>
#include <asm/ocp.h>
-#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE)
+#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \
+ defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \
+ defined(CONFIG_PPC_MPC52xx))
+
+#if USES_PPC_SYS
#include <asm/ppc_sys.h>
#endif
@@ -241,7 +245,7 @@
seq_printf(m, "bogomips\t: %lu.%02lu\n",
lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
-#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE)
+#if USES_PPC_SYS
if (cur_ppc_sys_spec->ppc_sys_name)
seq_printf(m, "chipset\t\t: %s\n",
cur_ppc_sys_spec->ppc_sys_name);
@@ -615,6 +619,26 @@
if (ppc_md.progress)
ppc_md.progress("id mach(): done", 0x200);
}
+#ifdef CONFIG_BOOKE_WDT
+/* Checks wdt=x and wdt_period=xx command-line option */
+int __init early_parse_wdt(char *p)
+{
+ if (p && strncmp(p, "0", 1) != 0)
+ booke_wdt_enabled = 1;
+
+ return 0;
+}
+early_param("wdt", early_parse_wdt);
+
+int __init early_parse_wdt_period (char *p)
+{
+ if (p)
+ booke_wdt_period = simple_strtoul(p, NULL, 0);
+
+ return 0;
+}
+early_param("wdt_period", early_parse_wdt_period);
+#endif /* CONFIG_BOOKE_WDT */
/* Checks "l2cr=xxxx" command-line option */
int __init ppc_setup_l2cr(char *str)
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index bf4ddca..a3c5281 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -169,7 +169,7 @@
* We should have an rtc call that only sets the minutes and
* seconds like on Intel to avoid problems with non UTC clocks.
*/
- if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
+ if ( ppc_md.set_rtc_time && ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
jiffies - wall_jiffies == 1) {
@@ -271,10 +271,7 @@
*/
last_rtc_update = new_sec - 658;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irqrestore(&xtime_lock, flags);
clock_was_set();
return 0;
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 9e6ae56..d87423d 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -904,6 +904,25 @@
}
#endif
+#ifdef CONFIG_BOOKE_WDT
+/*
+ * Default handler for a Watchdog exception,
+ * spins until a reboot occurs
+ */
+void __attribute__ ((weak)) WatchdogHandler(struct pt_regs *regs)
+{
+ /* Generic WatchdogHandler, implement your own */
+ mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE));
+ return;
+}
+
+void WatchdogException(struct pt_regs *regs)
+{
+ printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n");
+ WatchdogHandler(regs);
+}
+#endif
+
void __init trap_init(void)
{
}
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 33ada72..f421a4b 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -560,9 +560,10 @@
void flush_dcache_icache_page(struct page *page)
{
#ifdef CONFIG_BOOKE
- __flush_dcache_icache(kmap(page));
- kunmap(page);
-#elif CONFIG_8xx
+ void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE);
+ __flush_dcache_icache(start);
+ kunmap_atomic(start, KM_PPC_SYNC_ICACHE);
+#elif defined(CONFIG_8xx)
/* On 8xx there is no need to kmap since highmem is not supported */
__flush_dcache_icache(page_address(page));
#else
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
index 805dd98..76f4476 100644
--- a/arch/ppc/platforms/4xx/Kconfig
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -16,11 +16,6 @@
depends on 40x
default WALNUT
-config ASH
- bool "Ash"
- help
- This option enables support for the IBM NP405H evaluation board.
-
config BUBINGA
bool "Bubinga"
select WANT_EARLY_SERIAL
@@ -37,11 +32,6 @@
help
This option enables support for the EP405/EP405PC boards.
-config OAK
- bool "Oak"
- help
- This option enables support for the IBM 403GCX evaluation board.
-
config REDWOOD_5
bool "Redwood-5"
help
@@ -152,13 +142,13 @@
# All 405-based cores up until the 405GPR and 405EP have this errata.
config IBM405_ERR77
bool
- depends on 40x && !403GCX && !405GPR
+ depends on 40x && !403GCX && !405GPR && !405EP
default y
# All 40x-based cores, up until the 405GPR and 405EP have this errata.
config IBM405_ERR51
bool
- depends on 40x && !405GPR
+ depends on 40x && !405GPR && !405EP
default y
config BOOKE
@@ -186,6 +176,7 @@
depends on BUBINGA || EP405 || SYCAMORE || WALNUT
default y
+# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
config 403GCX
bool
depends OAK
diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile
index 844c3b5..1dd6d7f 100644
--- a/arch/ppc/platforms/4xx/Makefile
+++ b/arch/ppc/platforms/4xx/Makefile
@@ -1,14 +1,12 @@
#
# Makefile for the PowerPC 4xx linux kernel.
-obj-$(CONFIG_ASH) += ash.o
obj-$(CONFIG_BAMBOO) += bamboo.o
obj-$(CONFIG_CPCI405) += cpci405.o
obj-$(CONFIG_EBONY) += ebony.o
obj-$(CONFIG_EP405) += ep405.o
obj-$(CONFIG_BUBINGA) += bubinga.o
obj-$(CONFIG_LUAN) += luan.o
-obj-$(CONFIG_OAK) += oak.o
obj-$(CONFIG_OCOTEA) += ocotea.o
obj-$(CONFIG_REDWOOD_5) += redwood5.o
obj-$(CONFIG_REDWOOD_6) += redwood6.o
diff --git a/arch/ppc/platforms/4xx/ash.c b/arch/ppc/platforms/4xx/ash.c
deleted file mode 100644
index ce29117..0000000
--- a/arch/ppc/platforms/4xx/ash.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/ash.c
- *
- * Support for the IBM NP405H ash eval board
- *
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/pci.h>
-
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/io.h>
-#include <asm/ocp.h>
-#include <asm/ibm_ocp_pci.h>
-#include <asm/todc.h>
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-void *ash_rtc_base;
-
-/* Some IRQs unique to Walnut.
- * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
- */
-int __init
-ppc405_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
- */
- {
- {24, 24, 24, 24}, /* IDSEL 1 - PCI slot 1 */
- {25, 25, 25, 25}, /* IDSEL 2 - PCI slot 2 */
- {26, 26, 26, 26}, /* IDSEL 3 - PCI slot 3 */
- {27, 27, 27, 27}, /* IDSEL 4 - PCI slot 4 */
- };
-
- const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
-}
-
-void __init
-ash_setup_arch(void)
-{
- ppc4xx_setup_arch();
-
- ibm_ocp_set_emac(0, 3);
-
-#ifdef CONFIG_DEBUG_BRINGUP
- int i;
- printk("\n");
- printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
- printk("\n");
- printk("bi_s_version\t %s\n", bip->bi_s_version);
- printk("bi_r_version\t %s\n", bip->bi_r_version);
- printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,
- bip->bi_memsize / (1024 * 1000));
- for (i = 0; i < EMAC_NUMS; i++) {
- printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", i,
- bip->bi_enetaddr[i][0], bip->bi_enetaddr[i][1],
- bip->bi_enetaddr[i][2], bip->bi_enetaddr[i][3],
- bip->bi_enetaddr[i][4], bip->bi_enetaddr[i][5]);
- }
- printk("bi_pci_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
- bip->bi_pci_enetaddr[0], bip->bi_pci_enetaddr[1],
- bip->bi_pci_enetaddr[2], bip->bi_pci_enetaddr[3],
- bip->bi_pci_enetaddr[4], bip->bi_pci_enetaddr[5]);
-
- printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
- bip->bi_intfreq, bip->bi_intfreq / 1000000);
-
- printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
- bip->bi_busfreq, bip->bi_busfreq / 1000000);
- printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
- bip->bi_pci_busfreq, bip->bi_pci_busfreq / 1000000);
-
- printk("\n");
-#endif
- /* RTC step for ash */
- ash_rtc_base = (void *) ASH_RTC_VADDR;
- TODC_INIT(TODC_TYPE_DS1743, ash_rtc_base, ash_rtc_base, ash_rtc_base,
- 8);
-}
-
-void __init
-bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
-{
- /*
- * Expected PCI mapping:
- *
- * PLB addr PCI memory addr
- * --------------------- ---------------------
- * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
- * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
- *
- * PLB addr PCI io addr
- * --------------------- ---------------------
- * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
- *
- * The following code is simplified by assuming that the bootrom
- * has been well behaved in following this mapping.
- */
-
-#ifdef DEBUG
- int i;
-
- printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
- printk("PCI bridge regs before fixup \n");
- for (i = 0; i <= 2; i++) {
- printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
- printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
- printk(" pmm%dpcila\t0x%x\n", i,
- in_le32(&(pcip->pmm[i].pcila)));
- printk(" pmm%dpciha\t0x%x\n", i,
- in_le32(&(pcip->pmm[i].pciha)));
- }
- printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
- printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
- printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
- printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
- for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
- early_read_config_dword(hose, hose->first_busno,
- PCI_FUNC(hose->first_busno), bar,
- &bar_response);
- DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
- hose->first_busno, PCI_SLOT(hose->first_busno),
- PCI_FUNC(hose->first_busno), bar, bar_response);
- }
-
-#endif
- if (ppc_md.progress)
- ppc_md.progress("bios_fixup(): enter", 0x800);
-
- /* added for IBM boot rom version 1.15 bios bar changes -AK */
-
- /* Disable region first */
- out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
- /* PLB starting addr, PCI: 0x80000000 */
- out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
- /* PCI start addr, 0x80000000 */
- out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
- /* 512MB range of PLB to PCI */
- out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
- /* Enable no pre-fetch, enable region */
- out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
- (PPC405_PCI_UPPER_MEM -
- PPC405_PCI_MEM_BASE)) | 0x01));
-
- /* Disable region one */
- out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
- out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
- out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
- out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
- out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-
- /* Disable region two */
- out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
- out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
- out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
- out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
- out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-
- /* Enable PTM1 and PTM2, mapped to PLB address 0. */
-
- out_le32((void *) &(pcip->ptm1la), 0x00000000);
- out_le32((void *) &(pcip->ptm1ms), 0x00000001);
- out_le32((void *) &(pcip->ptm2la), 0x00000000);
- out_le32((void *) &(pcip->ptm2ms), 0x00000001);
-
- /* Write zero to PTM1 BAR. */
-
- early_write_config_dword(hose, hose->first_busno,
- PCI_FUNC(hose->first_busno),
- PCI_BASE_ADDRESS_1,
- 0x00000000);
-
- /* Disable PTM2 (unused) */
-
- out_le32((void *) &(pcip->ptm2la), 0x00000000);
- out_le32((void *) &(pcip->ptm2ms), 0x00000000);
-
- /* end work arround */
- if (ppc_md.progress)
- ppc_md.progress("bios_fixup(): done", 0x800);
-
-#ifdef DEBUG
- printk("PCI bridge regs after fixup \n");
- for (i = 0; i <= 2; i++) {
- printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
- printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
- printk(" pmm%dpcila\t0x%x\n", i,
- in_le32(&(pcip->pmm[i].pcila)));
- printk(" pmm%dpciha\t0x%x\n", i,
- in_le32(&(pcip->pmm[i].pciha)));
- }
- printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
- printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
- printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
- printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-
- for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
- early_read_config_dword(hose, hose->first_busno,
- PCI_FUNC(hose->first_busno), bar,
- &bar_response);
- DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
- hose->first_busno, PCI_SLOT(hose->first_busno),
- PCI_FUNC(hose->first_busno), bar, bar_response);
- }
-
-
-#endif
-}
-
-void __init
-ash_map_io(void)
-{
- ppc4xx_map_io();
- io_block_mapping(ASH_RTC_VADDR, ASH_RTC_PADDR, ASH_RTC_SIZE, _PAGE_IO);
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- ppc4xx_init(r3, r4, r5, r6, r7);
-
- ppc_md.setup_arch = ash_setup_arch;
- ppc_md.setup_io_mappings = ash_map_io;
-
-#ifdef CONFIG_PPC_RTC
- ppc_md.time_init = todc_time_init;
- ppc_md.set_rtc_time = todc_set_rtc_time;
- ppc_md.get_rtc_time = todc_get_rtc_time;
- ppc_md.nvram_read_val = todc_direct_read_val;
- ppc_md.nvram_write_val = todc_direct_write_val;
-#endif
-}
diff --git a/arch/ppc/platforms/4xx/ash.h b/arch/ppc/platforms/4xx/ash.h
deleted file mode 100644
index 5f7448e..0000000
--- a/arch/ppc/platforms/4xx/ash.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/ash.h
- *
- * Macros, definitions, and data structures specific to the IBM PowerPC
- * Ash eval board.
- *
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_ASH_H__
-#define __ASM_ASH_H__
-#include <platforms/4xx/ibmnp405h.h>
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Ash" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
- unsigned char bi_s_version[4]; /* Version of this structure */
- unsigned char bi_r_version[30]; /* Version of the IBM ROM */
- unsigned int bi_memsize; /* DRAM installed, in bytes */
- unsigned char bi_enetaddr[4][6]; /* Local Ethernet MAC address */
- unsigned char bi_pci_enetaddr[6];
- unsigned int bi_intfreq; /* Processor speed, in Hz */
- unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
- unsigned int bi_pci_busfreq; /* PCI speed in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-/* Memory map for the IBM "Ash" NP405H evaluation board.
- */
-
-extern void *ash_rtc_base;
-#define ASH_RTC_PADDR ((uint)0xf0000000)
-#define ASH_RTC_VADDR ASH_RTC_PADDR
-#define ASH_RTC_SIZE ((uint)8*1024)
-
-
-/* Early initialization address mapping for block_io.
- * Standard 405GP map.
- */
-#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE ((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE ((uint)4*1024)
-
-#define NR_BOARD_IRQS 32
-
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD 201600
-#else
-#define BASE_BAUD 691200
-#endif
-
-#define PPC4xx_MACHINE_NAME "IBM NP405H Ash"
-
-extern char pci_irq_table[][4];
-
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_ASH_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/bamboo.c b/arch/ppc/platforms/4xx/bamboo.c
index f116787..ac391d4 100644
--- a/arch/ppc/platforms/4xx/bamboo.c
+++ b/arch/ppc/platforms/4xx/bamboo.c
@@ -52,13 +52,6 @@
#include <syslib/gen550.h>
#include <syslib/ibm440gx_common.h>
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
bd_t __res;
static struct ibm44x_clocks clocks __initdata;
@@ -123,33 +116,69 @@
static void __init bamboo_set_emacdata(void)
{
- unsigned char * selection1_base;
+ u8 * base_addr;
struct ocp_def *def;
struct ocp_func_emac_data *emacdata;
- u8 selection1_val;
+ u8 val;
int mode;
+ u32 excluded = 0;
- selection1_base = ioremap64(BAMBOO_FPGA_SELECTION1_REG_ADDR, 16);
- selection1_val = readb(selection1_base);
- iounmap((void *) selection1_base);
- if (BAMBOO_SEL_MII(selection1_val))
+ base_addr = ioremap64(BAMBOO_FPGA_SELECTION1_REG_ADDR, 16);
+ val = readb(base_addr);
+ iounmap((void *) base_addr);
+ if (BAMBOO_SEL_MII(val))
mode = PHY_MODE_MII;
- else if (BAMBOO_SEL_RMII(selection1_val))
+ else if (BAMBOO_SEL_RMII(val))
mode = PHY_MODE_RMII;
else
mode = PHY_MODE_SMII;
- /* Set mac_addr and phy mode for each EMAC */
+ /*
+ * SW2 on the Bamboo is used for ethernet configuration and is accessed
+ * via the CONFIG2 register in the FPGA. If the ANEG pin is set,
+ * overwrite the supported features with the settings in SW2.
+ *
+ * This is used as a workaround for the improperly biased RJ-45 sockets
+ * on the Rev. 0 Bamboo. By default only 10baseT is functional.
+ * Removing inductors L17 and L18 from the board allows 100baseT, but
+ * disables 10baseT. The Rev. 1 has no such limitations.
+ */
+
+ base_addr = ioremap64(BAMBOO_FPGA_CONFIG2_REG_ADDR, 8);
+ val = readb(base_addr);
+ iounmap((void *) base_addr);
+ if (!BAMBOO_AUTONEGOTIATE(val)) {
+ excluded |= SUPPORTED_Autoneg;
+ if (BAMBOO_FORCE_100Mbps(val)) {
+ excluded |= SUPPORTED_10baseT_Full;
+ excluded |= SUPPORTED_10baseT_Half;
+ if (BAMBOO_FULL_DUPLEX_EN(val))
+ excluded |= SUPPORTED_100baseT_Half;
+ else
+ excluded |= SUPPORTED_100baseT_Full;
+ } else {
+ excluded |= SUPPORTED_100baseT_Full;
+ excluded |= SUPPORTED_100baseT_Half;
+ if (BAMBOO_FULL_DUPLEX_EN(val))
+ excluded |= SUPPORTED_10baseT_Half;
+ else
+ excluded |= SUPPORTED_10baseT_Full;
+ }
+ }
+
+ /* Set mac_addr, phy mode and unsupported phy features for each EMAC */
def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0);
emacdata = def->additions;
memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
emacdata->phy_mode = mode;
+ emacdata->phy_feat_exc = excluded;
def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 1);
emacdata = def->additions;
memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
emacdata->phy_mode = mode;
+ emacdata->phy_feat_exc = excluded;
}
static int
diff --git a/arch/ppc/platforms/4xx/bamboo.h b/arch/ppc/platforms/4xx/bamboo.h
index 63d714504..5c01928 100644
--- a/arch/ppc/platforms/4xx/bamboo.h
+++ b/arch/ppc/platforms/4xx/bamboo.h
@@ -88,7 +88,7 @@
#define STD_UART_OP(num) \
{ 0, BASE_BAUD, 0, UART##num##_INT, \
(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
- iomem_base: UART##num##_IO_BASE, \
+ iomem_base: (void*)UART##num##_IO_BASE, \
io_type: SERIAL_IO_MEM},
#define SERIAL_PORT_DFNS \
diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
index 509e69a..0fd3442 100644
--- a/arch/ppc/platforms/4xx/ebony.c
+++ b/arch/ppc/platforms/4xx/ebony.c
@@ -55,13 +55,6 @@
#include <syslib/gen550.h>
#include <syslib/ibm440gp_common.h>
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
bd_t __res;
static struct ibm44x_clocks clocks __initdata;
diff --git a/arch/ppc/platforms/4xx/ibm405ep.c b/arch/ppc/platforms/4xx/ibm405ep.c
index 6d44567..093b28d 100644
--- a/arch/ppc/platforms/4xx/ibm405ep.c
+++ b/arch/ppc/platforms/4xx/ibm405ep.c
@@ -33,6 +33,7 @@
.txde_irq = 13, /* TX Descriptor Error IRQ */
.rxde_irq = 14, /* RX Descriptor Error IRQ */
.serr_irq = 10, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibm405gp.c b/arch/ppc/platforms/4xx/ibm405gp.c
index dfd7ef3..e570046 100644
--- a/arch/ppc/platforms/4xx/ibm405gp.c
+++ b/arch/ppc/platforms/4xx/ibm405gp.c
@@ -46,6 +46,7 @@
.txde_irq = 13, /* TX Descriptor Error IRQ */
.rxde_irq = 14, /* RX Descriptor Error IRQ */
.serr_irq = 10, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibm405gpr.c b/arch/ppc/platforms/4xx/ibm405gpr.c
index 01c8ccb..cd0d00d 100644
--- a/arch/ppc/platforms/4xx/ibm405gpr.c
+++ b/arch/ppc/platforms/4xx/ibm405gpr.c
@@ -42,6 +42,7 @@
.txde_irq = 13, /* TX Descriptor Error IRQ */
.rxde_irq = 14, /* RX Descriptor Error IRQ */
.serr_irq = 10, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibm440ep.c b/arch/ppc/platforms/4xx/ibm440ep.c
index 284da01..4712de8 100644
--- a/arch/ppc/platforms/4xx/ibm440ep.c
+++ b/arch/ppc/platforms/4xx/ibm440ep.c
@@ -53,6 +53,7 @@
.txde_irq = 33, /* TX Descriptor Error IRQ */
.rxde_irq = 34, /* RX Descriptor Error IRQ */
.serr_irq = 32, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibm440gp.c b/arch/ppc/platforms/4xx/ibm440gp.c
index 27615ef..d926245 100644
--- a/arch/ppc/platforms/4xx/ibm440gp.c
+++ b/arch/ppc/platforms/4xx/ibm440gp.c
@@ -56,6 +56,7 @@
.txde_irq = 33, /* TX Descriptor Error IRQ */
.rxde_irq = 34, /* RX Descriptor Error IRQ */
.serr_irq = 32, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibm440gx.c b/arch/ppc/platforms/4xx/ibm440gx.c
index 1f38f42..956f45e 100644
--- a/arch/ppc/platforms/4xx/ibm440gx.c
+++ b/arch/ppc/platforms/4xx/ibm440gx.c
@@ -84,6 +84,7 @@
.txde_irq = 33, /* TX Descriptor Error IRQ */
.rxde_irq = 34, /* RX Descriptor Error IRQ */
.serr_irq = 32, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibm440sp.c b/arch/ppc/platforms/4xx/ibm440sp.c
index fa3e003..feb17e4 100644
--- a/arch/ppc/platforms/4xx/ibm440sp.c
+++ b/arch/ppc/platforms/4xx/ibm440sp.c
@@ -43,6 +43,7 @@
.txde_irq = 34, /* TX Descriptor Error IRQ */
.rxde_irq = 35, /* RX Descriptor Error IRQ */
.serr_irq = 33, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibmnp405h.c b/arch/ppc/platforms/4xx/ibmnp405h.c
index ecdc5be..a477a78 100644
--- a/arch/ppc/platforms/4xx/ibmnp405h.c
+++ b/arch/ppc/platforms/4xx/ibmnp405h.c
@@ -34,7 +34,7 @@
.zmii_mux = 1, /* ZMII input of this EMAC */
.mal_idx = 0, /* MAL device index */
.mal_rx_chan = 1, /* MAL rx channel number */
- .mal_tx_chan = 1, /* MAL tx channel number */
+ .mal_tx_chan = 2, /* MAL tx channel number */
.wol_irq = 41, /* WOL interrupt number */
.mdio_idx = -1, /* No shared MDIO */
.tah_idx = -1, /* No TAH */
@@ -46,7 +46,7 @@
.zmii_mux = 2, /* ZMII input of this EMAC */
.mal_idx = 0, /* MAL device index */
.mal_rx_chan = 2, /* MAL rx channel number */
- .mal_tx_chan = 2, /* MAL tx channel number */
+ .mal_tx_chan = 4, /* MAL tx channel number */
.wol_irq = 41, /* WOL interrupt number */
.mdio_idx = -1, /* No shared MDIO */
.tah_idx = -1, /* No TAH */
@@ -58,7 +58,7 @@
.zmii_mux = 3, /* ZMII input of this EMAC */
.mal_idx = 0, /* MAL device index */
.mal_rx_chan = 3, /* MAL rx channel number */
- .mal_tx_chan = 3, /* MAL tx channel number */
+ .mal_tx_chan = 6, /* MAL tx channel number */
.wol_irq = 41, /* WOL interrupt number */
.mdio_idx = -1, /* No shared MDIO */
.tah_idx = -1, /* No TAH */
@@ -73,6 +73,7 @@
.txde_irq = 46, /* TX Descriptor Error IRQ */
.rxde_irq = 47, /* RX Descriptor Error IRQ */
.serr_irq = 45, /* MAL System Error IRQ */
+ .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */
};
OCP_SYSFS_MAL_DATA()
diff --git a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c
index 874d16b..d90627b 100644
--- a/arch/ppc/platforms/4xx/ibmstb4.c
+++ b/arch/ppc/platforms/4xx/ibmstb4.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
#include <platforms/4xx/ibmstb4.h>
static struct ocp_func_iic_data ibmstb4_iic0_def = {
@@ -72,12 +73,51 @@
.irq = IDE0_IRQ,
.pm = OCP_CPM_NA,
},
- { .vendor = OCP_VENDOR_IBM,
- .function = OCP_FUNC_USB,
- .paddr = USB0_BASE,
- .irq = USB0_IRQ,
- .pm = OCP_CPM_NA,
- },
{ .vendor = OCP_VENDOR_INVALID,
}
};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0x7fffff01,
+ .triggering = 0x00000000,
+ .ext_irq_mask = 0x0000007e, /* IRQ0 - IRQ5 */
+ }
+};
+
+static struct resource ohci_usb_resources[] = {
+ [0] = {
+ .start = USB0_BASE,
+ .end = USB0_BASE + USB0_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = USB0_IRQ,
+ .end = USB0_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 dma_mask = 0xffffffffULL;
+
+static struct platform_device ohci_usb_device = {
+ .name = "ppc-soc-ohci",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(ohci_usb_resources),
+ .resource = ohci_usb_resources,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffffULL,
+ }
+};
+
+static struct platform_device *ibmstb4_devs[] __initdata = {
+ &ohci_usb_device,
+};
+
+static int __init
+ibmstb4_platform_add_devices(void)
+{
+ return platform_add_devices(ibmstb4_devs, ARRAY_SIZE(ibmstb4_devs));
+}
+arch_initcall(ibmstb4_platform_add_devices);
diff --git a/arch/ppc/platforms/4xx/ibmstb4.h b/arch/ppc/platforms/4xx/ibmstb4.h
index bcb4b1e..9f21d4c 100644
--- a/arch/ppc/platforms/4xx/ibmstb4.h
+++ b/arch/ppc/platforms/4xx/ibmstb4.h
@@ -73,9 +73,9 @@
#define OPB0_BASE 0x40000000
#define GPIO0_BASE 0x40060000
+#define USB0_BASE 0x40010000
+#define USB0_SIZE 0xA0
#define USB0_IRQ 18
-#define USB0_BASE STB04xxx_MAP_IO_ADDR(0x40010000)
-#define USB0_EXTENT 4096
#define IIC_NUMS 2
#define UART_NUMS 3
diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c
index 95359f7..a38e6f9 100644
--- a/arch/ppc/platforms/4xx/luan.c
+++ b/arch/ppc/platforms/4xx/luan.c
@@ -53,13 +53,6 @@
#include <syslib/ibm440gx_common.h>
#include <syslib/ibm440sp_common.h>
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
bd_t __res;
static struct ibm44x_clocks clocks __initdata;
diff --git a/arch/ppc/platforms/4xx/luan.h b/arch/ppc/platforms/4xx/luan.h
index 09b444c..bbe7d07 100644
--- a/arch/ppc/platforms/4xx/luan.h
+++ b/arch/ppc/platforms/4xx/luan.h
@@ -55,7 +55,7 @@
#define STD_UART_OP(num) \
{ 0, BASE_BAUD, 0, UART##num##_INT, \
(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
- iomem_base: UART##num##_IO_BASE, \
+ iomem_base: (void*)UART##num##_IO_BASE, \
io_type: SERIAL_IO_MEM},
#define SERIAL_PORT_DFNS \
diff --git a/arch/ppc/platforms/4xx/oak.c b/arch/ppc/platforms/4xx/oak.c
deleted file mode 100644
index fa25ee1..0000000
--- a/arch/ppc/platforms/4xx/oak.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Module name: oak.c
- *
- * Description:
- * Architecture- / platform-specific boot-time initialization code for
- * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- * <dan@net4x.com>.
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/initrd.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-
-#include <asm/board.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/bootinfo.h>
-#include <asm/ppc4xx_pic.h>
-#include <asm/time.h>
-
-#include "oak.h"
-
-/* Function Prototypes */
-
-extern void abort(void);
-
-/* Global Variables */
-
-unsigned char __res[sizeof(bd_t)];
-
-
-/*
- * void __init oak_init()
- *
- * Description:
- * This routine...
- *
- * Input(s):
- * r3 - Optional pointer to a board information structure.
- * r4 - Optional pointer to the physical starting address of the init RAM
- * disk.
- * r5 - Optional pointer to the physical ending address of the init RAM
- * disk.
- * r6 - Optional pointer to the physical starting address of any kernel
- * command-line parameters.
- * r7 - Optional pointer to the physical ending address of any kernel
- * command-line parameters.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- parse_bootinfo(find_bootinfo());
-
- /*
- * If we were passed in a board information, copy it into the
- * residual data area.
- */
- if (r3) {
- memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
- }
-
-#if defined(CONFIG_BLK_DEV_INITRD)
- /*
- * If the init RAM disk has been configured in, and there's a valid
- * starting address for it, set it up.
- */
- if (r4) {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
-
- /* Copy the kernel command line arguments to a safe place. */
-
- if (r6) {
- *(char *)(r7 + KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6 + KERNELBASE));
- }
-
- /* Initialize machine-dependency vectors */
-
- ppc_md.setup_arch = oak_setup_arch;
- ppc_md.show_percpuinfo = oak_show_percpuinfo;
- ppc_md.irq_canonicalize = NULL;
- ppc_md.init_IRQ = ppc4xx_pic_init;
- ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */
- ppc_md.init = NULL;
-
- ppc_md.restart = oak_restart;
- ppc_md.power_off = oak_power_off;
- ppc_md.halt = oak_halt;
-
- ppc_md.time_init = oak_time_init;
- ppc_md.set_rtc_time = oak_set_rtc_time;
- ppc_md.get_rtc_time = oak_get_rtc_time;
- ppc_md.calibrate_decr = oak_calibrate_decr;
-}
-
-/*
- * Document me.
- */
-void __init
-oak_setup_arch(void)
-{
- /* XXX - Implement me */
-}
-
-/*
- * int oak_show_percpuinfo()
- *
- * Description:
- * This routine pretty-prints the platform's internal CPU and bus clock
- * frequencies into the buffer for usage in /proc/cpuinfo.
- *
- * Input(s):
- * *buffer - Buffer into which CPU and bus clock frequencies are to be
- * printed.
- *
- * Output(s):
- * *buffer - Buffer with the CPU and bus clock frequencies.
- *
- * Returns:
- * The number of bytes copied into 'buffer' if OK, otherwise zero or less
- * on error.
- */
-int
-oak_show_percpuinfo(struct seq_file *m, int i)
-{
- bd_t *bp = (bd_t *)__res;
-
- seq_printf(m, "clock\t\t: %dMHz\n"
- "bus clock\t\t: %dMHz\n",
- bp->bi_intfreq / 1000000,
- bp->bi_busfreq / 1000000);
-
- return 0;
-}
-
-/*
- * Document me.
- */
-void
-oak_restart(char *cmd)
-{
- abort();
-}
-
-/*
- * Document me.
- */
-void
-oak_power_off(void)
-{
- oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-void
-oak_halt(void)
-{
- oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-long __init
-oak_time_init(void)
-{
- /* XXX - Implement me */
- return 0;
-}
-
-/*
- * Document me.
- */
-int __init
-oak_set_rtc_time(unsigned long time)
-{
- /* XXX - Implement me */
-
- return (0);
-}
-
-/*
- * Document me.
- */
-unsigned long __init
-oak_get_rtc_time(void)
-{
- /* XXX - Implement me */
-
- return (0);
-}
-
-/*
- * void __init oak_calibrate_decr()
- *
- * Description:
- * This routine retrieves the internal processor frequency from the board
- * information structure, sets up the kernel timer decrementer based on
- * that value, enables the 403 programmable interval timer (PIT) and sets
- * it up for auto-reload.
- *
- * Input(s):
- * N/A
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-void __init
-oak_calibrate_decr(void)
-{
- unsigned int freq;
- bd_t *bip = (bd_t *)__res;
-
- freq = bip->bi_intfreq;
-
- decrementer_count = freq / HZ;
- count_period_num = 1;
- count_period_den = freq;
-
- /* Enable the PIT and set auto-reload of its value */
-
- mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
- /* Clear any pending timer interrupts */
-
- mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-}
diff --git a/arch/ppc/platforms/4xx/oak.h b/arch/ppc/platforms/4xx/oak.h
deleted file mode 100644
index 1b86a4c..0000000
--- a/arch/ppc/platforms/4xx/oak.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *
- * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- * Module name: oak.h
- *
- * Description:
- * Macros, definitions, and data structures specific to the IBM PowerPC
- * 403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
- * cessor itself is defined elsewhere.
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_OAK_H__
-#define __ASM_OAK_H__
-
-/* We have an IBM 403G{A,B,C,CX} core */
-#include <asm/ibm403.h>
-
-#define _IO_BASE 0
-#define _ISA_MEM_BASE 0
-#define PCI_DRAM_OFFSET 0
-
-/* Memory map for the "Oak" evaluation board */
-
-#define PPC403SPU_IO_BASE 0x40000000 /* 403 On-chip serial port */
-#define PPC403SPU_IO_SIZE 0x00000008
-#define OAKSERIAL_IO_BASE 0x7E000000 /* NS16550DV serial port */
-#define OAKSERIAL_IO_SIZE 0x00000008
-#define OAKNET_IO_BASE 0xF4000000 /* NS83902AV Ethernet */
-#define OAKNET_IO_SIZE 0x00000040
-#define OAKPROM_IO_BASE 0xFFFE0000 /* AMD 29F010 Flash ROM */
-#define OAKPROM_IO_SIZE 0x00020000
-
-
-/* Interrupt assignments fixed by the hardware implementation */
-
-/* This is annoying kbuild-2.4 problem. -- Tom */
-
-#define PPC403SPU_RX_INT 4 /* AIC_INT4 */
-#define PPC403SPU_TX_INT 5 /* AIC_INT5 */
-#define OAKNET_INT 27 /* AIC_INT27 */
-#define OAKSERIAL_INT 28 /* AIC_INT28 */
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Oak" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
- unsigned char bi_s_version[4]; /* Version of this structure */
- unsigned char bi_r_version[30]; /* Version of the IBM ROM */
- unsigned int bi_memsize; /* DRAM installed, in bytes */
- unsigned char bi_enetaddr[6]; /* Ethernet MAC address */
- unsigned int bi_intfreq; /* Processor speed, in Hz */
- unsigned int bi_busfreq; /* Bus speed, in Hz */
-} bd_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void oak_init(unsigned long r3,
- unsigned long ird_start,
- unsigned long ird_end,
- unsigned long cline_start,
- unsigned long cline_end);
-extern void oak_setup_arch(void);
-extern int oak_setup_residual(char *buffer);
-extern void oak_init_IRQ(void);
-extern int oak_get_irq(struct pt_regs *regs);
-extern void oak_restart(char *cmd);
-extern void oak_power_off(void);
-extern void oak_halt(void);
-extern void oak_time_init(void);
-extern int oak_set_rtc_time(unsigned long now);
-extern unsigned long oak_get_rtc_time(void);
-extern void oak_calibrate_decr(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#define PPC4xx_MACHINE_NAME "IBM Oak"
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_OAK_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/oak_setup.h b/arch/ppc/platforms/4xx/oak_setup.h
deleted file mode 100644
index 8648bd0..0000000
--- a/arch/ppc/platforms/4xx/oak_setup.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Module name: oak_setup.h
- *
- * Description:
- * Architecture- / platform-specific boot-time initialization code for
- * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- * <dan@netx4.com>.
- *
- */
-
-#ifndef __OAK_SETUP_H__
-#define __OAK_SETUP_H__
-
-#include <asm/ptrace.h>
-#include <asm/board.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern unsigned char __res[sizeof(bd_t)];
-
-extern void oak_init(unsigned long r3,
- unsigned long ird_start,
- unsigned long ird_end,
- unsigned long cline_start,
- unsigned long cline_end);
-extern void oak_setup_arch(void);
-extern int oak_setup_residual(char *buffer);
-extern void oak_init_IRQ(void);
-extern int oak_get_irq(struct pt_regs *regs);
-extern void oak_restart(char *cmd);
-extern void oak_power_off(void);
-extern void oak_halt(void);
-extern void oak_time_init(void);
-extern int oak_set_rtc_time(unsigned long now);
-extern unsigned long oak_get_rtc_time(void);
-extern void oak_calibrate_decr(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __OAK_SETUP_H__ */
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
index 8fc34a3..80028df 100644
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -53,13 +53,6 @@
#include <syslib/gen550.h>
#include <syslib/ibm440gx_common.h>
-/*
- * This is a horrible kludge, we eventually need to abstract this
- * generic PHY stuff, so the standard phy mode defines can be
- * easily used from arch code.
- */
-#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
-
bd_t __res;
static struct ibm44x_clocks clocks __initdata;
diff --git a/arch/ppc/platforms/4xx/redwood5.c b/arch/ppc/platforms/4xx/redwood5.c
index 2f5e410..bee8b4a 100644
--- a/arch/ppc/platforms/4xx/redwood5.c
+++ b/arch/ppc/platforms/4xx/redwood5.c
@@ -18,6 +18,19 @@
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/machdep.h>
+#include <asm/ppc4xx_pic.h>
+
+/*
+ * Define external IRQ senses and polarities.
+ */
+unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 4 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 5 */
+};
static struct resource smc91x_resources[] = {
[0] = {
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index ddd04d4..b38a851 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -62,9 +62,29 @@
unsigned char __res[sizeof (bd_t)];
#ifdef CONFIG_PCI
-#error "PCI is not supported"
-/* NEED mpc83xx_map_irq & mpc83xx_exclude_device
- see platforms/85xx/mpc85xx_ads_common.c */
+int
+mpc83xx_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
+ */
+ {
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x11 */
+ {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x12 */
+ {PIRQD, PIRQA, PIRQB, PIRQC} /* idsel 0x13 */
+ };
+
+ const long min_idsel = 0x11, max_idsel = 0x13, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int
+mpc83xx_exclude_device(u_char bus, u_char devfn)
+{
+ return PCIBIOS_SUCCESSFUL;
+}
#endif /* CONFIG_PCI */
/* ************************************************************************
@@ -88,7 +108,7 @@
#ifdef CONFIG_PCI
/* setup PCI host bridges */
- mpc83xx_sys_setup_hose();
+ mpc83xx_setup_hose();
#endif
mpc83xx_early_serial_map();
@@ -175,10 +195,17 @@
IRQ_SENSE_LEVEL, /* EXT 1 */
IRQ_SENSE_LEVEL, /* EXT 2 */
0, /* EXT 3 */
+#ifdef CONFIG_PCI
+ IRQ_SENSE_LEVEL, /* EXT 4 */
+ IRQ_SENSE_LEVEL, /* EXT 5 */
+ IRQ_SENSE_LEVEL, /* EXT 6 */
+ IRQ_SENSE_LEVEL, /* EXT 7 */
+#else
0, /* EXT 4 */
0, /* EXT 5 */
0, /* EXT 6 */
0, /* EXT 7 */
+#endif
};
ipic_init(binfo->bi_immr_base + 0x00700, 0, MPC83xx_IPIC_IRQ_OFFSET, senses, 8);
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h
index a2f6e49..1584cd7 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.h
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.h
@@ -26,7 +26,7 @@
#define VIRT_IMMRBAR ((uint)0xfe000000)
#define BCSR_PHYS_ADDR ((uint)0xf8000000)
-#define BCSR_SIZE ((uint)(32 * 1024))
+#define BCSR_SIZE ((uint)(128 * 1024))
#define BCSR_MISC_REG2_OFF 0x07
#define BCSR_MISC_REG2_PORESET 0x01
@@ -34,23 +34,25 @@
#define BCSR_MISC_REG3_OFF 0x08
#define BCSR_MISC_REG3_CNFLOCK 0x80
-#ifdef CONFIG_PCI
-/* PCI interrupt controller */
-#define PIRQA MPC83xx_IRQ_IRQ4
-#define PIRQB MPC83xx_IRQ_IRQ5
-#define PIRQC MPC83xx_IRQ_IRQ6
-#define PIRQD MPC83xx_IRQ_IRQ7
+#define PIRQA MPC83xx_IRQ_EXT4
+#define PIRQB MPC83xx_IRQ_EXT5
+#define PIRQC MPC83xx_IRQ_EXT6
+#define PIRQD MPC83xx_IRQ_EXT7
-#define MPC834x_SYS_PCI1_LOWER_IO 0x00000000
-#define MPC834x_SYS_PCI1_UPPER_IO 0x00ffffff
+#define MPC83xx_PCI1_LOWER_IO 0x00000000
+#define MPC83xx_PCI1_UPPER_IO 0x00ffffff
+#define MPC83xx_PCI1_LOWER_MEM 0x80000000
+#define MPC83xx_PCI1_UPPER_MEM 0x9fffffff
+#define MPC83xx_PCI1_IO_BASE 0xe2000000
+#define MPC83xx_PCI1_MEM_OFFSET 0x00000000
+#define MPC83xx_PCI1_IO_SIZE 0x01000000
-#define MPC834x_SYS_PCI1_LOWER_MEM 0x80000000
-#define MPC834x_SYS_PCI1_UPPER_MEM 0x9fffffff
-
-#define MPC834x_SYS_PCI1_IO_BASE 0xe2000000
-#define MPC834x_SYS_PCI1_MEM_OFFSET 0x00000000
-
-#define MPC834x_SYS_PCI1_IO_SIZE 0x01000000
-#endif /* CONFIG_PCI */
+#define MPC83xx_PCI2_LOWER_IO 0x00000000
+#define MPC83xx_PCI2_UPPER_IO 0x00ffffff
+#define MPC83xx_PCI2_LOWER_MEM 0xa0000000
+#define MPC83xx_PCI2_UPPER_MEM 0xbfffffff
+#define MPC83xx_PCI2_IO_BASE 0xe3000000
+#define MPC83xx_PCI2_MEM_OFFSET 0x00000000
+#define MPC83xx_PCI2_IO_SIZE 0x01000000
#endif /* __MACH_MPC83XX_SYS_H__ */
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index 5488a05..ff7452e 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -21,22 +21,17 @@
endif
obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o
obj-$(CONFIG_PREP_RESIDUAL) += residual.o
-obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o
obj-$(CONFIG_PQ2ADS) += pq2ads.o
obj-$(CONFIG_TQM8260) += tqm8260_setup.o
obj-$(CONFIG_CPCI690) += cpci690.o
obj-$(CONFIG_EV64260) += ev64260.o
obj-$(CONFIG_CHESTNUT) += chestnut.o
obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o
-obj-$(CONFIG_K2) += k2.o
obj-$(CONFIG_LOPEC) += lopec.o
obj-$(CONFIG_KATANA) += katana.o
obj-$(CONFIG_HDPU) += hdpu.o
-obj-$(CONFIG_MCPN765) += mcpn765.o
-obj-$(CONFIG_MENF1) += menf1_setup.o menf1_pci.o
obj-$(CONFIG_MVME5100) += mvme5100.o
obj-$(CONFIG_PAL4) += pal4_setup.o pal4_pci.o
-obj-$(CONFIG_PCORE) += pcore.o
obj-$(CONFIG_POWERPMC250) += powerpmc250.o
obj-$(CONFIG_PPLUS) += pplus.o
obj-$(CONFIG_PRPMC750) += prpmc750.o
@@ -46,6 +41,7 @@
obj-$(CONFIG_SBC82xx) += sbc82xx.o
obj-$(CONFIG_SPRUCE) += spruce.o
obj-$(CONFIG_LITE5200) += lite5200.o
+obj-$(CONFIG_EV64360) += ev64360.o
ifeq ($(CONFIG_SMP),y)
obj-$(CONFIG_PPC_PMAC) += pmac_smp.o
diff --git a/arch/ppc/platforms/adir.h b/arch/ppc/platforms/adir.h
deleted file mode 100644
index 13a748b..0000000
--- a/arch/ppc/platforms/adir.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * arch/ppc/platforms/adir.h
- *
- * Definitions for SBS Adirondack board support
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- */
-
-#ifndef __PPC_PLATFORMS_ADIR_H
-#define __PPC_PLATFORMS_ADIR_H
-
-/*
- * SBS Adirondack definitions
- */
-
-/* PPC physical address space layout. We use the one set up by the firmware. */
-#define ADIR_PCI32_MEM_BASE 0x80000000
-#define ADIR_PCI32_MEM_SIZE 0x20000000
-#define ADIR_PCI64_MEM_BASE 0xA0000000
-#define ADIR_PCI64_MEM_SIZE 0x20000000
-#define ADIR_PCI32_IO_BASE 0xC0000000
-#define ADIR_PCI32_IO_SIZE 0x10000000
-#define ADIR_PCI64_IO_BASE 0xD0000000
-#define ADIR_PCI64_IO_SIZE 0x10000000
-#define ADIR_PCI64_PHB 0xFF400000
-#define ADIR_PCI32_PHB 0xFF500000
-
-#define ADIR_PCI64_CONFIG_ADDR (ADIR_PCI64_PHB + 0x000f8000)
-#define ADIR_PCI64_CONFIG_DATA (ADIR_PCI64_PHB + 0x000f8010)
-
-#define ADIR_PCI32_CONFIG_ADDR (ADIR_PCI32_PHB + 0x000f8000)
-#define ADIR_PCI32_CONFIG_DATA (ADIR_PCI32_PHB + 0x000f8010)
-
-/* System memory as seen from PCI */
-#define ADIR_PCI_SYS_MEM_BASE 0x80000000
-
-/* Static virtual mapping of PCI I/O */
-#define ADIR_PCI32_VIRT_IO_BASE 0xFE000000
-#define ADIR_PCI32_VIRT_IO_SIZE 0x01000000
-#define ADIR_PCI64_VIRT_IO_BASE 0xFF000000
-#define ADIR_PCI64_VIRT_IO_SIZE 0x01000000
-
-/* Registers */
-#define ADIR_NVRAM_RTC_ADDR 0x74
-#define ADIR_NVRAM_RTC_DATA 0x75
-
-#define ADIR_BOARD_ID_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF0)
-#define ADIR_CPLD1REV_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF1)
-#define ADIR_CPLD2REV_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF2)
-#define ADIR_FLASHCTL_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF3)
-#define ADIR_CPC710_STAT_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF4)
-#define ADIR_CLOCK_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF5)
-#define ADIR_GPIO_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF8)
-#define ADIR_MISC_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF9)
-#define ADIR_LED_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFFA)
-
-#define ADIR_CLOCK_REG_PD 0x10
-#define ADIR_CLOCK_REG_SPREAD 0x08
-#define ADIR_CLOCK_REG_SEL133 0x04
-#define ADIR_CLOCK_REG_SEL1 0x02
-#define ADIR_CLOCK_REG_SEL0 0x01
-
-#define ADIR_PROCA_INT_MASK (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF0)
-#define ADIR_PROCB_INT_MASK (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF2)
-#define ADIR_PROCA_INT_STAT (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF4)
-#define ADIR_PROCB_INT_STAT (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF6)
-
-/* Linux IRQ numbers */
-#define ADIR_IRQ_NONE -1
-#define ADIR_IRQ_SERIAL2 3
-#define ADIR_IRQ_SERIAL1 4
-#define ADIR_IRQ_FDC 6
-#define ADIR_IRQ_PARALLEL 7
-#define ADIR_IRQ_VIA_AUDIO 10
-#define ADIR_IRQ_VIA_USB 11
-#define ADIR_IRQ_IDE0 14
-#define ADIR_IRQ_IDE1 15
-#define ADIR_IRQ_PCI0_INTA 16
-#define ADIR_IRQ_PCI0_INTB 17
-#define ADIR_IRQ_PCI0_INTC 18
-#define ADIR_IRQ_PCI0_INTD 19
-#define ADIR_IRQ_PCI1_INTA 20
-#define ADIR_IRQ_PCI1_INTB 21
-#define ADIR_IRQ_PCI1_INTC 22
-#define ADIR_IRQ_PCI1_INTD 23
-#define ADIR_IRQ_MBSCSI 24 /* motherboard SCSI */
-#define ADIR_IRQ_MBETH1 25 /* motherboard Ethernet 1 */
-#define ADIR_IRQ_MBETH0 26 /* motherboard Ethernet 0 */
-#define ADIR_IRQ_CPC710_INT1 27
-#define ADIR_IRQ_CPC710_INT2 28
-#define ADIR_IRQ_VT82C686_NMI 29
-#define ADIR_IRQ_VT82C686_INTR 30
-#define ADIR_IRQ_INTERPROC 31
-
-#endif /* __PPC_PLATFORMS_ADIR_H */
diff --git a/arch/ppc/platforms/adir_pci.c b/arch/ppc/platforms/adir_pci.c
deleted file mode 100644
index f94ac53..0000000
--- a/arch/ppc/platforms/adir_pci.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * arch/ppc/platforms/adir_pci.c
- *
- * PCI support for SBS Adirondack
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- * based on the K2 version by Matt Porter <mporter@mvista.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-
-#include <syslib/cpc710.h>
-#include "adir.h"
-
-#undef DEBUG
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif /* DEBUG */
-
-static inline int __init
-adir_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-#define PCIIRQ(a,b,c,d) {ADIR_IRQ_##a,ADIR_IRQ_##b,ADIR_IRQ_##c,ADIR_IRQ_##d},
- struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
- /*
- * The three PCI devices on the motherboard have dedicated lines to the
- * CPLD interrupt controller, bypassing the standard PCI INTA-D and the
- * PC interrupt controller. All other PCI devices (slots) have usual
- * staggered INTA-D lines, resulting in 8 lines total (PCI0 INTA-D and
- * PCI1 INTA-D). All 8 go to the CPLD interrupt controller. PCI0 INTA-D
- * also go to the south bridge, so we have the option of taking them
- * via the CPLD interrupt controller or via the south bridge 8259
- * 8258 thingy. PCI1 INTA-D can only be taken via the CPLD interrupt
- * controller. We take all PCI interrupts via the CPLD interrupt
- * controller as recommended by SBS.
- *
- * We also have some monkey business with the PCI devices within the
- * VT82C686B south bridge itself. This chip actually has 7 functions on
- * its IDSEL. Function 0 is the actual south bridge, function 1 is IDE,
- * and function 4 is some special stuff. The other 4 functions are just
- * regular PCI devices bundled in the chip. 2 and 3 are USB UHCIs and 5
- * and 6 are audio (not supported on the Adirondack).
- *
- * This is where the monkey business begins. PCI devices are supposed
- * to signal normal PCI interrupts. But the 4 functions in question are
- * located in the south bridge chip, which is designed with the
- * assumption that it will be fielding PCI INTA-D interrupts rather
- * than generating them. Here's what it does. Each of the functions in
- * question routes its interrupt to one of the IRQs on the 8259 thingy.
- * Which one? It looks at the Interrupt Line register in the PCI config
- * space, even though the PCI spec says it's for BIOS/OS interaction
- * only.
- *
- * How do we deal with this? We take these interrupts via 8259 IRQs as
- * we have to. We return the desired IRQ numbers from this routine when
- * called for the functions in question. The PCI scan code will then
- * stick our return value into the Interrupt Line register in the PCI
- * config space, and the interrupt will actually go there. We identify
- * these functions within the south bridge IDSEL by their interrupt pin
- * numbers, as the VT82C686B has 04 in the Interrupt Pin register for
- * USB and 03 for audio.
- */
- if (!hose->index) {
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- /* south bridge */ PCIIRQ(IDE0, NONE, VIA_AUDIO, VIA_USB)
- /* Ethernet 0 */ PCIIRQ(MBETH0, MBETH0, MBETH0, MBETH0)
- /* PCI0 slot 1 */ PCIIRQ(PCI0_INTB, PCI0_INTC, PCI0_INTD, PCI0_INTA)
- /* PCI0 slot 2 */ PCIIRQ(PCI0_INTC, PCI0_INTD, PCI0_INTA, PCI0_INTB)
- /* PCI0 slot 3 */ PCIIRQ(PCI0_INTD, PCI0_INTA, PCI0_INTB, PCI0_INTC)
- };
- const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
- } else {
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- /* Ethernet 1 */ PCIIRQ(MBETH1, MBETH1, MBETH1, MBETH1)
- /* SCSI */ PCIIRQ(MBSCSI, MBSCSI, MBSCSI, MBSCSI)
- /* PCI1 slot 1 */ PCIIRQ(PCI1_INTB, PCI1_INTC, PCI1_INTD, PCI1_INTA)
- /* PCI1 slot 2 */ PCIIRQ(PCI1_INTC, PCI1_INTD, PCI1_INTA, PCI1_INTB)
- /* PCI1 slot 3 */ PCIIRQ(PCI1_INTD, PCI1_INTA, PCI1_INTB, PCI1_INTC)
- };
- const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
- }
-#undef PCIIRQ
-}
-
-static void
-adir_pcibios_fixup_resources(struct pci_dev *dev)
-{
- int i;
-
- if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
- (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64))
- {
- DBG("Fixup CPC710 resources\n");
- for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
- {
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- }
- }
-}
-
-/*
- * CPC710 DD3 has an errata causing it to hang the system if a type 0 config
- * cycle is attempted on its PCI32 interface with a device number > 21.
- * CPC710's PCI bridges map device numbers 1 through 21 to AD11 through AD31.
- * Per the PCI spec it MUST accept all other device numbers and do nothing, and
- * software MUST scan all device numbers without assuming how IDSELs are
- * mapped. However, as the CPC710 DD3's errata causes such correct scanning
- * procedure to hang the system, we have no choice but to introduce this hack
- * of knowingly avoiding device numbers > 21 on PCI0,
- */
-static int
-adir_exclude_device(u_char bus, u_char devfn)
-{
- if ((bus == 0) && (PCI_SLOT(devfn) > 21))
- return PCIBIOS_DEVICE_NOT_FOUND;
- else
- return PCIBIOS_SUCCESSFUL;
-}
-
-void adir_find_bridges(void)
-{
- struct pci_controller *hose_a, *hose_b;
-
- /* Setup PCI32 hose */
- hose_a = pcibios_alloc_controller();
- if (!hose_a)
- return;
-
- hose_a->first_busno = 0;
- hose_a->last_busno = 0xff;
- hose_a->pci_mem_offset = ADIR_PCI32_MEM_BASE;
- hose_a->io_space.start = 0;
- hose_a->io_space.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
- hose_a->mem_space.start = 0;
- hose_a->mem_space.end = ADIR_PCI32_MEM_SIZE - 1;
- hose_a->io_resource.start = 0;
- hose_a->io_resource.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
- hose_a->io_resource.flags = IORESOURCE_IO;
- hose_a->mem_resources[0].start = ADIR_PCI32_MEM_BASE;
- hose_a->mem_resources[0].end = ADIR_PCI32_MEM_BASE +
- ADIR_PCI32_MEM_SIZE - 1;
- hose_a->mem_resources[0].flags = IORESOURCE_MEM;
- hose_a->io_base_phys = ADIR_PCI32_IO_BASE;
- hose_a->io_base_virt = (void *) ADIR_PCI32_VIRT_IO_BASE;
-
- ppc_md.pci_exclude_device = adir_exclude_device;
- setup_indirect_pci(hose_a, ADIR_PCI32_CONFIG_ADDR,
- ADIR_PCI32_CONFIG_DATA);
-
- /* Initialize PCI32 bus registers */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_BUS_NUMBER,
- hose_a->first_busno);
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER,
- hose_a->last_busno);
-
- hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-
- /* Write out correct max subordinate bus number for hose A */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER,
- hose_a->last_busno);
-
- /* Setup PCI64 hose */
- hose_b = pcibios_alloc_controller();
- if (!hose_b)
- return;
-
- hose_b->first_busno = hose_a->last_busno + 1;
- hose_b->last_busno = 0xff;
- hose_b->pci_mem_offset = ADIR_PCI64_MEM_BASE;
- hose_b->io_space.start = 0;
- hose_b->io_space.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
- hose_b->mem_space.start = 0;
- hose_b->mem_space.end = ADIR_PCI64_MEM_SIZE - 1;
- hose_b->io_resource.start = 0;
- hose_b->io_resource.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
- hose_b->io_resource.flags = IORESOURCE_IO;
- hose_b->mem_resources[0].start = ADIR_PCI64_MEM_BASE;
- hose_b->mem_resources[0].end = ADIR_PCI64_MEM_BASE +
- ADIR_PCI64_MEM_SIZE - 1;
- hose_b->mem_resources[0].flags = IORESOURCE_MEM;
- hose_b->io_base_phys = ADIR_PCI64_IO_BASE;
- hose_b->io_base_virt = (void *) ADIR_PCI64_VIRT_IO_BASE;
-
- setup_indirect_pci(hose_b, ADIR_PCI64_CONFIG_ADDR,
- ADIR_PCI64_CONFIG_DATA);
-
- /* Initialize PCI64 bus registers */
- early_write_config_byte(hose_b,
- 0,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER,
- 0xff);
-
- early_write_config_byte(hose_b,
- 0,
- PCI_DEVFN(0, 0),
- CPC710_BUS_NUMBER,
- hose_b->first_busno);
-
- hose_b->last_busno = pciauto_bus_scan(hose_b,
- hose_b->first_busno);
-
- /* Write out correct max subordinate bus number for hose B */
- early_write_config_byte(hose_b,
- hose_b->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER,
- hose_b->last_busno);
-
- ppc_md.pcibios_fixup = NULL;
- ppc_md.pcibios_fixup_resources = adir_pcibios_fixup_resources;
- ppc_md.pci_swizzle = common_swizzle;
- ppc_md.pci_map_irq = adir_map_irq;
-}
diff --git a/arch/ppc/platforms/adir_pic.c b/arch/ppc/platforms/adir_pic.c
deleted file mode 100644
index 9947cba..0000000
--- a/arch/ppc/platforms/adir_pic.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * arch/ppc/platforms/adir_pic.c
- *
- * Interrupt controller support for SBS Adirondack
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com>
- */
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/i8259.h>
-#include "adir.h"
-
-static void adir_onboard_pic_enable(unsigned int irq);
-static void adir_onboard_pic_disable(unsigned int irq);
-
-__init static void
-adir_onboard_pic_init(void)
-{
- volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
-
- /* Disable all Adirondack onboard interrupts */
- out_be16(maskreg, 0xFFFF);
-}
-
-static int
-adir_onboard_pic_get_irq(void)
-{
- volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT;
- int irq;
- u_short int_status, int_test;
-
- int_status = in_be16(statreg);
- for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) {
- if (int_status & int_test)
- break;
- }
-
- if (irq == 16)
- return -1;
-
- return (irq+16);
-}
-
-static void
-adir_onboard_pic_enable(unsigned int irq)
-{
- volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
-
- /* Change irq to Adirondack onboard native value */
- irq -= 16;
-
- /* Enable requested irq number */
- out_be16(maskreg, in_be16(maskreg) & ~(1 << irq));
-}
-
-static void
-adir_onboard_pic_disable(unsigned int irq)
-{
- volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
-
- /* Change irq to Adirondack onboard native value */
- irq -= 16;
-
- /* Disable requested irq number */
- out_be16(maskreg, in_be16(maskreg) | (1 << irq));
-}
-
-static struct hw_interrupt_type adir_onboard_pic = {
- " ADIR PIC ",
- NULL,
- NULL,
- adir_onboard_pic_enable, /* unmask */
- adir_onboard_pic_disable, /* mask */
- adir_onboard_pic_disable, /* mask and ack */
- NULL,
- NULL
-};
-
-static struct irqaction noop_action = {
- .handler = no_action,
- .flags = SA_INTERRUPT,
- .mask = CPU_MASK_NONE,
- .name = "82c59 primary cascade",
-};
-
-/*
- * Linux interrupt values are assigned as follows:
- *
- * 0-15 VT82C686 8259 interrupts
- * 16-31 Adirondack CPLD interrupts
- */
-__init void
-adir_init_IRQ(void)
-{
- int i;
-
- /* Initialize the cascaded 8259's on the VT82C686 */
- for (i=0; i<16; i++)
- irq_desc[i].handler = &i8259_pic;
- i8259_init(NULL);
-
- /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */
- for (i=16; i<32; i++)
- irq_desc[i].handler = &adir_onboard_pic;
- adir_onboard_pic_init();
-
- /* Enable 8259 interrupt cascade */
- setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action);
-}
-
-int
-adir_get_irq(struct pt_regs *regs)
-{
- int irq;
-
- if ((irq = adir_onboard_pic_get_irq()) < 0)
- return irq;
-
- if (irq == ADIR_IRQ_VT82C686_INTR)
- irq = i8259_irq(regs);
-
- return irq;
-}
diff --git a/arch/ppc/platforms/adir_setup.c b/arch/ppc/platforms/adir_setup.c
deleted file mode 100644
index 6a6754e..0000000
--- a/arch/ppc/platforms/adir_setup.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * arch/ppc/platforms/adir_setup.c
- *
- * Board setup routines for SBS Adirondack
- *
- * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
- * based on the K2 version by Matt Porter <mporter@mvista.com>
- */
-
-#include <linux/config.h>
-#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/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-
-#include "adir.h"
-
-extern void adir_init_IRQ(void);
-extern int adir_get_irq(struct pt_regs *);
-extern void adir_find_bridges(void);
-extern unsigned long loops_per_jiffy;
-
-static unsigned int cpu_750cx[16] = {
- 5, 15, 14, 0, 4, 13, 0, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-
-static int
-adir_get_bus_speed(void)
-{
- if (!(*((u_char *) ADIR_CLOCK_REG) & ADIR_CLOCK_REG_SEL133))
- return 100000000;
- else
- return 133333333;
-}
-
-static int
-adir_get_cpu_speed(void)
-{
- unsigned long hid1;
- int cpu_speed;
-
- hid1 = mfspr(SPRN_HID1) >> 28;
-
- hid1 = cpu_750cx[hid1];
-
- cpu_speed = adir_get_bus_speed()*hid1/2;
- return cpu_speed;
-}
-
-static void __init
-adir_calibrate_decr(void)
-{
- int freq, divisor = 4;
-
- /* determine processor bus speed */
- freq = adir_get_bus_speed();
- tb_ticks_per_jiffy = freq / HZ / divisor;
- tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-static int
-adir_show_cpuinfo(struct seq_file *m)
-{
- seq_printf(m, "vendor\t\t: SBS\n");
- seq_printf(m, "machine\t\t: Adirondack\n");
- seq_printf(m, "cpu speed\t: %dMhz\n", adir_get_cpu_speed()/1000000);
- seq_printf(m, "bus speed\t: %dMhz\n", adir_get_bus_speed()/1000000);
- seq_printf(m, "memory type\t: SDRAM\n");
-
- return 0;
-}
-
-extern char cmd_line[];
-
-TODC_ALLOC();
-
-static void __init
-adir_setup_arch(void)
-{
- unsigned int cpu;
-
- /* Setup TODC access */
- TODC_INIT(TODC_TYPE_MC146818, ADIR_NVRAM_RTC_ADDR, 0,
- ADIR_NVRAM_RTC_DATA, 8);
-
- /* init to some ~sane value until calibrate_delay() runs */
- loops_per_jiffy = 50000000/HZ;
-
- /* Setup PCI host bridges */
- adir_find_bridges();
-
-#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_SDA1;
-#endif
-
- /* Identify the system */
- printk("System Identification: SBS Adirondack - PowerPC 750CXe @ %d Mhz\n", adir_get_cpu_speed()/1000000);
- printk("SBS Adirondack port (C) 2001 SBS Technologies, Inc.\n");
-
- /* Identify the CPU manufacturer */
- cpu = mfspr(SPRN_PVR);
- printk("CPU manufacturer: IBM [rev=%04x]\n", (cpu & 0xffff));
-}
-
-static void
-adir_restart(char *cmd)
-{
- local_irq_disable();
- /* SRR0 has system reset vector, SRR1 has default MSR value */
- /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
- __asm__ __volatile__
- ("lis 3,0xfff0\n\t"
- "ori 3,3,0x0100\n\t"
- "mtspr 26,3\n\t"
- "li 3,0\n\t"
- "mtspr 27,3\n\t"
- "rfi\n\t");
- for(;;);
-}
-
-static void
-adir_power_off(void)
-{
- for(;;);
-}
-
-static void
-adir_halt(void)
-{
- adir_restart(NULL);
-}
-
-static unsigned long __init
-adir_find_end_of_memory(void)
-{
- return boot_mem_size;
-}
-
-static void __init
-adir_map_io(void)
-{
- io_block_mapping(ADIR_PCI32_VIRT_IO_BASE, ADIR_PCI32_IO_BASE,
- ADIR_PCI32_VIRT_IO_SIZE, _PAGE_IO);
- io_block_mapping(ADIR_PCI64_VIRT_IO_BASE, ADIR_PCI64_IO_BASE,
- ADIR_PCI64_VIRT_IO_SIZE, _PAGE_IO);
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- /*
- * On the Adirondack we use bi_recs and pass the pointer to them in R3.
- */
- parse_bootinfo((struct bi_record *) (r3 + KERNELBASE));
-
- /* Remember, isa_io_base is virtual but isa_mem_base is physical! */
- isa_io_base = ADIR_PCI32_VIRT_IO_BASE;
- isa_mem_base = ADIR_PCI32_MEM_BASE;
- pci_dram_offset = ADIR_PCI_SYS_MEM_BASE;
-
- ppc_md.setup_arch = adir_setup_arch;
- ppc_md.show_cpuinfo = adir_show_cpuinfo;
- ppc_md.irq_canonicalize = NULL;
- ppc_md.init_IRQ = adir_init_IRQ;
- ppc_md.get_irq = adir_get_irq;
- ppc_md.init = NULL;
-
- ppc_md.find_end_of_memory = adir_find_end_of_memory;
- ppc_md.setup_io_mappings = adir_map_io;
-
- ppc_md.restart = adir_restart;
- ppc_md.power_off = adir_power_off;
- ppc_md.halt = adir_halt;
-
- ppc_md.time_init = todc_time_init;
- ppc_md.set_rtc_time = todc_set_rtc_time;
- ppc_md.get_rtc_time = todc_get_rtc_time;
- ppc_md.nvram_read_val = todc_mc146818_read_val;
- ppc_md.nvram_write_val = todc_mc146818_write_val;
- ppc_md.calibrate_decr = adir_calibrate_decr;
-}
diff --git a/arch/ppc/platforms/cpci690.c b/arch/ppc/platforms/cpci690.c
index 507870c..f64ac2a 100644
--- a/arch/ppc/platforms/cpci690.c
+++ b/arch/ppc/platforms/cpci690.c
@@ -35,11 +35,7 @@
#define SET_PCI_IDE_NATIVE
static struct mv64x60_handle bh;
-static u32 cpci690_br_base;
-
-static const unsigned int cpu_7xx[16] = { /* 7xx & 74xx (but not 745x) */
- 18, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
+static void __iomem *cpci690_br_base;
TODC_ALLOC();
@@ -55,7 +51,7 @@
* A B C D
*/
{
- { 90, 91, 88, 89}, /* IDSEL 30/20 - Sentinel */
+ { 90, 91, 88, 89 }, /* IDSEL 30/20 - Sentinel */
};
const long min_idsel = 20, max_idsel = 20, irqs_per_slot = 4;
@@ -67,9 +63,9 @@
* A B C D
*/
{
- { 93, 94, 95, 92}, /* IDSEL 28/18 - PMC slot 2 */
- { 0, 0, 0, 0}, /* IDSEL 29/19 - Not used */
- { 94, 95, 92, 93}, /* IDSEL 30/20 - PMC slot 1 */
+ { 93, 94, 95, 92 }, /* IDSEL 28/18 - PMC slot 2 */
+ { 0, 0, 0, 0 }, /* IDSEL 29/19 - Not used */
+ { 94, 95, 92, 93 }, /* IDSEL 30/20 - PMC slot 1 */
};
const long min_idsel = 18, max_idsel = 20, irqs_per_slot = 4;
@@ -77,68 +73,29 @@
}
}
-static int
-cpci690_get_cpu_speed(void)
-{
- unsigned long hid1;
+#define GB (1024UL * 1024UL * 1024UL)
- hid1 = mfspr(SPRN_HID1) >> 28;
- return CPCI690_BUS_FREQ * cpu_7xx[hid1]/2;
+static u32
+cpci690_get_bus_freq(void)
+{
+ if (boot_mem_size >= (1*GB)) /* bus speed based on mem size */
+ return 100000000;
+ else
+ return 133333333;
}
-#define KB (1024UL)
-#define MB (1024UL * KB)
-#define GB (1024UL * MB)
+static const unsigned int cpu_750xx[32] = { /* 750FX & 750GX */
+ 0, 0, 2, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,/* 0-15*/
+ 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0 /*16-31*/
+};
-unsigned long __init
-cpci690_find_end_of_memory(void)
+static int
+cpci690_get_cpu_freq(void)
{
- u32 mem_ctlr_size;
- static u32 board_size;
- static u8 first_time = 1;
+ unsigned long pll_cfg;
- if (first_time) {
- /* Using cpci690_set_bat() mapping ==> virt addr == phys addr */
- switch (in_8((u8 *) (cpci690_br_base +
- CPCI690_BR_MEM_CTLR)) & 0x07) {
- case 0x01:
- board_size = 256*MB;
- break;
- case 0x02:
- board_size = 512*MB;
- break;
- case 0x03:
- board_size = 768*MB;
- break;
- case 0x04:
- board_size = 1*GB;
- break;
- case 0x05:
- board_size = 1*GB + 512*MB;
- break;
- case 0x06:
- board_size = 2*GB;
- break;
- default:
- board_size = 0xffffffff; /* use mem ctlr size */
- } /* switch */
-
- mem_ctlr_size = mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
- MV64x60_TYPE_GT64260A);
-
- /* Check that mem ctlr & board reg agree. If not, pick MIN. */
- if (board_size != mem_ctlr_size) {
- printk(KERN_WARNING "Board register & memory controller"
- "mem size disagree (board reg: 0x%lx, "
- "mem ctlr: 0x%lx)\n",
- (ulong)board_size, (ulong)mem_ctlr_size);
- board_size = min(board_size, mem_ctlr_size);
- }
-
- first_time = 0;
- } /* if */
-
- return board_size;
+ pll_cfg = (mfspr(SPRN_HID1) & 0xf8000000) >> 27;
+ return cpci690_get_bus_freq() * cpu_750xx[pll_cfg]/2;
}
static void __init
@@ -228,7 +185,7 @@
mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, CPCI690_BR_BASE,
CPCI690_BR_SIZE, 0);
bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
- cpci690_br_base = (u32)ioremap(CPCI690_BR_BASE, CPCI690_BR_SIZE);
+ cpci690_br_base = ioremap(CPCI690_BR_BASE, CPCI690_BR_SIZE);
mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, CPCI690_TODC_BASE,
CPCI690_TODC_SIZE, 0);
@@ -329,7 +286,7 @@
pdata->max_idle = 40;
pdata->default_baud = CPCI690_MPSC_BAUD;
pdata->brg_clk_src = CPCI690_MPSC_CLK_SRC;
- pdata->brg_clk_freq = CPCI690_BUS_FREQ;
+ pdata->brg_clk_freq = cpci690_get_bus_freq();
}
static int __init
@@ -365,7 +322,7 @@
u32 i = 10000;
local_irq_disable();
- out_8((u8 *)(cpci690_br_base + CPCI690_BR_SW_RESET), 0x11);
+ out_8((cpci690_br_base + CPCI690_BR_SW_RESET), 0x11);
while (i != 0) i++;
panic("restart failed\n");
@@ -394,10 +351,40 @@
static int
cpci690_show_cpuinfo(struct seq_file *m)
{
+ char *s;
+
+ seq_printf(m, "cpu MHz\t\t: %d\n",
+ (cpci690_get_cpu_freq() + 500000) / 1000000);
+ seq_printf(m, "bus MHz\t\t: %d\n",
+ (cpci690_get_bus_freq() + 500000) / 1000000);
seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
- seq_printf(m, "cpu MHz\t\t: %d\n", cpci690_get_cpu_speed()/1000/1000);
- seq_printf(m, "bus MHz\t\t: %d\n", CPCI690_BUS_FREQ/1000/1000);
+ seq_printf(m, "FPGA Revision\t: %d\n",
+ in_8(cpci690_br_base + CPCI690_BR_MEM_CTLR) >> 5);
+
+ switch(bh.type) {
+ case MV64x60_TYPE_GT64260A:
+ s = "gt64260a";
+ break;
+ case MV64x60_TYPE_GT64260B:
+ s = "gt64260b";
+ break;
+ case MV64x60_TYPE_MV64360:
+ s = "mv64360";
+ break;
+ case MV64x60_TYPE_MV64460:
+ s = "mv64460";
+ break;
+ default:
+ s = "Unknown";
+ }
+ seq_printf(m, "bridge type\t: %s\n", s);
+ seq_printf(m, "bridge rev\t: 0x%x\n", bh.rev);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ seq_printf(m, "coherency\t: %s\n", "off");
+#else
+ seq_printf(m, "coherency\t: %s\n", "on");
+#endif
return 0;
}
@@ -407,7 +394,7 @@
{
ulong freq;
- freq = CPCI690_BUS_FREQ / 4;
+ freq = cpci690_get_bus_freq() / 4;
printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
freq/1000000, freq%1000000);
@@ -416,25 +403,12 @@
tb_to_us = mulhwu_scale_factor(freq, 1000000);
}
-static __inline__ void
-cpci690_set_bat(u32 addr, u32 size)
-{
- addr &= 0xfffe0000;
- size &= 0x1ffe0000;
- size = ((size >> 17) - 1) << 2;
-
- mb();
- mtspr(SPRN_DBAT1U, addr | size | 0x2); /* Vs == 1; Vp == 0 */
- mtspr(SPRN_DBAT1L, addr | 0x2a); /* WIMG bits == 0101; PP == r/w access */
- mb();
-}
-
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC)
static void __init
cpci690_map_io(void)
{
io_block_mapping(CONFIG_MV64X60_NEW_BASE, CONFIG_MV64X60_NEW_BASE,
- 128 * KB, _PAGE_IO);
+ 128 * 1024, _PAGE_IO);
}
#endif
@@ -442,14 +416,15 @@
platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
-#ifdef CONFIG_BLK_DEV_INITRD
- initrd_start=initrd_end=0;
- initrd_below_start_ok=0;
-#endif /* CONFIG_BLK_DEV_INITRD */
-
parse_bootinfo(find_bootinfo());
- loops_per_jiffy = cpci690_get_cpu_speed() / HZ;
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
isa_mem_base = 0;
@@ -460,7 +435,6 @@
ppc_md.restart = cpci690_restart;
ppc_md.power_off = cpci690_power_off;
ppc_md.halt = cpci690_halt;
- ppc_md.find_end_of_memory = cpci690_find_end_of_memory;
ppc_md.time_init = todc_time_init;
ppc_md.set_rtc_time = todc_set_rtc_time;
ppc_md.get_rtc_time = todc_get_rtc_time;
@@ -468,22 +442,13 @@
ppc_md.nvram_write_val = todc_direct_write_val;
ppc_md.calibrate_decr = cpci690_calibrate_decr;
- /*
- * Need to map in board regs (used by cpci690_find_end_of_memory())
- * and the bridge's regs (used by progress);
- */
- cpci690_set_bat(CPCI690_BR_BASE, 32 * MB);
- cpci690_br_base = CPCI690_BR_BASE;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC)
ppc_md.setup_io_mappings = cpci690_map_io;
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
ppc_md.progress = mv64x60_mpsc_progress;
mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef CONFIG_KGDB
- ppc_md.setup_io_mappings = cpci690_map_io;
- ppc_md.early_serial_map = cpci690_early_serial_map;
-#endif /* CONFIG_KGDB */
+#endif /* defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_MPSC) */
#if defined(CONFIG_SERIAL_MPSC)
platform_notify = cpci690_platform_notify;
diff --git a/arch/ppc/platforms/cpci690.h b/arch/ppc/platforms/cpci690.h
index 36cd267..49584c9 100644
--- a/arch/ppc/platforms/cpci690.h
+++ b/arch/ppc/platforms/cpci690.h
@@ -73,6 +73,4 @@
#define CPCI690_MPSC_BAUD 9600
#define CPCI690_MPSC_CLK_SRC 8 /* TCLK */
-#define CPCI690_BUS_FREQ 133333333
-
#endif /* __PPC_PLATFORMS_CPCI690_H */
diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c
new file mode 100644
index 0000000..9811a8a
--- /dev/null
+++ b/arch/ppc/platforms/ev64360.c
@@ -0,0 +1,510 @@
+/*
+ * arch/ppc/platforms/ev64360.c
+ *
+ * Board setup routines for the Marvell EV-64360-BP Evaluation Board.
+ *
+ * Author: Lee Nicks <allinux@gmail.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/bootmem.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx.h>
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/smp.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppcboot.h>
+#include <asm/mv64x60.h>
+#include <platforms/ev64360.h>
+
+#define BOARD_VENDOR "Marvell"
+#define BOARD_MACHINE "EV-64360-BP"
+
+static struct mv64x60_handle bh;
+static void __iomem *sram_base;
+
+static u32 ev64360_flash_size_0;
+static u32 ev64360_flash_size_1;
+
+static u32 ev64360_bus_frequency;
+
+unsigned char __res[sizeof(bd_t)];
+
+static int __init
+ev64360_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ return 0;
+}
+
+static void __init
+ev64360_setup_bridge(void)
+{
+ struct mv64x60_setup_info si;
+ int i;
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+ #ifdef CONFIG_PCI
+ si.pci_1.enable_bus = 1;
+ si.pci_1.pci_io.cpu_base = EV64360_PCI1_IO_START_PROC_ADDR;
+ si.pci_1.pci_io.pci_base_hi = 0;
+ si.pci_1.pci_io.pci_base_lo = EV64360_PCI1_IO_START_PCI_ADDR;
+ si.pci_1.pci_io.size = EV64360_PCI1_IO_SIZE;
+ si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[0].cpu_base = EV64360_PCI1_MEM_START_PROC_ADDR;
+ si.pci_1.pci_mem[0].pci_base_hi = EV64360_PCI1_MEM_START_PCI_HI_ADDR;
+ si.pci_1.pci_mem[0].pci_base_lo = EV64360_PCI1_MEM_START_PCI_LO_ADDR;
+ si.pci_1.pci_mem[0].size = EV64360_PCI1_MEM_SIZE;
+ si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_cmd_bits = 0;
+ si.pci_1.latency_timer = 0x80;
+ #else
+ si.pci_0.enable_bus = 0;
+ si.pci_1.enable_bus = 0;
+ #endif
+
+ for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
+ }
+
+ if (mv64x60_init(&bh, &si))
+ printk(KERN_WARNING "Bridge initialization failed.\n");
+
+ #ifdef CONFIG_PCI
+ pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = ev64360_map_irq;
+ ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+ mv64x60_set_bus(&bh, 1, 0);
+ bh.hose_b->first_busno = 0;
+ bh.hose_b->last_busno = 0xff;
+ #endif
+}
+
+/* Bridge & platform setup routines */
+void __init
+ev64360_intr_setup(void)
+{
+ /* MPP 8, 9, and 10 */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0xfff);
+
+ /*
+ * Define GPP 8,9,and 10 interrupt polarity as active low
+ * input signal and level triggered
+ */
+ mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0x700);
+ mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, 0x700);
+
+ /* Config GPP intr ctlr to respond to level trigger */
+ mv64x60_set_bits(&bh, MV64x60_COMM_ARBITER_CNTL, (1<<10));
+
+ /* Erranum FEr PCI-#8 */
+ mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1<<5) | (1<<9));
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<5) | (1<<9));
+
+ /*
+ * Dismiss and then enable interrupt on GPP interrupt cause
+ * for CPU #0
+ */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~0x700);
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, 0x700);
+
+ /*
+ * Dismiss and then enable interrupt on CPU #0 high cause reg
+ * BIT25 summarizes GPP interrupts 8-15
+ */
+ mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1<<25));
+}
+
+void __init
+ev64360_setup_peripherals(void)
+{
+ u32 base;
+
+ /* Set up window for boot CS */
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ EV64360_BOOT_WINDOW_BASE, EV64360_BOOT_WINDOW_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+ /* We only use the 32-bit flash */
+ mv64x60_get_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, &base,
+ &ev64360_flash_size_0);
+ ev64360_flash_size_1 = 0;
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+ EV64360_RTC_WINDOW_BASE, EV64360_RTC_WINDOW_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+ sram_base = ioremap(EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
+
+ /* Set up Enet->SRAM window */
+ mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN,
+ EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0x2);
+ bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+
+ /* Give enet r/w access to memory region */
+ mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_0, (0x3 << (4 << 1)));
+ mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_1, (0x3 << (4 << 1)));
+ mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_2, (0x3 << (4 << 1)));
+
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3));
+ mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+ ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24)));
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x00160000);
+#else
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
+#endif
+
+ /*
+ * Setting the SRAM to 0. Note that this generates parity errors on
+ * internal data path in SRAM since it's first time accessing it
+ * while after reset it's not configured.
+ */
+ memset(sram_base, 0, MV64360_SRAM_SIZE);
+
+ /* set up PCI interrupt controller */
+ ev64360_intr_setup();
+}
+
+static void __init
+ev64360_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("ev64360_setup_arch: enter", 0);
+
+ set_tb(0, 0);
+
+#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_SDA2;
+#endif
+
+ /*
+ * Set up the L2CR register.
+ */
+ _set_L2CR(L2CR_L2E | L2CR_L2PE);
+
+ if (ppc_md.progress)
+ ppc_md.progress("ev64360_setup_arch: calling setup_bridge", 0);
+
+ ev64360_setup_bridge();
+ ev64360_setup_peripherals();
+ ev64360_bus_frequency = ev64360_bus_freq();
+
+ printk(KERN_INFO "%s %s port (C) 2005 Lee Nicks "
+ "(allinux@gmail.com)\n", BOARD_VENDOR, BOARD_MACHINE);
+ if (ppc_md.progress)
+ ppc_md.progress("ev64360_setup_arch: exit", 0);
+}
+
+/* Platform device data fixup routines. */
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init
+ev64360_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+ struct mpsc_pdata *pdata;
+
+ pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+ pdata->max_idle = 40;
+ pdata->default_baud = EV64360_DEFAULT_BAUD;
+ pdata->brg_clk_src = EV64360_MPSC_CLK_SRC;
+ /*
+ * TCLK (not SysCLk) is routed to BRG, then to the MPSC. On most parts,
+ * TCLK == SysCLK but on 64460, they are separate pins.
+ * SysCLK can go up to 200 MHz but TCLK can only go up to 133 MHz.
+ */
+ pdata->brg_clk_freq = min(ev64360_bus_frequency, MV64x60_TCLK_FREQ_MAX);
+}
+#endif
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init
+ev64360_fixup_eth_pdata(struct platform_device *pdev)
+{
+ struct mv643xx_eth_platform_data *eth_pd;
+ static u16 phy_addr[] = {
+ EV64360_ETH0_PHY_ADDR,
+ EV64360_ETH1_PHY_ADDR,
+ EV64360_ETH2_PHY_ADDR,
+ };
+
+ eth_pd = pdev->dev.platform_data;
+ eth_pd->force_phy_addr = 1;
+ eth_pd->phy_addr = phy_addr[pdev->id];
+ eth_pd->tx_queue_size = EV64360_ETH_TX_QUEUE_SIZE;
+ eth_pd->rx_queue_size = EV64360_ETH_RX_QUEUE_SIZE;
+}
+#endif
+
+static int __init
+ev64360_platform_notify(struct device *dev)
+{
+ static struct {
+ char *bus_id;
+ void ((*rtn)(struct platform_device *pdev));
+ } dev_map[] = {
+#if defined(CONFIG_SERIAL_MPSC)
+ { MPSC_CTLR_NAME ".0", ev64360_fixup_mpsc_pdata },
+ { MPSC_CTLR_NAME ".1", ev64360_fixup_mpsc_pdata },
+#endif
+#if defined(CONFIG_MV643XX_ETH)
+ { MV643XX_ETH_NAME ".0", ev64360_fixup_eth_pdata },
+ { MV643XX_ETH_NAME ".1", ev64360_fixup_eth_pdata },
+ { MV643XX_ETH_NAME ".2", ev64360_fixup_eth_pdata },
+#endif
+ };
+ struct platform_device *pdev;
+ int i;
+
+ if (dev && dev->bus_id)
+ for (i=0; i<ARRAY_SIZE(dev_map); i++)
+ if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+ BUS_ID_SIZE)) {
+
+ pdev = container_of(dev,
+ struct platform_device, dev);
+ dev_map[i].rtn(pdev);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+
+#ifndef MB
+#define MB (1 << 20)
+#endif
+
+/*
+ * MTD Layout.
+ *
+ * FLASH Amount: 0xff000000 - 0xffffffff
+ * ------------- -----------------------
+ * Reserved: 0xff000000 - 0xff03ffff
+ * JFFS2 file system: 0xff040000 - 0xffefffff
+ * U-boot: 0xfff00000 - 0xffffffff
+ */
+static int __init
+ev64360_setup_mtd(void)
+{
+ u32 size;
+ int ptbl_entries;
+ static struct mtd_partition *ptbl;
+
+ size = ev64360_flash_size_0 + ev64360_flash_size_1;
+ if (!size)
+ return -ENOMEM;
+
+ ptbl_entries = 3;
+
+ if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
+ GFP_KERNEL)) == NULL) {
+
+ printk(KERN_WARNING "Can't alloc MTD partition table\n");
+ return -ENOMEM;
+ }
+ memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition));
+
+ ptbl[0].name = "reserved";
+ ptbl[0].offset = 0;
+ ptbl[0].size = EV64360_MTD_RESERVED_SIZE;
+ ptbl[1].name = "jffs2";
+ ptbl[1].offset = EV64360_MTD_RESERVED_SIZE;
+ ptbl[1].size = EV64360_MTD_JFFS2_SIZE;
+ ptbl[2].name = "U-BOOT";
+ ptbl[2].offset = EV64360_MTD_RESERVED_SIZE + EV64360_MTD_JFFS2_SIZE;
+ ptbl[2].size = EV64360_MTD_UBOOT_SIZE;
+
+ physmap_map.size = size;
+ physmap_set_partitions(ptbl, ptbl_entries);
+ return 0;
+}
+
+arch_initcall(ev64360_setup_mtd);
+#endif
+
+static void
+ev64360_restart(char *cmd)
+{
+ ulong i = 0xffffffff;
+ volatile unsigned char * rtc_base = ioremap(EV64360_RTC_WINDOW_BASE,0x4000);
+
+ /* issue hard reset */
+ rtc_base[0xf] = 0x80;
+ rtc_base[0xc] = 0x00;
+ rtc_base[0xd] = 0x01;
+ rtc_base[0xf] = 0x83;
+
+ while (i-- > 0) ;
+ panic("restart failed\n");
+}
+
+static void
+ev64360_halt(void)
+{
+ while (1) ;
+ /* NOTREACHED */
+}
+
+static void
+ev64360_power_off(void)
+{
+ ev64360_halt();
+ /* NOTREACHED */
+}
+
+static int
+ev64360_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
+ seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
+ seq_printf(m, "bus speed\t: %dMHz\n", ev64360_bus_frequency/1000/1000);
+
+ return 0;
+}
+
+static void __init
+ev64360_calibrate_decr(void)
+{
+ u32 freq;
+
+ freq = ev64360_bus_frequency / 4;
+
+ printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ (long)freq / 1000000, (long)freq % 1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+unsigned long __init
+ev64360_find_end_of_memory(void)
+{
+ return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+ MV64x60_TYPE_MV64360);
+}
+
+static inline void
+ev64360_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT2U, 0xf0001ffe);
+ mtspr(SPRN_DBAT2L, 0xf000002a);
+ mb();
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init
+ev64360_map_io(void)
+{
+ io_block_mapping(CONFIG_MV64X60_NEW_BASE, \
+ CONFIG_MV64X60_NEW_BASE, \
+ 0x00020000, _PAGE_IO);
+}
+#endif
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer)
+ * are non-zero, then we should use the board info from the bd_t
+ * structure and the cmdline pointed to by r6 instead of the
+ * information from birecs, if any. Otherwise, use the information
+ * from birecs as discovered by the preceeding call to
+ * parse_bootinfo(). This rule should work with both PPCBoot, which
+ * uses a bd_t board info structure, and the kernel boot wrapper,
+ * which uses birecs.
+ */
+ if (r3 && r6) {
+ /* copy board info structure */
+ memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+ /* copy command line */
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ #ifdef CONFIG_ISA
+ isa_mem_base = 0;
+ #endif
+
+ ppc_md.setup_arch = ev64360_setup_arch;
+ ppc_md.show_cpuinfo = ev64360_show_cpuinfo;
+ ppc_md.init_IRQ = mv64360_init_irq;
+ ppc_md.get_irq = mv64360_get_irq;
+ ppc_md.restart = ev64360_restart;
+ ppc_md.power_off = ev64360_power_off;
+ ppc_md.halt = ev64360_halt;
+ ppc_md.find_end_of_memory = ev64360_find_end_of_memory;
+ ppc_md.calibrate_decr = ev64360_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ ppc_md.setup_io_mappings = ev64360_map_io;
+ ppc_md.progress = mv64x60_mpsc_progress;
+ mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#endif
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
+ platform_notify = ev64360_platform_notify;
+#endif
+
+ ev64360_set_bat(); /* Need for ev64360_find_end_of_memory and progress */
+}
diff --git a/arch/ppc/platforms/ev64360.h b/arch/ppc/platforms/ev64360.h
new file mode 100644
index 0000000..68eabe4
--- /dev/null
+++ b/arch/ppc/platforms/ev64360.h
@@ -0,0 +1,116 @@
+/*
+ * arch/ppc/platforms/ev64360.h
+ *
+ * Definitions for Marvell EV-64360-BP Evaluation Board.
+ *
+ * Author: Lee Nicks <allinux@gmail.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by Mark A. Greer <mgreer@mvista.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.
+ */
+
+/*
+ * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 64KB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ * 0x42000000-0x4203ffff - Internal SRAM
+ * 0xf1000000-0xf100ffff - MV64360 Registers (CONFIG_MV64X60_NEW_BASE)
+ * 0xfc800000-0xfcffffff - RTC
+ * 0xff000000-0xffffffff - Boot window, 16 MB flash
+ * 0xc0000000-0xc3ffffff - PCI I/O (second hose)
+ * 0x80000000-0xbfffffff - PCI MEM (second hose)
+ */
+
+#ifndef __PPC_PLATFORMS_EV64360_H
+#define __PPC_PLATFORMS_EV64360_H
+
+/* CPU Physical Memory Map setup. */
+#define EV64360_BOOT_WINDOW_BASE 0xff000000
+#define EV64360_BOOT_WINDOW_SIZE 0x01000000 /* 16 MB */
+#define EV64360_INTERNAL_SRAM_BASE 0x42000000
+#define EV64360_RTC_WINDOW_BASE 0xfc800000
+#define EV64360_RTC_WINDOW_SIZE 0x00800000 /* 8 MB */
+
+#define EV64360_PCI1_MEM_START_PROC_ADDR 0x80000000
+#define EV64360_PCI1_MEM_START_PCI_HI_ADDR 0x00000000
+#define EV64360_PCI1_MEM_START_PCI_LO_ADDR 0x80000000
+#define EV64360_PCI1_MEM_SIZE 0x40000000 /* 1 GB */
+#define EV64360_PCI1_IO_START_PROC_ADDR 0xc0000000
+#define EV64360_PCI1_IO_START_PCI_ADDR 0x00000000
+#define EV64360_PCI1_IO_SIZE 0x04000000 /* 64 MB */
+
+#define EV64360_DEFAULT_BAUD 115200
+#define EV64360_MPSC_CLK_SRC 8 /* TCLK */
+#define EV64360_MPSC_CLK_FREQ 133333333
+
+#define EV64360_MTD_RESERVED_SIZE 0x40000
+#define EV64360_MTD_JFFS2_SIZE 0xec0000
+#define EV64360_MTD_UBOOT_SIZE 0x100000
+
+#define EV64360_ETH0_PHY_ADDR 8
+#define EV64360_ETH1_PHY_ADDR 9
+#define EV64360_ETH2_PHY_ADDR 10
+
+#define EV64360_ETH_TX_QUEUE_SIZE 800
+#define EV64360_ETH_RX_QUEUE_SIZE 400
+
+#define EV64360_ETH_PORT_CONFIG_VALUE \
+ ETH_UNICAST_NORMAL_MODE | \
+ ETH_DEFAULT_RX_QUEUE_0 | \
+ ETH_DEFAULT_RX_ARP_QUEUE_0 | \
+ ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \
+ ETH_RECEIVE_BC_IF_IP | \
+ ETH_RECEIVE_BC_IF_ARP | \
+ ETH_CAPTURE_TCP_FRAMES_DIS | \
+ ETH_CAPTURE_UDP_FRAMES_DIS | \
+ ETH_DEFAULT_RX_TCP_QUEUE_0 | \
+ ETH_DEFAULT_RX_UDP_QUEUE_0 | \
+ ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+#define EV64360_ETH_PORT_CONFIG_EXTEND_VALUE \
+ ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \
+ ETH_PARTITION_DISABLE
+
+#define GT_ETH_IPG_INT_RX(value) \
+ ((value & 0x3fff) << 8)
+
+#define EV64360_ETH_PORT_SDMA_CONFIG_VALUE \
+ ETH_RX_BURST_SIZE_4_64BIT | \
+ GT_ETH_IPG_INT_RX(0) | \
+ ETH_TX_BURST_SIZE_4_64BIT
+
+#define EV64360_ETH_PORT_SERIAL_CONTROL_VALUE \
+ ETH_FORCE_LINK_PASS | \
+ ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \
+ ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \
+ ETH_ADV_SYMMETRIC_FLOW_CTRL | \
+ ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \
+ ETH_FORCE_BP_MODE_NO_JAM | \
+ BIT9 | \
+ ETH_DO_NOT_FORCE_LINK_FAIL | \
+ ETH_RETRANSMIT_16_ATTEMPTS | \
+ ETH_ENABLE_AUTO_NEG_SPEED_GMII | \
+ ETH_DTE_ADV_0 | \
+ ETH_DISABLE_AUTO_NEG_BYPASS | \
+ ETH_AUTO_NEG_NO_CHANGE | \
+ ETH_MAX_RX_PACKET_9700BYTE | \
+ ETH_CLR_EXT_LOOPBACK | \
+ ETH_SET_FULL_DUPLEX_MODE | \
+ ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+static inline u32
+ev64360_bus_freq(void)
+{
+ return 133333333;
+}
+
+#endif /* __PPC_PLATFORMS_EV64360_H */
diff --git a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c
deleted file mode 100644
index aacb438..0000000
--- a/arch/ppc/platforms/k2.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * arch/ppc/platforms/k2.c
- *
- * Board setup routines for SBS K2
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * Updated by: Randy Vinson <rvinson@mvista.com.
- *
- * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/config.h>
-#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/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/i8259.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-
-#include <syslib/cpc710.h>
-#include "k2.h"
-
-extern unsigned long loops_per_jiffy;
-extern void gen550_progress(char *, unsigned short);
-
-static unsigned int cpu_7xx[16] = {
- 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-static unsigned int cpu_6xx[16] = {
- 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
-};
-
-static inline int __init
-k2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
- struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
- /*
- * Check our hose index. If we are zero then we are on the
- * local PCI hose, otherwise we are on the cPCI hose.
- */
- if (!hose->index) {
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- {1, 0, 0, 0}, /* Ethernet */
- {5, 5, 5, 5}, /* PMC Site 1 */
- {6, 6, 6, 6}, /* PMC Site 2 */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* PCI-ISA Bridge */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {0, 0, 0, 0}, /* unused */
- {15, 0, 0, 0}, /* M5229 IDE */
- };
- const long min_idsel = 3, max_idsel = 17, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
- } else {
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- {10, 11, 12, 9}, /* cPCI slot 8 */
- {11, 12, 9, 10}, /* cPCI slot 7 */
- {12, 9, 10, 11}, /* cPCI slot 6 */
- {9, 10, 11, 12}, /* cPCI slot 5 */
- {10, 11, 12, 9}, /* cPCI slot 4 */
- {11, 12, 9, 10}, /* cPCI slot 3 */
- {12, 9, 10, 11}, /* cPCI slot 2 */
- };
- const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
- }
-}
-
-void k2_pcibios_fixup(void)
-{
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
- struct pci_dev *ide_dev;
-
- /*
- * Enable DMA support on hdc
- */
- ide_dev = pci_get_device(PCI_VENDOR_ID_AL,
- PCI_DEVICE_ID_AL_M5229, NULL);
-
- if (ide_dev) {
-
- unsigned long ide_dma_base;
-
- ide_dma_base = pci_resource_start(ide_dev, 4);
- outb(0x00, ide_dma_base + 0x2);
- outb(0x20, ide_dma_base + 0xa);
- pci_dev_put(ide_dev);
- }
-#endif
-}
-
-void k2_pcibios_fixup_resources(struct pci_dev *dev)
-{
- int i;
-
- if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
- (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) {
- pr_debug("Fixup CPC710 resources\n");
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- }
- }
-}
-
-void k2_setup_hoses(void)
-{
- struct pci_controller *hose_a, *hose_b;
-
- /*
- * Reconfigure CPC710 memory map so
- * we have some more PCI memory space.
- */
-
- /* Set FPHB mode */
- __raw_writel(0x808000e0, PGCHP); /* Set FPHB mode */
-
- /* PCI32 mappings */
- __raw_writel(0x00000000, K2_PCI32_BAR + PIBAR); /* PCI I/O base */
- __raw_writel(0x00000000, K2_PCI32_BAR + PMBAR); /* PCI Mem base */
- __raw_writel(0xf0000000, K2_PCI32_BAR + MSIZE); /* 256MB */
- __raw_writel(0xfff00000, K2_PCI32_BAR + IOSIZE); /* 1MB */
- __raw_writel(0xc0000000, K2_PCI32_BAR + SMBAR); /* Base@0xc0000000 */
- __raw_writel(0x80000000, K2_PCI32_BAR + SIBAR); /* Base@0x80000000 */
- __raw_writel(0x000000c0, K2_PCI32_BAR + PSSIZE); /* 1GB space */
- __raw_writel(0x000000c0, K2_PCI32_BAR + PPSIZE); /* 1GB space */
- __raw_writel(0x00000000, K2_PCI32_BAR + BARPS); /* Base@0x00000000 */
- __raw_writel(0x00000000, K2_PCI32_BAR + BARPP); /* Base@0x00000000 */
- __raw_writel(0x00000080, K2_PCI32_BAR + PSBAR); /* Base@0x80 */
- __raw_writel(0x00000000, K2_PCI32_BAR + PPBAR);
-
- __raw_writel(0xc0000000, K2_PCI32_BAR + BPMDLK);
- __raw_writel(0xd0000000, K2_PCI32_BAR + TPMDLK);
- __raw_writel(0x80000000, K2_PCI32_BAR + BIODLK);
- __raw_writel(0x80100000, K2_PCI32_BAR + TIODLK);
- __raw_writel(0xe0008000, K2_PCI32_BAR + DLKCTRL);
- __raw_writel(0xffffffff, K2_PCI32_BAR + DLKDEV);
-
- /* PCI64 mappings */
- __raw_writel(0x00100000, K2_PCI64_BAR + PIBAR); /* PCI I/O base */
- __raw_writel(0x10000000, K2_PCI64_BAR + PMBAR); /* PCI Mem base */
- __raw_writel(0xf0000000, K2_PCI64_BAR + MSIZE); /* 256MB */
- __raw_writel(0xfff00000, K2_PCI64_BAR + IOSIZE); /* 1MB */
- __raw_writel(0xd0000000, K2_PCI64_BAR + SMBAR); /* Base@0xd0000000 */
- __raw_writel(0x80100000, K2_PCI64_BAR + SIBAR); /* Base@0x80100000 */
- __raw_writel(0x000000c0, K2_PCI64_BAR + PSSIZE); /* 1GB space */
- __raw_writel(0x000000c0, K2_PCI64_BAR + PPSIZE); /* 1GB space */
- __raw_writel(0x00000000, K2_PCI64_BAR + BARPS); /* Base@0x00000000 */
- __raw_writel(0x00000000, K2_PCI64_BAR + BARPP); /* Base@0x00000000 */
-
- /* Setup PCI32 hose */
- hose_a = pcibios_alloc_controller();
- if (!hose_a)
- return;
-
- hose_a->first_busno = 0;
- hose_a->last_busno = 0xff;
- hose_a->pci_mem_offset = K2_PCI32_MEM_BASE;
-
- pci_init_resource(&hose_a->io_resource,
- K2_PCI32_LOWER_IO,
- K2_PCI32_UPPER_IO,
- IORESOURCE_IO, "PCI32 host bridge");
-
- pci_init_resource(&hose_a->mem_resources[0],
- K2_PCI32_LOWER_MEM + K2_PCI32_MEM_BASE,
- K2_PCI32_UPPER_MEM + K2_PCI32_MEM_BASE,
- IORESOURCE_MEM, "PCI32 host bridge");
-
- hose_a->io_space.start = K2_PCI32_LOWER_IO;
- hose_a->io_space.end = K2_PCI32_UPPER_IO;
- hose_a->mem_space.start = K2_PCI32_LOWER_MEM;
- hose_a->mem_space.end = K2_PCI32_UPPER_MEM;
- hose_a->io_base_virt = (void *)K2_ISA_IO_BASE;
-
- setup_indirect_pci(hose_a, K2_PCI32_CONFIG_ADDR, K2_PCI32_CONFIG_DATA);
-
- /* Initialize PCI32 bus registers */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_BUS_NUMBER, hose_a->first_busno);
-
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER, hose_a->last_busno);
-
- /* Enable PCI interrupt polling */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x45, 0x80);
-
- /* Route polled PCI interrupts */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x48, 0x58);
-
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x49, 0x07);
-
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x4a, 0x31);
-
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x4b, 0xb9);
-
- /* route secondary IDE channel interrupt to IRQ 15 */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x75, 0x0f);
-
- /* enable IDE controller IDSEL */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(8, 0), 0x58, 0x48);
-
- /* Enable IDE function */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(17, 0), 0x50, 0x03);
-
- /* Set M5229 IDE controller to native mode */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(17, 0), PCI_CLASS_PROG, 0xdf);
-
- hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-
- /* Write out correct max subordinate bus number for hose A */
- early_write_config_byte(hose_a,
- hose_a->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER, hose_a->last_busno);
-
- /* Only setup PCI64 hose if we are in the system slot */
- if (!(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK)) {
- /* Setup PCI64 hose */
- hose_b = pcibios_alloc_controller();
- if (!hose_b)
- return;
-
- hose_b->first_busno = hose_a->last_busno + 1;
- hose_b->last_busno = 0xff;
-
- /* Reminder: quit changing the following, it is correct. */
- hose_b->pci_mem_offset = K2_PCI32_MEM_BASE;
-
- pci_init_resource(&hose_b->io_resource,
- K2_PCI64_LOWER_IO,
- K2_PCI64_UPPER_IO,
- IORESOURCE_IO, "PCI64 host bridge");
-
- pci_init_resource(&hose_b->mem_resources[0],
- K2_PCI64_LOWER_MEM + K2_PCI32_MEM_BASE,
- K2_PCI64_UPPER_MEM + K2_PCI32_MEM_BASE,
- IORESOURCE_MEM, "PCI64 host bridge");
-
- hose_b->io_space.start = K2_PCI64_LOWER_IO;
- hose_b->io_space.end = K2_PCI64_UPPER_IO;
- hose_b->mem_space.start = K2_PCI64_LOWER_MEM;
- hose_b->mem_space.end = K2_PCI64_UPPER_MEM;
- hose_b->io_base_virt = (void *)K2_ISA_IO_BASE;
-
- setup_indirect_pci(hose_b,
- K2_PCI64_CONFIG_ADDR, K2_PCI64_CONFIG_DATA);
-
- /* Initialize PCI64 bus registers */
- early_write_config_byte(hose_b,
- 0,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER, 0xff);
-
- early_write_config_byte(hose_b,
- 0,
- PCI_DEVFN(0, 0),
- CPC710_BUS_NUMBER, hose_b->first_busno);
-
- hose_b->last_busno = pciauto_bus_scan(hose_b,
- hose_b->first_busno);
-
- /* Write out correct max subordinate bus number for hose B */
- early_write_config_byte(hose_b,
- hose_b->first_busno,
- PCI_DEVFN(0, 0),
- CPC710_SUB_BUS_NUMBER,
- hose_b->last_busno);
-
- /* Configure PCI64 PSBAR */
- early_write_config_dword(hose_b,
- hose_b->first_busno,
- PCI_DEVFN(0, 0),
- PCI_BASE_ADDRESS_0,
- K2_PCI64_SYS_MEM_BASE);
- }
-
- /* Configure i8259 level/edge settings */
- outb(0x62, 0x4d0);
- outb(0xde, 0x4d1);
-
-#ifdef CONFIG_CPC710_DATA_GATHERING
- {
- unsigned int tmp;
- tmp = __raw_readl(ABCNTL);
- /* Enable data gathering on both PCI interfaces */
- __raw_writel(tmp | 0x05000000, ABCNTL);
- }
-#endif
-
- ppc_md.pcibios_fixup = k2_pcibios_fixup;
- ppc_md.pcibios_fixup_resources = k2_pcibios_fixup_resources;
- ppc_md.pci_swizzle = common_swizzle;
- ppc_md.pci_map_irq = k2_map_irq;
-}
-
-static int k2_get_bus_speed(void)
-{
- int bus_speed;
- unsigned char board_id;
-
- board_id = *(unsigned char *)K2_BOARD_ID_REG;
-
- switch (K2_BUS_SPD(board_id)) {
-
- case 0:
- default:
- bus_speed = 100000000;
- break;
-
- case 1:
- bus_speed = 83333333;
- break;
-
- case 2:
- bus_speed = 75000000;
- break;
-
- case 3:
- bus_speed = 66666666;
- break;
- }
- return bus_speed;
-}
-
-static int k2_get_cpu_speed(void)
-{
- unsigned long hid1;
- int cpu_speed;
-
- hid1 = mfspr(SPRN_HID1) >> 28;
-
- if ((mfspr(SPRN_PVR) >> 16) == 8)
- hid1 = cpu_7xx[hid1];
- else
- hid1 = cpu_6xx[hid1];
-
- cpu_speed = k2_get_bus_speed() * hid1 / 2;
- return cpu_speed;
-}
-
-static void __init k2_calibrate_decr(void)
-{
- int freq, divisor = 4;
-
- /* determine processor bus speed */
- freq = k2_get_bus_speed();
- tb_ticks_per_jiffy = freq / HZ / divisor;
- tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
-}
-
-static int k2_show_cpuinfo(struct seq_file *m)
-{
- unsigned char k2_geo_bits, k2_system_slot;
-
- seq_printf(m, "vendor\t\t: SBS\n");
- seq_printf(m, "machine\t\t: K2\n");
- seq_printf(m, "cpu speed\t: %dMhz\n", k2_get_cpu_speed() / 1000000);
- seq_printf(m, "bus speed\t: %dMhz\n", k2_get_bus_speed() / 1000000);
- seq_printf(m, "memory type\t: SDRAM\n");
-
- k2_geo_bits = readb(K2_MSIZ_GEO_REG) & K2_GEO_ADR_MASK;
- k2_system_slot = !(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK);
- seq_printf(m, "backplane\t: %s slot board",
- k2_system_slot ? "System" : "Non system");
- seq_printf(m, "with geographical address %x\n", k2_geo_bits);
-
- return 0;
-}
-
-TODC_ALLOC();
-
-static void __init k2_setup_arch(void)
-{
- unsigned int cpu;
-
- /* Setup TODC access */
- TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
- ioremap(K2_RTC_BASE_ADDRESS, K2_RTC_SIZE), 8);
-
- /* init to some ~sane value until calibrate_delay() runs */
- loops_per_jiffy = 50000000 / HZ;
-
- /* make FLASH transactions higher priority than PCI to avoid deadlock */
- __raw_writel(__raw_readl(SIOC1) | 0x80000000, SIOC1);
-
- /* Set hardware to access FLASH page 2 */
- __raw_writel(1 << 29, GPOUT);
-
- /* Setup PCI host bridges */
- k2_setup_hoses();
-
-#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_HDC1;
-#endif
-
- /* Identify the system */
- printk(KERN_INFO "System Identification: SBS K2 - PowerPC 750 @ "
- "%d Mhz\n", k2_get_cpu_speed() / 1000000);
- printk(KERN_INFO "Port by MontaVista Software, Inc. "
- "(source@mvista.com)\n");
-
- /* Identify the CPU manufacturer */
- cpu = PVR_REV(mfspr(SPRN_PVR));
- printk(KERN_INFO "CPU manufacturer: %s [rev=%04x]\n",
- (cpu & (1 << 15)) ? "IBM" : "Motorola", cpu);
-}
-
-static void k2_restart(char *cmd)
-{
- local_irq_disable();
-
- /* Flip FLASH back to page 1 to access firmware image */
- __raw_writel(0, GPOUT);
-
- /* SRR0 has system reset vector, SRR1 has default MSR value */
- /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
- mtspr(SPRN_SRR0, 0xfff00100);
- mtspr(SPRN_SRR1, 0);
- __asm__ __volatile__("rfi\n\t");
-
- /* not reached */
- for (;;) ;
-}
-
-static void k2_power_off(void)
-{
- for (;;) ;
-}
-
-static void k2_halt(void)
-{
- k2_restart(NULL);
-}
-
-/*
- * Set BAT 3 to map PCI32 I/O space.
- */
-static __inline__ void k2_set_bat(void)
-{
- /* wait for all outstanding memory accesses to complete */
- mb();
-
- /* setup DBATs */
- mtspr(SPRN_DBAT2U, 0x80001ffe);
- mtspr(SPRN_DBAT2L, 0x8000002a);
- mtspr(SPRN_DBAT3U, 0xf0001ffe);
- mtspr(SPRN_DBAT3L, 0xf000002a);
-
- /* wait for updates */
- mb();
-}
-
-static unsigned long __init k2_find_end_of_memory(void)
-{
- unsigned long total;
- unsigned char msize = 7; /* Default to 128MB */
-
- msize = K2_MEM_SIZE(readb(K2_MSIZ_GEO_REG));
-
- switch (msize) {
- case 2:
- /*
- * This will break without a lowered
- * KERNELBASE or CONFIG_HIGHMEM on.
- * It seems non 1GB builds exist yet,
- * though.
- */
- total = K2_MEM_SIZE_1GB;
- break;
- case 3:
- case 4:
- total = K2_MEM_SIZE_512MB;
- break;
- case 5:
- case 6:
- total = K2_MEM_SIZE_256MB;
- break;
- case 7:
- total = K2_MEM_SIZE_128MB;
- break;
- default:
- printk
- ("K2: Invalid memory size detected, defaulting to 128MB\n");
- total = K2_MEM_SIZE_128MB;
- break;
- }
- return total;
-}
-
-static void __init k2_map_io(void)
-{
- io_block_mapping(K2_PCI32_IO_BASE,
- K2_PCI32_IO_BASE, 0x00200000, _PAGE_IO);
- io_block_mapping(0xff000000, 0xff000000, 0x01000000, _PAGE_IO);
-}
-
-static void __init k2_init_irq(void)
-{
- int i;
-
- for (i = 0; i < 16; i++)
- irq_desc[i].handler = &i8259_pic;
-
- i8259_init(0);
-}
-
-void __init platform_init(unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, unsigned long r7)
-{
- parse_bootinfo((struct bi_record *)(r3 + KERNELBASE));
-
- k2_set_bat();
-
- isa_io_base = K2_ISA_IO_BASE;
- isa_mem_base = K2_ISA_MEM_BASE;
- pci_dram_offset = K2_PCI32_SYS_MEM_BASE;
-
- ppc_md.setup_arch = k2_setup_arch;
- ppc_md.show_cpuinfo = k2_show_cpuinfo;
- ppc_md.init_IRQ = k2_init_irq;
- ppc_md.get_irq = i8259_irq;
-
- ppc_md.find_end_of_memory = k2_find_end_of_memory;
- ppc_md.setup_io_mappings = k2_map_io;
-
- ppc_md.restart = k2_restart;
- ppc_md.power_off = k2_power_off;
- ppc_md.halt = k2_halt;
-
- ppc_md.time_init = todc_time_init;
- ppc_md.set_rtc_time = todc_set_rtc_time;
- ppc_md.get_rtc_time = todc_get_rtc_time;
- ppc_md.calibrate_decr = k2_calibrate_decr;
-
- ppc_md.nvram_read_val = todc_direct_read_val;
- ppc_md.nvram_write_val = todc_direct_write_val;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
- ppc_md.progress = gen550_progress;
-#endif
-}
diff --git a/arch/ppc/platforms/k2.h b/arch/ppc/platforms/k2.h
deleted file mode 100644
index 78326ab..0000000
--- a/arch/ppc/platforms/k2.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * arch/ppc/platforms/k2.h
- *
- * Definitions for SBS K2 board support
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_K2_H
-#define __PPC_PLATFORMS_K2_H
-
-/*
- * SBS K2 definitions
- */
-
-#define K2_PCI64_BAR 0xff400000
-#define K2_PCI32_BAR 0xff500000
-
-#define K2_PCI64_CONFIG_ADDR (K2_PCI64_BAR + 0x000f8000)
-#define K2_PCI64_CONFIG_DATA (K2_PCI64_BAR + 0x000f8010)
-
-#define K2_PCI32_CONFIG_ADDR (K2_PCI32_BAR + 0x000f8000)
-#define K2_PCI32_CONFIG_DATA (K2_PCI32_BAR + 0x000f8010)
-
-#define K2_PCI64_MEM_BASE 0xd0000000
-#define K2_PCI64_IO_BASE 0x80100000
-
-#define K2_PCI32_MEM_BASE 0xc0000000
-#define K2_PCI32_IO_BASE 0x80000000
-
-#define K2_PCI32_SYS_MEM_BASE 0x80000000
-#define K2_PCI64_SYS_MEM_BASE K2_PCI32_SYS_MEM_BASE
-
-#define K2_PCI32_LOWER_MEM 0x00000000
-#define K2_PCI32_UPPER_MEM 0x0fffffff
-#define K2_PCI32_LOWER_IO 0x00000000
-#define K2_PCI32_UPPER_IO 0x000fffff
-
-#define K2_PCI64_LOWER_MEM 0x10000000
-#define K2_PCI64_UPPER_MEM 0x1fffffff
-#define K2_PCI64_LOWER_IO 0x00100000
-#define K2_PCI64_UPPER_IO 0x001fffff
-
-#define K2_ISA_IO_BASE K2_PCI32_IO_BASE
-#define K2_ISA_MEM_BASE K2_PCI32_MEM_BASE
-
-#define K2_BOARD_ID_REG (K2_ISA_IO_BASE + 0x800)
-#define K2_MISC_REG (K2_ISA_IO_BASE + 0x804)
-#define K2_MSIZ_GEO_REG (K2_ISA_IO_BASE + 0x808)
-#define K2_HOT_SWAP_REG (K2_ISA_IO_BASE + 0x80c)
-#define K2_PLD2_REG (K2_ISA_IO_BASE + 0x80e)
-#define K2_PLD3_REG (K2_ISA_IO_BASE + 0x80f)
-
-#define K2_BUS_SPD(board_id) (board_id >> 2) & 3
-
-#define K2_RTC_BASE_OFFSET 0x90000
-#define K2_RTC_BASE_ADDRESS (K2_PCI32_MEM_BASE + K2_RTC_BASE_OFFSET)
-#define K2_RTC_SIZE 0x8000
-
-#define K2_MEM_SIZE_MASK 0xe0
-#define K2_MEM_SIZE(size_reg) (size_reg & K2_MEM_SIZE_MASK) >> 5
-#define K2_MEM_SIZE_1GB 0x40000000
-#define K2_MEM_SIZE_512MB 0x20000000
-#define K2_MEM_SIZE_256MB 0x10000000
-#define K2_MEM_SIZE_128MB 0x08000000
-
-#define K2_L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */
-#define K2_L2CACHE_512KB 0x00 /* 512KB */
-#define K2_L2CACHE_256KB 0x01 /* 256KB */
-#define K2_L2CACHE_1MB 0x02 /* 1MB */
-#define K2_L2CACHE_NONE 0x03 /* None */
-
-#define K2_GEO_ADR_MASK 0x1f
-
-#define K2_SYS_SLOT_MASK 0x08
-
-#endif /* __PPC_PLATFORMS_K2_H */
diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
index 169dbf6..2b53afa 100644
--- a/arch/ppc/platforms/katana.c
+++ b/arch/ppc/platforms/katana.c
@@ -33,6 +33,7 @@
#include <linux/bootimg.h>
#endif
#include <asm/io.h>
+#include <asm/unistd.h>
#include <asm/page.h>
#include <asm/time.h>
#include <asm/smp.h>
@@ -42,15 +43,14 @@
#include <asm/mv64x60.h>
#include <platforms/katana.h>
-static struct mv64x60_handle bh;
-static katana_id_t katana_id;
-static void __iomem *cpld_base;
-static void __iomem *sram_base;
-
-static u32 katana_flash_size_0;
-static u32 katana_flash_size_1;
-
-static u32 katana_bus_frequency;
+static struct mv64x60_handle bh;
+static katana_id_t katana_id;
+static void __iomem *cpld_base;
+static void __iomem *sram_base;
+static u32 katana_flash_size_0;
+static u32 katana_flash_size_1;
+static u32 katana_bus_frequency;
+static struct pci_controller katana_hose_a;
unsigned char __res[sizeof(bd_t)];
@@ -71,8 +71,12 @@
KATANA_PCI_INTA_IRQ_750i, KATANA_PCI_INTB_IRQ_750i },
/* IDSEL 6 (T8110) */
{KATANA_PCI_INTD_IRQ_750i, 0, 0, 0 },
+ /* IDSEL 7 (unused) */
+ {0, 0, 0, 0 },
+ /* IDSEL 8 (Intel 82544) (752i only but doesn't harm 750i) */
+ {KATANA_PCI_INTD_IRQ_750i, 0, 0, 0 },
};
- const long min_idsel = 4, max_idsel = 6, irqs_per_slot = 4;
+ const long min_idsel = 4, max_idsel = 8, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
}
@@ -148,7 +152,7 @@
save_exclude = mv64x60_pci_exclude_bridge;
mv64x60_pci_exclude_bridge = 0;
- early_read_config_word(bh.hose_a, 0,
+ early_read_config_word(bh.hose_b, 0,
PCI_DEVFN(0,0), PCI_DEVICE_ID, &val);
mv64x60_pci_exclude_bridge = save_exclude;
@@ -191,7 +195,8 @@
struct mv64x60_setup_info si;
void __iomem *vaddr;
int i;
- u16 val;
+ u32 v;
+ u16 val, type;
u8 save_exclude;
/*
@@ -222,6 +227,20 @@
PCI_DEVICE_ID, val);
}
+ /*
+ * While we're in here, set the hotswap register correctly.
+ * Turn off blue LED; mask ENUM#, clear insertion & extraction bits.
+ */
+ early_read_config_dword(&hose, 0, PCI_DEVFN(0, 0),
+ MV64360_PCICFG_CPCI_HOTSWAP, &v);
+ v &= ~(1<<19);
+ v |= ((1<<17) | (1<<22) | (1<<23));
+ early_write_config_dword(&hose, 0, PCI_DEVFN(0, 0),
+ MV64360_PCICFG_CPCI_HOTSWAP, v);
+
+ /* While we're at it, grab the bridge type for later */
+ early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_DEVICE_ID, &type);
+
mv64x60_pci_exclude_bridge = save_exclude;
iounmap(vaddr);
@@ -251,21 +270,23 @@
si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
si.pci_1.acc_cntl_options[i] =
- MV64360_PCI_ACC_CNTL_SNOOP_NONE |
- MV64360_PCI_ACC_CNTL_SWAP_NONE |
- MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
- MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
#else
si.cpu_prot_options[i] = 0;
- si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
- si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
- si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB;
si.pci_1.acc_cntl_options[i] =
- MV64360_PCI_ACC_CNTL_SNOOP_WB |
- MV64360_PCI_ACC_CNTL_SWAP_NONE |
- MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
- MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ ((type == PCI_DEVICE_ID_MARVELL_MV64360) ?
+ MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES :
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES);
#endif
}
@@ -281,12 +302,26 @@
mv64x60_set_bus(&bh, 1, 0);
bh.hose_b->first_busno = 0;
bh.hose_b->last_busno = 0xff;
+
+ /*
+ * Need to access hotswap reg which is in the pci config area of the
+ * bridge's hose 0. Note that pcibios_alloc_controller() can't be used
+ * to alloc hose_a b/c that would make hose 0 known to the generic
+ * pci code which we don't want.
+ */
+ bh.hose_a = &katana_hose_a;
+ setup_indirect_pci_nomap(bh.hose_a,
+ bh.v_base + MV64x60_PCI0_CONFIG_ADDR,
+ bh.v_base + MV64x60_PCI0_CONFIG_DATA);
}
/* Bridge & platform setup routines */
void __init
katana_intr_setup(void)
{
+ if (bh.type == MV64x60_TYPE_MV64460) /* As per instns from Marvell */
+ mv64x60_clr_bits(&bh, MV64x60_CPU_MASTER_CNTL, 1 << 15);
+
/* MPP 8, 9, and 10 */
mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0xfff);
@@ -309,9 +344,16 @@
/* Config GPP intr ctlr to respond to level trigger */
mv64x60_set_bits(&bh, MV64x60_COMM_ARBITER_CNTL, (1<<10));
- /* Erranum FEr PCI-#8 */
- mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1<<5) | (1<<9));
- mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<5) | (1<<9));
+ if (bh.type == MV64x60_TYPE_MV64360) {
+ /* Erratum FEr PCI-#9 */
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD,
+ (1<<4) | (1<<5) | (1<<6) | (1<<7));
+ mv64x60_set_bits(&bh, MV64x60_PCI1_CMD, (1<<8) | (1<<9));
+ } else {
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<6) | (1<<7));
+ mv64x60_set_bits(&bh, MV64x60_PCI1_CMD,
+ (1<<4) | (1<<5) | (1<<8) | (1<<9));
+ }
/*
* Dismiss and then enable interrupt on GPP interrupt cause
@@ -473,17 +515,46 @@
ppc_md.progress("katana_setup_arch: exit", 0);
}
+void
+katana_fixup_resources(struct pci_dev *dev)
+{
+ u16 v16;
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_LINE_SIZE>>2);
+
+ pci_read_config_word(dev, PCI_COMMAND, &v16);
+ v16 |= PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK;
+ pci_write_config_word(dev, PCI_COMMAND, v16);
+}
+
+static const unsigned int cpu_750xx[32] = { /* 750FX & 750GX */
+ 0, 0, 2, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,/* 0-15*/
+ 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0 /*16-31*/
+};
+
+static int
+katana_get_cpu_freq(void)
+{
+ unsigned long pll_cfg;
+
+ pll_cfg = (mfspr(SPRN_HID1) & 0xf8000000) >> 27;
+ return katana_bus_frequency * cpu_750xx[pll_cfg]/2;
+}
+
/* Platform device data fixup routines. */
#if defined(CONFIG_SERIAL_MPSC)
static void __init
katana_fixup_mpsc_pdata(struct platform_device *pdev)
{
- struct mpsc_pdata *pdata;
+ struct mpsc_pdata *pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+ bd_t *bdp = (bd_t *)__res;
- pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+ if (bdp->bi_baudrate)
+ pdata->default_baud = bdp->bi_baudrate;
+ else
+ pdata->default_baud = KATANA_DEFAULT_BAUD;
pdata->max_idle = 40;
- pdata->default_baud = KATANA_DEFAULT_BAUD;
pdata->brg_clk_src = KATANA_MPSC_CLK_SRC;
/*
* TCLK (not SysCLk) is routed to BRG, then to the MPSC. On most parts,
@@ -513,6 +584,18 @@
}
#endif
+#if defined(CONFIG_SYSFS)
+static void __init
+katana_fixup_mv64xxx_pdata(struct platform_device *pdev)
+{
+ struct mv64xxx_pdata *pdata = (struct mv64xxx_pdata *)
+ pdev->dev.platform_data;
+
+ /* Katana supports the mv64xxx hotswap register */
+ pdata->hs_reg_valid = 1;
+}
+#endif
+
static int __init
katana_platform_notify(struct device *dev)
{
@@ -529,6 +612,9 @@
{ MV643XX_ETH_NAME ".1", katana_fixup_eth_pdata },
{ MV643XX_ETH_NAME ".2", katana_fixup_eth_pdata },
#endif
+#if defined(CONFIG_SYSFS)
+ { MV64XXX_DEV_NAME ".0", katana_fixup_mv64xxx_pdata },
+#endif
};
struct platform_device *pdev;
int i;
@@ -536,8 +622,7 @@
if (dev && dev->bus_id)
for (i=0; i<ARRAY_SIZE(dev_map); i++)
if (!strncmp(dev->bus_id, dev_map[i].bus_id,
- BUS_ID_SIZE)) {
-
+ BUS_ID_SIZE)) {
pdev = container_of(dev,
struct platform_device, dev);
dev_map[i].rtn(pdev);
@@ -578,8 +663,7 @@
ptbl_entries = (size >= (64*MB)) ? 6 : 4;
if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
- GFP_KERNEL)) == NULL) {
-
+ GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "Can't alloc MTD partition table\n");
return -ENOMEM;
}
@@ -611,7 +695,6 @@
physmap_set_partitions(ptbl, ptbl_entries);
return 0;
}
-
arch_initcall(katana_setup_mtd);
#endif
@@ -632,7 +715,22 @@
{
u8 v;
- if (katana_id == KATANA_ID_752I) {
+ /* Turn on blue LED to indicate its okay to remove */
+ if (katana_id == KATANA_ID_750I) {
+ u32 v;
+ u8 save_exclude;
+
+ /* Set LOO bit in cPCI HotSwap reg of hose 0 to turn on LED. */
+ save_exclude = mv64x60_pci_exclude_bridge;
+ mv64x60_pci_exclude_bridge = 0;
+ early_read_config_dword(bh.hose_a, 0, PCI_DEVFN(0, 0),
+ MV64360_PCICFG_CPCI_HOTSWAP, &v);
+ v &= 0xff;
+ v |= (1 << 19);
+ early_write_config_dword(bh.hose_a, 0, PCI_DEVFN(0, 0),
+ MV64360_PCICFG_CPCI_HOTSWAP, v);
+ mv64x60_pci_exclude_bridge = save_exclude;
+ } else if (katana_id == KATANA_ID_752I) {
v = in_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF);
v |= HSL_PLD_HOT_SWAP_LED_BIT;
out_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF, v);
@@ -652,37 +750,65 @@
static int
katana_show_cpuinfo(struct seq_file *m)
{
+ char *s;
+
+ seq_printf(m, "cpu freq\t: %dMHz\n",
+ (katana_get_cpu_freq() + 500000) / 1000000);
+ seq_printf(m, "bus freq\t: %ldMHz\n",
+ ((long)katana_bus_frequency + 500000) / 1000000);
seq_printf(m, "vendor\t\t: Artesyn Communication Products, LLC\n");
seq_printf(m, "board\t\t: ");
-
switch (katana_id) {
case KATANA_ID_3750:
- seq_printf(m, "Katana 3750\n");
+ seq_printf(m, "Katana 3750");
break;
case KATANA_ID_750I:
- seq_printf(m, "Katana 750i\n");
+ seq_printf(m, "Katana 750i");
break;
case KATANA_ID_752I:
- seq_printf(m, "Katana 752i\n");
+ seq_printf(m, "Katana 752i");
break;
default:
- seq_printf(m, "Unknown\n");
+ seq_printf(m, "Unknown");
break;
}
-
- seq_printf(m, "product ID\t: 0x%x\n",
+ seq_printf(m, " (product id: 0x%x)\n",
in_8(cpld_base + KATANA_CPLD_PRODUCT_ID));
+
+ seq_printf(m, "pci mode\t: %sMonarch\n",
+ katana_is_monarch()? "" : "Non-");
seq_printf(m, "hardware rev\t: 0x%x\n",
in_8(cpld_base+KATANA_CPLD_HARDWARE_VER));
- seq_printf(m, "PLD rev\t\t: 0x%x\n",
+ seq_printf(m, "pld rev\t\t: 0x%x\n",
in_8(cpld_base + KATANA_CPLD_PLD_VER));
- seq_printf(m, "PLB freq\t: %ldMhz\n",
- (long)katana_bus_frequency / 1000000);
- seq_printf(m, "PCI\t\t: %sMonarch\n", katana_is_monarch()? "" : "Non-");
+
+ switch(bh.type) {
+ case MV64x60_TYPE_GT64260A:
+ s = "gt64260a";
+ break;
+ case MV64x60_TYPE_GT64260B:
+ s = "gt64260b";
+ break;
+ case MV64x60_TYPE_MV64360:
+ s = "mv64360";
+ break;
+ case MV64x60_TYPE_MV64460:
+ s = "mv64460";
+ break;
+ default:
+ s = "Unknown";
+ }
+ seq_printf(m, "bridge type\t: %s\n", s);
+ seq_printf(m, "bridge rev\t: 0x%x\n", bh.rev);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ seq_printf(m, "coherency\t: %s\n", "off");
+#else
+ seq_printf(m, "coherency\t: %s\n", "on");
+#endif
return 0;
}
@@ -701,11 +827,20 @@
tb_to_us = mulhwu_scale_factor(freq, 1000000);
}
+/*
+ * The katana supports both uImage and zImage. If uImage, get the mem size
+ * from the bd info. If zImage, the bootwrapper adds a BI_MEMSIZE entry in
+ * the bi_rec data which is sucked out and put into boot_mem_size by
+ * parse_bootinfo(). MMU_init() will then use the boot_mem_size for the mem
+ * size and not call this routine. The only way this will fail is when a uImage
+ * is used but the fw doesn't pass in a valid bi_memsize. This should never
+ * happen, though.
+ */
unsigned long __init
katana_find_end_of_memory(void)
{
- return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
- MV64x60_TYPE_MV64360);
+ bd_t *bdp = (bd_t *)__res;
+ return bdp->bi_memsize;
}
#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
@@ -729,15 +864,6 @@
late_initcall(katana_rtc_hookup);
#endif
-static inline void
-katana_set_bat(void)
-{
- mb();
- mtspr(SPRN_DBAT2U, 0xf0001ffe);
- mtspr(SPRN_DBAT2L, 0xf000002a);
- mb();
-}
-
#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
static void __init
katana_map_io(void)
@@ -763,15 +889,24 @@
*/
if (r3 && r6) {
/* copy board info structure */
- memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+ memcpy((void *)__res, (void *)(r3+KERNELBASE), sizeof(bd_t));
/* copy command line */
*(char *)(r7+KERNELBASE) = 0;
strcpy(cmd_line, (char *)(r6+KERNELBASE));
}
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
isa_mem_base = 0;
ppc_md.setup_arch = katana_setup_arch;
+ ppc_md.pcibios_fixup_resources = katana_fixup_resources;
ppc_md.show_cpuinfo = katana_show_cpuinfo;
ppc_md.init_IRQ = mv64360_init_irq;
ppc_md.get_irq = mv64360_get_irq;
@@ -790,6 +925,4 @@
#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
platform_notify = katana_platform_notify;
#endif
-
- katana_set_bat(); /* Need for katana_find_end_of_memory and progress */
}
diff --git a/arch/ppc/platforms/katana.h b/arch/ppc/platforms/katana.h
index b82ed81..597257e 100644
--- a/arch/ppc/platforms/katana.h
+++ b/arch/ppc/platforms/katana.h
@@ -56,14 +56,14 @@
#define KATANA_PCI1_IO_SIZE 0x04000000 /* 64 MB */
/* Board-specific IRQ info */
-#define KATANA_PCI_INTA_IRQ_3750 64+8
-#define KATANA_PCI_INTB_IRQ_3750 64+9
-#define KATANA_PCI_INTC_IRQ_3750 64+10
+#define KATANA_PCI_INTA_IRQ_3750 (64+8)
+#define KATANA_PCI_INTB_IRQ_3750 (64+9)
+#define KATANA_PCI_INTC_IRQ_3750 (64+10)
-#define KATANA_PCI_INTA_IRQ_750i 64+8
-#define KATANA_PCI_INTB_IRQ_750i 64+9
-#define KATANA_PCI_INTC_IRQ_750i 64+10
-#define KATANA_PCI_INTD_IRQ_750i 64+14
+#define KATANA_PCI_INTA_IRQ_750i (64+8)
+#define KATANA_PCI_INTB_IRQ_750i (64+9)
+#define KATANA_PCI_INTC_IRQ_750i (64+10)
+#define KATANA_PCI_INTD_IRQ_750i (64+14)
#define KATANA_CPLD_RST_EVENT 0x00000000
#define KATANA_CPLD_RST_CMD 0x00001000
diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c
deleted file mode 100644
index e88d294..0000000
--- a/arch/ppc/platforms/mcpn765.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * arch/ppc/platforms/mcpn765.c
- *
- * Board setup routines for the Motorola MCG MCPN765 cPCI Board.
- *
- * Author: Mark A. Greer
- * mgreer@mvista.com
- *
- * Modified by Randy Vinson (rvinson@mvista.com)
- *
- * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/*
- * This file adds support for the Motorola MCG MCPN765.
- */
-#include <linux/config.h>
-#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/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/serial.h>
-#include <linux/tty.h> /* for linux/serial_core.h */
-#include <linux/serial_core.h>
-#include <linux/slab.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/time.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/open_pic.h>
-#include <asm/i8259.h>
-#include <asm/todc.h>
-#include <asm/pci-bridge.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/bootinfo.h>
-#include <asm/hawk.h>
-#include <asm/kgdb.h>
-
-#include "mcpn765.h"
-
-static u_char mcpn765_openpic_initsenses[] __initdata = {
- (IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE),/* 16: i8259 cascade */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 17: COM1,2,3,4 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 18: Enet 1 (front) */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 19: HAWK WDT XXXX */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 20: 21554 bridge */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 21: cPCI INTA# */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 22: cPCI INTB# */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 23: cPCI INTC# */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 24: cPCI INTD# */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 25: PMC1 INTA#,PMC2 INTB#*/
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 26: PMC1 INTB#,PMC2 INTC#*/
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 27: PMC1 INTC#,PMC2 INTD#*/
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 28: PMC1 INTD#,PMC2 INTA#*/
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 29: Enet 2 (J3) */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 30: Abort Switch */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 31: RTC Alarm */
-};
-
-extern void mcpn765_set_VIA_IDE_native(void);
-
-extern u_int openpic_irq(void);
-extern char cmd_line[];
-
-extern void gen550_progress(char *, unsigned short);
-extern void gen550_init(int, struct uart_port *);
-
-int use_of_interrupt_tree = 0;
-
-static void mcpn765_halt(void);
-
-TODC_ALLOC();
-
-/*
- * Motorola MCG MCPN765 interrupt routing.
- */
-static inline int
-mcpn765_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
- */
- {
- { 14, 0, 0, 0 }, /* IDSEL 11 - have to manually set */
- { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
- { 0, 0, 0, 0 }, /* IDSEL 13 - unused */
- { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 0 */
- { 0, 0, 0, 0 }, /* IDSEL 15 - unused */
- { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */
- { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */
- { 0, 0, 0, 0 }, /* IDSEL 18 - PMC 2B Connector XXXX */
- { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 1 */
- { 20, 0, 0, 0 }, /* IDSEL 20 - 21554 cPCI bridge */
- };
-
- const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
-}
-
-void __init
-mcpn765_set_VIA_IDE_legacy(void)
-{
- unsigned short vend, dev;
-
- early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
- early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
-
- if ((vend == PCI_VENDOR_ID_VIA) &&
- (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
-
- unsigned char temp;
-
- /* put back original "standard" port base addresses */
- early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
- PCI_BASE_ADDRESS_0, 0x1f1);
- early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
- PCI_BASE_ADDRESS_1, 0x3f5);
- early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
- PCI_BASE_ADDRESS_2, 0x171);
- early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
- PCI_BASE_ADDRESS_3, 0x375);
- early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
- PCI_BASE_ADDRESS_4, 0xcc01);
-
- /* put into legacy mode */
- early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
- &temp);
- temp &= ~0x05;
- early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
- temp);
- }
-}
-
-void
-mcpn765_set_VIA_IDE_native(void)
-{
- unsigned short vend, dev;
-
- early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
- early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
-
- if ((vend == PCI_VENDOR_ID_VIA) &&
- (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
-
- unsigned char temp;
-
- /* put into native mode */
- early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
- &temp);
- temp |= 0x05;
- early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
- temp);
- }
-}
-
-/*
- * Initialize the VIA 82c586b.
- */
-static void __init
-mcpn765_setup_via_82c586b(void)
-{
- struct pci_dev *dev;
- u_char c;
-
- if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C586_0,
- NULL)) == NULL) {
- printk("No VIA ISA bridge found\n");
- mcpn765_halt();
- /* NOTREACHED */
- }
-
- /*
- * If the firmware left the EISA 4d0/4d1 ports enabled, make sure
- * IRQ 14 is set for edge.
- */
- pci_read_config_byte(dev, 0x47, &c);
-
- if (c & (1<<5)) {
- c = inb(0x4d1);
- c &= ~(1<<6);
- outb(c, 0x4d1);
- }
-
- /* Disable PNP IRQ routing since we use the Hawk's MPIC */
- pci_write_config_dword(dev, 0x54, 0);
- pci_write_config_byte(dev, 0x58, 0);
-
- pci_dev_put(dev);
- if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C586_1,
- NULL)) == NULL) {
- printk("No VIA ISA bridge found\n");
- mcpn765_halt();
- /* NOTREACHED */
- }
-
- /*
- * PPCBug doesn't set the enable bits for the IDE device.
- * Turn them on now.
- */
- pci_read_config_byte(dev, 0x40, &c);
- c |= 0x03;
- pci_write_config_byte(dev, 0x40, c);
- pci_dev_put(dev);
-
- return;
-}
-
-void __init
-mcpn765_pcibios_fixup(void)
-{
- /* Do MCPN765 board specific initialization. */
- mcpn765_setup_via_82c586b();
-}
-
-void __init
-mcpn765_find_bridges(void)
-{
- struct pci_controller *hose;
-
- hose = pcibios_alloc_controller();
-
- if (!hose)
- return;
-
- hose->first_busno = 0;
- hose->last_busno = 0xff;
- hose->pci_mem_offset = MCPN765_PCI_PHY_MEM_OFFSET;
-
- pci_init_resource(&hose->io_resource,
- MCPN765_PCI_IO_START,
- MCPN765_PCI_IO_END,
- IORESOURCE_IO,
- "PCI host bridge");
-
- pci_init_resource(&hose->mem_resources[0],
- MCPN765_PCI_MEM_START,
- MCPN765_PCI_MEM_END,
- IORESOURCE_MEM,
- "PCI host bridge");
-
- hose->io_space.start = MCPN765_PCI_IO_START;
- hose->io_space.end = MCPN765_PCI_IO_END;
- hose->mem_space.start = MCPN765_PCI_MEM_START;
- hose->mem_space.end = MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE;
-
- if (hawk_init(hose,
- MCPN765_HAWK_PPC_REG_BASE,
- MCPN765_PROC_PCI_MEM_START,
- MCPN765_PROC_PCI_MEM_END - HAWK_MPIC_SIZE,
- MCPN765_PROC_PCI_IO_START,
- MCPN765_PROC_PCI_IO_END,
- MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE + 1) != 0) {
- printk("Could not initialize HAWK bridge\n");
- }
-
- /* VIA IDE BAR decoders are only 16-bits wide. PCI Auto Config
- * will reassign the bars outside of 16-bit I/O space, which will
- * "break" things. To prevent this, we'll set the IDE chip into
- * legacy mode and seed the bars with their legacy addresses (in 16-bit
- * I/O space). The Auto Config code will skip the IDE contoller in
- * legacy mode, so our bar values will stick.
- */
- mcpn765_set_VIA_IDE_legacy();
-
- hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
- /* Now that we've got 16-bit addresses in the bars, we can switch the
- * IDE controller back into native mode so we can do "modern" resource
- * and interrupt management.
- */
- mcpn765_set_VIA_IDE_native();
-
- ppc_md.pcibios_fixup = mcpn765_pcibios_fixup;
- ppc_md.pcibios_fixup_bus = NULL;
- ppc_md.pci_swizzle = common_swizzle;
- ppc_md.pci_map_irq = mcpn765_map_irq;
-
- return;
-}
-static void __init
-mcpn765_setup_arch(void)
-{
- struct pci_controller *hose;
-
- if ( ppc_md.progress )
- ppc_md.progress("mcpn765_setup_arch: enter", 0);
-
- loops_per_jiffy = 50000000 / HZ;
-
-#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_SDA2;
-#endif
-
- if ( ppc_md.progress )
- ppc_md.progress("mcpn765_setup_arch: find_bridges", 0);
-
- /* Lookup PCI host bridges */
- mcpn765_find_bridges();
-
- hose = pci_bus_to_hose(0);
- isa_io_base = (ulong)hose->io_base_virt;
-
- TODC_INIT(TODC_TYPE_MK48T37,
- (MCPN765_PHYS_NVRAM_AS0 - isa_io_base),
- (MCPN765_PHYS_NVRAM_AS1 - isa_io_base),
- (MCPN765_PHYS_NVRAM_DATA - isa_io_base),
- 8);
-
- OpenPIC_InitSenses = mcpn765_openpic_initsenses;
- OpenPIC_NumInitSenses = sizeof(mcpn765_openpic_initsenses);
-
- printk("Motorola MCG MCPN765 cPCI Non-System Board\n");
- printk("MCPN765 port (MontaVista Software, Inc. (source@mvista.com))\n");
-
- if ( ppc_md.progress )
- ppc_md.progress("mcpn765_setup_arch: exit", 0);
-
- return;
-}
-
-static void __init
-mcpn765_init2(void)
-{
-
- request_region(0x00,0x20,"dma1");
- request_region(0x20,0x20,"pic1");
- request_region(0x40,0x20,"timer");
- request_region(0x80,0x10,"dma page reg");
- request_region(0xa0,0x20,"pic2");
- request_region(0xc0,0x20,"dma2");
-
- return;
-}
-
-/*
- * Interrupt setup and service.
- * Have MPIC on HAWK and cascaded 8259s on VIA 82586 cascaded to MPIC.
- */
-static void __init
-mcpn765_init_IRQ(void)
-{
- int i;
-
- if ( ppc_md.progress )
- ppc_md.progress("init_irq: enter", 0);
-
- openpic_init(NUM_8259_INTERRUPTS);
- openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
- i8259_irq);
-
- for(i=0; i < NUM_8259_INTERRUPTS; i++)
- irq_desc[i].handler = &i8259_pic;
-
- i8259_init(0);
-
- if ( ppc_md.progress )
- ppc_md.progress("init_irq: exit", 0);
-
- return;
-}
-
-static u32
-mcpn765_irq_canonicalize(u32 irq)
-{
- if (irq == 2)
- return 9;
- else
- return irq;
-}
-
-static unsigned long __init
-mcpn765_find_end_of_memory(void)
-{
- return hawk_get_mem_size(MCPN765_HAWK_SMC_BASE);
-}
-
-static void __init
-mcpn765_map_io(void)
-{
- io_block_mapping(0xfe800000, 0xfe800000, 0x00800000, _PAGE_IO);
-}
-
-static void
-mcpn765_reset_board(void)
-{
- local_irq_disable();
-
- /* set VIA IDE controller into native mode */
- mcpn765_set_VIA_IDE_native();
-
- /* Set exception prefix high - to the firmware */
- _nmask_and_or_msr(0, MSR_IP);
-
- out_8((u_char *)MCPN765_BOARD_MODRST_REG, 0x01);
-
- return;
-}
-
-static void
-mcpn765_restart(char *cmd)
-{
- volatile ulong i = 10000000;
-
- mcpn765_reset_board();
-
- while (i-- > 0);
- panic("restart failed\n");
-}
-
-static void
-mcpn765_power_off(void)
-{
- mcpn765_halt();
- /* NOTREACHED */
-}
-
-static void
-mcpn765_halt(void)
-{
- local_irq_disable();
- while (1);
- /* NOTREACHED */
-}
-
-static int
-mcpn765_show_cpuinfo(struct seq_file *m)
-{
- seq_printf(m, "vendor\t\t: Motorola MCG\n");
- seq_printf(m, "machine\t\t: MCPN765\n");
-
- return 0;
-}
-
-/*
- * Set BAT 3 to map 0xf0000000 to end of physical memory space.
- */
-static __inline__ void
-mcpn765_set_bat(void)
-{
- mb();
- mtspr(SPRN_DBAT1U, 0xfe8000fe);
- mtspr(SPRN_DBAT1L, 0xfe80002a);
- mb();
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- parse_bootinfo(find_bootinfo());
-
- /* Map in board regs, etc. */
- mcpn765_set_bat();
-
- isa_mem_base = MCPN765_ISA_MEM_BASE;
- pci_dram_offset = MCPN765_PCI_DRAM_OFFSET;
- ISA_DMA_THRESHOLD = 0x00ffffff;
- DMA_MODE_READ = 0x44;
- DMA_MODE_WRITE = 0x48;
-
- ppc_md.setup_arch = mcpn765_setup_arch;
- ppc_md.show_cpuinfo = mcpn765_show_cpuinfo;
- ppc_md.irq_canonicalize = mcpn765_irq_canonicalize;
- ppc_md.init_IRQ = mcpn765_init_IRQ;
- ppc_md.get_irq = openpic_get_irq;
- ppc_md.init = mcpn765_init2;
-
- ppc_md.restart = mcpn765_restart;
- ppc_md.power_off = mcpn765_power_off;
- ppc_md.halt = mcpn765_halt;
-
- ppc_md.find_end_of_memory = mcpn765_find_end_of_memory;
- ppc_md.setup_io_mappings = mcpn765_map_io;
-
- ppc_md.time_init = todc_time_init;
- ppc_md.set_rtc_time = todc_set_rtc_time;
- ppc_md.get_rtc_time = todc_get_rtc_time;
- ppc_md.calibrate_decr = todc_calibrate_decr;
-
- ppc_md.nvram_read_val = todc_m48txx_read_val;
- ppc_md.nvram_write_val = todc_m48txx_write_val;
-
- ppc_md.heartbeat = NULL;
- ppc_md.heartbeat_reset = 0;
- ppc_md.heartbeat_count = 0;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
- ppc_md.progress = gen550_progress;
-#endif
-#ifdef CONFIG_KGDB
- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
-
- return;
-}
diff --git a/arch/ppc/platforms/mcpn765.h b/arch/ppc/platforms/mcpn765.h
deleted file mode 100644
index 4d35eca..0000000
--- a/arch/ppc/platforms/mcpn765.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * arch/ppc/platforms/mcpn765.h
- *
- * Definitions for Motorola MCG MCPN765 cPCI Board.
- *
- * Author: Mark A. Greer
- * mgreer@mvista.com
- *
- * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/*
- * From Processor to PCI:
- * PCI Mem Space: 0x80000000 - 0xc0000000 -> 0x80000000 - 0xc0000000 (1 GB)
- * PCI I/O Space: 0xfd800000 - 0xfe000000 -> 0x00000000 - 0x00800000 (8 MB)
- * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
- * MPIC in PCI Mem Space: 0xfe800000 - 0xfe830000 (not all used by MPIC)
- *
- * From PCI to Processor:
- * System Memory: 0x00000000 -> 0x00000000
- */
-
-#ifndef __PPC_PLATFORMS_MCPN765_H
-#define __PPC_PLATFORMS_MCPN765_H
-#include <linux/config.h>
-
-/* PCI Memory space mapping info */
-#define MCPN765_PCI_MEM_SIZE 0x40000000U
-#define MCPN765_PROC_PCI_MEM_START 0x80000000U
-#define MCPN765_PROC_PCI_MEM_END (MCPN765_PROC_PCI_MEM_START + \
- MCPN765_PCI_MEM_SIZE - 1)
-#define MCPN765_PCI_MEM_START 0x80000000U
-#define MCPN765_PCI_MEM_END (MCPN765_PCI_MEM_START + \
- MCPN765_PCI_MEM_SIZE - 1)
-
-/* PCI I/O space mapping info */
-#define MCPN765_PCI_IO_SIZE 0x00800000U
-#define MCPN765_PROC_PCI_IO_START 0xfd800000U
-#define MCPN765_PROC_PCI_IO_END (MCPN765_PROC_PCI_IO_START + \
- MCPN765_PCI_IO_SIZE - 1)
-#define MCPN765_PCI_IO_START 0x00000000U
-#define MCPN765_PCI_IO_END (MCPN765_PCI_IO_START + \
- MCPN765_PCI_IO_SIZE - 1)
-
-/* System memory mapping info */
-#define MCPN765_PCI_DRAM_OFFSET 0x00000000U
-#define MCPN765_PCI_PHY_MEM_OFFSET 0x00000000U
-
-#define MCPN765_ISA_MEM_BASE 0x00000000U
-#define MCPN765_ISA_IO_BASE MCPN765_PROC_PCI_IO_START
-
-/* Define base addresses for important sets of registers */
-#define MCPN765_HAWK_MPIC_BASE 0xfe800000U
-#define MCPN765_HAWK_SMC_BASE 0xfef80000U
-#define MCPN765_HAWK_PPC_REG_BASE 0xfeff0000U
-
-/* Define MCPN765 board register addresses. */
-#define MCPN765_BOARD_STATUS_REG 0xfef88080U
-#define MCPN765_BOARD_MODFAIL_REG 0xfef88090U
-#define MCPN765_BOARD_MODRST_REG 0xfef880a0U
-#define MCPN765_BOARD_TBEN_REG 0xfef880c0U
-#define MCPN765_BOARD_GEOGRAPHICAL_REG 0xfef880e8U
-#define MCPN765_BOARD_EXT_FEATURE_REG 0xfef880f0U
-#define MCPN765_BOARD_LAST_RESET_REG 0xfef880f8U
-
-/* Defines for UART */
-
-/* Define the UART base addresses */
-#define MCPN765_SERIAL_1 0xfef88000
-#define MCPN765_SERIAL_2 0xfef88200
-#define MCPN765_SERIAL_3 0xfef88400
-#define MCPN765_SERIAL_4 0xfef88600
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE 4
-#endif
-
-/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
-#define BASE_BAUD ( 1843200 / 16 )
-#define UART_CLK 1843200
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-/* All UART IRQ's are wire-OR'd to IRQ 17 */
-#define STD_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\
- iomem_base: (u8 *)MCPN765_SERIAL_1, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\
- iomem_base: (u8 *)MCPN765_SERIAL_2, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\
- iomem_base: (u8 *)MCPN765_SERIAL_3, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\
- iomem_base: (u8 *)MCPN765_SERIAL_4, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM },
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DFNS
-
-/* Define the NVRAM/RTC address strobe & data registers */
-#define MCPN765_PHYS_NVRAM_AS0 0xfef880c8U
-#define MCPN765_PHYS_NVRAM_AS1 0xfef880d0U
-#define MCPN765_PHYS_NVRAM_DATA 0xfef880d8U
-
-extern void mcpn765_find_bridges(void);
-
-#endif /* __PPC_PLATFORMS_MCPN765_H */
diff --git a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c
deleted file mode 100644
index d719163..0000000
--- a/arch/ppc/platforms/pcore.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * arch/ppc/platforms/pcore_setup.c
- *
- * Setup routines for Force PCORE boards
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/config.h>
-#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/initrd.h>
-#include <linux/console.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/i8259.h>
-#include <asm/mpc10x.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-#include <asm/kgdb.h>
-
-#include "pcore.h"
-
-extern unsigned long loops_per_jiffy;
-
-static int board_type;
-
-static inline int __init
-pcore_6750_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
- */
- {
- {9, 10, 11, 12}, /* IDSEL 24 - DEC 21554 */
- {10, 0, 0, 0}, /* IDSEL 25 - DEC 21143 */
- {11, 12, 9, 10}, /* IDSEL 26 - PMC I */
- {12, 9, 10, 11}, /* IDSEL 27 - PMC II */
- {0, 0, 0, 0}, /* IDSEL 28 - unused */
- {0, 0, 9, 0}, /* IDSEL 29 - unused */
- {0, 0, 0, 0}, /* IDSEL 30 - Winbond */
- };
- const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
-};
-
-static inline int __init
-pcore_680_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
- */
- {
- {9, 10, 11, 12}, /* IDSEL 24 - Sentinel */
- {10, 0, 0, 0}, /* IDSEL 25 - i82559 #1 */
- {11, 12, 9, 10}, /* IDSEL 26 - PMC I */
- {12, 9, 10, 11}, /* IDSEL 27 - PMC II */
- {9, 0, 0, 0}, /* IDSEL 28 - i82559 #2 */
- {0, 0, 0, 0}, /* IDSEL 29 - unused */
- {0, 0, 0, 0}, /* IDSEL 30 - Winbond */
- };
- const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
-};
-
-void __init
-pcore_pcibios_fixup(void)
-{
- struct pci_dev *dev;
-
- if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
- PCI_DEVICE_ID_WINBOND_83C553,
- 0)))
- {
- /* Reroute interrupts both IDE channels to 15 */
- pci_write_config_byte(dev,
- PCORE_WINBOND_IDE_INT,
- 0xff);
-
- /* Route INTA-D to IRQ9-12, respectively */
- pci_write_config_word(dev,
- PCORE_WINBOND_PCI_INT,
- 0x9abc);
-
- /*
- * Set up 8259 edge/level triggering
- */
- outb(0x00, PCORE_WINBOND_PRI_EDG_LVL);
- outb(0x1e, PCORE_WINBOND_SEC_EDG_LVL);
- pci_dev_put(dev);
- }
-}
-
-int __init
-pcore_find_bridges(void)
-{
- struct pci_controller* hose;
- int host_bridge, board_type;
-
- hose = pcibios_alloc_controller();
- if (!hose)
- return 0;
-
- mpc10x_bridge_init(hose,
- MPC10X_MEM_MAP_B,
- MPC10X_MEM_MAP_B,
- MPC10X_MAPB_EUMB_BASE);
-
- /* Determine board type */
- early_read_config_dword(hose,
- 0,
- PCI_DEVFN(0,0),
- PCI_VENDOR_ID,
- &host_bridge);
- if (host_bridge == MPC10X_BRIDGE_106)
- board_type = PCORE_TYPE_6750;
- else /* MPC10X_BRIDGE_107 */
- board_type = PCORE_TYPE_680;
-
- hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
- ppc_md.pcibios_fixup = pcore_pcibios_fixup;
- ppc_md.pci_swizzle = common_swizzle;
-
- if (board_type == PCORE_TYPE_6750)
- ppc_md.pci_map_irq = pcore_6750_map_irq;
- else /* PCORE_TYPE_680 */
- ppc_md.pci_map_irq = pcore_680_map_irq;
-
- return board_type;
-}
-
-/* Dummy variable to satisfy mpc10x_common.o */
-void *OpenPIC_Addr;
-
-static int
-pcore_show_cpuinfo(struct seq_file *m)
-{
- seq_printf(m, "vendor\t\t: Force Computers\n");
-
- if (board_type == PCORE_TYPE_6750)
- seq_printf(m, "machine\t\t: PowerCore 6750\n");
- else /* PCORE_TYPE_680 */
- seq_printf(m, "machine\t\t: PowerCore 680\n");
-
- seq_printf(m, "L2\t\t: " );
- if (board_type == PCORE_TYPE_6750)
- switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK)
- {
- case PCORE_DCCR_L2_0KB:
- seq_printf(m, "nocache");
- break;
- case PCORE_DCCR_L2_256KB:
- seq_printf(m, "256KB");
- break;
- case PCORE_DCCR_L2_1MB:
- seq_printf(m, "1MB");
- break;
- case PCORE_DCCR_L2_512KB:
- seq_printf(m, "512KB");
- break;
- default:
- seq_printf(m, "error");
- break;
- }
- else /* PCORE_TYPE_680 */
- switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK)
- {
- case PCORE_DCCR_L2_2MB:
- seq_printf(m, "2MB");
- break;
- case PCORE_DCCR_L2_256KB:
- seq_printf(m, "reserved");
- break;
- case PCORE_DCCR_L2_1MB:
- seq_printf(m, "1MB");
- break;
- case PCORE_DCCR_L2_512KB:
- seq_printf(m, "512KB");
- break;
- default:
- seq_printf(m, "error");
- break;
- }
-
- seq_printf(m, "\n");
-
- return 0;
-}
-
-static void __init
-pcore_setup_arch(void)
-{
- /* init to some ~sane value until calibrate_delay() runs */
- loops_per_jiffy = 50000000/HZ;
-
- /* Lookup PCI host bridges */
- board_type = pcore_find_bridges();
-
-#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_SDA2;
-#endif
-
- printk(KERN_INFO "Force PowerCore ");
- if (board_type == PCORE_TYPE_6750)
- printk("6750\n");
- else
- printk("680\n");
- printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
- _set_L2CR(L2CR_L2E | _get_L2CR());
-
-}
-
-static void
-pcore_restart(char *cmd)
-{
- local_irq_disable();
- /* Hard reset */
- writeb(0x11, 0xfe000332);
- while(1);
-}
-
-static void
-pcore_halt(void)
-{
- local_irq_disable();
- /* Turn off user LEDs */
- writeb(0x00, 0xfe000300);
- while (1);
-}
-
-static void
-pcore_power_off(void)
-{
- pcore_halt();
-}
-
-
-static void __init
-pcore_init_IRQ(void)
-{
- int i;
-
- for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].handler = &i8259_pic;
-
- i8259_init(0);
-}
-
-/*
- * Set BAT 3 to map 0xf0000000 to end of physical memory space.
- */
-static __inline__ void
-pcore_set_bat(void)
-{
- mb();
- mtspr(SPRN_DBAT3U, 0xf0001ffe);
- mtspr(SPRN_DBAT3L, 0xfe80002a);
- mb();
-
-}
-
-static unsigned long __init
-pcore_find_end_of_memory(void)
-{
-
- return mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
-}
-
-static void __init
-pcore_map_io(void)
-{
- io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
-}
-
-TODC_ALLOC();
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- parse_bootinfo(find_bootinfo());
-
- /* Cover I/O space with a BAT */
- /* yuck, better hope your ram size is a power of 2 -- paulus */
- pcore_set_bat();
-
- isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
- isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
- pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
-
- ppc_md.setup_arch = pcore_setup_arch;
- ppc_md.show_cpuinfo = pcore_show_cpuinfo;
- ppc_md.init_IRQ = pcore_init_IRQ;
- ppc_md.get_irq = i8259_irq;
-
- ppc_md.find_end_of_memory = pcore_find_end_of_memory;
- ppc_md.setup_io_mappings = pcore_map_io;
-
- ppc_md.restart = pcore_restart;
- ppc_md.power_off = pcore_power_off;
- ppc_md.halt = pcore_halt;
-
- TODC_INIT(TODC_TYPE_MK48T59,
- PCORE_NVRAM_AS0,
- PCORE_NVRAM_AS1,
- PCORE_NVRAM_DATA,
- 8);
-
- ppc_md.time_init = todc_time_init;
- ppc_md.get_rtc_time = todc_get_rtc_time;
- ppc_md.set_rtc_time = todc_set_rtc_time;
- ppc_md.calibrate_decr = todc_calibrate_decr;
-
- ppc_md.nvram_read_val = todc_m48txx_read_val;
- ppc_md.nvram_write_val = todc_m48txx_write_val;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
- ppc_md.progress = gen550_progress;
-#endif
-#ifdef CONFIG_KGDB
- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
-}
diff --git a/arch/ppc/platforms/pcore.h b/arch/ppc/platforms/pcore.h
deleted file mode 100644
index c6a26e7..0000000
--- a/arch/ppc/platforms/pcore.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * arch/ppc/platforms/pcore.h
- *
- * Definitions for Force PowerCore board support
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_PCORE_H
-#define __PPC_PLATFORMS_PCORE_H
-
-#include <asm/mpc10x.h>
-
-#define PCORE_TYPE_6750 1
-#define PCORE_TYPE_680 2
-
-#define PCORE_NVRAM_AS0 0x73
-#define PCORE_NVRAM_AS1 0x75
-#define PCORE_NVRAM_DATA 0x77
-
-#define PCORE_DCCR_REG (MPC10X_MAPB_ISA_IO_BASE + 0x308)
-#define PCORE_DCCR_L2_MASK 0xc0
-#define PCORE_DCCR_L2_0KB 0x00
-#define PCORE_DCCR_L2_256KB 0x40
-#define PCORE_DCCR_L2_512KB 0xc0
-#define PCORE_DCCR_L2_1MB 0x80
-#define PCORE_DCCR_L2_2MB 0x00
-
-#define PCORE_WINBOND_IDE_INT 0x43
-#define PCORE_WINBOND_PCI_INT 0x44
-#define PCORE_WINBOND_PRI_EDG_LVL 0x4d0
-#define PCORE_WINBOND_SEC_EDG_LVL 0x4d1
-
-#endif /* __PPC_PLATFORMS_PCORE_H */
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
index 9f92e1b..2ce0588 100644
--- a/arch/ppc/platforms/pmac_pic.c
+++ b/arch/ppc/platforms/pmac_pic.c
@@ -619,7 +619,7 @@
return viaint;
}
-static int pmacpic_suspend(struct sys_device *sysdev, u32 state)
+static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
{
int viaint = pmacpic_find_viaint();
diff --git a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h
deleted file mode 100644
index ed48d14..0000000
--- a/arch/ppc/platforms/spd8xx.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Speech Design SPD8xxTS board specific definitions
- *
- * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_SPD8XX_H__
-#define __ASM_SPD8XX_H__
-
-#include <linux/config.h>
-
-#include <asm/ppcboot.h>
-
-#ifndef __ASSEMBLY__
-#define SPD_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */
-#define SPD_IMAP_SIZE (64 * 1024) /* size of mapped area */
-
-#define IMAP_ADDR SPD_IMMR_BASE /* physical base address of IMMR area */
-#define IMAP_SIZE SPD_IMAP_SIZE /* mapped size of IMMR area */
-
-#define PCMCIA_MEM_ADDR ((uint)0xFE100000)
-#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
-
-#define IDE0_INTERRUPT 10 /* = IRQ5 */
-#define IDE1_INTERRUPT 12 /* = IRQ6 */
-#define CPM_INTERRUPT 13 /* = SIU_LEVEL6 (was: SIU_LEVEL2) */
-
-/* override the default number of IDE hardware interfaces */
-#define MAX_HWIFS 2
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */
-#define IDE0_DATA_REG_OFFSET 0x0000
-#define IDE0_ERROR_REG_OFFSET 0x0081
-#define IDE0_NSECTOR_REG_OFFSET 0x0082
-#define IDE0_SECTOR_REG_OFFSET 0x0083
-#define IDE0_LCYL_REG_OFFSET 0x0084
-#define IDE0_HCYL_REG_OFFSET 0x0085
-#define IDE0_SELECT_REG_OFFSET 0x0086
-#define IDE0_STATUS_REG_OFFSET 0x0087
-#define IDE0_CONTROL_REG_OFFSET 0x0106
-#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */
-
-/*
- * Definitions for IDE1 Interface
- */
-#define IDE1_BASE_OFFSET 0x0C00 /* Offset in PCMCIA memory */
-#define IDE1_DATA_REG_OFFSET 0x0000
-#define IDE1_ERROR_REG_OFFSET 0x0081
-#define IDE1_NSECTOR_REG_OFFSET 0x0082
-#define IDE1_SECTOR_REG_OFFSET 0x0083
-#define IDE1_LCYL_REG_OFFSET 0x0084
-#define IDE1_HCYL_REG_OFFSET 0x0085
-#define IDE1_SELECT_REG_OFFSET 0x0086
-#define IDE1_STATUS_REG_OFFSET 0x0087
-#define IDE1_CONTROL_REG_OFFSET 0x0106
-#define IDE1_IRQ_REG_OFFSET 0x000A /* not used */
-
-/* CPM Ethernet through SCCx.
- *
- * Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC2 use.
- */
-#define PA_ENET_MDC ((ushort)0x0001) /* PA 15 !!! */
-#define PA_ENET_MDIO ((ushort)0x0002) /* PA 14 !!! */
-#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */
-#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */
-#define PA_ENET_RCLK ((ushort)0x0200) /* PA 6 */
-#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
-
-#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */
-
-#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */
-#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */
-#define PC_ENET_RESET ((ushort)0x0100) /* PC 7 !!! */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to
- * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
- */
-#define SICR_ENET_MASK ((uint)0x0000ff00)
-#define SICR_ENET_CLKRT ((uint)0x00002E00)
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS 0
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_SPD8XX_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/tqm8xx.h b/arch/ppc/platforms/tqm8xx.h
index 2150dc8..43ac064 100644
--- a/arch/ppc/platforms/tqm8xx.h
+++ b/arch/ppc/platforms/tqm8xx.h
@@ -147,29 +147,6 @@
#define SICR_ENET_CLKRT ((uint)0x00002600)
#endif /* CONFIG_FPS850L */
-/*** SM850 *********************************************************/
-
-/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */
-
-#ifdef CONFIG_SM850
-#define PB_ENET_RXD ((uint)0x00000004) /* PB 29 */
-#define PB_ENET_TXD ((uint)0x00000002) /* PB 30 */
-#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
-#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
-
-#define PC_ENET_LBK ((ushort)0x0008) /* PC 12 */
-#define PC_ENET_TENA ((ushort)0x0004) /* PC 13 */
-
-#define PC_ENET_RENA ((ushort)0x0800) /* PC 4 */
-#define PC_ENET_CLSN ((ushort)0x0400) /* PC 5 */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
- * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero.
- */
-#define SICR_ENET_MASK ((uint)0x00FF0000)
-#define SICR_ENET_CLKRT ((uint)0x00260000)
-#endif /* CONFIG_SM850 */
-
/* We don't use the 8259.
*/
#define NR_8259_INTS 0
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 220a65a..8b9b226 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -43,8 +43,6 @@
obj-$(CONFIG_POWER4) += open_pic2.o
obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o
obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o todc_time.o
-obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \
- todc_time.o
obj-$(CONFIG_BAMBOO) += indirect_pci.o pci_auto.o todc_time.o
obj-$(CONFIG_CPCI690) += todc_time.o pci_auto.o
obj-$(CONFIG_EBONY) += indirect_pci.o pci_auto.o todc_time.o
@@ -52,16 +50,10 @@
obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o
obj-$(CONFIG_GEMINI) += open_pic.o indirect_pci.o
obj-$(CONFIG_GT64260) += gt64260_pic.o
-obj-$(CONFIG_K2) += i8259.o indirect_pci.o todc_time.o \
- pci_auto.o
obj-$(CONFIG_LOPEC) += i8259.o pci_auto.o todc_time.o
obj-$(CONFIG_HDPU) += pci_auto.o
obj-$(CONFIG_LUAN) += indirect_pci.o pci_auto.o todc_time.o
obj-$(CONFIG_KATANA) += pci_auto.o
-obj-$(CONFIG_MCPN765) += todc_time.o indirect_pci.o pci_auto.o \
- open_pic.o i8259.o hawk_common.o
-obj-$(CONFIG_MENF1) += todc_time.o i8259.o mpc10x_common.o \
- pci_auto.o indirect_pci.o
obj-$(CONFIG_MV64360) += mv64360_pic.o
obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_win.o indirect_pci.o
obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o indirect_pci.o \
@@ -69,7 +61,6 @@
obj-$(CONFIG_MVME5100_IPMC761_PRESENT) += i8259.o
obj-$(CONFIG_OCOTEA) += indirect_pci.o pci_auto.o todc_time.o
obj-$(CONFIG_PAL4) += cpc700_pic.o
-obj-$(CONFIG_PCORE) += todc_time.o i8259.o pci_auto.o
obj-$(CONFIG_POWERPMC250) += pci_auto.o
obj-$(CONFIG_PPLUS) += hawk_common.o open_pic.o i8259.o \
indirect_pci.o todc_time.o pci_auto.o
@@ -82,7 +73,8 @@
obj-$(CONFIG_SBC82xx) += todc_time.o
obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \
todc_time.o
-obj-$(CONFIG_8260) += m8260_setup.o
+obj-$(CONFIG_8260) += m8260_setup.o pq2_devices.o pq2_sys.o \
+ ppc_sys.o
obj-$(CONFIG_PCI_8260) += m82xx_pci.o indirect_pci.o pci_auto.o
obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o
obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c
index 74d8996..8356da4 100644
--- a/arch/ppc/syslib/mv64360_pic.c
+++ b/arch/ppc/syslib/mv64360_pic.c
@@ -366,10 +366,16 @@
return IRQ_HANDLED;
}
+/*
+ * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of
+ * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as
+ * well. IOW, don't set bit 0.
+ */
+#define MV64360_PCI0_ERR_MASK_VAL 0x00a50c24
+
static int __init
mv64360_register_hdlrs(void)
{
- u32 mask;
int rc;
/* Clear old errors and register CPU interface error intr handler */
@@ -387,17 +393,6 @@
mv64360_sram_error_int_handler,SA_INTERRUPT,SRAM_INTR_STR, 0)))
printk(KERN_WARNING "Can't register SRAM error handler: %d",rc);
- /*
- * Bit 0 reserved on 64360 and erratum FEr PCI-#11 (PCI internal
- * data parity error set incorrectly) on rev 0 & 1 of 64460 requires
- * bit 0 to be cleared.
- */
- mask = 0x00a50c24;
-
- if ((mv64x60_get_bridge_type() == MV64x60_TYPE_MV64460) &&
- (mv64x60_get_bridge_rev() > 1))
- mask |= 0x1; /* enable DPErr on 64460 */
-
/* Clear old errors and register PCI 0 error intr handler */
mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, 0);
if ((rc = request_irq(MV64360_IRQ_PCI0 + mv64360_irq_base,
@@ -407,7 +402,11 @@
rc);
mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, 0);
- mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, mask);
+ mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, MV64360_PCI0_ERR_MASK_VAL);
+
+ /* Erratum FEr PCI-#16 says to clear bit 0 of PCI SERRn Mask reg. */
+ mv64x60_write(&bh, MV64x60_PCI0_ERR_SERR_MASK,
+ mv64x60_read(&bh, MV64x60_PCI0_ERR_SERR_MASK) & ~0x1UL);
/* Clear old errors and register PCI 1 error intr handler */
mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, 0);
@@ -418,7 +417,11 @@
rc);
mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, 0);
- mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, mask);
+ mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, MV64360_PCI0_ERR_MASK_VAL);
+
+ /* Erratum FEr PCI-#16 says to clear bit 0 of PCI Intr Mask reg. */
+ mv64x60_write(&bh, MV64x60_PCI1_ERR_SERR_MASK,
+ mv64x60_read(&bh, MV64x60_PCI1_ERR_SERR_MASK) & ~0x1UL);
return 0;
}
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
index cc77177..6262b11 100644
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -30,13 +30,16 @@
#include <asm/mv64x60.h>
-u8 mv64x60_pci_exclude_bridge = 1;
+u8 mv64x60_pci_exclude_bridge = 1;
spinlock_t mv64x60_lock = SPIN_LOCK_UNLOCKED;
-static phys_addr_t mv64x60_bridge_pbase = 0;
-static void *mv64x60_bridge_vbase = 0;
+static phys_addr_t mv64x60_bridge_pbase;
+static void *mv64x60_bridge_vbase;
static u32 mv64x60_bridge_type = MV64x60_TYPE_INVALID;
-static u32 mv64x60_bridge_rev = 0;
+static u32 mv64x60_bridge_rev;
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+static struct pci_controller sysfs_hose_a;
+#endif
static u32 gt64260_translate_size(u32 base, u32 size, u32 num_bits);
static u32 gt64260_untranslate_size(u32 base, u32 size, u32 num_bits);
@@ -432,6 +435,20 @@
};
#endif
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+static struct mv64xxx_pdata mv64xxx_pdata = {
+ .hs_reg_valid = 0,
+};
+
+static struct platform_device mv64xxx_device = { /* general mv64x60 stuff */
+ .name = MV64XXX_DEV_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &mv64xxx_pdata,
+ },
+};
+#endif
+
static struct platform_device *mv64x60_pd_devs[] __initdata = {
#ifdef CONFIG_SERIAL_MPSC
&mpsc_shared_device,
@@ -453,6 +470,9 @@
#ifdef CONFIG_I2C_MV64XXX
&i2c_device,
#endif
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+ &mv64xxx_device,
+#endif
};
/*
@@ -574,6 +594,11 @@
bh->hose_a = &hose_a;
bh->hose_b = &hose_b;
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+ /* Save a copy of hose_a for sysfs functions -- hack */
+ memcpy(&sysfs_hose_a, &hose_a, sizeof(hose_a));
+#endif
+
mv64x60_set_bus(bh, 0, 0);
mv64x60_set_bus(bh, 1, 0);
@@ -590,8 +615,6 @@
mv64x60_set_bits(bh, MV64x60_PCI0_TO_RETRY, 0xffff);
mv64x60_set_bits(bh, MV64x60_PCI1_TO_RETRY, 0xffff);
-
- return;
}
/*
@@ -628,19 +651,15 @@
val = mv64x60_read(bh, size_reg);
val = get_from_field(val, size_bits);
*size = bh->ci->untranslate_size(*base, val, size_bits);
- }
- else
+ } else
*size = 0;
- }
- else {
+ } else {
*base = 0;
*size = 0;
}
pr_debug("get 32bit window: %d, base: 0x%x, size: 0x%x\n",
window, *base, *size);
-
- return;
}
/*
@@ -677,8 +696,6 @@
(void)mv64x60_read(bh, base_reg); /* Flush FIFO */
}
-
- return;
}
/*
@@ -712,11 +729,9 @@
val = get_from_field(val, size_bits);
*size = bh->ci->untranslate_size(*base_lo, val,
size_bits);
- }
- else
+ } else
*size = 0;
- }
- else {
+ } else {
*base_hi = 0;
*base_lo = 0;
*size = 0;
@@ -724,8 +739,6 @@
pr_debug("get 64bit window: %d, base hi: 0x%x, base lo: 0x%x, "
"size: 0x%x\n", window, *base_hi, *base_lo, *size);
-
- return;
}
/*
@@ -766,8 +779,6 @@
(void)mv64x60_read(bh, base_lo_reg); /* Flush FIFO */
}
-
- return;
}
/*
@@ -1008,8 +1019,6 @@
mem_windows[i][0] = 0;
mem_windows[i][1] = 0;
}
-
- return;
}
/*
@@ -1077,8 +1086,6 @@
}
}
-
- return;
}
/*
@@ -1112,8 +1119,7 @@
mv64x60_set_32bit_window(bh, remap_tab[bus][0],
pi->pci_io.pci_base_lo, 0, 0);
bh->ci->enable_window_32bit(bh, win_tab[bus][0]);
- }
- else /* Actually, the window should already be disabled */
+ } else /* Actually, the window should already be disabled */
bh->ci->disable_window_32bit(bh, win_tab[bus][0]);
for (i=0; i<3; i++)
@@ -1125,11 +1131,8 @@
pi->pci_mem[i].pci_base_hi,
pi->pci_mem[i].pci_base_lo, 0, 0);
bh->ci->enable_window_32bit(bh, win_tab[bus][i+1]);
- }
- else /* Actually, the window should already be disabled */
+ } else /* Actually, the window should already be disabled */
bh->ci->disable_window_32bit(bh, win_tab[bus][i+1]);
-
- return;
}
/*
@@ -1206,8 +1209,6 @@
MV64x60_PCI0_BAR_ENABLE :
MV64x60_PCI1_BAR_ENABLE), (1 << i));
}
-
- return;
}
/*
@@ -1229,7 +1230,6 @@
*hose = pcibios_alloc_controller();
setup_indirect_pci_nomap(*hose, bh->v_base + cfg_addr,
bh->v_base + cfg_data);
- return;
}
/*
@@ -1272,7 +1272,6 @@
pi->pci_mem[0].size - 1;
hose->pci_mem_offset = pi->pci_mem[0].cpu_base -
pi->pci_mem[0].pci_base_lo;
- return;
}
/*
@@ -1309,7 +1308,6 @@
early_write_config_word(hose, 0, devfn, PCI_CACHE_LINE_SIZE, u16_val);
mv64x60_pci_exclude_bridge = save_exclude;
- return;
}
/*
@@ -1336,8 +1334,7 @@
p2p_cfg = MV64x60_PCI0_P2P_CONFIG;
pci_cfg_offset = 0x64;
hose = bh->hose_a;
- }
- else {
+ } else {
pci_mode = bh->pci_mode_b;
p2p_cfg = MV64x60_PCI1_P2P_CONFIG;
pci_cfg_offset = 0xe4;
@@ -1352,8 +1349,7 @@
val |= (child_bus << 16) | 0xff;
mv64x60_write(bh, p2p_cfg, val);
(void)mv64x60_read(bh, p2p_cfg); /* Flush FIFO */
- }
- else { /* PCI-X */
+ } else { /* PCI-X */
/*
* Need to use the current bus/dev number (that's in the
* P2P CONFIG reg) to access the bridge's pci config space.
@@ -1365,8 +1361,6 @@
pci_cfg_offset, child_bus << 8);
mv64x60_pci_exclude_bridge = save_exclude;
}
-
- return;
}
/*
@@ -1423,8 +1417,6 @@
j++;
}
}
-
- return;
}
/*
@@ -1498,8 +1490,6 @@
early_write_config_dword(hose, 0, PCI_DEVFN(0, 0),
gt64260_reg_addrs[bus][window], mv64x60_mask(base, 20) | 0x8);
mv64x60_pci_exclude_bridge = save_exclude;
-
- return;
}
/*
@@ -1523,8 +1513,6 @@
early_write_config_dword(hose, 0, PCI_DEVFN(0,0), gt64260_offset[bus],
(base << 16));
mv64x60_pci_exclude_bridge = save_exclude;
-
- return;
}
/*
@@ -1561,7 +1549,6 @@
gt64260_enable_window_32bit(struct mv64x60_handle *bh, u32 window)
{
pr_debug("enable 32bit window: %d\n", window);
- return;
}
/*
@@ -1584,8 +1571,6 @@
mv64x60_write(bh, gt64260_32bit_windows[window].base_reg,0xfff);
mv64x60_write(bh, gt64260_32bit_windows[window].size_reg, 0);
}
-
- return;
}
/*
@@ -1599,7 +1584,6 @@
gt64260_enable_window_64bit(struct mv64x60_handle *bh, u32 window)
{
pr_debug("enable 64bit window: %d\n", window);
- return; /* Enabled when window configured (i.e., when top >= base) */
}
/*
@@ -1624,8 +1608,6 @@
mv64x60_write(bh, gt64260_64bit_windows[window].base_hi_reg, 0);
mv64x60_write(bh, gt64260_64bit_windows[window].size_reg, 0);
}
-
- return;
}
/*
@@ -1712,8 +1694,6 @@
mv64x60_write(bh, GT64260_IC_CPU_INT_1_MASK, 0);
mv64x60_write(bh, GT64260_IC_CPU_INT_2_MASK, 0);
mv64x60_write(bh, GT64260_IC_CPU_INT_3_MASK, 0);
-
- return;
}
/*
@@ -1781,14 +1761,11 @@
mv64x60_mpsc1_pdata.cache_mgmt = 1;
if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0))
- != NULL) {
-
+ != NULL) {
r->start = MV64x60_IRQ_SDMA_0;
r->end = MV64x60_IRQ_SDMA_0;
}
#endif
-
- return;
}
/*
@@ -1861,14 +1838,11 @@
mv64x60_mpsc1_pdata.cache_mgmt = 1;
if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0))
- != NULL) {
-
+ != NULL) {
r->start = MV64x60_IRQ_SDMA_0;
r->end = MV64x60_IRQ_SDMA_0;
}
#endif
-
- return;
}
/*
@@ -1945,8 +1919,6 @@
mv64360_reg_addrs[bus][window].base_lo_bar,
mv64x60_mask(base,20) | 0xc);
mv64x60_pci_exclude_bridge = save_exclude;
-
- return;
}
/*
@@ -1972,8 +1944,6 @@
early_write_config_dword(hose, 0, PCI_DEVFN(0,0),
mv64360_offset[bus][1], 0);
mv64x60_pci_exclude_bridge = save_exclude;
-
- return;
}
/*
@@ -2082,8 +2052,6 @@
"32bit table corrupted");
}
}
-
- return;
}
/*
@@ -2139,8 +2107,6 @@
"32bit table corrupted");
}
}
-
- return;
}
/*
@@ -2158,8 +2124,7 @@
(mv64360_64bit_windows[window].size_reg != 0)) {
if ((mv64360_64bit_windows[window].extra & MV64x60_EXTRA_MASK)
- == MV64x60_EXTRA_PCIACC_ENAB)
-
+ == MV64x60_EXTRA_PCIACC_ENAB)
mv64x60_set_bits(bh,
mv64360_64bit_windows[window].base_lo_reg,
(1 << (mv64360_64bit_windows[window].extra &
@@ -2168,8 +2133,6 @@
printk(KERN_ERR "mv64360_enable: %s\n",
"64bit table corrupted");
}
-
- return;
}
/*
@@ -2186,11 +2149,9 @@
mv64360_64bit_windows[window].size_reg);
if ((mv64360_64bit_windows[window].base_lo_reg != 0) &&
- (mv64360_64bit_windows[window].size_reg != 0)) {
-
+ (mv64360_64bit_windows[window].size_reg != 0)) {
if ((mv64360_64bit_windows[window].extra & MV64x60_EXTRA_MASK)
- == MV64x60_EXTRA_PCIACC_ENAB)
-
+ == MV64x60_EXTRA_PCIACC_ENAB)
mv64x60_clr_bits(bh,
mv64360_64bit_windows[window].base_lo_reg,
(1 << (mv64360_64bit_windows[window].extra &
@@ -2199,8 +2160,6 @@
printk(KERN_ERR "mv64360_disable: %s\n",
"64bit table corrupted");
}
-
- return;
}
/*
@@ -2241,8 +2200,6 @@
/* Disable all PCI-><whatever> windows */
mv64x60_set_bits(bh, MV64x60_PCI0_BAR_ENABLE, 0x0000f9ff);
mv64x60_set_bits(bh, MV64x60_PCI1_BAR_ENABLE, 0x0000f9ff);
-
- return;
}
/*
@@ -2335,8 +2292,6 @@
mv64x60_set_bits(bh, MV64360_IDMA2MEM_ACC_PROT_3,
(0x3 << (i << 1)));
}
-
- return;
}
/*
@@ -2350,42 +2305,145 @@
mv64360_set_mpsc2regs_window(struct mv64x60_handle *bh, u32 base)
{
pr_debug("set mpsc->internal regs, base: 0x%x\n", base);
-
mv64x60_write(bh, MV64360_MPSC2REGS_BASE, base & 0xffff0000);
- return;
}
/*
* mv64360_chip_specific_init()
*
- * No errata work arounds for the MV64360 implemented at this point.
+ * Implement errata work arounds for the MV64360.
*/
static void __init
mv64360_chip_specific_init(struct mv64x60_handle *bh,
struct mv64x60_setup_info *si)
{
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+ mv64x60_set_bits(bh, MV64360_D_UNIT_CONTROL_HIGH, (1<<24));
+#endif
#ifdef CONFIG_SERIAL_MPSC
mv64x60_mpsc0_pdata.brg_can_tune = 1;
mv64x60_mpsc0_pdata.cache_mgmt = 1;
mv64x60_mpsc1_pdata.brg_can_tune = 1;
mv64x60_mpsc1_pdata.cache_mgmt = 1;
#endif
-
- return;
}
/*
* mv64460_chip_specific_init()
*
- * No errata work arounds for the MV64460 implemented at this point.
+ * Implement errata work arounds for the MV64460.
*/
static void __init
mv64460_chip_specific_init(struct mv64x60_handle *bh,
struct mv64x60_setup_info *si)
{
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+ mv64x60_set_bits(bh, MV64360_D_UNIT_CONTROL_HIGH, (1<<24) | (1<<25));
+ mv64x60_set_bits(bh, MV64460_D_UNIT_MMASK, (1<<1) | (1<<4));
+#endif
#ifdef CONFIG_SERIAL_MPSC
mv64x60_mpsc0_pdata.brg_can_tune = 1;
+ mv64x60_mpsc0_pdata.cache_mgmt = 1;
mv64x60_mpsc1_pdata.brg_can_tune = 1;
+ mv64x60_mpsc1_pdata.cache_mgmt = 1;
#endif
- return;
}
+
+
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+/* Export the hotswap register via sysfs for enum event monitoring */
+#define VAL_LEN_MAX 11 /* 32-bit hex or dec stringified number + '\n' */
+
+DECLARE_MUTEX(mv64xxx_hs_lock);
+
+static ssize_t
+mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ u32 v;
+ u8 save_exclude;
+
+ if (off > 0)
+ return 0;
+ if (count < VAL_LEN_MAX)
+ return -EINVAL;
+
+ if (down_interruptible(&mv64xxx_hs_lock))
+ return -ERESTARTSYS;
+ save_exclude = mv64x60_pci_exclude_bridge;
+ mv64x60_pci_exclude_bridge = 0;
+ early_read_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
+ MV64360_PCICFG_CPCI_HOTSWAP, &v);
+ mv64x60_pci_exclude_bridge = save_exclude;
+ up(&mv64xxx_hs_lock);
+
+ return sprintf(buf, "0x%08x\n", v);
+}
+
+static ssize_t
+mv64xxx_hs_reg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ u32 v;
+ u8 save_exclude;
+
+ if (off > 0)
+ return 0;
+ if (count <= 0)
+ return -EINVAL;
+
+ if (sscanf(buf, "%i", &v) == 1) {
+ if (down_interruptible(&mv64xxx_hs_lock))
+ return -ERESTARTSYS;
+ save_exclude = mv64x60_pci_exclude_bridge;
+ mv64x60_pci_exclude_bridge = 0;
+ early_write_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
+ MV64360_PCICFG_CPCI_HOTSWAP, v);
+ mv64x60_pci_exclude_bridge = save_exclude;
+ up(&mv64xxx_hs_lock);
+ }
+ else
+ count = -EINVAL;
+
+ return count;
+}
+
+static struct bin_attribute mv64xxx_hs_reg_attr = { /* Hotswap register */
+ .attr = {
+ .name = "hs_reg",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = VAL_LEN_MAX,
+ .read = mv64xxx_hs_reg_read,
+ .write = mv64xxx_hs_reg_write,
+};
+
+/* Provide sysfs file indicating if this platform supports the hs_reg */
+static ssize_t
+mv64xxx_hs_reg_valid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev;
+ struct mv64xxx_pdata *pdp;
+ u32 v;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ pdp = (struct mv64xxx_pdata *)pdev->dev.platform_data;
+
+ if (down_interruptible(&mv64xxx_hs_lock))
+ return -ERESTARTSYS;
+ v = pdp->hs_reg_valid;
+ up(&mv64xxx_hs_lock);
+
+ return sprintf(buf, "%i\n", v);
+}
+static DEVICE_ATTR(hs_reg_valid, S_IRUGO, mv64xxx_hs_reg_valid_show, NULL);
+
+static int __init
+mv64xxx_sysfs_init(void)
+{
+ sysfs_create_bin_file(&mv64xxx_device.dev.kobj, &mv64xxx_hs_reg_attr);
+ sysfs_create_file(&mv64xxx_device.dev.kobj,&dev_attr_hs_reg_valid.attr);
+ return 0;
+}
+subsys_initcall(mv64xxx_sysfs_init);
+#endif
diff --git a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c
index e5fd2ae..9ccce43 100644
--- a/arch/ppc/syslib/ocp.c
+++ b/arch/ppc/syslib/ocp.c
@@ -165,7 +165,7 @@
}
static int
-ocp_device_suspend(struct device *dev, u32 state)
+ocp_device_suspend(struct device *dev, pm_message_t state)
{
struct ocp_device *ocp_dev = to_ocp_dev(dev);
struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver);
diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c
index 1eb4f72..da8a0f2 100644
--- a/arch/ppc/syslib/of_device.c
+++ b/arch/ppc/syslib/of_device.c
@@ -105,7 +105,7 @@
return 0;
}
-static int of_device_suspend(struct device *dev, u32 state)
+static int of_device_suspend(struct device *dev, pm_message_t state)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
index ad39b86..53da585 100644
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -948,7 +948,7 @@
* we need something better to deal with that... Maybe switch to S1 for
* cpufreq changes
*/
-int openpic_suspend(struct sys_device *sysdev, u32 state)
+int openpic_suspend(struct sys_device *sysdev, pm_message_t state)
{
int i;
unsigned long flags;
diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c
index e170aeb..b843c4f 100644
--- a/arch/ppc/syslib/ppc4xx_setup.c
+++ b/arch/ppc/syslib/ppc4xx_setup.c
@@ -48,10 +48,6 @@
extern void abort(void);
extern void ppc4xx_find_bridges(void);
-extern void ppc4xx_wdt_heartbeat(void);
-extern int wdt_enable;
-extern unsigned long wdt_period;
-
/* Global Variables */
bd_t __res;
@@ -171,7 +167,7 @@
unsigned int freq;
bd_t *bip = &__res;
-#if defined(CONFIG_WALNUT) || defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE)
+#if defined(CONFIG_WALNUT) || defined(CONFIG_SYCAMORE)
/* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE);
#endif
@@ -257,22 +253,6 @@
*(char *) (r7 + KERNELBASE) = 0;
strcpy(cmd_line, (char *) (r6 + KERNELBASE));
}
-#if defined(CONFIG_PPC405_WDT)
-/* Look for wdt= option on command line */
- if (strstr(cmd_line, "wdt=")) {
- int valid_wdt = 0;
- char *p, *q;
- for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
- q = p + 4;
- if (p > cmd_line && p[-1] != ' ')
- continue;
- wdt_period = simple_strtoul(q, &q, 0);
- valid_wdt = 1;
- ++q;
- }
- wdt_enable = valid_wdt;
- }
-#endif
/* Initialize machine-dependent vectors */
@@ -287,11 +267,6 @@
ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
-#ifdef CONFIG_PPC405_WDT
- ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
-#endif
- ppc_md.heartbeat_count = 0;
-
ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
ppc_md.setup_io_mappings = ppc4xx_map_io;
diff --git a/arch/ppc/syslib/ppc83xx_pci.h b/arch/ppc/syslib/ppc83xx_pci.h
new file mode 100644
index 0000000..ec69164
--- /dev/null
+++ b/arch/ppc/syslib/ppc83xx_pci.h
@@ -0,0 +1,151 @@
+/* Created by Tony Li <tony.li@freescale.com>
+ * Copyright (c) 2005 freescale semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_SYSLIB_PPC83XX_PCI_H
+#define __PPC_SYSLIB_PPC83XX_PCI_H
+
+typedef struct immr_clk {
+ u32 spmr; /* system PLL mode Register */
+ u32 occr; /* output clock control Register */
+ u32 sccr; /* system clock control Register */
+ u8 res0[0xF4];
+} immr_clk_t;
+
+/*
+ * Sequencer
+ */
+typedef struct immr_ios {
+ u32 potar0;
+ u8 res0[4];
+ u32 pobar0;
+ u8 res1[4];
+ u32 pocmr0;
+ u8 res2[4];
+ u32 potar1;
+ u8 res3[4];
+ u32 pobar1;
+ u8 res4[4];
+ u32 pocmr1;
+ u8 res5[4];
+ u32 potar2;
+ u8 res6[4];
+ u32 pobar2;
+ u8 res7[4];
+ u32 pocmr2;
+ u8 res8[4];
+ u32 potar3;
+ u8 res9[4];
+ u32 pobar3;
+ u8 res10[4];
+ u32 pocmr3;
+ u8 res11[4];
+ u32 potar4;
+ u8 res12[4];
+ u32 pobar4;
+ u8 res13[4];
+ u32 pocmr4;
+ u8 res14[4];
+ u32 potar5;
+ u8 res15[4];
+ u32 pobar5;
+ u8 res16[4];
+ u32 pocmr5;
+ u8 res17[4];
+ u8 res18[0x60];
+ u32 pmcr;
+ u8 res19[4];
+ u32 dtcr;
+ u8 res20[4];
+} immr_ios_t;
+#define POTAR_TA_MASK 0x000fffff
+#define POBAR_BA_MASK 0x000fffff
+#define POCMR_EN 0x80000000
+#define POCMR_IO 0x40000000 /* 0--memory space 1--I/O space */
+#define POCMR_SE 0x20000000 /* streaming enable */
+#define POCMR_DST 0x10000000 /* 0--PCI1 1--PCI2 */
+#define POCMR_CM_MASK 0x000fffff
+
+/*
+ * PCI Controller Control and Status Registers
+ */
+typedef struct immr_pcictrl {
+ u32 esr;
+ u32 ecdr;
+ u32 eer;
+ u32 eatcr;
+ u32 eacr;
+ u32 eeacr;
+ u32 edlcr;
+ u32 edhcr;
+ u32 gcr;
+ u32 ecr;
+ u32 gsr;
+ u8 res0[12];
+ u32 pitar2;
+ u8 res1[4];
+ u32 pibar2;
+ u32 piebar2;
+ u32 piwar2;
+ u8 res2[4];
+ u32 pitar1;
+ u8 res3[4];
+ u32 pibar1;
+ u32 piebar1;
+ u32 piwar1;
+ u8 res4[4];
+ u32 pitar0;
+ u8 res5[4];
+ u32 pibar0;
+ u8 res6[4];
+ u32 piwar0;
+ u8 res7[132];
+} immr_pcictrl_t;
+#define PITAR_TA_MASK 0x000fffff
+#define PIBAR_MASK 0xffffffff
+#define PIEBAR_EBA_MASK 0x000fffff
+#define PIWAR_EN 0x80000000
+#define PIWAR_PF 0x20000000
+#define PIWAR_RTT_MASK 0x000f0000
+#define PIWAR_RTT_NO_SNOOP 0x00040000
+#define PIWAR_RTT_SNOOP 0x00050000
+#define PIWAR_WTT_MASK 0x0000f000
+#define PIWAR_WTT_NO_SNOOP 0x00004000
+#define PIWAR_WTT_SNOOP 0x00005000
+#define PIWAR_IWS_MASK 0x0000003F
+#define PIWAR_IWS_4K 0x0000000B
+#define PIWAR_IWS_8K 0x0000000C
+#define PIWAR_IWS_16K 0x0000000D
+#define PIWAR_IWS_32K 0x0000000E
+#define PIWAR_IWS_64K 0x0000000F
+#define PIWAR_IWS_128K 0x00000010
+#define PIWAR_IWS_256K 0x00000011
+#define PIWAR_IWS_512K 0x00000012
+#define PIWAR_IWS_1M 0x00000013
+#define PIWAR_IWS_2M 0x00000014
+#define PIWAR_IWS_4M 0x00000015
+#define PIWAR_IWS_8M 0x00000016
+#define PIWAR_IWS_16M 0x00000017
+#define PIWAR_IWS_32M 0x00000018
+#define PIWAR_IWS_64M 0x00000019
+#define PIWAR_IWS_128M 0x0000001A
+#define PIWAR_IWS_256M 0x0000001B
+#define PIWAR_IWS_512M 0x0000001C
+#define PIWAR_IWS_1G 0x0000001D
+#define PIWAR_IWS_2G 0x0000001E
+
+#endif /* __PPC_SYSLIB_PPC83XX_PCI_H */
diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c
index 602a868..890484e 100644
--- a/arch/ppc/syslib/ppc83xx_setup.c
+++ b/arch/ppc/syslib/ppc83xx_setup.c
@@ -11,6 +11,17 @@
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Added PCI support -- Tony Li <tony.li@freescale.com>
*/
#include <linux/config.h>
@@ -31,6 +42,10 @@
#include <asm/delay.h>
#include <syslib/ppc83xx_setup.h>
+#if defined(CONFIG_PCI)
+#include <asm/delay.h>
+#include <syslib/ppc83xx_pci.h>
+#endif
phys_addr_t immrbar;
@@ -162,4 +177,237 @@
for(;;);
}
-/* PCI SUPPORT DOES NOT EXIT, MODEL after ppc85xx_setup.c */
+#if defined(CONFIG_PCI)
+void __init
+mpc83xx_setup_pci1(struct pci_controller *hose)
+{
+ u16 reg16;
+ volatile immr_pcictrl_t * pci_ctrl;
+ volatile immr_ios_t * ios;
+ bd_t *binfo = (bd_t *) __res;
+
+ pci_ctrl = ioremap(binfo->bi_immr_base + 0x8500, sizeof(immr_pcictrl_t));
+ ios = ioremap(binfo->bi_immr_base + 0x8400, sizeof(immr_ios_t));
+
+ /*
+ * Configure PCI Outbound Translation Windows
+ */
+ ios->potar0 = (MPC83xx_PCI1_LOWER_MEM >> 12) & POTAR_TA_MASK;
+ ios->pobar0 = (MPC83xx_PCI1_LOWER_MEM >> 12) & POBAR_BA_MASK;
+ ios->pocmr0 = POCMR_EN |
+ (((0xffffffff - (MPC83xx_PCI1_UPPER_MEM -
+ MPC83xx_PCI1_LOWER_MEM)) >> 12) & POCMR_CM_MASK);
+
+ /* mapped to PCI1 IO space */
+ ios->potar1 = (MPC83xx_PCI1_LOWER_IO >> 12) & POTAR_TA_MASK;
+ ios->pobar1 = (MPC83xx_PCI1_IO_BASE >> 12) & POBAR_BA_MASK;
+ ios->pocmr1 = POCMR_EN | POCMR_IO |
+ (((0xffffffff - (MPC83xx_PCI1_UPPER_IO -
+ MPC83xx_PCI1_LOWER_IO)) >> 12) & POCMR_CM_MASK);
+
+ /*
+ * Configure PCI Inbound Translation Windows
+ */
+ pci_ctrl->pitar1 = 0x0;
+ pci_ctrl->pibar1 = 0x0;
+ pci_ctrl->piebar1 = 0x0;
+ pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+
+ /*
+ * Release PCI RST signal
+ */
+ pci_ctrl->gcr = 0;
+ udelay(2000);
+ pci_ctrl->gcr = 1;
+ udelay(2000);
+
+ reg16 = 0xff;
+ early_read_config_word(hose, hose->first_busno, 0, PCI_COMMAND, ®16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ early_write_config_word(hose, hose->first_busno, 0, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ early_write_config_word(hose, hose->first_busno, 0, PCI_STATUS, 0xffff);
+ early_write_config_byte(hose, hose->first_busno, 0, PCI_LATENCY_TIMER, 0x80);
+
+ iounmap(pci_ctrl);
+ iounmap(ios);
+}
+
+void __init
+mpc83xx_setup_pci2(struct pci_controller *hose)
+{
+ u16 reg16;
+ volatile immr_pcictrl_t * pci_ctrl;
+ volatile immr_ios_t * ios;
+ bd_t *binfo = (bd_t *) __res;
+
+ pci_ctrl = ioremap(binfo->bi_immr_base + 0x8600, sizeof(immr_pcictrl_t));
+ ios = ioremap(binfo->bi_immr_base + 0x8400, sizeof(immr_ios_t));
+
+ /*
+ * Configure PCI Outbound Translation Windows
+ */
+ ios->potar3 = (MPC83xx_PCI2_LOWER_MEM >> 12) & POTAR_TA_MASK;
+ ios->pobar3 = (MPC83xx_PCI2_LOWER_MEM >> 12) & POBAR_BA_MASK;
+ ios->pocmr3 = POCMR_EN | POCMR_DST |
+ (((0xffffffff - (MPC83xx_PCI2_UPPER_MEM -
+ MPC83xx_PCI2_LOWER_MEM)) >> 12) & POCMR_CM_MASK);
+
+ /* mapped to PCI2 IO space */
+ ios->potar4 = (MPC83xx_PCI2_LOWER_IO >> 12) & POTAR_TA_MASK;
+ ios->pobar4 = (MPC83xx_PCI2_IO_BASE >> 12) & POBAR_BA_MASK;
+ ios->pocmr4 = POCMR_EN | POCMR_DST | POCMR_IO |
+ (((0xffffffff - (MPC83xx_PCI2_UPPER_IO -
+ MPC83xx_PCI2_LOWER_IO)) >> 12) & POCMR_CM_MASK);
+
+ /*
+ * Configure PCI Inbound Translation Windows
+ */
+ pci_ctrl->pitar1 = 0x0;
+ pci_ctrl->pibar1 = 0x0;
+ pci_ctrl->piebar1 = 0x0;
+ pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+
+ /*
+ * Release PCI RST signal
+ */
+ pci_ctrl->gcr = 0;
+ udelay(2000);
+ pci_ctrl->gcr = 1;
+ udelay(2000);
+
+ reg16 = 0xff;
+ early_read_config_word(hose, hose->first_busno, 0, PCI_COMMAND, ®16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ early_write_config_word(hose, hose->first_busno, 0, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ early_write_config_word(hose, hose->first_busno, 0, PCI_STATUS, 0xffff);
+ early_write_config_byte(hose, hose->first_busno, 0, PCI_LATENCY_TIMER, 0x80);
+
+ iounmap(pci_ctrl);
+ iounmap(ios);
+}
+
+/*
+ * PCI buses can be enabled only if SYS board combinates with PIB
+ * (Platform IO Board) board which provide 3 PCI slots. There is 2 PCI buses
+ * and 3 PCI slots, so people must configure the routes between them before
+ * enable PCI bus. This routes are under the control of PCA9555PW device which
+ * can be accessed via I2C bus 2 and are configured by firmware. Refer to
+ * Freescale to get more information about firmware configuration.
+ */
+
+extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
+extern int mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel,
+ unsigned char pin);
+void __init
+mpc83xx_setup_hose(void)
+{
+ u32 val32;
+ volatile immr_clk_t * clk;
+ struct pci_controller * hose1;
+#ifdef CONFIG_MPC83xx_PCI2
+ struct pci_controller * hose2;
+#endif
+ bd_t * binfo = (bd_t *)__res;
+
+ clk = ioremap(binfo->bi_immr_base + 0xA00,
+ sizeof(immr_clk_t));
+
+ /*
+ * Configure PCI controller and PCI_CLK_OUTPUT both in 66M mode
+ */
+ val32 = clk->occr;
+ udelay(2000);
+ clk->occr = 0xff000000;
+ udelay(2000);
+
+ iounmap(clk);
+
+ hose1 = pcibios_alloc_controller();
+ if(!hose1)
+ return;
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mpc83xx_map_irq;
+
+ hose1->bus_offset = 0;
+ hose1->first_busno = 0;
+ hose1->last_busno = 0xff;
+
+ setup_indirect_pci(hose1, binfo->bi_immr_base + PCI1_CFG_ADDR_OFFSET,
+ binfo->bi_immr_base + PCI1_CFG_DATA_OFFSET);
+ hose1->set_cfg_type = 1;
+
+ mpc83xx_setup_pci1(hose1);
+
+ hose1->pci_mem_offset = MPC83xx_PCI1_MEM_OFFSET;
+ hose1->mem_space.start = MPC83xx_PCI1_LOWER_MEM;
+ hose1->mem_space.end = MPC83xx_PCI1_UPPER_MEM;
+
+ hose1->io_base_phys = MPC83xx_PCI1_IO_BASE;
+ hose1->io_space.start = MPC83xx_PCI1_LOWER_IO;
+ hose1->io_space.end = MPC83xx_PCI1_UPPER_IO;
+#ifdef CONFIG_MPC83xx_PCI2
+ isa_io_base = (unsigned long)ioremap(MPC83xx_PCI1_IO_BASE,
+ MPC83xx_PCI1_IO_SIZE + MPC83xx_PCI2_IO_SIZE);
+#else
+ isa_io_base = (unsigned long)ioremap(MPC83xx_PCI1_IO_BASE,
+ MPC83xx_PCI1_IO_SIZE);
+#endif /* CONFIG_MPC83xx_PCI2 */
+ hose1->io_base_virt = (void *)isa_io_base;
+ /* setup resources */
+ pci_init_resource(&hose1->io_resource,
+ MPC83xx_PCI1_LOWER_IO,
+ MPC83xx_PCI1_UPPER_IO,
+ IORESOURCE_IO, "PCI host bridge 1");
+ pci_init_resource(&hose1->mem_resources[0],
+ MPC83xx_PCI1_LOWER_MEM,
+ MPC83xx_PCI1_UPPER_MEM,
+ IORESOURCE_MEM, "PCI host bridge 1");
+
+ ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+ hose1->last_busno = pciauto_bus_scan(hose1, hose1->first_busno);
+
+#ifdef CONFIG_MPC83xx_PCI2
+ hose2 = pcibios_alloc_controller();
+ if(!hose2)
+ return;
+
+ hose2->bus_offset = hose1->last_busno + 1;
+ hose2->first_busno = hose1->last_busno + 1;
+ hose2->last_busno = 0xff;
+ setup_indirect_pci(hose2, binfo->bi_immr_base + PCI2_CFG_ADDR_OFFSET,
+ binfo->bi_immr_base + PCI2_CFG_DATA_OFFSET);
+ hose2->set_cfg_type = 1;
+
+ mpc83xx_setup_pci2(hose2);
+
+ hose2->pci_mem_offset = MPC83xx_PCI2_MEM_OFFSET;
+ hose2->mem_space.start = MPC83xx_PCI2_LOWER_MEM;
+ hose2->mem_space.end = MPC83xx_PCI2_UPPER_MEM;
+
+ hose2->io_base_phys = MPC83xx_PCI2_IO_BASE;
+ hose2->io_space.start = MPC83xx_PCI2_LOWER_IO;
+ hose2->io_space.end = MPC83xx_PCI2_UPPER_IO;
+ hose2->io_base_virt = (void *)(isa_io_base + MPC83xx_PCI1_IO_SIZE);
+ /* setup resources */
+ pci_init_resource(&hose2->io_resource,
+ MPC83xx_PCI2_LOWER_IO,
+ MPC83xx_PCI2_UPPER_IO,
+ IORESOURCE_IO, "PCI host bridge 2");
+ pci_init_resource(&hose2->mem_resources[0],
+ MPC83xx_PCI2_LOWER_MEM,
+ MPC83xx_PCI2_UPPER_MEM,
+ IORESOURCE_MEM, "PCI host bridge 2");
+
+ hose2->last_busno = pciauto_bus_scan(hose2, hose2->first_busno);
+#endif /* CONFIG_MPC83xx_PCI2 */
+}
+#endif /*CONFIG_PCI*/
diff --git a/arch/ppc/syslib/ppc83xx_setup.h b/arch/ppc/syslib/ppc83xx_setup.h
index 683f179..c766c1a 100644
--- a/arch/ppc/syslib/ppc83xx_setup.h
+++ b/arch/ppc/syslib/ppc83xx_setup.h
@@ -12,6 +12,14 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __PPC_SYSLIB_PPC83XX_SETUP_H
@@ -19,7 +27,6 @@
#include <linux/config.h>
#include <linux/init.h>
-#include <asm/ppcboot.h>
extern unsigned long mpc83xx_find_end_of_memory(void) __init;
extern long mpc83xx_time_init(void) __init;
@@ -31,13 +38,11 @@
extern void mpc83xx_setup_hose(void) __init;
/* PCI config */
-#if 0
-#define PCI1_CFG_ADDR_OFFSET (FIXME)
-#define PCI1_CFG_DATA_OFFSET (FIXME)
+#define PCI1_CFG_ADDR_OFFSET (0x8300)
+#define PCI1_CFG_DATA_OFFSET (0x8304)
-#define PCI2_CFG_ADDR_OFFSET (FIXME)
-#define PCI2_CFG_DATA_OFFSET (FIXME)
-#endif
+#define PCI2_CFG_ADDR_OFFSET (0x8380)
+#define PCI2_CFG_DATA_OFFSET (0x8384)
/* Serial Config */
#ifdef CONFIG_SERIAL_MANY_PORTS
diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c
index 8792023..52ba0c6 100644
--- a/arch/ppc/syslib/ppc_sys.c
+++ b/arch/ppc/syslib/ppc_sys.c
@@ -6,6 +6,7 @@
* Maintainer: Kumar Gala <kumar.gala@freescale.com>
*
* Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.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
@@ -35,10 +36,59 @@
void __init identify_ppc_sys_by_name(char *name)
{
- /* TODO */
+ unsigned int i = 0;
+ while (ppc_sys_specs[i].ppc_sys_name[0])
+ {
+ if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
+ break;
+ i++;
+ }
+ cur_ppc_sys_spec = &ppc_sys_specs[i];
return;
}
+static int __init count_sys_specs(void)
+{
+ int i = 0;
+ while (ppc_sys_specs[i].ppc_sys_name[0])
+ i++;
+ return i;
+}
+
+static int __init find_chip_by_name_and_id(char *name, u32 id)
+{
+ int ret = -1;
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int dups = 0;
+
+ unsigned char matched[count_sys_specs()];
+
+ while (ppc_sys_specs[i].ppc_sys_name[0]) {
+ if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
+ matched[j++] = i;
+ i++;
+ }
+ if (j != 0) {
+ for (i = 0; i < j; i++) {
+ if ((ppc_sys_specs[matched[i]].mask & id) ==
+ ppc_sys_specs[matched[i]].value) {
+ ret = matched[i];
+ dups++;
+ }
+ }
+ ret = (dups == 1) ? ret : (-1 * dups);
+ }
+ return ret;
+}
+
+void __init identify_ppc_sys_by_name_and_id(char *name, u32 id)
+{
+ int i = find_chip_by_name_and_id(name, id);
+ BUG_ON(i < 0);
+ cur_ppc_sys_spec = &ppc_sys_specs[i];
+}
+
/* Update all memory resources by paddr, call before platform_device_register */
void __init
ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr)
diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c
new file mode 100644
index 0000000..1d38697
--- /dev/null
+++ b/arch/ppc/syslib/pq2_devices.c
@@ -0,0 +1,389 @@
+/*
+ * arch/ppc/syslib/pq2_devices.c
+ *
+ * PQ2 Device descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <asm/cpm2.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+
+struct platform_device ppc_sys_platform_devices[] = {
+ [MPC82xx_CPM_FCC1] = {
+ .name = "fsl-cpm-fcc",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "fcc_regs",
+ .start = 0x11300,
+ .end = 0x1131f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fcc_pram",
+ .start = 0x8400,
+ .end = 0x84ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_FCC1,
+ .end = SIU_INT_FCC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_FCC2] = {
+ .name = "fsl-cpm-fcc",
+ .id = 2,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "fcc_regs",
+ .start = 0x11320,
+ .end = 0x1133f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fcc_pram",
+ .start = 0x8500,
+ .end = 0x85ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_FCC2,
+ .end = SIU_INT_FCC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_FCC3] = {
+ .name = "fsl-cpm-fcc",
+ .id = 3,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "fcc_regs",
+ .start = 0x11340,
+ .end = 0x1135f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fcc_pram",
+ .start = 0x8600,
+ .end = 0x86ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_FCC3,
+ .end = SIU_INT_FCC3,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_I2C] = {
+ .name = "fsl-cpm-i2c",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "i2c_mem",
+ .start = 0x11860,
+ .end = 0x118BF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "i2c_pram",
+ .start = 0x8afc,
+ .end = 0x8afd,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_I2C,
+ .end = SIU_INT_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SCC1] = {
+ .name = "fsl-cpm-scc",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "scc_mem",
+ .start = 0x11A00,
+ .end = 0x11A1F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "scc_pram",
+ .start = 0x8000,
+ .end = 0x80ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SCC1,
+ .end = SIU_INT_SCC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SCC2] = {
+ .name = "fsl-cpm-scc",
+ .id = 2,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "scc_mem",
+ .start = 0x11A20,
+ .end = 0x11A3F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "scc_pram",
+ .start = 0x8100,
+ .end = 0x81ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SCC2,
+ .end = SIU_INT_SCC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SCC3] = {
+ .name = "fsl-cpm-scc",
+ .id = 3,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "scc_mem",
+ .start = 0x11A40,
+ .end = 0x11A5F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "scc_pram",
+ .start = 0x8200,
+ .end = 0x82ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SCC3,
+ .end = SIU_INT_SCC3,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SCC4] = {
+ .name = "fsl-cpm-scc",
+ .id = 4,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "scc_mem",
+ .start = 0x11A60,
+ .end = 0x11A7F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "scc_pram",
+ .start = 0x8300,
+ .end = 0x83ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SCC4,
+ .end = SIU_INT_SCC4,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SPI] = {
+ .name = "fsl-cpm-spi",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "spi_mem",
+ .start = 0x11AA0,
+ .end = 0x11AFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "spi_pram",
+ .start = 0x89fc,
+ .end = 0x89fd,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SPI,
+ .end = SIU_INT_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_MCC1] = {
+ .name = "fsl-cpm-mcc",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "mcc_mem",
+ .start = 0x11B30,
+ .end = 0x11B3F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mcc_pram",
+ .start = 0x8700,
+ .end = 0x877f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_MCC1,
+ .end = SIU_INT_MCC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_MCC2] = {
+ .name = "fsl-cpm-mcc",
+ .id = 2,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "mcc_mem",
+ .start = 0x11B50,
+ .end = 0x11B5F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mcc_pram",
+ .start = 0x8800,
+ .end = 0x887f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_MCC2,
+ .end = SIU_INT_MCC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SMC1] = {
+ .name = "fsl-cpm-smc",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "smc_mem",
+ .start = 0x11A80,
+ .end = 0x11A8F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "smc_pram",
+ .start = 0x87fc,
+ .end = 0x87fd,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SMC1,
+ .end = SIU_INT_SMC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_SMC2] = {
+ .name = "fsl-cpm-smc",
+ .id = 2,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "smc_mem",
+ .start = 0x11A90,
+ .end = 0x11A9F,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "smc_pram",
+ .start = 0x88fc,
+ .end = 0x88fd,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_SMC2,
+ .end = SIU_INT_SMC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC82xx_CPM_USB] = {
+ .name = "fsl-cpm-usb",
+ .id = 1,
+ .num_resources = 3,
+ .resource = (struct resource[]) {
+ {
+ .name = "usb_mem",
+ .start = 0x11b60,
+ .end = 0x11b78,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "usb_pram",
+ .start = 0x8b00,
+ .end = 0x8bff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_USB,
+ .end = SIU_INT_USB,
+ .flags = IORESOURCE_IRQ,
+ },
+
+ },
+ },
+ [MPC82xx_SEC1] = {
+ .name = "fsl-sec",
+ .id = 1,
+ .num_resources = 1,
+ .resource = (struct resource[]) {
+ {
+ .name = "sec_mem",
+ .start = 0x40000,
+ .end = 0x52fff,
+ .flags = IORESOURCE_MEM,
+ },
+ },
+ },
+};
+
+static int __init mach_mpc82xx_fixup(struct platform_device *pdev)
+{
+ ppc_sys_fixup_mem_resource(pdev, CPM_MAP_ADDR);
+ return 0;
+}
+
+static int __init mach_mpc82xx_init(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("mach_mpc82xx_init:enter", 0);
+ ppc_sys_device_fixup = mach_mpc82xx_fixup;
+ return 0;
+}
+
+postcore_initcall(mach_mpc82xx_init);
diff --git a/arch/ppc/syslib/pq2_sys.c b/arch/ppc/syslib/pq2_sys.c
new file mode 100644
index 0000000..7b6c9eb
--- /dev/null
+++ b/arch/ppc/syslib/pq2_sys.c
@@ -0,0 +1,200 @@
+/*
+ * arch/ppc/syslib/pq2_devices.c
+ *
+ * PQ2 System descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <asm/ppc_sys.h>
+
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+ /* below is a list of the 8260 family of processors */
+ {
+ .ppc_sys_name = "8250",
+ .mask = 0x0000ff00,
+ .value = 0x00000000,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ }
+ },
+ {
+ .ppc_sys_name = "8255",
+ .mask = 0x0000ff00,
+ .value = 0x00000000,
+ .num_devices = 11,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+ MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SCC4,
+ MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2,
+ MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ }
+ },
+ {
+ .ppc_sys_name = "8260",
+ .mask = 0x0000ff00,
+ .value = 0x00000000,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ }
+ },
+ {
+ .ppc_sys_name = "8264",
+ .mask = 0x0000ff00,
+ .value = 0x00000000,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ }
+ },
+ {
+ .ppc_sys_name = "8265",
+ .mask = 0x0000ff00,
+ .value = 0x00000000,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ }
+ },
+ {
+ .ppc_sys_name = "8266",
+ .mask = 0x0000ff00,
+ .value = 0x00000000,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ }
+ },
+ /* below is a list of the 8272 family of processors */
+ {
+ .ppc_sys_name = "8247",
+ .mask = 0x0000ff00,
+ .value = 0x00000d00,
+ .num_devices = 10,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+ MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ MPC82xx_CPM_USB,
+ },
+ },
+ {
+ .ppc_sys_name = "8248",
+ .mask = 0x0000ff00,
+ .value = 0x00000c00,
+ .num_devices = 11,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+ MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ MPC82xx_CPM_USB, MPC82xx_SEC1,
+ },
+ },
+ {
+ .ppc_sys_name = "8271",
+ .mask = 0x0000ff00,
+ .value = 0x00000d00,
+ .num_devices = 10,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+ MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ MPC82xx_CPM_USB,
+ },
+ },
+ {
+ .ppc_sys_name = "8272",
+ .mask = 0x0000ff00,
+ .value = 0x00000c00,
+ .num_devices = 11,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
+ MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ MPC82xx_CPM_USB, MPC82xx_SEC1,
+ },
+ },
+ /* below is a list of the 8280 family of processors */
+ {
+ .ppc_sys_name = "8270",
+ .mask = 0x0000ff00,
+ .value = 0x00000a00,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ },
+ },
+ {
+ .ppc_sys_name = "8275",
+ .mask = 0x0000ff00,
+ .value = 0x00000a00,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C,
+ },
+ },
+ {
+ .ppc_sys_name = "8280",
+ .mask = 0x0000ff00,
+ .value = 0x00000a00,
+ .num_devices = 13,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4, MPC82xx_CPM_MCC1, MPC82xx_CPM_MCC2,
+ MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI,
+ MPC82xx_CPM_I2C,
+ },
+ },
+ {
+ /* default match */
+ .ppc_sys_name = "",
+ .mask = 0x00000000,
+ .value = 0x00000000,
+ },
+};
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index 13b262f..deca68a 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -44,6 +44,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
# We optimistically allocate largepages from the VM, so make the limit
# large enough (16MB). This badly named config option is actually
# max order + 1
diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug
index 46b1ce5..f16a503 100644
--- a/arch/ppc64/Kconfig.debug
+++ b/arch/ppc64/Kconfig.debug
@@ -41,10 +41,19 @@
help
Include in-kernel hooks for the xmon kernel monitor/debugger.
Unless you are intending to debug the kernel, say N here.
+ Make sure to enable also CONFIG_BOOTX_TEXT on Macs. Otherwise
+ nothing will appear on the screen (xmon writes directly to the
+ framebuffer memory).
+ The cmdline option 'xmon' or 'xmon=early' will drop into xmon very
+ early during boot. 'xmon=on' will just enable the xmon debugger hooks.
+ 'xmon=off' will disable the debugger hooks if CONFIG_XMON_DEFAULT is set.
config XMON_DEFAULT
bool "Enable xmon by default"
depends on XMON
+ help
+ xmon is normally disabled unless booted with 'xmon=on'.
+ Use 'xmon=off' to disable xmon init during runtime.
config PPCDBG
bool "Include PPCDBG realtime debugging"
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile
index 6350cce..8189953 100644
--- a/arch/ppc64/Makefile
+++ b/arch/ppc64/Makefile
@@ -49,7 +49,7 @@
endif
-CHECKFLAGS += -m64 -D__powerpc__
+CHECKFLAGS += -m64 -D__powerpc__ -D__powerpc64__
LDFLAGS := -m elf64ppc
LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD)
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
index f4b3bfc..ae60eb1 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -31,7 +31,7 @@
obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \
- pSeries_setup.o pSeries_iommu.o
+ pSeries_setup.o pSeries_iommu.o udbg_16550.o
obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \
bpa_iic.o spider-pic.o
@@ -58,9 +58,11 @@
obj-$(CONFIG_MPIC) += mpic.o
obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \
- pmac_time.o pmac_nvram.o pmac_low_i2c.o
+ pmac_time.o pmac_nvram.o pmac_low_i2c.o \
+ udbg_scc.o
-obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o
+obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \
+ udbg_16550.o
obj-$(CONFIG_U3_DART) += u3_iommu.o
diff --git a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c
index c53f079..b6fbfbe 100644
--- a/arch/ppc64/kernel/btext.c
+++ b/arch/ppc64/kernel/btext.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <asm/sections.h>
#include <asm/prom.h>
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
index 4847f2a..8831a28 100644
--- a/arch/ppc64/kernel/cputable.c
+++ b/arch/ppc64/kernel/cputable.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <asm/oprofile_impl.h>
#include <asm/cputable.h>
struct cpu_spec* cur_cpu_spec = NULL;
@@ -54,24 +55,32 @@
.pvr_value = 0x00400000,
.cpu_name = "POWER3 (630)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
- CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
- CPU_FTR_PMC8,
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/power3",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* Power3+ */
.pvr_mask = 0xffff0000,
.pvr_value = 0x00410000,
.cpu_name = "POWER3 (630+)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
- CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
- CPU_FTR_PMC8,
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/power3",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* Northstar */
.pvr_mask = 0xffff0000,
@@ -79,11 +88,16 @@
.cpu_name = "RS64-II (northstar)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
- CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ CPU_FTR_MMCRA | CPU_FTR_CTRL,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/rs64",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* Pulsar */
.pvr_mask = 0xffff0000,
@@ -91,11 +105,16 @@
.cpu_name = "RS64-III (pulsar)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
- CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ CPU_FTR_MMCRA | CPU_FTR_CTRL,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/rs64",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* I-star */
.pvr_mask = 0xffff0000,
@@ -103,11 +122,16 @@
.cpu_name = "RS64-III (icestar)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
- CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ CPU_FTR_MMCRA | CPU_FTR_CTRL,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/rs64",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* S-star */
.pvr_mask = 0xffff0000,
@@ -115,11 +139,16 @@
.cpu_name = "RS64-IV (sstar)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
- CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ CPU_FTR_MMCRA | CPU_FTR_CTRL,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power3,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/rs64",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* Power4 */
.pvr_mask = 0xffff0000,
@@ -127,11 +156,16 @@
.cpu_name = "POWER4 (gp)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power4,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/power4",
+ .oprofile_model = &op_model_rs64,
+#endif
},
{ /* Power4+ */
.pvr_mask = 0xffff0000,
@@ -139,11 +173,16 @@
.cpu_name = "POWER4+ (gq)",
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA,
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_power4,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/power4",
+ .oprofile_model = &op_model_power4,
+#endif
},
{ /* PPC970 */
.pvr_mask = 0xffff0000,
@@ -152,12 +191,17 @@
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
.cpu_user_features = COMMON_USER_PPC64 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/970",
+ .oprofile_model = &op_model_power4,
+#endif
},
{ /* PPC970FX */
.pvr_mask = 0xffff0000,
@@ -166,12 +210,17 @@
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
.cpu_user_features = COMMON_USER_PPC64 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/970",
+ .oprofile_model = &op_model_power4,
+#endif
},
{ /* PPC970MP */
.pvr_mask = 0xffff0000,
@@ -180,12 +229,16 @@
.cpu_features = CPU_FTR_SPLIT_ID_CACHE |
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ CPU_FTR_CAN_NAP | CPU_FTR_MMCRA,
.cpu_user_features = COMMON_USER_PPC64 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_ppc970,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/970",
+ .oprofile_model = &op_model_power4,
+#endif
},
{ /* Power5 */
.pvr_mask = 0xffff0000,
@@ -199,7 +252,12 @@
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 6,
.cpu_setup = __setup_cpu_power4,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/power5",
+ .oprofile_model = &op_model_power4,
+#endif
},
{ /* Power5 */
.pvr_mask = 0xffff0000,
@@ -213,7 +271,12 @@
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 6,
.cpu_setup = __setup_cpu_power4,
+#ifdef CONFIG_OPROFILE
+ .oprofile_cpu_type = "ppc64/power5",
+ .oprofile_model = &op_model_power4,
+#endif
},
{ /* BE DD1.x */
.pvr_mask = 0xffff0000,
@@ -239,6 +302,7 @@
.cpu_user_features = COMMON_USER_PPC64,
.icache_bsize = 128,
.dcache_bsize = 128,
+ .num_pmcs = 6,
.cpu_setup = __setup_cpu_power4,
}
};
diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
index b61572e..bf99b4a 100644
--- a/arch/ppc64/kernel/entry.S
+++ b/arch/ppc64/kernel/entry.S
@@ -400,15 +400,14 @@
cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */
cror eq,4*cr1+eq,eq
beq 2f /* if yes, don't slbie it */
- oris r0,r6,0x0800 /* set C (class) bit */
/* Bolt in the new stack SLB entry */
ld r7,KSP_VSID(r4) /* Get new stack's VSID */
- oris r6,r6,(SLB_ESID_V)@h
- ori r6,r6,(SLB_NUM_BOLTED-1)@l
- slbie r0
- slbie r0 /* Workaround POWER5 < DD2.1 issue */
- slbmte r7,r6
+ oris r0,r6,(SLB_ESID_V)@h
+ ori r0,r0,(SLB_NUM_BOLTED-1)@l
+ slbie r6
+ slbie r6 /* Workaround POWER5 < DD2.1 issue */
+ slbmte r7,r0
isync
2:
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index 0369597..b436206 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -1646,8 +1646,9 @@
#else
/* set the ASR */
ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */
+ ld r3,0(r3)
lwz r3,PLATFORM(r3) /* r3 = platform flags */
- cmpldi r3,PLATFORM_PSERIES_LPAR
+ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */
bne 98f
mfspr r3,PVR
srwi r3,r3,16
@@ -1809,8 +1810,9 @@
ld r3,PACASTABREAL(r13)
ori r4,r3,1 /* turn on valid bit */
ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */
+ ld r3,0(r3)
lwz r3,PLATFORM(r3) /* r3 = platform flags */
- cmpldi r3,PLATFORM_PSERIES_LPAR
+ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */
bne 98f
mfspr r3,PVR
srwi r3,r3,16
@@ -1828,9 +1830,10 @@
99:
/* Set SDR1 (hash table pointer) */
ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */
+ ld r3,0(r3)
lwz r3,PLATFORM(r3) /* r3 = platform flags */
/* Test if bit 0 is set (LPAR bit) */
- andi. r3,r3,0x1
+ andi. r3,r3,PLATFORM_LPAR
bne 98f
LOADADDR(r6,_SDR1) /* Only if NOT LPAR */
sub r6,r6,r26
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index a3d5195..7e80d49 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -44,7 +44,7 @@
static unsigned long kprobe_status_prev, kprobe_saved_msr_prev;
static struct pt_regs jprobe_saved_regs;
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
int ret = 0;
kprobe_opcode_t insn = *p->addr;
@@ -68,27 +68,27 @@
return ret;
}
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
}
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
{
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
{
up(&kprobe_mutex);
free_insn_slot(p->ainsn.insn);
@@ -102,7 +102,7 @@
regs->msr |= MSR_SE;
/* single step inline if it is a trap variant */
- if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
+ if (is_trap(insn))
regs->nip = (unsigned long)p->addr;
else
regs->nip = (unsigned long)p->ainsn.insn;
@@ -122,7 +122,8 @@
kprobe_saved_msr = kprobe_saved_msr_prev;
}
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+ struct pt_regs *regs)
{
struct kretprobe_instance *ri;
@@ -151,7 +152,9 @@
Disarm the probe we just hit, and ignore it. */
p = get_kprobe(addr);
if (p) {
- if (kprobe_status == KPROBE_HIT_SS) {
+ kprobe_opcode_t insn = *p->ainsn.insn;
+ if (kprobe_status == KPROBE_HIT_SS &&
+ is_trap(insn)) {
regs->msr &= ~MSR_SE;
regs->msr |= kprobe_saved_msr;
unlock_kprobes();
@@ -191,8 +194,7 @@
* trap variant, it could belong to someone else
*/
kprobe_opcode_t cur_insn = *addr;
- if (IS_TW(cur_insn) || IS_TD(cur_insn) ||
- IS_TWI(cur_insn) || IS_TDI(cur_insn))
+ if (is_trap(cur_insn))
goto no_kprobe;
/*
* The breakpoint instruction was removed right
@@ -244,7 +246,7 @@
/*
* Called when the probe at kretprobe trampoline is hit
*/
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head;
@@ -308,7 +310,7 @@
* single-stepped a copy of the instruction. The address of this
* copy is p->ainsn.insn.
*/
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
int ret;
unsigned int insn = *p->ainsn.insn;
@@ -373,8 +375,8 @@
/*
* Wrapper routine to for handling exceptions.
*/
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
- void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
int ret = NOTIFY_DONE;
@@ -402,11 +404,11 @@
default:
break;
}
- preempt_enable();
+ preempt_enable_no_resched();
return ret;
}
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
@@ -419,16 +421,16 @@
return 1;
}
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
{
asm volatile("trap" ::: "memory");
}
-void jprobe_return_end(void)
+void __kprobes jprobe_return_end(void)
{
};
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
/*
* FIXME - we should ideally be validating that we got here 'cos
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c
index edad361..cae19bb 100644
--- a/arch/ppc64/kernel/lparcfg.c
+++ b/arch/ppc64/kernel/lparcfg.c
@@ -569,7 +569,7 @@
int __init lparcfg_init(void)
{
struct proc_dir_entry *ent;
- mode_t mode = S_IRUSR;
+ mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
/* Allow writing if we have FW_FEATURE_SPLPAR */
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c
index bb55b5a..fc05674 100644
--- a/arch/ppc64/kernel/maple_setup.c
+++ b/arch/ppc64/kernel/maple_setup.c
@@ -207,9 +207,6 @@
comport = (void *)ioremap(physport, 16);
udbg_init_uart(comport, default_speed);
- ppc_md.udbg_putc = udbg_putc;
- ppc_md.udbg_getc = udbg_getc;
- ppc_md.udbg_getc_poll = udbg_getc_poll;
DBG("Hello World !\n");
}
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index 474df0a..6d860c1 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -183,7 +183,7 @@
* flush all bytes from start through stop-1 inclusive
*/
-_GLOBAL(__flush_icache_range)
+_KPROBE(__flush_icache_range)
/*
* Flush the data cache to memory
@@ -223,7 +223,7 @@
bdnz 2b
isync
blr
-
+ .previous .text
/*
* Like above, but only do the D-cache.
*
@@ -957,7 +957,7 @@
.llong .ppc_fork
.llong .sys_read
.llong .sys_write
- .llong .sys32_open /* 5 */
+ .llong .compat_sys_open /* 5 */
.llong .sys_close
.llong .sys32_waitpid
.llong .sys32_creat
diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
index 0a3ddc9..a6de83f 100644
--- a/arch/ppc64/kernel/pSeries_lpar.c
+++ b/arch/ppc64/kernel/pSeries_lpar.c
@@ -192,9 +192,9 @@
void udbg_init_debug_lpar(void)
{
vtermno = 0;
- ppc_md.udbg_putc = udbg_putcLP;
- ppc_md.udbg_getc = udbg_getcLP;
- ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+ udbg_putc = udbg_putcLP;
+ udbg_getc = udbg_getcLP;
+ udbg_getc_poll = udbg_getc_pollLP;
}
/* returns 0 if couldn't find or use /chosen/stdout as console */
@@ -227,18 +227,18 @@
termno = (u32 *)get_property(stdout_node, "reg", NULL);
if (termno) {
vtermno = termno[0];
- ppc_md.udbg_putc = udbg_putcLP;
- ppc_md.udbg_getc = udbg_getcLP;
- ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+ udbg_putc = udbg_putcLP;
+ udbg_getc = udbg_getcLP;
+ udbg_getc_poll = udbg_getc_pollLP;
found = 1;
}
} else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
termno = (u32 *)get_property(stdout_node, "reg", NULL);
if (termno) {
vtermno = termno[0];
- ppc_md.udbg_putc = udbg_hvsi_putc;
- ppc_md.udbg_getc = udbg_hvsi_getc;
- ppc_md.udbg_getc_poll = udbg_hvsi_getc_poll;
+ udbg_putc = udbg_hvsi_putc;
+ udbg_getc = udbg_hvsi_getc;
+ udbg_getc_poll = udbg_hvsi_getc_poll;
found = 1;
}
}
@@ -266,6 +266,10 @@
/* Register the Virtual Processor Area (VPA) */
flags = 1UL << (63 - 18);
+
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ paca[cpu].lppaca.vmxregs_in_use = 1;
+
ret = register_vpa(flags, hwcpu, __pa(vpa));
if (ret)
diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/ppc64/kernel/pSeries_reconfig.c
index dc2a69d..58c6121 100644
--- a/arch/ppc64/kernel/pSeries_reconfig.c
+++ b/arch/ppc64/kernel/pSeries_reconfig.c
@@ -111,7 +111,7 @@
struct device_node *np;
int err = -ENOMEM;
- np = kcalloc(1, sizeof(*np), GFP_KERNEL);
+ np = kzalloc(sizeof(*np), GFP_KERNEL);
if (!np)
goto out_err;
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
index f0f0630..9490b6c 100644
--- a/arch/ppc64/kernel/pSeries_setup.c
+++ b/arch/ppc64/kernel/pSeries_setup.c
@@ -37,7 +37,7 @@
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/pci.h>
-#include <linux/version.h>
+#include <linux/utsname.h>
#include <linux/adb.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -272,7 +272,7 @@
{
/* Manually leave the kernel version on the panel. */
ppc_md.progress("Linux ppc64\n", 0);
- ppc_md.progress(UTS_RELEASE, 0);
+ ppc_md.progress(system_utsname.version, 0);
return 0;
}
@@ -397,9 +397,6 @@
comport = (void *)ioremap(physport, 16);
udbg_init_uart(comport, default_speed);
- ppc_md.udbg_putc = udbg_putc;
- ppc_md.udbg_getc = udbg_getc;
- ppc_md.udbg_getc_poll = udbg_getc_poll;
DBG("Hello World !\n");
}
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
index 6182a2c..33a2d8d 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/ppc64/kernel/pacaData.c
@@ -59,6 +59,7 @@
.fpregs_in_use = 1, \
.end_of_quantum = 0xfffffffffffffffful, \
.slb_count = 64, \
+ .vmxregs_in_use = 0, \
}, \
#ifdef CONFIG_PPC_ISERIES
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
index 8ff86a7..e7f695d 100644
--- a/arch/ppc64/kernel/pmac_setup.c
+++ b/arch/ppc64/kernel/pmac_setup.c
@@ -274,16 +274,6 @@
}
#ifdef CONFIG_BOOTX_TEXT
-static int dummy_getc_poll(void)
-{
- return -1;
-}
-
-static unsigned char dummy_getc(void)
-{
- return 0;
-}
-
static void btext_putc(unsigned char c)
{
btext_drawchar(c);
@@ -342,16 +332,13 @@
sccdbg = 1;
udbg_init_scc(NULL);
}
-
- else {
#ifdef CONFIG_BOOTX_TEXT
+ else {
init_boot_display();
- ppc_md.udbg_putc = btext_putc;
- ppc_md.udbg_getc = dummy_getc;
- ppc_md.udbg_getc_poll = dummy_getc_poll;
-#endif /* CONFIG_BOOTX_TEXT */
+ udbg_putc = btext_putc;
}
+#endif /* CONFIG_BOOTX_TEXT */
/* Setup interrupt mapping options */
ppc64_interrupt_controller = IC_OPEN_PIC;
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index b218488..6ad5a84 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/threads.h>
#include <linux/spinlock.h>
#include <linux/types.h>
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
index 122283a..9979919 100644
--- a/arch/ppc64/kernel/prom_init.c
+++ b/arch/ppc64/kernel/prom_init.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/threads.h>
#include <linux/spinlock.h>
#include <linux/types.h>
diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
index b0c3b82..e26b042 100644
--- a/arch/ppc64/kernel/rtasd.c
+++ b/arch/ppc64/kernel/rtasd.c
@@ -19,6 +19,7 @@
#include <linux/vmalloc.h>
#include <linux/spinlock.h>
#include <linux/cpu.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -412,8 +413,7 @@
/* Drop hotplug lock, and sleep for the specified delay */
unlock_cpu_hotplug();
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(delay);
+ msleep_interruptible(delay);
lock_cpu_hotplug();
cpu = next_cpu(cpu, cpu_online_map);
@@ -442,7 +442,7 @@
printk(KERN_INFO "RTAS daemon started\n");
- DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2);
+ DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate));
/* See if we have any error stored in NVRAM */
memset(logdata, 0, rtas_error_log_max);
@@ -459,7 +459,7 @@
}
/* First pass. */
- do_event_scan_all_cpus(HZ);
+ do_event_scan_all_cpus(1000);
if (surveillance_timeout != -1) {
DEBUG("enabling surveillance\n");
@@ -471,7 +471,7 @@
* machines have problems if we call event-scan too
* quickly. */
for (;;)
- do_event_scan_all_cpus((HZ*60/rtas_event_scan_rate) / 2);
+ do_event_scan_all_cpus(30000/rtas_event_scan_rate);
error:
/* Should delete proc entries */
diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c
index d729fef..6ff52bc 100644
--- a/arch/ppc64/kernel/rtc.c
+++ b/arch/ppc64/kernel/rtc.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <linux/bcd.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -351,8 +352,7 @@
return; /* delay not allowed */
}
wait_time = rtas_extended_busy_delay_time(error);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(wait_time);
+ msleep_interruptible(wait_time);
error = RTAS_CLOCK_BUSY;
}
} while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
@@ -386,8 +386,7 @@
if (in_interrupt())
return 1; /* probably decrementer */
wait_time = rtas_extended_busy_delay_time(error);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(wait_time);
+ msleep_interruptible(wait_time);
error = RTAS_CLOCK_BUSY;
}
} while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c
index 4d70736..215bf89 100644
--- a/arch/ppc64/kernel/scanlog.c
+++ b/arch/ppc64/kernel/scanlog.c
@@ -25,6 +25,7 @@
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/rtas.h>
#include <asm/prom.h>
@@ -77,7 +78,7 @@
return -EFAULT;
for (;;) {
- wait_time = HZ/2; /* default wait if no data */
+ wait_time = 500; /* default wait if no data */
spin_lock(&rtas_data_buf_lock);
memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
@@ -107,24 +108,14 @@
break;
default:
if (status > 9900 && status <= 9905) {
- /* No data. RTAS is hinting at a delay required
- * between 1-100000 milliseconds
- */
- int ms = 1;
- for (; status > 9900; status--)
- ms = ms * 10;
- /* Use microseconds for reasonable accuracy */
- ms *= 1000;
- wait_time = ms / (1000000/HZ); /* round down is fine */
- /* Fall through to sleep */
+ wait_time = rtas_extended_busy_delay_time(status);
} else {
printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status);
return -EIO;
}
}
/* Apparently no data yet. Wait and try again. */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(wait_time);
+ msleep_interruptible(wait_time);
}
/*NOTREACHED*/
}
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
index ee3b20d..d0bb68a 100644
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -25,7 +25,7 @@
#include <linux/seq_file.h>
#include <linux/ioport.h>
#include <linux/console.h>
-#include <linux/version.h>
+#include <linux/utsname.h>
#include <linux/tty.h>
#include <linux/root_dev.h>
#include <linux/notifier.h>
@@ -89,7 +89,7 @@
#define EARLY_DEBUG_INIT() udbg_init_maple_realmode()
#define EARLY_DEBUG_INIT() udbg_init_pmac_realmode()
#define EARLY_DEBUG_INIT() \
- do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0)
+ do { udbg_putc = call_rtas_display_status_delay; } while(0)
#endif
/* extern void *stab; */
@@ -108,7 +108,6 @@
int boot_cpuid_phys = 0;
dev_t boot_dev;
u64 ppc64_pft_size;
-u64 ppc64_debug_switch;
struct ppc64_caches ppc64_caches;
EXPORT_SYMBOL_GPL(ppc64_caches);
@@ -154,34 +153,6 @@
.orig_video_points = 16
};
-/*
- * Initialize the PPCDBG state. Called before relocation has been enabled.
- */
-void __init ppcdbg_initialize(void)
-{
- ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
- /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
-}
-
-/*
- * Early boot console based on udbg
- */
-static struct console udbg_console = {
- .name = "udbg",
- .write = udbg_console_write,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-static int early_console_initialized;
-
-void __init disable_early_printk(void)
-{
- if (!early_console_initialized)
- return;
- unregister_console(&udbg_console);
- early_console_initialized = 0;
-}
-
#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP)
static int smt_enabled_cmdline;
@@ -425,12 +396,6 @@
}
ppc_md = **mach;
- /* our udbg callbacks got overriden by the above, let's put them
- * back in. Ultimately, I want those things to be split from the
- * main ppc_md
- */
- EARLY_DEBUG_INIT();
-
DBG("Found, Initializing memory management...\n");
/*
@@ -636,8 +601,7 @@
/*
* Register early console
*/
- early_console_initialized = 1;
- register_console(&udbg_console);
+ register_early_udbg_console();
/* Save unparsed command line copy for /proc/cmdline */
strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
@@ -657,7 +621,7 @@
smp_release_cpus();
#endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */
- printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
+ printk("Starting Linux PPC64 %s\n", system_utsname.version);
printk("-----------------------------------------------------\n");
printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
index 2066190..214914a 100644
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -867,37 +867,6 @@
return sys_lseek(fd, (int)offset, origin);
}
-/*
- * This is just a version for 32-bit applications which does
- * not force O_LARGEFILE on.
- */
-asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
-{
- char * tmp;
- int fd, error;
-
- tmp = getname(filename);
- fd = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
- if (fd >= 0) {
- struct file * f = filp_open(tmp, flags, mode);
- error = PTR_ERR(f);
- if (IS_ERR(f))
- goto out_error;
- fd_install(fd, f);
- }
-out:
- putname(tmp);
- }
- return fd;
-
-out_error:
- put_unused_fd(fd);
- fd = error;
- goto out;
-}
-
/* Note: it is necessary to treat bufsiz as an unsigned int,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c
index f311ee7..6654b35 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/ppc64/kernel/sysfs.c
@@ -215,18 +215,23 @@
if (cpu_has_feature(CPU_FTR_MMCRA))
sysdev_create_file(s, &attr_mmcra);
- sysdev_create_file(s, &attr_pmc1);
- sysdev_create_file(s, &attr_pmc2);
- sysdev_create_file(s, &attr_pmc3);
- sysdev_create_file(s, &attr_pmc4);
- sysdev_create_file(s, &attr_pmc5);
- sysdev_create_file(s, &attr_pmc6);
-
- if (cpu_has_feature(CPU_FTR_PMC8)) {
+ if (cur_cpu_spec->num_pmcs >= 1)
+ sysdev_create_file(s, &attr_pmc1);
+ if (cur_cpu_spec->num_pmcs >= 2)
+ sysdev_create_file(s, &attr_pmc2);
+ if (cur_cpu_spec->num_pmcs >= 3)
+ sysdev_create_file(s, &attr_pmc3);
+ if (cur_cpu_spec->num_pmcs >= 4)
+ sysdev_create_file(s, &attr_pmc4);
+ if (cur_cpu_spec->num_pmcs >= 5)
+ sysdev_create_file(s, &attr_pmc5);
+ if (cur_cpu_spec->num_pmcs >= 6)
+ sysdev_create_file(s, &attr_pmc6);
+ if (cur_cpu_spec->num_pmcs >= 7)
sysdev_create_file(s, &attr_pmc7);
+ if (cur_cpu_spec->num_pmcs >= 8)
sysdev_create_file(s, &attr_pmc8);
- }
-
+
if (cpu_has_feature(CPU_FTR_SMT))
sysdev_create_file(s, &attr_purr);
}
@@ -252,17 +257,22 @@
if (cpu_has_feature(CPU_FTR_MMCRA))
sysdev_remove_file(s, &attr_mmcra);
- sysdev_remove_file(s, &attr_pmc1);
- sysdev_remove_file(s, &attr_pmc2);
- sysdev_remove_file(s, &attr_pmc3);
- sysdev_remove_file(s, &attr_pmc4);
- sysdev_remove_file(s, &attr_pmc5);
- sysdev_remove_file(s, &attr_pmc6);
-
- if (cpu_has_feature(CPU_FTR_PMC8)) {
+ if (cur_cpu_spec->num_pmcs >= 1)
+ sysdev_remove_file(s, &attr_pmc1);
+ if (cur_cpu_spec->num_pmcs >= 2)
+ sysdev_remove_file(s, &attr_pmc2);
+ if (cur_cpu_spec->num_pmcs >= 3)
+ sysdev_remove_file(s, &attr_pmc3);
+ if (cur_cpu_spec->num_pmcs >= 4)
+ sysdev_remove_file(s, &attr_pmc4);
+ if (cur_cpu_spec->num_pmcs >= 5)
+ sysdev_remove_file(s, &attr_pmc5);
+ if (cur_cpu_spec->num_pmcs >= 6)
+ sysdev_remove_file(s, &attr_pmc6);
+ if (cur_cpu_spec->num_pmcs >= 7)
sysdev_remove_file(s, &attr_pmc7);
+ if (cur_cpu_spec->num_pmcs >= 8)
sysdev_remove_file(s, &attr_pmc8);
- }
if (cpu_has_feature(CPU_FTR_SMT))
sysdev_remove_file(s, &attr_purr);
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
index 1696e1b..9939c20 100644
--- a/arch/ppc64/kernel/time.c
+++ b/arch/ppc64/kernel/time.c
@@ -51,7 +51,6 @@
#include <linux/cpu.h>
#include <linux/security.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/nvram.h>
@@ -129,7 +128,7 @@
* We should have an rtc call that only sets the minutes and
* seconds like on Intel to avoid problems with non UTC clocks.
*/
- if ( (time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ &&
jiffies - wall_jiffies == 1) {
@@ -436,10 +435,7 @@
*/
last_rtc_update = new_sec - 658;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
delta_xsec = mulhdu( (tb_last_stamp-do_gtod.varp->tb_orig_stamp),
do_gtod.varp->tb_to_xs );
diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
index a8d5e83..7467ae5 100644
--- a/arch/ppc64/kernel/traps.c
+++ b/arch/ppc64/kernel/traps.c
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/kprobes.h>
#include <asm/kdebug.h>
#include <asm/pgtable.h>
@@ -220,7 +221,7 @@
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
}
-void single_step_exception(struct pt_regs *regs)
+void __kprobes single_step_exception(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
@@ -398,7 +399,7 @@
return 0;
}
-void program_check_exception(struct pt_regs *regs)
+void __kprobes program_check_exception(struct pt_regs *regs)
{
if (debugger_fault_handler(regs))
return;
diff --git a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c
index c0da455..ed6766e 100644
--- a/arch/ppc64/kernel/udbg.c
+++ b/arch/ppc64/kernel/udbg.c
@@ -1,5 +1,5 @@
/*
- * NS16550 Serial Port (uart) debugging stuff.
+ * polling mode stateless debugging stuff, originally for NS16550 Serial Ports
*
* c 2001 PPC 64 Team, IBM Corp
*
@@ -13,249 +13,24 @@
#define WANT_PPCDBG_TAB /* Only defined here */
#include <linux/config.h>
#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/console.h>
#include <asm/ppcdebug.h>
#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pmac_feature.h>
-extern u8 real_readb(volatile u8 __iomem *addr);
-extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+void (*udbg_putc)(unsigned char c);
+unsigned char (*udbg_getc)(void);
+int (*udbg_getc_poll)(void);
-struct NS16550 {
- /* this struct must be packed */
- unsigned char rbr; /* 0 */
- unsigned char ier; /* 1 */
- unsigned char fcr; /* 2 */
- unsigned char lcr; /* 3 */
- unsigned char mcr; /* 4 */
- unsigned char lsr; /* 5 */
- unsigned char msr; /* 6 */
- unsigned char scr; /* 7 */
-};
-
-#define thr rbr
-#define iir fcr
-#define dll rbr
-#define dlm ier
-#define dlab lcr
-
-#define LSR_DR 0x01 /* Data ready */
-#define LSR_OE 0x02 /* Overrun */
-#define LSR_PE 0x04 /* Parity error */
-#define LSR_FE 0x08 /* Framing error */
-#define LSR_BI 0x10 /* Break */
-#define LSR_THRE 0x20 /* Xmit holding register empty */
-#define LSR_TEMT 0x40 /* Xmitter empty */
-#define LSR_ERR 0x80 /* Error */
-
-static volatile struct NS16550 __iomem *udbg_comport;
-
-void udbg_init_uart(void __iomem *comport, unsigned int speed)
-{
- u16 dll = speed ? (115200 / speed) : 12;
-
- if (comport) {
- udbg_comport = (struct NS16550 __iomem *)comport;
- out_8(&udbg_comport->lcr, 0x00);
- out_8(&udbg_comport->ier, 0xff);
- out_8(&udbg_comport->ier, 0x00);
- out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */
- out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600,
- 3 = 38400, 12 = 9600 baud */
- out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero
- for fast rates; */
- out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */
- out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */
- out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */
- }
-}
-
-#ifdef CONFIG_PPC_PMAC
-
-#define SCC_TXRDY 4
-#define SCC_RXRDY 1
-
-static volatile u8 __iomem *sccc;
-static volatile u8 __iomem *sccd;
-
-static unsigned char scc_inittab[] = {
- 13, 0, /* set baud rate divisor */
- 12, 0,
- 14, 1, /* baud rate gen enable, src=rtxc */
- 11, 0x50, /* clocks = br gen */
- 5, 0xea, /* tx 8 bits, assert DTR & RTS */
- 4, 0x46, /* x16 clock, 1 stop */
- 3, 0xc1, /* rx enable, 8 bits */
-};
-
-void udbg_init_scc(struct device_node *np)
-{
- u32 *reg;
- unsigned long addr;
- int i, x;
-
- if (np == NULL)
- np = of_find_node_by_name(NULL, "escc");
- if (np == NULL || np->parent == NULL)
- return;
-
- udbg_printf("found SCC...\n");
- /* Get address within mac-io ASIC */
- reg = (u32 *)get_property(np, "reg", NULL);
- if (reg == NULL)
- return;
- addr = reg[0];
- udbg_printf("local addr: %lx\n", addr);
- /* Get address of mac-io PCI itself */
- reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
- if (reg == NULL)
- return;
- addr += reg[2];
- udbg_printf("final addr: %lx\n", addr);
-
- /* Setup for 57600 8N1 */
- addr += 0x20;
- sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
- sccc += addr & ~PAGE_MASK;
- sccd = sccc + 0x10;
-
- udbg_printf("ioremap result sccc: %p\n", sccc);
- mb();
-
- for (i = 20000; i != 0; --i)
- x = in_8(sccc);
- out_8(sccc, 0x09); /* reset A or B side */
- out_8(sccc, 0xc0);
- for (i = 0; i < sizeof(scc_inittab); ++i)
- out_8(sccc, scc_inittab[i]);
-
- ppc_md.udbg_putc = udbg_putc;
- ppc_md.udbg_getc = udbg_getc;
- ppc_md.udbg_getc_poll = udbg_getc_poll;
-
- udbg_puts("Hello World !\n");
-}
-
-#endif /* CONFIG_PPC_PMAC */
-
-#ifdef CONFIG_PPC_PMAC
-static void udbg_real_putc(unsigned char c)
-{
- while ((real_readb(sccc) & SCC_TXRDY) == 0)
- ;
- real_writeb(c, sccd);
- if (c == '\n')
- udbg_real_putc('\r');
-}
-
-void udbg_init_pmac_realmode(void)
-{
- sccc = (volatile u8 __iomem *)0x80013020ul;
- sccd = (volatile u8 __iomem *)0x80013030ul;
-
- ppc_md.udbg_putc = udbg_real_putc;
- ppc_md.udbg_getc = NULL;
- ppc_md.udbg_getc_poll = NULL;
-}
-#endif /* CONFIG_PPC_PMAC */
-
-#ifdef CONFIG_PPC_MAPLE
-void udbg_maple_real_putc(unsigned char c)
-{
- if (udbg_comport) {
- while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
- /* wait for idle */;
- real_writeb(c, &udbg_comport->thr); eieio();
- if (c == '\n') {
- /* Also put a CR. This is for convenience. */
- while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
- /* wait for idle */;
- real_writeb('\r', &udbg_comport->thr); eieio();
- }
- }
-}
-
-void udbg_init_maple_realmode(void)
-{
- udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;
-
- ppc_md.udbg_putc = udbg_maple_real_putc;
- ppc_md.udbg_getc = NULL;
- ppc_md.udbg_getc_poll = NULL;
-}
-#endif /* CONFIG_PPC_MAPLE */
-
-void udbg_putc(unsigned char c)
-{
- if (udbg_comport) {
- while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
- /* wait for idle */;
- out_8(&udbg_comport->thr, c);
- if (c == '\n') {
- /* Also put a CR. This is for convenience. */
- while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
- /* wait for idle */;
- out_8(&udbg_comport->thr, '\r');
- }
- }
-#ifdef CONFIG_PPC_PMAC
- else if (sccc) {
- while ((in_8(sccc) & SCC_TXRDY) == 0)
- ;
- out_8(sccd, c);
- if (c == '\n')
- udbg_putc('\r');
- }
-#endif /* CONFIG_PPC_PMAC */
-}
-
-int udbg_getc_poll(void)
-{
- if (udbg_comport) {
- if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
- return in_8(&udbg_comport->rbr);
- else
- return -1;
- }
-#ifdef CONFIG_PPC_PMAC
- else if (sccc) {
- if ((in_8(sccc) & SCC_RXRDY) != 0)
- return in_8(sccd);
- else
- return -1;
- }
-#endif /* CONFIG_PPC_PMAC */
- return -1;
-}
-
-unsigned char udbg_getc(void)
-{
- if (udbg_comport) {
- while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
- /* wait for char */;
- return in_8(&udbg_comport->rbr);
- }
-#ifdef CONFIG_PPC_PMAC
- else if (sccc) {
- while ((in_8(sccc) & SCC_RXRDY) == 0)
- ;
- return in_8(sccd);
- }
-#endif /* CONFIG_PPC_PMAC */
- return 0;
-}
-
+/* udbg library, used by xmon et al */
void udbg_puts(const char *s)
{
- if (ppc_md.udbg_putc) {
+ if (udbg_putc) {
char c;
if (s && *s != '\0') {
while ((c = *s++) != '\0')
- ppc_md.udbg_putc(c);
+ udbg_putc(c);
}
}
#if 0
@@ -270,12 +45,12 @@
int remain = n;
char c;
- if (!ppc_md.udbg_putc)
+ if (!udbg_putc)
return 0;
if (s && *s != '\0') {
while (((c = *s++) != '\0') && (remain-- > 0)) {
- ppc_md.udbg_putc(c);
+ udbg_putc(c);
}
}
@@ -287,12 +62,12 @@
char c, *p = buf;
int i;
- if (!ppc_md.udbg_getc)
+ if (!udbg_getc)
return 0;
for (i = 0; i < buflen; ++i) {
do {
- c = ppc_md.udbg_getc();
+ c = udbg_getc();
} while (c == 0x11 || c == 0x13);
if (c == 0)
break;
@@ -302,11 +77,6 @@
return i;
}
-void udbg_console_write(struct console *con, const char *s, unsigned int n)
-{
- udbg_write(s, n);
-}
-
#define UDBG_BUFSIZE 256
void udbg_printf(const char *fmt, ...)
{
@@ -319,6 +89,10 @@
va_end(args);
}
+/* PPCDBG stuff */
+
+u64 ppc64_debug_switch;
+
/* Special print used by PPCDBG() macro */
void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
{
@@ -358,3 +132,43 @@
{
return (flags & ppc64_debug_switch);
}
+
+/*
+ * Initialize the PPCDBG state. Called before relocation has been enabled.
+ */
+void __init ppcdbg_initialize(void)
+{
+ ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
+ /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
+}
+
+/*
+ * Early boot console based on udbg
+ */
+static void udbg_console_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ udbg_write(s, n);
+}
+
+static struct console udbg_console = {
+ .name = "udbg",
+ .write = udbg_console_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+void __init disable_early_printk(void)
+{
+ unregister_console(&udbg_console);
+}
+
+/* called by setup_system */
+void register_early_udbg_console(void)
+{
+ register_console(&udbg_console);
+}
+
+#if 0 /* if you want to use this as a regular output console */
+console_initcall(register_udbg_console);
+#endif
diff --git a/arch/ppc64/kernel/udbg_16550.c b/arch/ppc64/kernel/udbg_16550.c
new file mode 100644
index 0000000..9313574
--- /dev/null
+++ b/arch/ppc64/kernel/udbg_16550.c
@@ -0,0 +1,123 @@
+/*
+ * udbg for for NS16550 compatable serial ports
+ *
+ * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/udbg.h>
+#include <asm/io.h>
+
+extern u8 real_readb(volatile u8 __iomem *addr);
+extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+
+struct NS16550 {
+ /* this struct must be packed */
+ unsigned char rbr; /* 0 */
+ unsigned char ier; /* 1 */
+ unsigned char fcr; /* 2 */
+ unsigned char lcr; /* 3 */
+ unsigned char mcr; /* 4 */
+ unsigned char lsr; /* 5 */
+ unsigned char msr; /* 6 */
+ unsigned char scr; /* 7 */
+};
+
+#define thr rbr
+#define iir fcr
+#define dll rbr
+#define dlm ier
+#define dlab lcr
+
+#define LSR_DR 0x01 /* Data ready */
+#define LSR_OE 0x02 /* Overrun */
+#define LSR_PE 0x04 /* Parity error */
+#define LSR_FE 0x08 /* Framing error */
+#define LSR_BI 0x10 /* Break */
+#define LSR_THRE 0x20 /* Xmit holding register empty */
+#define LSR_TEMT 0x40 /* Xmitter empty */
+#define LSR_ERR 0x80 /* Error */
+
+static volatile struct NS16550 __iomem *udbg_comport;
+
+static void udbg_550_putc(unsigned char c)
+{
+ if (udbg_comport) {
+ while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
+ /* wait for idle */;
+ out_8(&udbg_comport->thr, c);
+ if (c == '\n')
+ udbg_550_putc('\r');
+ }
+}
+
+static int udbg_550_getc_poll(void)
+{
+ if (udbg_comport) {
+ if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
+ return in_8(&udbg_comport->rbr);
+ else
+ return -1;
+ }
+ return -1;
+}
+
+static unsigned char udbg_550_getc(void)
+{
+ if (udbg_comport) {
+ while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
+ /* wait for char */;
+ return in_8(&udbg_comport->rbr);
+ }
+ return 0;
+}
+
+void udbg_init_uart(void __iomem *comport, unsigned int speed)
+{
+ u16 dll = speed ? (115200 / speed) : 12;
+
+ if (comport) {
+ udbg_comport = (struct NS16550 __iomem *)comport;
+ out_8(&udbg_comport->lcr, 0x00);
+ out_8(&udbg_comport->ier, 0xff);
+ out_8(&udbg_comport->ier, 0x00);
+ out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */
+ out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600,
+ 3 = 38400, 12 = 9600 baud */
+ out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero
+ for fast rates; */
+ out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */
+ out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */
+ out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */
+ udbg_putc = udbg_550_putc;
+ udbg_getc = udbg_550_getc;
+ udbg_getc_poll = udbg_550_getc_poll;
+ }
+}
+
+#ifdef CONFIG_PPC_MAPLE
+void udbg_maple_real_putc(unsigned char c)
+{
+ if (udbg_comport) {
+ while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+ /* wait for idle */;
+ real_writeb(c, &udbg_comport->thr); eieio();
+ if (c == '\n')
+ udbg_maple_real_putc('\r');
+ }
+}
+
+void udbg_init_maple_realmode(void)
+{
+ udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;
+
+ udbg_putc = udbg_maple_real_putc;
+ udbg_getc = NULL;
+ udbg_getc_poll = NULL;
+}
+#endif /* CONFIG_PPC_MAPLE */
diff --git a/arch/ppc64/kernel/udbg_scc.c b/arch/ppc64/kernel/udbg_scc.c
new file mode 100644
index 0000000..c47fd6c
--- /dev/null
+++ b/arch/ppc64/kernel/udbg_scc.c
@@ -0,0 +1,136 @@
+/*
+ * udbg for for zilog scc ports as found on Apple PowerMacs
+ *
+ * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/udbg.h>
+#include <asm/processor.h>
+#include <asm/naca.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pmac_feature.h>
+
+extern u8 real_readb(volatile u8 __iomem *addr);
+extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+
+#define SCC_TXRDY 4
+#define SCC_RXRDY 1
+
+static volatile u8 __iomem *sccc;
+static volatile u8 __iomem *sccd;
+
+static void udbg_scc_putc(unsigned char c)
+{
+ if (sccc) {
+ while ((in_8(sccc) & SCC_TXRDY) == 0)
+ ;
+ out_8(sccd, c);
+ if (c == '\n')
+ udbg_scc_putc('\r');
+ }
+}
+
+static int udbg_scc_getc_poll(void)
+{
+ if (sccc) {
+ if ((in_8(sccc) & SCC_RXRDY) != 0)
+ return in_8(sccd);
+ else
+ return -1;
+ }
+ return -1;
+}
+
+static unsigned char udbg_scc_getc(void)
+{
+ if (sccc) {
+ while ((in_8(sccc) & SCC_RXRDY) == 0)
+ ;
+ return in_8(sccd);
+ }
+ return 0;
+}
+
+static unsigned char scc_inittab[] = {
+ 13, 0, /* set baud rate divisor */
+ 12, 0,
+ 14, 1, /* baud rate gen enable, src=rtxc */
+ 11, 0x50, /* clocks = br gen */
+ 5, 0xea, /* tx 8 bits, assert DTR & RTS */
+ 4, 0x46, /* x16 clock, 1 stop */
+ 3, 0xc1, /* rx enable, 8 bits */
+};
+
+void udbg_init_scc(struct device_node *np)
+{
+ u32 *reg;
+ unsigned long addr;
+ int i, x;
+
+ if (np == NULL)
+ np = of_find_node_by_name(NULL, "escc");
+ if (np == NULL || np->parent == NULL)
+ return;
+
+ udbg_printf("found SCC...\n");
+ /* Get address within mac-io ASIC */
+ reg = (u32 *)get_property(np, "reg", NULL);
+ if (reg == NULL)
+ return;
+ addr = reg[0];
+ udbg_printf("local addr: %lx\n", addr);
+ /* Get address of mac-io PCI itself */
+ reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
+ if (reg == NULL)
+ return;
+ addr += reg[2];
+ udbg_printf("final addr: %lx\n", addr);
+
+ /* Setup for 57600 8N1 */
+ addr += 0x20;
+ sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+ sccc += addr & ~PAGE_MASK;
+ sccd = sccc + 0x10;
+
+ udbg_printf("ioremap result sccc: %p\n", sccc);
+ mb();
+
+ for (i = 20000; i != 0; --i)
+ x = in_8(sccc);
+ out_8(sccc, 0x09); /* reset A or B side */
+ out_8(sccc, 0xc0);
+ for (i = 0; i < sizeof(scc_inittab); ++i)
+ out_8(sccc, scc_inittab[i]);
+
+ udbg_putc = udbg_scc_putc;
+ udbg_getc = udbg_scc_getc;
+ udbg_getc_poll = udbg_scc_getc_poll;
+
+ udbg_puts("Hello World !\n");
+}
+
+static void udbg_real_scc_putc(unsigned char c)
+{
+ while ((real_readb(sccc) & SCC_TXRDY) == 0)
+ ;
+ real_writeb(c, sccd);
+ if (c == '\n')
+ udbg_real_scc_putc('\r');
+}
+
+void udbg_init_pmac_realmode(void)
+{
+ sccc = (volatile u8 __iomem *)0x80013020ul;
+ sccd = (volatile u8 __iomem *)0x80013030ul;
+
+ udbg_putc = udbg_real_scc_putc;
+ udbg_getc = NULL;
+ udbg_getc_poll = NULL;
+}
diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S
index 4103cc1..0306510 100644
--- a/arch/ppc64/kernel/vmlinux.lds.S
+++ b/arch/ppc64/kernel/vmlinux.lds.S
@@ -15,6 +15,7 @@
*(.text .text.*)
SCHED_TEXT
LOCK_TEXT
+ KPROBES_TEXT
*(.fixup)
. = ALIGN(4096);
_etext = .;
diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c
index 20b0f37..772f071 100644
--- a/arch/ppc64/mm/fault.c
+++ b/arch/ppc64/mm/fault.c
@@ -29,6 +29,7 @@
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/module.h>
+#include <linux/kprobes.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -84,8 +85,8 @@
* The return value is 0 if the fault was handled, or the signal
* number if this is a kernel fault that can't be handled here.
*/
-int do_page_fault(struct pt_regs *regs, unsigned long address,
- unsigned long error_code)
+int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
index e7833c8..338771e 100644
--- a/arch/ppc64/mm/hugetlbpage.c
+++ b/arch/ppc64/mm/hugetlbpage.c
@@ -144,7 +144,8 @@
for (i = 0; i < NUM_LOW_AREAS; i++) {
if (! (areas & (1U << i)))
continue;
- asm volatile("slbie %0" : : "r" (i << SID_SHIFT));
+ asm volatile("slbie %0"
+ : : "r" ((i << SID_SHIFT) | SLBIE_C));
}
asm volatile("isync" : : : "memory");
@@ -164,7 +165,8 @@
continue;
for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
asm volatile("slbie %0"
- :: "r" ((i << HTLB_AREA_SHIFT) + (j << SID_SHIFT)));
+ :: "r" (((i << HTLB_AREA_SHIFT)
+ + (j << SID_SHIFT)) | SLBIE_C));
}
asm volatile("isync" : : : "memory");
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
index c02dc98..a14ab87 100644
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -392,6 +392,7 @@
addr = (unsigned long)__init_begin;
for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
+ memset((void *)addr, 0xcc, PAGE_SIZE);
ClearPageReserved(virt_to_page(addr));
set_page_count(virt_to_page(addr), 1);
free_page(addr);
@@ -552,27 +553,18 @@
/* Add all physical memory to the bootmem map, mark each area
* present.
*/
- for (i=0; i < lmb.memory.cnt; i++) {
- unsigned long base, size;
- unsigned long start_pfn, end_pfn;
-
- base = lmb.memory.region[i].base;
- size = lmb.memory.region[i].size;
-
- start_pfn = base >> PAGE_SHIFT;
- end_pfn = start_pfn + (size >> PAGE_SHIFT);
- memory_present(0, start_pfn, end_pfn);
-
- free_bootmem(base, size);
- }
+ for (i=0; i < lmb.memory.cnt; i++)
+ free_bootmem(lmb_start_pfn(&lmb.memory, i),
+ lmb_size_bytes(&lmb.memory, i));
/* reserve the sections we're already using */
- for (i=0; i < lmb.reserved.cnt; i++) {
- unsigned long base = lmb.reserved.region[i].base;
- unsigned long size = lmb.reserved.region[i].size;
+ for (i=0; i < lmb.reserved.cnt; i++)
+ reserve_bootmem(lmb_start_pfn(&lmb.reserved, i),
+ lmb_size_bytes(&lmb.reserved, i));
- reserve_bootmem(base, size);
- }
+ for (i=0; i < lmb.memory.cnt; i++)
+ memory_present(0, lmb_start_pfn(&lmb.memory, i),
+ lmb_end_pfn(&lmb.memory, i));
}
/*
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
index c3116f0..cb864b8 100644
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -440,8 +440,6 @@
for (i = start ; i < (start+size); i += MEMORY_INCREMENT)
numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
numa_domain;
- memory_present(numa_domain, start >> PAGE_SHIFT,
- (start + size) >> PAGE_SHIFT);
if (--ranges)
goto new_range;
@@ -483,7 +481,6 @@
for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT)
numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0;
- memory_present(0, 0, init_node_data[0].node_end_pfn);
}
static void __init dump_numa_topology(void)
@@ -695,6 +692,46 @@
size);
}
}
+ /*
+ * This loop may look famaliar, but we have to do it again
+ * after marking our reserved memory to mark memory present
+ * for sparsemem.
+ */
+ addr_cells = get_mem_addr_cells();
+ size_cells = get_mem_size_cells();
+ memory = NULL;
+ while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
+ unsigned long mem_start, mem_size;
+ int numa_domain, ranges;
+ unsigned int *memcell_buf;
+ unsigned int len;
+
+ memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
+ if (!memcell_buf || len <= 0)
+ continue;
+
+ ranges = memory->n_addrs; /* ranges in cell */
+new_range2:
+ mem_start = read_n_cells(addr_cells, &memcell_buf);
+ mem_size = read_n_cells(size_cells, &memcell_buf);
+ if (numa_enabled) {
+ numa_domain = of_node_numa_domain(memory);
+ if (numa_domain >= MAX_NUMNODES)
+ numa_domain = 0;
+ } else
+ numa_domain = 0;
+
+ if (numa_domain != nid)
+ continue;
+
+ mem_size = numa_enforce_memory_limit(mem_start, mem_size);
+ memory_present(numa_domain, mem_start >> PAGE_SHIFT,
+ (mem_start + mem_size) >> PAGE_SHIFT);
+
+ if (--ranges) /* process all ranges in cell */
+ goto new_range2;
+ }
+
}
}
diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c
index 244150a..0473953 100644
--- a/arch/ppc64/mm/slb.c
+++ b/arch/ppc64/mm/slb.c
@@ -87,8 +87,8 @@
int i;
asm volatile("isync" : : : "memory");
for (i = 0; i < offset; i++) {
- esid_data = (unsigned long)get_paca()->slb_cache[i]
- << SID_SHIFT;
+ esid_data = ((unsigned long)get_paca()->slb_cache[i]
+ << SID_SHIFT) | SLBIE_C;
asm volatile("slbie %0" : : "r" (esid_data));
}
asm volatile("isync" : : : "memory");
diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S
index bab2558..698d6b9 100644
--- a/arch/ppc64/mm/slb_low.S
+++ b/arch/ppc64/mm/slb_low.S
@@ -97,25 +97,21 @@
lhz r9,PACAHIGHHTLBAREAS(r13)
srdi r11,r3,(HTLB_AREA_SHIFT-SID_SHIFT)
srd r9,r9,r11
- andi. r9,r9,1
- bne 5f
-
- li r11,SLB_VSID_USER
-
- cmpldi r3,16
- bge 6f
-
- lhz r9,PACALOWHTLBAREAS(r13)
- srd r9,r9,r3
- andi. r9,r9,1
-
- beq 6f
-
-5: li r11,SLB_VSID_USER|SLB_VSID_L
+ lhz r11,PACALOWHTLBAREAS(r13)
+ srd r11,r11,r3
+ or r9,r9,r11
END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
#endif /* CONFIG_HUGETLB_PAGE */
-6: ld r9,PACACONTEXTID(r13)
+ li r11,SLB_VSID_USER
+
+#ifdef CONFIG_HUGETLB_PAGE
+BEGIN_FTR_SECTION
+ rldimi r11,r9,8,55 /* shift masked bit into SLB_VSID_L */
+END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
+#endif /* CONFIG_HUGETLB_PAGE */
+
+ ld r9,PACACONTEXTID(r13)
rldimi r3,r9,USER_ESID_BITS,0
9: /* r3 = protovsid, r11 = flags, r10 = esid_data, cr7 = <>KERNELBASE */
diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c
index 4acd1a4..e5f5727 100644
--- a/arch/ppc64/oprofile/common.c
+++ b/arch/ppc64/oprofile/common.c
@@ -16,11 +16,9 @@
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/pmc.h>
+#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
-#include "op_impl.h"
-
-extern struct op_ppc64_model op_model_rs64;
-extern struct op_ppc64_model op_model_power4;
static struct op_ppc64_model *model;
static struct op_counter_config ctr[OP_MAX_COUNTER];
@@ -123,53 +121,13 @@
int __init oprofile_arch_init(struct oprofile_operations *ops)
{
- unsigned int pvr;
+ if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
+ return -ENODEV;
- pvr = mfspr(SPRN_PVR);
+ model = cur_cpu_spec->oprofile_model;
+ model->num_counters = cur_cpu_spec->num_pmcs;
- switch (PVR_VER(pvr)) {
- case PV_630:
- case PV_630p:
- model = &op_model_rs64;
- model->num_counters = 8;
- ops->cpu_type = "ppc64/power3";
- break;
-
- case PV_NORTHSTAR:
- case PV_PULSAR:
- case PV_ICESTAR:
- case PV_SSTAR:
- model = &op_model_rs64;
- model->num_counters = 8;
- ops->cpu_type = "ppc64/rs64";
- break;
-
- case PV_POWER4:
- case PV_POWER4p:
- model = &op_model_power4;
- model->num_counters = 8;
- ops->cpu_type = "ppc64/power4";
- break;
-
- case PV_970:
- case PV_970FX:
- case PV_970MP:
- model = &op_model_power4;
- model->num_counters = 8;
- ops->cpu_type = "ppc64/970";
- break;
-
- case PV_POWER5:
- case PV_POWER5p:
- model = &op_model_power4;
- model->num_counters = 6;
- ops->cpu_type = "ppc64/power5";
- break;
-
- default:
- return -ENODEV;
- }
-
+ ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
ops->create_files = op_ppc64_create_files;
ops->setup = op_ppc64_setup;
ops->shutdown = op_ppc64_shutdown;
diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c
index 3d103d6..32b2bb5 100644
--- a/arch/ppc64/oprofile/op_model_power4.c
+++ b/arch/ppc64/oprofile/op_model_power4.c
@@ -16,14 +16,12 @@
#include <asm/cputable.h>
#include <asm/systemcfg.h>
#include <asm/rtas.h>
+#include <asm/oprofile_impl.h>
#define dbg(args...)
-#include "op_impl.h"
-
static unsigned long reset_value[OP_MAX_COUNTER];
-static int num_counters;
static int oprofile_running;
static int mmcra_has_sihv;
@@ -45,8 +43,6 @@
{
int i;
- num_counters = num_ctrs;
-
/*
* SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
* However we disable it on all POWER4 until we verify it works
@@ -68,7 +64,7 @@
backtrace_spinlocks = sys->backtrace_spinlocks;
- for (i = 0; i < num_counters; ++i)
+ for (i = 0; i < cur_cpu_spec->num_pmcs; ++i)
reset_value[i] = 0x80000000UL - ctr[i].count;
/* setup user and kernel profiling */
@@ -121,7 +117,7 @@
/* set the PMM bit (see comment below) */
mtmsrd(mfmsr() | MSR_PMM);
- for (i = 0; i < num_counters; ++i) {
+ for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
if (ctr[i].enabled) {
ctr_write(i, reset_value[i]);
} else {
@@ -272,7 +268,7 @@
/* set the PMM bit (see comment below) */
mtmsrd(mfmsr() | MSR_PMM);
- for (i = 0; i < num_counters; ++i) {
+ for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
val = ctr_read(i);
if (val < 0) {
if (oprofile_running && ctr[i].enabled) {
diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c
index bcec506..08c5b33 100644
--- a/arch/ppc64/oprofile/op_model_rs64.c
+++ b/arch/ppc64/oprofile/op_model_rs64.c
@@ -14,11 +14,10 @@
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
#define dbg(args...)
-#include "op_impl.h"
-
static void ctrl_write(unsigned int i, unsigned int val)
{
unsigned int tmp = 0;
diff --git a/arch/ppc64/xmon/start.c b/arch/ppc64/xmon/start.c
index f86b584..e50c158 100644
--- a/arch/ppc64/xmon/start.c
+++ b/arch/ppc64/xmon/start.c
@@ -61,7 +61,9 @@
int
xmon_read_poll(void)
{
- return udbg_getc_poll();
+ if (udbg_getc_poll)
+ return udbg_getc_poll();
+ return -1;
}
FILE *xmon_stdin;
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index 960ba60..bc59282 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -62,7 +62,7 @@
} debug_sprintf_entry_t;
-extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+extern void tod_to_timeval(uint64_t todval, struct timespec *xtime);
/* internal function prototyes */
@@ -374,9 +374,24 @@
{
int i,j;
debug_info_t* rc;
+ unsigned long flags;
- rc = debug_info_alloc(in->name, in->pages_per_area, in->nr_areas,
- in->buf_size, in->level, mode);
+ /* get a consistent copy of the debug areas */
+ do {
+ rc = debug_info_alloc(in->name, in->pages_per_area,
+ in->nr_areas, in->buf_size, in->level, mode);
+ spin_lock_irqsave(&in->lock, flags);
+ if(!rc)
+ goto out;
+ /* has something changed in the meantime ? */
+ if((rc->pages_per_area == in->pages_per_area) &&
+ (rc->nr_areas == in->nr_areas)) {
+ break;
+ }
+ spin_unlock_irqrestore(&in->lock, flags);
+ debug_info_free(rc);
+ } while (1);
+
if(!rc || (mode == NO_AREAS))
goto out;
@@ -386,6 +401,7 @@
}
}
out:
+ spin_unlock_irqrestore(&in->lock, flags);
return rc;
}
@@ -593,19 +609,15 @@
debug_info_t *debug_info, *debug_info_snapshot;
down(&debug_lock);
-
- /* find debug log and view */
- debug_info = debug_area_first;
- while(debug_info != NULL){
- for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
- if (!debug_info->views[i])
- continue;
- else if (debug_info->debugfs_entries[i] ==
- file->f_dentry) {
- goto found; /* found view ! */
- }
+ debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip;
+ /* find debug view */
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (!debug_info->views[i])
+ continue;
+ else if (debug_info->debugfs_entries[i] ==
+ file->f_dentry) {
+ goto found; /* found view ! */
}
- debug_info = debug_info->next;
}
/* no entry found */
rc = -EINVAL;
@@ -833,7 +845,7 @@
debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
int exception)
{
- STCK(active->id.stck);
+ active->id.stck = get_clock();
active->id.fields.cpuid = smp_processor_id();
active->caller = __builtin_return_address(0);
active->id.fields.exception = exception;
@@ -1078,7 +1090,7 @@
if (view->input_proc)
mode |= S_IWUSR;
pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
- NULL, &debug_file_ops);
+ id , &debug_file_ops);
if (!pde){
printk(KERN_WARNING "debug: debugfs_create_file() failed!"\
" Cannot register view %s/%s\n", id->name,view->name);
@@ -1432,7 +1444,7 @@
debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
int area, debug_entry_t * entry, char *out_buf)
{
- struct timeval time_val;
+ struct timespec time_spec;
unsigned long long time;
char *except_str;
unsigned long caller;
@@ -1443,7 +1455,7 @@
time = entry->id.stck;
/* adjust todclock to 1970 */
time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
- tod_to_timeval(time, &time_val);
+ tod_to_timeval(time, &time_spec);
if (entry->id.fields.exception)
except_str = "*";
@@ -1451,7 +1463,7 @@
except_str = "-";
caller = ((unsigned long) entry->caller) & PSW_ADDR_INSN;
rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %p ",
- area, time_val.tv_sec, time_val.tv_usec, level,
+ area, time_spec.tv_sec, time_spec.tv_nsec / 1000, level,
except_str, entry->id.fields.cpuid, (void *) caller);
return rc;
}
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 1a271b1..cbe7d6a 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -138,14 +138,14 @@
st %r12,__SF_BACKCHAIN(%r15) # clear back chain
.endm
- .macro RESTORE_ALL sync
- mvc __LC_RETURN_PSW(8),SP_PSW(%r15) # move user PSW to lowcore
+ .macro RESTORE_ALL psworg,sync
+ mvc \psworg(8),SP_PSW(%r15) # move user PSW to lowcore
.if !\sync
- ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
+ ni \psworg+1,0xfd # clear wait state bit
.endif
lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user
STORE_TIMER __LC_EXIT_TIMER
- lpsw __LC_RETURN_PSW # back to caller
+ lpsw \psworg # back to caller
.endm
/*
@@ -235,7 +235,7 @@
tm __TI_flags+3(%r9),_TIF_WORK_SVC
bnz BASED(sysc_work) # there is work to do (signals etc.)
sysc_leave:
- RESTORE_ALL 1
+ RESTORE_ALL __LC_RETURN_PSW,1
#
# recheck if there is more work to do
@@ -312,8 +312,6 @@
la %r14,BASED(sysc_return) # load adr. of system return
br %r1 # branch to do_single_step
-__critical_end:
-
#
# call trace before and after sys_call
#
@@ -571,7 +569,8 @@
tm __TI_flags+3(%r9),_TIF_WORK_INT
bnz BASED(io_work) # there is work to do (signals etc.)
io_leave:
- RESTORE_ALL 0
+ RESTORE_ALL __LC_RETURN_PSW,0
+io_done:
#ifdef CONFIG_PREEMPT
io_preempt:
@@ -621,7 +620,7 @@
#
io_mcck_pending:
l %r1,BASED(.Ls390_handle_mcck)
- l %r14,BASED(io_work_loop)
+ la %r14,BASED(io_work_loop)
br %r1 # TIF bit will be cleared by handler
#
@@ -674,6 +673,8 @@
basr %r14,%r1
b BASED(io_return)
+__critical_end:
+
/*
* Machine check handler routines
*/
@@ -681,6 +682,7 @@
.globl mcck_int_handler
mcck_int_handler:
spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer
+ mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+32
la %r12,__LC_MCK_OLD_PSW
@@ -693,17 +695,8 @@
mvc __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
mvc __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
mvc __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
-0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
- bno BASED(mcck_no_vtime) # no -> skip cleanup critical
- tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
- bz BASED(mcck_no_vtime)
- UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
- UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
- mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
-mcck_no_vtime:
#endif
-0:
- tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+0: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
bno BASED(mcck_int_main) # no -> skip cleanup critical
tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
bnz BASED(mcck_int_main) # from user -> load async stack
@@ -720,6 +713,16 @@
be BASED(0f)
l %r15,__LC_PANIC_STACK # load panic stack
0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ bno BASED(mcck_no_vtime) # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+ bz BASED(mcck_no_vtime)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Ls390_mcck)
@@ -737,7 +740,7 @@
l %r1,BASED(.Ls390_handle_mcck)
basr %r14,%r1 # call machine check handler
mcck_return:
- RESTORE_ALL 0
+ RESTORE_ALL __LC_RETURN_MCCK_PSW,0
#ifdef CONFIG_SMP
/*
@@ -803,6 +806,10 @@
.long sysc_leave + 0x80000000, sysc_work_loop + 0x80000000
cleanup_table_sysc_work_loop:
.long sysc_work_loop + 0x80000000, sysc_reschedule + 0x80000000
+cleanup_table_io_leave:
+ .long io_leave + 0x80000000, io_done + 0x80000000
+cleanup_table_io_work_loop:
+ .long io_work_loop + 0x80000000, io_mcck_pending + 0x80000000
cleanup_critical:
clc 4(4,%r12),BASED(cleanup_table_system_call)
@@ -825,10 +832,26 @@
clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
bl BASED(cleanup_sysc_return)
0:
+ clc 4(4,%r12),BASED(cleanup_table_io_leave)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_io_leave+4)
+ bl BASED(cleanup_io_leave)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_io_work_loop)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_io_work_loop+4)
+ bl BASED(cleanup_io_return)
+0:
br %r14
cleanup_system_call:
mvc __LC_RETURN_PSW(8),0(%r12)
+ c %r12,BASED(.Lmck_old_psw)
+ be BASED(0f)
+ la %r12,__LC_SAVE_AREA+16
+ b BASED(1f)
+0: la %r12,__LC_SAVE_AREA+32
+1:
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4)
bh BASED(0f)
@@ -838,11 +861,13 @@
#endif
clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn)
bh BASED(0f)
- mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
-0: st %r13,__LC_SAVE_AREA+20
+ mvc __LC_SAVE_AREA(16),0(%r12)
+0: st %r13,4(%r12)
+ st %r12,__LC_SAVE_AREA+48 # argh
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
- st %r15,__LC_SAVE_AREA+28
+ l %r12,__LC_SAVE_AREA+48 # argh
+ st %r15,12(%r12)
lh %r7,0x8a
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
cleanup_vtime:
@@ -879,17 +904,21 @@
cleanup_sysc_leave:
clc 4(4,%r12),BASED(cleanup_sysc_leave_insn)
- be BASED(0f)
+ be BASED(2f)
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4)
- be BASED(0f)
+ be BASED(2f)
#endif
mvc __LC_RETURN_PSW(8),SP_PSW(%r15)
- mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
- lm %r0,%r11,SP_R0(%r15)
+ c %r12,BASED(.Lmck_old_psw)
+ bne BASED(0f)
+ mvc __LC_SAVE_AREA+32(16),SP_R12(%r15)
+ b BASED(1f)
+0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
+1: lm %r0,%r11,SP_R0(%r15)
l %r15,SP_R15(%r15)
-0: la %r12,__LC_RETURN_PSW
+2: la %r12,__LC_RETURN_PSW
br %r14
cleanup_sysc_leave_insn:
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -897,6 +926,36 @@
#endif
.long sysc_leave + 10 + 0x80000000
+cleanup_io_return:
+ mvc __LC_RETURN_PSW(4),0(%r12)
+ mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_work_loop)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+
+cleanup_io_leave:
+ clc 4(4,%r12),BASED(cleanup_io_leave_insn)
+ be BASED(2f)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ clc 4(4,%r12),BASED(cleanup_io_leave_insn+4)
+ be BASED(2f)
+#endif
+ mvc __LC_RETURN_PSW(8),SP_PSW(%r15)
+ c %r12,BASED(.Lmck_old_psw)
+ bne BASED(0f)
+ mvc __LC_SAVE_AREA+32(16),SP_R12(%r15)
+ b BASED(1f)
+0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
+1: lm %r0,%r11,SP_R0(%r15)
+ l %r15,SP_R15(%r15)
+2: la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_io_leave_insn:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .long io_leave + 18 + 0x80000000
+#endif
+ .long io_leave + 14 + 0x80000000
+
/*
* Integer constants
*/
@@ -918,6 +977,7 @@
.Ls390_mcck: .long s390_do_machine_check
.Ls390_handle_mcck:
.long s390_handle_mcck
+.Lmck_old_psw: .long __LC_MCK_OLD_PSW
.Ldo_IRQ: .long do_IRQ
.Ldo_extint: .long do_extint
.Ldo_signal: .long do_signal
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index d9f2291..fb77b72 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -131,14 +131,14 @@
stg %r12,__SF_BACKCHAIN(%r15)
.endm
- .macro RESTORE_ALL sync
- mvc __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore
+ .macro RESTORE_ALL psworg,sync
+ mvc \psworg(16),SP_PSW(%r15) # move user PSW to lowcore
.if !\sync
- ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
+ ni \psworg+1,0xfd # clear wait state bit
.endif
lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user
STORE_TIMER __LC_EXIT_TIMER
- lpswe __LC_RETURN_PSW # back to caller
+ lpswe \psworg # back to caller
.endm
/*
@@ -214,8 +214,8 @@
sysc_do_restart:
larl %r10,sys_call_table
#ifdef CONFIG_S390_SUPPORT
- tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ?
- jo sysc_noemu
+ tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ?
+ jno sysc_noemu
larl %r10,sys_call_table_emu # use 31 bit emulation system calls
sysc_noemu:
#endif
@@ -233,7 +233,7 @@
tm __TI_flags+7(%r9),_TIF_WORK_SVC
jnz sysc_work # there is work to do (signals etc.)
sysc_leave:
- RESTORE_ALL 1
+ RESTORE_ALL __LC_RETURN_PSW,1
#
# recheck if there is more work to do
@@ -308,8 +308,6 @@
jg do_single_step # branch to do_sigtrap
-__critical_end:
-
#
# call syscall_trace before and after system call
# special linkage: %r12 contains the return address for trace_svc
@@ -612,7 +610,8 @@
tm __TI_flags+7(%r9),_TIF_WORK_INT
jnz io_work # there is work to do (signals etc.)
io_leave:
- RESTORE_ALL 0
+ RESTORE_ALL __LC_RETURN_PSW,0
+io_done:
#ifdef CONFIG_PREEMPT
io_preempt:
@@ -711,6 +710,8 @@
brasl %r14,do_extint
j io_return
+__critical_end:
+
/*
* Machine check handler routines
*/
@@ -718,6 +719,7 @@
mcck_int_handler:
la %r1,4095 # revalidate r1
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
+ mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r1)
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+64
la %r12,__LC_MCK_OLD_PSW
@@ -730,17 +732,8 @@
mvc __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
mvc __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
mvc __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
-0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
- jno mcck_no_vtime # no -> no timer update
- tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
- jz mcck_no_vtime
- UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
- UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
- mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
-mcck_no_vtime:
#endif
-0:
- tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+0: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
jno mcck_int_main # no -> skip cleanup critical
tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
jnz mcck_int_main # from user -> load kernel stack
@@ -756,6 +749,16 @@
jz 0f
lg %r15,__LC_PANIC_STACK # load panic stack
0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ jno mcck_no_vtime # no -> no timer update
+ tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+ jz mcck_no_vtime
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
la %r2,SP_PTREGS(%r15) # load pt_regs
brasl %r14,s390_do_machine_check
@@ -771,7 +774,7 @@
jno mcck_return
brasl %r14,s390_handle_mcck
mcck_return:
- RESTORE_ALL 0
+ RESTORE_ALL __LC_RETURN_MCCK_PSW,0
#ifdef CONFIG_SMP
/*
@@ -833,6 +836,10 @@
.quad sysc_leave, sysc_work_loop
cleanup_table_sysc_work_loop:
.quad sysc_work_loop, sysc_reschedule
+cleanup_table_io_leave:
+ .quad io_leave, io_done
+cleanup_table_io_work_loop:
+ .quad io_work_loop, io_mcck_pending
cleanup_critical:
clc 8(8,%r12),BASED(cleanup_table_system_call)
@@ -855,10 +862,26 @@
clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
jl cleanup_sysc_return
0:
+ clc 8(8,%r12),BASED(cleanup_table_io_leave)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_io_leave+8)
+ jl cleanup_io_leave
+0:
+ clc 8(8,%r12),BASED(cleanup_table_io_work_loop)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_io_work_loop+8)
+ jl cleanup_io_return
+0:
br %r14
cleanup_system_call:
mvc __LC_RETURN_PSW(16),0(%r12)
+ cghi %r12,__LC_MCK_OLD_PSW
+ je 0f
+ la %r12,__LC_SAVE_AREA+32
+ j 1f
+0: la %r12,__LC_SAVE_AREA+64
+1:
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
jh 0f
@@ -868,11 +891,13 @@
#endif
clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
jh 0f
- mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
-0: stg %r13,__LC_SAVE_AREA+40
+ mvc __LC_SAVE_AREA(32),0(%r12)
+0: stg %r13,8(%r12)
+ stg %r12,__LC_SAVE_AREA+96 # argh
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
- stg %r15,__LC_SAVE_AREA+56
+ lg %r12,__LC_SAVE_AREA+96 # argh
+ stg %r15,24(%r12)
llgh %r7,__LC_SVC_INT_CODE
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
cleanup_vtime:
@@ -909,17 +934,21 @@
cleanup_sysc_leave:
clc 8(8,%r12),BASED(cleanup_sysc_leave_insn)
- je 0f
+ je 2f
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8)
- je 0f
+ je 2f
#endif
mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
- mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
- lmg %r0,%r11,SP_R0(%r15)
+ cghi %r12,__LC_MCK_OLD_PSW
+ jne 0f
+ mvc __LC_SAVE_AREA+64(32),SP_R12(%r15)
+ j 1f
+0: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
+1: lmg %r0,%r11,SP_R0(%r15)
lg %r15,SP_R15(%r15)
-0: la %r12,__LC_RETURN_PSW
+2: la %r12,__LC_RETURN_PSW
br %r14
cleanup_sysc_leave_insn:
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -927,6 +956,36 @@
#endif
.quad sysc_leave + 12
+cleanup_io_return:
+ mvc __LC_RETURN_PSW(8),0(%r12)
+ mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_work_loop)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+
+cleanup_io_leave:
+ clc 8(8,%r12),BASED(cleanup_io_leave_insn)
+ je 2f
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ clc 8(8,%r12),BASED(cleanup_io_leave_insn+8)
+ je 2f
+#endif
+ mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
+ cghi %r12,__LC_MCK_OLD_PSW
+ jne 0f
+ mvc __LC_SAVE_AREA+64(32),SP_R12(%r15)
+ j 1f
+0: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
+1: lmg %r0,%r11,SP_R0(%r15)
+ lg %r15,SP_R15(%r15)
+2: la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_io_leave_insn:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .quad io_leave + 20
+#endif
+ .quad io_leave + 16
+
/*
* Integer constants
*/
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 8ca4856..2fd75da 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -139,10 +139,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 75fde94..856a971 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -563,12 +563,14 @@
* interrupt. pfault_wait is valid. Set pfault_wait
* back to zero and wake up the process. This can
* safely be done because the task is still sleeping
- * and can't procude new pfaults. */
+ * and can't produce new pfaults. */
tsk->thread.pfault_wait = 0;
wake_up_process(tsk);
+ put_task_struct(tsk);
}
} else {
/* signal bit not set -> a real page is missing. */
+ get_task_struct(tsk);
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
/* Completion interrupt was faster than the initial
@@ -578,6 +580,7 @@
* mode and can't produce new pfaults. */
tsk->thread.pfault_wait = 0;
set_task_state(tsk, TASK_RUNNING);
+ put_task_struct(tsk);
} else
set_tsk_need_resched(tsk);
}
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index adc8109f..3e804c7 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -37,6 +37,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
source "init/Kconfig"
menu "System type"
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index df7a9b9..02ca699 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -215,10 +215,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
@@ -234,7 +231,7 @@
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
{
do_timer(regs);
#ifndef CONFIG_SMP
@@ -252,7 +249,7 @@
* RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -285,7 +282,7 @@
* locally disabled. -arca
*/
write_seqlock(&xtime_lock);
- do_timer_interrupt(irq, NULL, regs);
+ do_timer_interrupt(irq, regs);
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
index 4c3e533..fb35b45 100644
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -29,10 +29,6 @@
bool
default y
-config LOG_BUF_SHIFT
- int
- default 14
-
config RWSEM_XCHGADD_ALGORITHM
bool
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
index 6c84da3..f4a62a1 100644
--- a/arch/sh64/kernel/time.c
+++ b/arch/sh64/kernel/time.c
@@ -247,10 +247,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
@@ -303,7 +300,7 @@
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
{
unsigned long long current_ctc;
asm ("getcon cr62, %0" : "=r" (current_ctc));
@@ -328,7 +325,7 @@
* RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -361,7 +358,7 @@
* locally disabled. -arca
*/
write_lock(&xtime_lock);
- do_timer_interrupt(irq, NULL, regs);
+ do_timer_interrupt(irq, regs);
write_unlock(&xtime_lock);
return IRQ_HANDLED;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index aca028a..aba0539 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -211,6 +211,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
config SUN_PM
bool
default y
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 597d3ff..36a4069 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -840,10 +840,7 @@
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_nsec;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
return 0;
}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 8faa8dc..5d974a2 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -175,7 +175,6 @@
EXPORT_SYMBOL(get_auxio);
#endif
EXPORT_SYMBOL(request_fast_irq);
-EXPORT_SYMBOL(io_remap_page_range);
EXPORT_SYMBOL(io_remap_pfn_range);
/* P3: iounit_xxx may be needed, sun4d users */
/* EXPORT_SYMBOL(iounit_map_dma_init); */
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 3b759ae..bc015e9 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -139,7 +139,7 @@
/* Determine when to update the Mostek clock. */
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -554,10 +554,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
return 0;
}
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
index db27eee..20ccb95 100644
--- a/arch/sparc/mm/generic.c
+++ b/arch/sparc/mm/generic.c
@@ -16,31 +16,6 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
-static inline void forget_pte(pte_t page)
-{
-#if 0 /* old 2.4 code */
- if (pte_none(page))
- return;
- if (pte_present(page)) {
- unsigned long pfn = pte_pfn(page);
- struct page *ptpage;
- if (!pfn_valid(pfn))
- return;
- ptpage = pfn_to_page(pfn);
- if (PageReserved(ptpage))
- return;
- page_cache_release(ptpage);
- return;
- }
- swap_free(pte_to_swp_entry(page));
-#else
- if (!pte_none(page)) {
- printk("forget_pte: old mapping existed!\n");
- BUG();
- }
-#endif
-}
-
/* Remap IO memory, the same way as remap_pfn_range(), but use
* the obio memory space.
*
@@ -60,7 +35,6 @@
pte_t oldpage = *pte;
pte_clear(mm, address, pte);
set_pte(pte, mk_pte_io(offset, prot, space));
- forget_pte(oldpage);
address += PAGE_SIZE;
offset += PAGE_SIZE;
pte++;
@@ -88,37 +62,6 @@
return 0;
}
-int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
-{
- int error = 0;
- pgd_t * dir;
- unsigned long beg = from;
- unsigned long end = from + size;
- struct mm_struct *mm = vma->vm_mm;
-
- prot = __pgprot(pg_iobits);
- offset -= from;
- dir = pgd_offset(mm, from);
- flush_cache_range(vma, beg, end);
-
- spin_lock(&mm->page_table_lock);
- while (from < end) {
- pmd_t *pmd = pmd_alloc(current->mm, dir, from);
- error = -ENOMEM;
- if (!pmd)
- break;
- error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
- if (error)
- break;
- from = (from + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- }
- spin_unlock(&mm->page_table_lock);
-
- flush_tlb_range(vma, beg, end);
- return error;
-}
-
int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 9afd28e..1e9d863 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -5,6 +5,16 @@
mainmenu "Linux/UltraSPARC Kernel Configuration"
+config SPARC64
+ bool
+ default y
+ help
+ SPARC is a family of RISC microprocessors designed and marketed by
+ Sun Microsystems, incorporated. This port covers the newer 64-bit
+ UltraSPARC. The UltraLinux project maintains both the SPARC32 and
+ SPARC64 ports; its web page is available at
+ <http://www.ultralinux.org/>.
+
config 64BIT
def_bool y
@@ -16,6 +26,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
choice
prompt "Kernel page size"
default SPARC64_PAGE_SIZE_8KB
@@ -71,75 +85,6 @@
menu "General machine setup"
-config BBC_I2C
- tristate "UltraSPARC-III bootbus i2c controller driver"
- depends on PCI
- help
- The BBC devices on the UltraSPARC III have two I2C controllers. The
- first I2C controller connects mainly to configuration PROMs (NVRAM,
- CPU configuration, DIMM types, etc.). The second I2C controller
- connects to environmental control devices such as fans and
- temperature sensors. The second controller also connects to the
- smartcard reader, if present. Say Y to enable support for these.
-
-config VT
- bool "Virtual terminal" if EMBEDDED
- select INPUT
- default y
- ---help---
- If you say Y here, you will get support for terminal devices with
- display and keyboard devices. These are called "virtual" because you
- can run several virtual terminals (also called virtual consoles) on
- one physical terminal. This is rather useful, for example one
- virtual terminal can collect system messages and warnings, another
- one can be used for a text-mode user session, and a third could run
- an X session, all in parallel. Switching between virtual terminals
- is done with certain key combinations, usually Alt-<function key>.
-
- The setterm command ("man setterm") can be used to change the
- properties (such as colors or beeping) of a virtual terminal. The
- man page console_codes(4) ("man console_codes") contains the special
- character sequences that can be used to change those properties
- directly. The fonts used on virtual terminals can be changed with
- the setfont ("man setfont") command and the key bindings are defined
- with the loadkeys ("man loadkeys") command.
-
- You need at least one virtual terminal device in order to make use
- of your keyboard and monitor. Therefore, only people configuring an
- embedded system would want to say N here in order to save some
- memory; the only way to log into such a system is then via a serial
- or network connection.
-
- If unsure, say Y, or else you won't be able to do much with your new
- shiny Linux system :-)
-
-config VT_CONSOLE
- bool "Support for console on virtual terminal" if EMBEDDED
- depends on VT
- default y
- ---help---
- The system console is the device which receives all kernel messages
- and warnings and which allows logins in single user mode. If you
- answer Y here, a virtual terminal (the device used to interact with
- a physical terminal) can be used as system console. This is the most
- common mode of operations, so you should say Y here unless you want
- the kernel messages be output only to a serial port (in which case
- you should say Y to "Console on serial port", below).
-
- If you do say Y here, by default the currently visible virtual
- terminal (/dev/tty0) will be used as system console. You can change
- that with a kernel command line option such as "console=tty3" which
- would use the third virtual terminal as system console. (Try "man
- bootparam" or see the documentation of your boot loader (lilo or
- loadlin) about how to pass options to the kernel at boot time.)
-
- If unsure, say Y.
-
-config HW_CONSOLE
- bool
- depends on VT
- default y
-
config SMP
bool "Symmetric multi-processing support"
---help---
@@ -205,17 +150,6 @@
If in doubt, say N.
-# Identify this as a Sparc64 build
-config SPARC64
- bool
- default y
- help
- SPARC is a family of RISC microprocessors designed and marketed by
- Sun Microsystems, incorporated. This port covers the newer 64-bit
- UltraSPARC. The UltraLinux project maintains both the SPARC32 and
- SPARC64 ports; its web page is available at
- <http://www.ultralinux.org/>.
-
# Global things across all Sun machines.
config RWSEM_GENERIC_SPINLOCK
bool
@@ -246,6 +180,10 @@
endchoice
+endmenu
+
+source "mm/Kconfig"
+
config GENERIC_ISA_DMA
bool
default y
@@ -344,33 +282,6 @@
bool
default PCI
-config RTC
- tristate
- depends on PCI
- default y
- ---help---
- If you say Y here and create a character special file /dev/rtc with
- major number 10 and minor number 135 using mknod ("man mknod"), you
- will get access to the real time clock (or hardware clock) built
- into your computer.
-
- Every PC has such a clock built in. It can be used to generate
- signals from as low as 1Hz up to 8192Hz, and can also be used
- as a 24 hour alarm. It reports status information via the file
- /proc/driver/rtc and its behaviour is set by various ioctls on
- /dev/rtc.
-
- If you run Linux on a multiprocessor machine and said Y to
- "Symmetric Multi Processing" above, you should say Y here to read
- and set the RTC in an SMP compatible fashion.
-
- If you think you have a use for such a device (such as periodic data
- sampling), then say Y here, and read <file:Documentation/rtc.txt>
- for details.
-
- To compile this driver as a module, choose M here: the
- module will be called rtc.
-
source "drivers/pci/Kconfig"
config SUN_OPENPROMFS
@@ -414,6 +325,8 @@
If you want to run SunOS binaries (see SunOS binary emulation below)
or other a.out binaries, say Y. If unsure, say N.
+menu "Executable file formats"
+
source "fs/Kconfig.binfmt"
config SUNOS_EMUL
@@ -436,74 +349,7 @@
To compile this code as a module, choose M here: the
module will be called solaris.
-source "drivers/parport/Kconfig"
-
-config PRINTER
- tristate "Parallel printer support"
- depends on PARPORT
- ---help---
- If you intend to attach a printer to the parallel port of your Linux
- box (as opposed to using a serial printer; if the connector at the
- printer has 9 or 25 holes ["female"], then it's serial), say Y.
- Also read the Printing-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- It is possible to share one parallel port among several devices
- (e.g. printer and ZIP drive) and it is safe to compile the
- corresponding drivers into the kernel.
- To compile this driver as a module, choose M here and read
- <file:Documentation/parport.txt>. The module will be called lp.
-
- If you have several parallel ports, you can specify which ports to
- use with the "lp" kernel command line option. (Try "man bootparam"
- or see the documentation of your boot loader (lilo or loadlin) about
- how to pass options to the kernel at boot time.) The syntax of the
- "lp" command line option can be found in <file:drivers/char/lp.c>.
-
- If you have more than 8 printers, you need to increase the LP_NO
- macro in lp.c and the PARPORT_MAX macro in parport.h.
-
-config PPDEV
- tristate "Support for user-space parallel port device drivers"
- depends on PARPORT
- ---help---
- Saying Y to this adds support for /dev/parport device nodes. This
- is needed for programs that want portable access to the parallel
- port, for instance deviceid (which displays Plug-and-Play device
- IDs).
-
- This is the parallel port equivalent of SCSI generic support (sg).
- It is safe to say N to this -- it is not needed for normal printing
- or parallel port CD-ROM/disk support.
-
- To compile this driver as a module, choose M here: the
- module will be called ppdev.
-
- If unsure, say N.
-
-config ENVCTRL
- tristate "SUNW, envctrl support"
- depends on PCI
- help
- Kernel support for temperature and fan monitoring on Sun SME
- machines.
-
- To compile this driver as a module, choose M here: the
- module will be called envctrl.
-
-config DISPLAY7SEG
- tristate "7-Segment Display support"
- depends on PCI
- ---help---
- This is the driver for the 7-segment display and LED present on
- Sun Microsystems CompactPCI models CP1400 and CP1500.
-
- To compile this driver as a module, choose M here: the
- module will be called display7seg.
-
- If you do not have a CompactPCI model CP1400 or CP1500, or
- another UltraSPARC-IIi-cEngine boardset with a 7-segment display,
- you should say N to this option.
+endmenu
config CMDLINE_BOOL
bool "Default bootloader kernel arguments"
@@ -521,148 +367,16 @@
NOTE: This option WILL override the PROM bootargs setting!
-source "mm/Kconfig"
-
-endmenu
-
source "net/Kconfig"
-source "drivers/base/Kconfig"
-
-source "drivers/video/Kconfig"
-
-source "drivers/serial/Kconfig"
+source "drivers/Kconfig"
source "drivers/sbus/char/Kconfig"
-source "drivers/mtd/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
source "drivers/fc4/Kconfig"
-source "drivers/md/Kconfig"
-
-if PCI
-source "drivers/message/fusion/Kconfig"
-endif
-
-source "drivers/ieee1394/Kconfig"
-
-source "drivers/net/Kconfig"
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/telephony/Kconfig"
-
-# This one must be before the filesystem configs. -DaveM
-
-menu "Unix98 PTY support"
-
-config UNIX98_PTYS
- bool "Unix98 PTY support"
- ---help---
- A pseudo terminal (PTY) is a software device consisting of two
- halves: a master and a slave. The slave device behaves identical to
- a physical terminal; the master device is used by a process to
- read data from and write data to the slave, thereby emulating a
- terminal. Typical programs for the master side are telnet servers
- and xterms.
-
- Linux has traditionally used the BSD-like names /dev/ptyxx for
- masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
- has a number of problems. The GNU C library glibc 2.1 and later,
- however, supports the Unix98 naming standard: in order to acquire a
- pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
- terminal is then made available to the process and the pseudo
- terminal slave can be accessed as /dev/pts/<number>. What was
- traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
- The entries in /dev/pts/ are created on the fly by a virtual
- file system; therefore, if you say Y here you should say Y to
- "/dev/pts file system for Unix98 PTYs" as well.
-
- If you want to say Y here, you need to have the C library glibc 2.1
- or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
- Read the instructions in <file:Documentation/Changes> pertaining to
- pseudo terminals. It's safe to say N.
-
-config UNIX98_PTY_COUNT
- int "Maximum number of Unix98 PTYs in use (0-2048)"
- depends on UNIX98_PTYS
- default "256"
- help
- The maximum number of Unix98 PTYs that can be used at any one time.
- The default is 256, and should be enough for desktop systems. Server
- machines which support incoming telnet/rlogin/ssh connections and/or
- serve several X terminals may want to increase this: every incoming
- connection and every xterm uses up one PTY.
-
- When not in use, each additional set of 256 PTYs occupy
- approximately 8 KB of kernel memory on 32-bit architectures.
-
-endmenu
-
-menu "XFree86 DRI support"
-
-config DRM
- bool "Direct Rendering Manager (XFree86 DRI support)"
- help
- Kernel-level support for the Direct Rendering Infrastructure (DRI)
- introduced in XFree86 4.0. If you say Y here, you need to select
- the module that's right for your graphics card from the list below.
- These modules provide support for synchronization, security, and
- DMA transfers. Please see <http://dri.sourceforge.net/> for more
- details. You should also select and configure AGP
- (/dev/agpgart) support.
-
-config DRM_FFB
- tristate "Creator/Creator3D"
- depends on DRM && BROKEN
- help
- Choose this option if you have one of Sun's Creator3D-based graphics
- and frame buffer cards. Product page at
- <http://www.sun.com/desktop/products/Graphics/creator3d.html>.
-
-config DRM_TDFX
- tristate "3dfx Banshee/Voodoo3+"
- depends on DRM
- help
- Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
- graphics card. If M is selected, the module will be called tdfx.
-
-config DRM_R128
- tristate "ATI Rage 128"
- depends on DRM
- help
- Choose this option if you have an ATI Rage 128 graphics card. If M
- is selected, the module will be called r128. AGP support for
- this card is strongly suggested (unless you have a PCI version).
-
-endmenu
-
-source "drivers/input/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-source "drivers/hwmon/Kconfig"
-
source "fs/Kconfig"
-source "drivers/media/Kconfig"
-
-source "sound/Kconfig"
-
-source "drivers/usb/Kconfig"
-
-source "drivers/infiniband/Kconfig"
-
-source "drivers/char/watchdog/Kconfig"
-
source "arch/sparc64/oprofile/Kconfig"
source "arch/sparc64/Kconfig.debug"
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index cecdc0a..3e0badb 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -927,139 +927,6 @@
ba,pt %xcc, rtrap
clr %l6
- /* Capture I/D/E-cache state into per-cpu error scoreboard.
- *
- * %g1: (TL>=0) ? 1 : 0
- * %g2: scratch
- * %g3: scratch
- * %g4: AFSR
- * %g5: AFAR
- * %g6: current thread ptr
- * %g7: scratch
- */
-#define CHEETAH_LOG_ERROR \
- /* Put "TL1" software bit into AFSR. */ \
- and %g1, 0x1, %g1; \
- sllx %g1, 63, %g2; \
- or %g4, %g2, %g4; \
- /* Get log entry pointer for this cpu at this trap level. */ \
- BRANCH_IF_JALAPENO(g2,g3,50f) \
- ldxa [%g0] ASI_SAFARI_CONFIG, %g2; \
- srlx %g2, 17, %g2; \
- ba,pt %xcc, 60f; \
- and %g2, 0x3ff, %g2; \
-50: ldxa [%g0] ASI_JBUS_CONFIG, %g2; \
- srlx %g2, 17, %g2; \
- and %g2, 0x1f, %g2; \
-60: sllx %g2, 9, %g2; \
- sethi %hi(cheetah_error_log), %g3; \
- ldx [%g3 + %lo(cheetah_error_log)], %g3; \
- brz,pn %g3, 80f; \
- nop; \
- add %g3, %g2, %g3; \
- sllx %g1, 8, %g1; \
- add %g3, %g1, %g1; \
- /* %g1 holds pointer to the top of the logging scoreboard */ \
- ldx [%g1 + 0x0], %g7; \
- cmp %g7, -1; \
- bne,pn %xcc, 80f; \
- nop; \
- stx %g4, [%g1 + 0x0]; \
- stx %g5, [%g1 + 0x8]; \
- add %g1, 0x10, %g1; \
- /* %g1 now points to D-cache logging area */ \
- set 0x3ff8, %g2; /* DC_addr mask */ \
- and %g5, %g2, %g2; /* DC_addr bits of AFAR */ \
- srlx %g5, 12, %g3; \
- or %g3, 1, %g3; /* PHYS tag + valid */ \
-10: ldxa [%g2] ASI_DCACHE_TAG, %g7; \
- cmp %g3, %g7; /* TAG match? */ \
- bne,pt %xcc, 13f; \
- nop; \
- /* Yep, what we want, capture state. */ \
- stx %g2, [%g1 + 0x20]; \
- stx %g7, [%g1 + 0x28]; \
- /* A membar Sync is required before and after utag access. */ \
- membar #Sync; \
- ldxa [%g2] ASI_DCACHE_UTAG, %g7; \
- membar #Sync; \
- stx %g7, [%g1 + 0x30]; \
- ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7; \
- stx %g7, [%g1 + 0x38]; \
- clr %g3; \
-12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7; \
- stx %g7, [%g1]; \
- add %g3, (1 << 5), %g3; \
- cmp %g3, (4 << 5); \
- bl,pt %xcc, 12b; \
- add %g1, 0x8, %g1; \
- ba,pt %xcc, 20f; \
- add %g1, 0x20, %g1; \
-13: sethi %hi(1 << 14), %g7; \
- add %g2, %g7, %g2; \
- srlx %g2, 14, %g7; \
- cmp %g7, 4; \
- bl,pt %xcc, 10b; \
- nop; \
- add %g1, 0x40, %g1; \
-20: /* %g1 now points to I-cache logging area */ \
- set 0x1fe0, %g2; /* IC_addr mask */ \
- and %g5, %g2, %g2; /* IC_addr bits of AFAR */ \
- sllx %g2, 1, %g2; /* IC_addr[13:6]==VA[12:5] */ \
- srlx %g5, (13 - 8), %g3; /* Make PTAG */ \
- andn %g3, 0xff, %g3; /* Mask off undefined bits */ \
-21: ldxa [%g2] ASI_IC_TAG, %g7; \
- andn %g7, 0xff, %g7; \
- cmp %g3, %g7; \
- bne,pt %xcc, 23f; \
- nop; \
- /* Yep, what we want, capture state. */ \
- stx %g2, [%g1 + 0x40]; \
- stx %g7, [%g1 + 0x48]; \
- add %g2, (1 << 3), %g2; \
- ldxa [%g2] ASI_IC_TAG, %g7; \
- add %g2, (1 << 3), %g2; \
- stx %g7, [%g1 + 0x50]; \
- ldxa [%g2] ASI_IC_TAG, %g7; \
- add %g2, (1 << 3), %g2; \
- stx %g7, [%g1 + 0x60]; \
- ldxa [%g2] ASI_IC_TAG, %g7; \
- stx %g7, [%g1 + 0x68]; \
- sub %g2, (3 << 3), %g2; \
- ldxa [%g2] ASI_IC_STAG, %g7; \
- stx %g7, [%g1 + 0x58]; \
- clr %g3; \
- srlx %g2, 2, %g2; \
-22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7; \
- stx %g7, [%g1]; \
- add %g3, (1 << 3), %g3; \
- cmp %g3, (8 << 3); \
- bl,pt %xcc, 22b; \
- add %g1, 0x8, %g1; \
- ba,pt %xcc, 30f; \
- add %g1, 0x30, %g1; \
-23: sethi %hi(1 << 14), %g7; \
- add %g2, %g7, %g2; \
- srlx %g2, 14, %g7; \
- cmp %g7, 4; \
- bl,pt %xcc, 21b; \
- nop; \
- add %g1, 0x70, %g1; \
-30: /* %g1 now points to E-cache logging area */ \
- andn %g5, (32 - 1), %g2; /* E-cache subblock */ \
- stx %g2, [%g1 + 0x20]; \
- ldxa [%g2] ASI_EC_TAG_DATA, %g7; \
- stx %g7, [%g1 + 0x28]; \
- ldxa [%g2] ASI_EC_R, %g0; \
- clr %g3; \
-31: ldxa [%g3] ASI_EC_DATA, %g7; \
- stx %g7, [%g1 + %g3]; \
- add %g3, 0x8, %g3; \
- cmp %g3, 0x20; \
- bl,pt %xcc, 31b; \
- nop; \
-80: /* DONE */
-
/* These get patched into the trap table at boot time
* once we know we have a cheetah processor.
*/
@@ -1296,6 +1163,170 @@
membar #Sync
retry
+ /* Capture I/D/E-cache state into per-cpu error scoreboard.
+ *
+ * %g1: (TL>=0) ? 1 : 0
+ * %g2: scratch
+ * %g3: scratch
+ * %g4: AFSR
+ * %g5: AFAR
+ * %g6: current thread ptr
+ * %g7: scratch
+ */
+__cheetah_log_error:
+ /* Put "TL1" software bit into AFSR. */
+ and %g1, 0x1, %g1
+ sllx %g1, 63, %g2
+ or %g4, %g2, %g4
+
+ /* Get log entry pointer for this cpu at this trap level. */
+ BRANCH_IF_JALAPENO(g2,g3,50f)
+ ldxa [%g0] ASI_SAFARI_CONFIG, %g2
+ srlx %g2, 17, %g2
+ ba,pt %xcc, 60f
+ and %g2, 0x3ff, %g2
+
+50: ldxa [%g0] ASI_JBUS_CONFIG, %g2
+ srlx %g2, 17, %g2
+ and %g2, 0x1f, %g2
+
+60: sllx %g2, 9, %g2
+ sethi %hi(cheetah_error_log), %g3
+ ldx [%g3 + %lo(cheetah_error_log)], %g3
+ brz,pn %g3, 80f
+ nop
+
+ add %g3, %g2, %g3
+ sllx %g1, 8, %g1
+ add %g3, %g1, %g1
+
+ /* %g1 holds pointer to the top of the logging scoreboard */
+ ldx [%g1 + 0x0], %g7
+ cmp %g7, -1
+ bne,pn %xcc, 80f
+ nop
+
+ stx %g4, [%g1 + 0x0]
+ stx %g5, [%g1 + 0x8]
+ add %g1, 0x10, %g1
+
+ /* %g1 now points to D-cache logging area */
+ set 0x3ff8, %g2 /* DC_addr mask */
+ and %g5, %g2, %g2 /* DC_addr bits of AFAR */
+ srlx %g5, 12, %g3
+ or %g3, 1, %g3 /* PHYS tag + valid */
+
+10: ldxa [%g2] ASI_DCACHE_TAG, %g7
+ cmp %g3, %g7 /* TAG match? */
+ bne,pt %xcc, 13f
+ nop
+
+ /* Yep, what we want, capture state. */
+ stx %g2, [%g1 + 0x20]
+ stx %g7, [%g1 + 0x28]
+
+ /* A membar Sync is required before and after utag access. */
+ membar #Sync
+ ldxa [%g2] ASI_DCACHE_UTAG, %g7
+ membar #Sync
+ stx %g7, [%g1 + 0x30]
+ ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7
+ stx %g7, [%g1 + 0x38]
+ clr %g3
+
+12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7
+ stx %g7, [%g1]
+ add %g3, (1 << 5), %g3
+ cmp %g3, (4 << 5)
+ bl,pt %xcc, 12b
+ add %g1, 0x8, %g1
+
+ ba,pt %xcc, 20f
+ add %g1, 0x20, %g1
+
+13: sethi %hi(1 << 14), %g7
+ add %g2, %g7, %g2
+ srlx %g2, 14, %g7
+ cmp %g7, 4
+ bl,pt %xcc, 10b
+ nop
+
+ add %g1, 0x40, %g1
+
+ /* %g1 now points to I-cache logging area */
+20: set 0x1fe0, %g2 /* IC_addr mask */
+ and %g5, %g2, %g2 /* IC_addr bits of AFAR */
+ sllx %g2, 1, %g2 /* IC_addr[13:6]==VA[12:5] */
+ srlx %g5, (13 - 8), %g3 /* Make PTAG */
+ andn %g3, 0xff, %g3 /* Mask off undefined bits */
+
+21: ldxa [%g2] ASI_IC_TAG, %g7
+ andn %g7, 0xff, %g7
+ cmp %g3, %g7
+ bne,pt %xcc, 23f
+ nop
+
+ /* Yep, what we want, capture state. */
+ stx %g2, [%g1 + 0x40]
+ stx %g7, [%g1 + 0x48]
+ add %g2, (1 << 3), %g2
+ ldxa [%g2] ASI_IC_TAG, %g7
+ add %g2, (1 << 3), %g2
+ stx %g7, [%g1 + 0x50]
+ ldxa [%g2] ASI_IC_TAG, %g7
+ add %g2, (1 << 3), %g2
+ stx %g7, [%g1 + 0x60]
+ ldxa [%g2] ASI_IC_TAG, %g7
+ stx %g7, [%g1 + 0x68]
+ sub %g2, (3 << 3), %g2
+ ldxa [%g2] ASI_IC_STAG, %g7
+ stx %g7, [%g1 + 0x58]
+ clr %g3
+ srlx %g2, 2, %g2
+
+22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7
+ stx %g7, [%g1]
+ add %g3, (1 << 3), %g3
+ cmp %g3, (8 << 3)
+ bl,pt %xcc, 22b
+ add %g1, 0x8, %g1
+
+ ba,pt %xcc, 30f
+ add %g1, 0x30, %g1
+
+23: sethi %hi(1 << 14), %g7
+ add %g2, %g7, %g2
+ srlx %g2, 14, %g7
+ cmp %g7, 4
+ bl,pt %xcc, 21b
+ nop
+
+ add %g1, 0x70, %g1
+
+ /* %g1 now points to E-cache logging area */
+30: andn %g5, (32 - 1), %g2
+ stx %g2, [%g1 + 0x20]
+ ldxa [%g2] ASI_EC_TAG_DATA, %g7
+ stx %g7, [%g1 + 0x28]
+ ldxa [%g2] ASI_EC_R, %g0
+ clr %g3
+
+31: ldxa [%g3] ASI_EC_DATA, %g7
+ stx %g7, [%g1 + %g3]
+ add %g3, 0x8, %g3
+ cmp %g3, 0x20
+
+ bl,pt %xcc, 31b
+ nop
+80:
+ rdpr %tt, %g2
+ cmp %g2, 0x70
+ be c_fast_ecc
+ cmp %g2, 0x63
+ be c_cee
+ nop
+ ba,pt %xcc, c_deferred
+
/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
* in the trap table. That code has done a memory barrier
* and has disabled both the I-cache and D-cache in the DCU
@@ -1321,8 +1352,10 @@
stxa %g4, [%g0] ASI_AFSR
membar #Sync
- CHEETAH_LOG_ERROR
+ ba,pt %xcc, __cheetah_log_error
+ nop
+c_fast_ecc:
rdpr %pil, %g2
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
@@ -1347,8 +1380,10 @@
stxa %g4, [%g0] ASI_AFSR
membar #Sync
- CHEETAH_LOG_ERROR
+ ba,pt %xcc, __cheetah_log_error
+ nop
+c_cee:
rdpr %pil, %g2
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
@@ -1373,8 +1408,10 @@
stxa %g4, [%g0] ASI_AFSR
membar #Sync
- CHEETAH_LOG_ERROR
+ ba,pt %xcc, __cheetah_log_error
+ nop
+c_deferred:
rdpr %pil, %g2
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 8104a56..1fa06c4 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -538,11 +538,12 @@
nop
call cheetah_plus_patch_winfixup
nop
-
2: /* Patch copy/page operations to cheetah optimized versions. */
call cheetah_patch_copyops
nop
+ call cheetah_patch_copy_page
+ nop
call cheetah_patch_cachetlbops
nop
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index bbf11f8..0d66d07 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -8,6 +8,7 @@
#include <linux/kprobes.h>
#include <asm/kdebug.h>
#include <asm/signal.h>
+#include <asm/cacheflush.h>
/* We do not have hardware single-stepping on sparc64.
* So we implement software single-stepping with breakpoint
@@ -37,31 +38,31 @@
* - Mark that we are no longer actively in a kprobe.
*/
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
return 0;
}
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
{
p->ainsn.insn[0] = *p->addr;
p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
p->opcode = *p->addr;
}
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
{
*p->addr = BREAKPOINT_INSTRUCTION;
flushi(p->addr);
}
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flushi(p->addr);
}
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
{
}
@@ -111,7 +112,7 @@
}
}
-static int kprobe_handler(struct pt_regs *regs)
+static int __kprobes kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
void *addr = (void *) regs->tpc;
@@ -191,8 +192,9 @@
* The original INSN location was REAL_PC, it actually
* executed at PC and produced destination address NPC.
*/
-static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc,
- unsigned long pc, unsigned long npc)
+static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
+ unsigned long pc,
+ unsigned long npc)
{
/* Branch not taken, no mods necessary. */
if (npc == pc + 0x4UL)
@@ -217,7 +219,8 @@
/* If INSN is an instruction which writes it's PC location
* into a destination register, fix that up.
*/
-static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
+static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
+ unsigned long real_pc)
{
unsigned long *slot = NULL;
@@ -257,7 +260,7 @@
* This function prepares to return from the post-single-step
* breakpoint trap.
*/
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
u32 insn = p->ainsn.insn[0];
@@ -315,8 +318,8 @@
/*
* Wrapper routine to for handling exceptions.
*/
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
- void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
switch (val) {
@@ -344,7 +347,8 @@
return NOTIFY_DONE;
}
-asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
+asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
+ struct pt_regs *regs)
{
BUG_ON(trap_level != 0x170 && trap_level != 0x171);
@@ -368,7 +372,7 @@
static struct pt_regs *jprobe_saved_regs_location;
static struct sparc_stackf jprobe_saved_stack;
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
@@ -390,7 +394,7 @@
return 1;
}
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
{
preempt_enable_no_resched();
__asm__ __volatile__(
@@ -403,7 +407,7 @@
extern void __show_regs(struct pt_regs * regs);
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
u32 *addr = (u32 *) regs->tpc;
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index f21c993..ec8bf40 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -736,8 +736,7 @@
static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- /* Our io_remap_page_range/io_remap_pfn_range takes care of this,
- do nothing. */
+ /* Our io_remap_pfn_range takes care of this, do nothing. */
}
/* Perform the actual remap of the pages for a PCI device mapping, as appropriate
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 0696ed4..fafd227 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -153,11 +153,14 @@
rtrap_irq:
rtrap_clr_l6: clr %l6
rtrap:
- ldub [%g6 + TI_CPU], %l0
- sethi %hi(irq_stat), %l2 ! &softirq_active
- or %l2, %lo(irq_stat), %l2 ! &softirq_active
-irqsz_patchme: sllx %l0, 0, %l0
- lduw [%l2 + %l0], %l1 ! softirq_pending
+#ifndef CONFIG_SMP
+ sethi %hi(per_cpu____cpu_data), %l0
+ lduw [%l0 + %lo(per_cpu____cpu_data)], %l1
+#else
+ sethi %hi(per_cpu____cpu_data), %l0
+ or %l0, %lo(per_cpu____cpu_data), %l0
+ lduw [%l0 + %g5], %l1
+#endif
cmp %l1, 0
/* mm/ultra.S:xcall_report_regs KNOWS about this load. */
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index fbdfed3..ddbed33 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -511,18 +511,6 @@
conswitchp = &prom_con;
#endif
-#ifdef CONFIG_SMP
- i = (unsigned long)&irq_stat[1] - (unsigned long)&irq_stat[0];
- if ((i == SMP_CACHE_BYTES) || (i == (2 * SMP_CACHE_BYTES))) {
- extern unsigned int irqsz_patchme[1];
- irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
- SMP_CACHE_BYTES_SHIFT + 1);
- flushi((long)&irqsz_patchme[0]);
- } else {
- prom_printf("Unexpected size of irq_stat[] elements\n");
- prom_halt();
- }
-#endif
/* Work out if we are starfire early on */
check_if_starfire();
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index a3ea697..d89fc24 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -88,8 +88,6 @@
extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
extern long sparc32_open(const char __user * filename, int flags, int mode);
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
- unsigned long offset, unsigned long size, pgprot_t prot, int space);
extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn, unsigned long size, pgprot_t prot);
extern void (*prom_palette)(int);
@@ -245,7 +243,6 @@
#endif
/* I/O device mmaping on Sparc64. */
-EXPORT_SYMBOL(io_remap_page_range);
EXPORT_SYMBOL(io_remap_pfn_range);
/* Solaris/SunOS binary compatibility */
diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c
index 87c1aeb..7654b8a 100644
--- a/arch/sparc64/kernel/sunos_ioctl32.c
+++ b/arch/sparc64/kernel/sunos_ioctl32.c
@@ -152,11 +152,12 @@
ret = compat_sys_ioctl(fd, SIOCGIFCONF, arg);
goto out;
- case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */
- ret = sys_ioctl(fd, SIOCSIFMTU, arg);
+ case _IOW('i', 21, struct ifreq32):
+ ret = compat_sys_ioctl(fd, SIOCSIFMTU, arg);
goto out;
- case _IOWR('i', 22, struct ifreq): /* SIOCGIFMTU */
- ret = sys_ioctl(fd, SIOCGIFMTU, arg);
+
+ case _IOWR('i', 22, struct ifreq32):
+ ret = compat_sys_ioctl(fd, SIOCGIFMTU, arg);
goto out;
case _IOWR('i', 23, struct ifreq32):
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 1d3aa58..7f6239e 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1002,29 +1002,7 @@
asmlinkage long sparc32_open(const char __user *filename,
int flags, int mode)
{
- char * tmp;
- int fd, error;
-
- tmp = getname(filename);
- fd = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
- if (fd >= 0) {
- struct file * f = filp_open(tmp, flags, mode);
- error = PTR_ERR(f);
- if (IS_ERR(f))
- goto out_error;
- fd_install(fd, f);
- }
-out:
- putname(tmp);
- }
- return fd;
-
-out_error:
- put_unused_fd(fd);
- fd = error;
- goto out;
+ return do_sys_open(filename, flags, mode);
}
extern unsigned long do_mremap(unsigned long addr,
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 362b9c2..3f08a32 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -449,7 +449,7 @@
static long last_rtc_update;
/* Determine when to update the Mostek clock. */
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 950423d..f47d0be 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -17,6 +17,7 @@
*(.text)
SCHED_TEXT
LOCK_TEXT
+ KPROBES_TEXT
*(.gnu.warning)
} =0
_etext = .;
diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c
index 3008d53..3c6cfbb 100644
--- a/arch/sparc64/lib/PeeCeeI.c
+++ b/arch/sparc64/lib/PeeCeeI.c
@@ -7,28 +7,31 @@
#include <asm/io.h>
#include <asm/byteorder.h>
-void outsb(void __iomem *addr, const void *src, unsigned long count)
+void outsb(unsigned long __addr, const void *src, unsigned long count)
{
+ void __iomem *addr = (void __iomem *) __addr;
const u8 *p = src;
- while(count--)
+ while (count--)
outb(*p++, addr);
}
-void outsw(void __iomem *addr, const void *src, unsigned long count)
+void outsw(unsigned long __addr, const void *src, unsigned long count)
{
- if(count) {
+ void __iomem *addr = (void __iomem *) __addr;
+
+ if (count) {
u16 *ps = (u16 *)src;
u32 *pi;
- if(((u64)src) & 0x2) {
+ if (((u64)src) & 0x2) {
u16 val = le16_to_cpup(ps);
outw(val, addr);
ps++;
count--;
}
pi = (u32 *)ps;
- while(count >= 2) {
+ while (count >= 2) {
u32 w = le32_to_cpup(pi);
pi++;
@@ -37,19 +40,21 @@
count -= 2;
}
ps = (u16 *)pi;
- if(count) {
+ if (count) {
u16 val = le16_to_cpup(ps);
outw(val, addr);
}
}
}
-void outsl(void __iomem *addr, const void *src, unsigned long count)
+void outsl(unsigned long __addr, const void *src, unsigned long count)
{
- if(count) {
- if((((u64)src) & 0x3) == 0) {
+ void __iomem *addr = (void __iomem *) __addr;
+
+ if (count) {
+ if ((((u64)src) & 0x3) == 0) {
u32 *p = (u32 *)src;
- while(count--) {
+ while (count--) {
u32 val = cpu_to_le32p(p);
outl(val, addr);
p++;
@@ -60,13 +65,13 @@
u32 l = 0, l2;
u32 *pi;
- switch(((u64)src) & 0x3) {
+ switch (((u64)src) & 0x3) {
case 0x2:
count -= 1;
l = cpu_to_le16p(ps) << 16;
ps++;
pi = (u32 *)ps;
- while(count--) {
+ while (count--) {
l2 = cpu_to_le32p(pi);
pi++;
outl(((l >> 16) | (l2 << 16)), addr);
@@ -86,7 +91,7 @@
ps++;
l |= (l2 << 16);
pi = (u32 *)ps;
- while(count--) {
+ while (count--) {
l2 = cpu_to_le32p(pi);
pi++;
outl(((l >> 8) | (l2 << 24)), addr);
@@ -101,7 +106,7 @@
pb = (u8 *)src;
l = (*pb++ << 24);
pi = (u32 *)pb;
- while(count--) {
+ while (count--) {
l2 = cpu_to_le32p(pi);
pi++;
outl(((l >> 24) | (l2 << 8)), addr);
@@ -119,16 +124,18 @@
}
}
-void insb(void __iomem *addr, void *dst, unsigned long count)
+void insb(unsigned long __addr, void *dst, unsigned long count)
{
- if(count) {
+ void __iomem *addr = (void __iomem *) __addr;
+
+ if (count) {
u32 *pi;
u8 *pb = dst;
- while((((unsigned long)pb) & 0x3) && count--)
+ while ((((unsigned long)pb) & 0x3) && count--)
*pb++ = inb(addr);
pi = (u32 *)pb;
- while(count >= 4) {
+ while (count >= 4) {
u32 w;
w = (inb(addr) << 24);
@@ -139,23 +146,25 @@
count -= 4;
}
pb = (u8 *)pi;
- while(count--)
+ while (count--)
*pb++ = inb(addr);
}
}
-void insw(void __iomem *addr, void *dst, unsigned long count)
+void insw(unsigned long __addr, void *dst, unsigned long count)
{
- if(count) {
+ void __iomem *addr = (void __iomem *) __addr;
+
+ if (count) {
u16 *ps = dst;
u32 *pi;
- if(((unsigned long)ps) & 0x2) {
+ if (((unsigned long)ps) & 0x2) {
*ps++ = le16_to_cpu(inw(addr));
count--;
}
pi = (u32 *)ps;
- while(count >= 2) {
+ while (count >= 2) {
u32 w;
w = (le16_to_cpu(inw(addr)) << 16);
@@ -164,31 +173,33 @@
count -= 2;
}
ps = (u16 *)pi;
- if(count)
+ if (count)
*ps = le16_to_cpu(inw(addr));
}
}
-void insl(void __iomem *addr, void *dst, unsigned long count)
+void insl(unsigned long __addr, void *dst, unsigned long count)
{
- if(count) {
- if((((unsigned long)dst) & 0x3) == 0) {
+ void __iomem *addr = (void __iomem *) __addr;
+
+ if (count) {
+ if ((((unsigned long)dst) & 0x3) == 0) {
u32 *pi = dst;
- while(count--)
+ while (count--)
*pi++ = le32_to_cpu(inl(addr));
} else {
u32 l = 0, l2, *pi;
u16 *ps;
u8 *pb;
- switch(((unsigned long)dst) & 3) {
+ switch (((unsigned long)dst) & 3) {
case 0x2:
ps = dst;
count -= 1;
l = le32_to_cpu(inl(addr));
*ps++ = l;
pi = (u32 *)ps;
- while(count--) {
+ while (count--) {
l2 = le32_to_cpu(inl(addr));
*pi++ = (l << 16) | (l2 >> 16);
l = l2;
@@ -205,7 +216,7 @@
ps = (u16 *)pb;
*ps++ = ((l >> 8) & 0xffff);
pi = (u32 *)ps;
- while(count--) {
+ while (count--) {
l2 = le32_to_cpu(inl(addr));
*pi++ = (l << 24) | (l2 >> 8);
l = l2;
@@ -220,7 +231,7 @@
l = le32_to_cpu(inl(addr));
*pb++ = l >> 24;
pi = (u32 *)pb;
- while(count--) {
+ while (count--) {
l2 = le32_to_cpu(inl(addr));
*pi++ = (l << 8) | (l2 >> 24);
l = l2;
diff --git a/arch/sparc64/lib/copy_page.S b/arch/sparc64/lib/copy_page.S
index 23ebf2c..feebb14 100644
--- a/arch/sparc64/lib/copy_page.S
+++ b/arch/sparc64/lib/copy_page.S
@@ -87,7 +87,7 @@
membar #Sync
wrpr %o2, 0x0, %pstate
- BRANCH_IF_ANY_CHEETAH(g3,o2,1f)
+cheetah_copy_page_insn:
ba,pt %xcc, 9f
nop
@@ -240,3 +240,14 @@
stw %o4, [%g6 + TI_PRE_COUNT]
.size copy_user_page, .-copy_user_page
+
+ .globl cheetah_patch_copy_page
+cheetah_patch_copy_page:
+ sethi %hi(0x01000000), %o1 ! NOP
+ sethi %hi(cheetah_copy_page_insn), %o0
+ or %o0, %lo(cheetah_copy_page_insn), %o0
+ stw %o1, [%o0]
+ membar #StoreStore
+ flush %o0
+ retl
+ nop
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 52e9375..db1e331 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -18,6 +18,7 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/kprobes.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -117,8 +118,9 @@
return tally;
}
-static void unhandled_fault(unsigned long address, struct task_struct *tsk,
- struct pt_regs *regs)
+static void __kprobes unhandled_fault(unsigned long address,
+ struct task_struct *tsk,
+ struct pt_regs *regs)
{
if ((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -304,7 +306,7 @@
unhandled_fault (address, current, regs);
}
-asmlinkage void do_sparc64_fault(struct pt_regs *regs)
+asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
index 6b31f61..c954d91 100644
--- a/arch/sparc64/mm/generic.c
+++ b/arch/sparc64/mm/generic.c
@@ -116,37 +116,6 @@
return 0;
}
-int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
-{
- int error = 0;
- pgd_t * dir;
- unsigned long beg = from;
- unsigned long end = from + size;
- struct mm_struct *mm = vma->vm_mm;
-
- prot = __pgprot(pg_iobits);
- offset -= from;
- dir = pgd_offset(mm, from);
- flush_cache_range(vma, beg, end);
-
- spin_lock(&mm->page_table_lock);
- while (from < end) {
- pud_t *pud = pud_alloc(mm, dir, from);
- error = -ENOMEM;
- if (!pud)
- break;
- error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
- if (error)
- break;
- from = (from + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- }
- flush_tlb_range(vma, beg, end);
- spin_unlock(&mm->page_table_lock);
-
- return error;
-}
-
int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 3fbaf34..fdb1ebb 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -19,6 +19,7 @@
#include <linux/pagemap.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
+#include <linux/kprobes.h>
#include <asm/head.h>
#include <asm/system.h>
@@ -250,7 +251,7 @@
put_cpu();
}
-void flush_icache_range(unsigned long start, unsigned long end)
+void __kprobes flush_icache_range(unsigned long start, unsigned long end)
{
/* Cheetah has coherent I-cache. */
if (tlb_type == spitfire) {
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 3637708..b2ee9b5 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -10,6 +10,7 @@
#include <asm/page.h>
#include <asm/spitfire.h>
#include <asm/mmu_context.h>
+#include <asm/mmu.h>
#include <asm/pil.h>
#include <asm/head.h>
#include <asm/thread_info.h>
@@ -45,6 +46,8 @@
nop
nop
nop
+ nop
+ nop
.align 32
.globl __flush_tlb_pending
@@ -73,6 +76,9 @@
retl
wrpr %g7, 0x0, %pstate
nop
+ nop
+ nop
+ nop
.align 32
.globl __flush_tlb_kernel_range
@@ -113,6 +119,7 @@
#else
#error unsupported PAGE_SIZE
#endif
+ .section .kprobes.text, "ax"
.align 32
.globl __flush_icache_page
__flush_icache_page: /* %o0 = phys_page */
@@ -195,6 +202,7 @@
nop
#endif /* DCACHE_ALIASING_POSSIBLE */
+ .previous .text
.align 32
__prefill_dtlb:
rdpr %pstate, %g7
@@ -224,16 +232,8 @@
or %o5, %o0, %o5
ba,a,pt %xcc, __prefill_itlb
- /* Cheetah specific versions, patched at boot time.
- *
- * This writes of the PRIMARY_CONTEXT register in this file are
- * safe even on Cheetah+ and later wrt. the page size fields.
- * The nucleus page size fields do not matter because we make
- * no data references, and these instructions execute out of a
- * locked I-TLB entry sitting in the fully assosciative I-TLB.
- * This sequence should also never trap.
- */
-__cheetah_flush_tlb_mm: /* 15 insns */
+ /* Cheetah specific versions, patched at boot time. */
+__cheetah_flush_tlb_mm: /* 18 insns */
rdpr %pstate, %g7
andn %g7, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
@@ -241,6 +241,9 @@
mov PRIMARY_CONTEXT, %o2
mov 0x40, %g3
ldxa [%o2] ASI_DMMU, %g2
+ srlx %g2, CTX_PGSZ1_NUC_SHIFT, %o1
+ sllx %o1, CTX_PGSZ1_NUC_SHIFT, %o1
+ or %o0, %o1, %o0 /* Preserve nucleus page size fields */
stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
@@ -250,7 +253,7 @@
retl
wrpr %g7, 0x0, %pstate
-__cheetah_flush_tlb_pending: /* 23 insns */
+__cheetah_flush_tlb_pending: /* 26 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
rdpr %pstate, %g7
sllx %o1, 3, %o1
@@ -259,6 +262,9 @@
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o4
ldxa [%o4] ASI_DMMU, %g2
+ srlx %g2, CTX_PGSZ1_NUC_SHIFT, %o3
+ sllx %o3, CTX_PGSZ1_NUC_SHIFT, %o3
+ or %o0, %o3, %o0 /* Preserve nucleus page size fields */
stxa %o0, [%o4] ASI_DMMU
1: sub %o1, (1 << 3), %o1
ldx [%o2 + %o1], %o3
@@ -311,14 +317,14 @@
sethi %hi(__cheetah_flush_tlb_mm), %o1
or %o1, %lo(__cheetah_flush_tlb_mm), %o1
call cheetah_patch_one
- mov 15, %o2
+ mov 18, %o2
sethi %hi(__flush_tlb_pending), %o0
or %o0, %lo(__flush_tlb_pending), %o0
sethi %hi(__cheetah_flush_tlb_pending), %o1
or %o1, %lo(__cheetah_flush_tlb_pending), %o1
call cheetah_patch_one
- mov 23, %o2
+ mov 26, %o2
#ifdef DCACHE_ALIASING_POSSIBLE
sethi %hi(__flush_dcache_page), %o0
@@ -352,9 +358,12 @@
.globl xcall_flush_tlb_mm
xcall_flush_tlb_mm:
mov PRIMARY_CONTEXT, %g2
- mov 0x40, %g4
ldxa [%g2] ASI_DMMU, %g3
+ srlx %g3, CTX_PGSZ1_NUC_SHIFT, %g4
+ sllx %g4, CTX_PGSZ1_NUC_SHIFT, %g4
+ or %g5, %g4, %g5 /* Preserve nucleus page size fields */
stxa %g5, [%g2] ASI_DMMU
+ mov 0x40, %g4
stxa %g0, [%g4] ASI_DMMU_DEMAP
stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
@@ -366,6 +375,10 @@
sllx %g1, 3, %g1
mov PRIMARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g2
+ srlx %g2, CTX_PGSZ1_NUC_SHIFT, %g4
+ sllx %g4, CTX_PGSZ1_NUC_SHIFT, %g4
+ or %g5, %g4, %g5
+ mov PRIMARY_CONTEXT, %g4
stxa %g5, [%g4] ASI_DMMU
1: sub %g1, (1 << 3), %g1
ldx [%g7 + %g1], %g5
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index f945444..684e1f8 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -73,7 +73,7 @@
to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this
option will shrink the UML binary slightly.
-source "arch/um/Kconfig_arch"
+source "arch/um/Kconfig.arch"
source "mm/Kconfig"
config LD_SCRIPT_STATIC
@@ -196,7 +196,7 @@
config SMP
bool "Symmetric multi-processing support (EXPERIMENTAL)"
default n
- depends on MODE_TT && EXPERIMENTAL
+ depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN)
help
This option enables UML SMP support.
It is NOT related to having a real SMP box. Not directly, at least.
@@ -279,7 +279,7 @@
source "drivers/base/Kconfig"
-source "arch/um/Kconfig_char"
+source "arch/um/Kconfig.char"
source "drivers/block/Kconfig"
@@ -287,7 +287,7 @@
bool
default NET
-source "arch/um/Kconfig_net"
+source "arch/um/Kconfig.net"
source "drivers/net/Kconfig"
@@ -311,7 +311,7 @@
depends on SCSI
default y
-source "arch/um/Kconfig_scsi"
+source "arch/um/Kconfig.scsi"
endmenu
diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig.char
similarity index 100%
rename from arch/um/Kconfig_char
rename to arch/um/Kconfig.char
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index bd41e42..5681a8b 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -2,6 +2,17 @@
source "lib/Kconfig.debug"
+config CMDLINE_ON_HOST
+ bool "Show command line arguments on the host in TT mode"
+ depends on MODE_TT
+ default !DEBUG_INFO
+ help
+ This controls whether arguments in guest processes should be shown on
+ the host's ps output.
+ Enabling this option hinders debugging on some recent GDB versions
+ (because GDB gets "confused" when we do an execvp()). So probably you
+ should disable it.
+
config PT_PROXY
bool "Enable ptrace proxy"
depends on XTERM_CHAN && DEBUG_INFO && MODE_TT
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig.i386
similarity index 93%
rename from arch/um/Kconfig_i386
rename to arch/um/Kconfig.i386
index 27c18a8..8ad156a 100644
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig.i386
@@ -6,6 +6,10 @@
bool
default n
+config SEMAPHORE_SLEEPERS
+ bool
+ default y
+
config TOP_ADDR
hex
default 0xc0000000 if !HOST_2G_2G
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig.net
similarity index 98%
rename from arch/um/Kconfig_net
rename to arch/um/Kconfig.net
index fa2ab2d..14a04eb 100644
--- a/arch/um/Kconfig_net
+++ b/arch/um/Kconfig.net
@@ -34,7 +34,7 @@
link with the host.
To use this, your host kernel must have support for Ethertap
- devices. Also, if your host kernel is 2.4.x, it must have
+ devices. Also, if your host kernel is 2.4.x, it must have
CONFIG_NETLINK_DEV configured as Y or M.
For more information, see
@@ -43,7 +43,7 @@
networking.
If you'd like to set up an IP network with the host and/or the
- outside world, say Y to this, the Daemon Transport and/or the
+ outside world, say Y to this, the Daemon Transport and/or the
Slip Transport. You'll need at least one of them, but may choose
more than one without conflict. If you don't need UML networking,
say N.
@@ -78,7 +78,7 @@
The Ethertap Transport is preferred over slip because of its
limitations. If you prefer slip, however, say Y here. Otherwise
- choose the Multicast transport (to network multiple UMLs on
+ choose the Multicast transport (to network multiple UMLs on
multiple hosts), Ethertap (to network with the host and the
outside world), and/or the Daemon transport (to network multiple
UMLs on a single host). You may choose more than one without
@@ -138,7 +138,7 @@
depends on UML_NET && EXPERIMENTAL
help
The pcap transport makes a pcap packet stream on the host look
- like an ethernet device inside UML. This is useful for making
+ like an ethernet device inside UML. This is useful for making
UML act as a network monitor for the host. You must have libcap
installed in order to build the pcap transport into UML.
@@ -169,11 +169,11 @@
setup string. The effect of this transport on the UML is similar
that of a host behind a firewall that masquerades all network
connections passing through it (but is less secure).
-
+
To use this you should first have slirp compiled somewhere
accessible on the host, and have read its documentation. If you
don't need UML networking, say N.
-
+
Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
endmenu
diff --git a/arch/um/Kconfig_scsi b/arch/um/Kconfig.scsi
similarity index 100%
rename from arch/um/Kconfig_scsi
rename to arch/um/Kconfig.scsi
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig.x86_64
similarity index 82%
rename from arch/um/Kconfig_x86_64
rename to arch/um/Kconfig.x86_64
index 735a047..bd35e59 100644
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig.x86_64
@@ -6,6 +6,10 @@
bool
default y
+config SEMAPHORE_SLEEPERS
+ bool
+ default y
+
config TOP_ADDR
hex
default 0x80000000
@@ -33,3 +37,7 @@
config ARCH_REUSE_HOST_VSYSCALL_AREA
bool
default n
+
+config SMP_BROKEN
+ bool
+ default y
diff --git a/arch/um/Makefile b/arch/um/Makefile
index f5a83a7..b15f604 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -56,6 +56,7 @@
CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap
+AFLAGS += $(ARCH_INCLUDE)
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
@@ -101,10 +102,10 @@
endef
ifneq ($(KBUILD_SRC),)
-$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig_$(SUBARCH) $(ARCH_DIR)/Kconfig_arch)
-CLEAN_FILES += $(ARCH_DIR)/Kconfig_arch
+$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig.$(SUBARCH) $(ARCH_DIR)/Kconfig.arch)
+CLEAN_FILES += $(ARCH_DIR)/Kconfig.arch
else
-$(shell cd $(ARCH_DIR) && ln -sf Kconfig_$(SUBARCH) Kconfig_arch)
+$(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch)
endif
prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
@@ -147,7 +148,7 @@
MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \
- $(ARCH_DIR)/Kconfig_arch
+ $(ARCH_DIR)/Kconfig.arch
archclean:
$(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index a777e57..1ab431a 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -27,7 +27,7 @@
endif
endif
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
ifneq ($(CONFIG_GPROF),y)
ARCH_CFLAGS += -DUM_FASTCALL
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index aa2f717..baddb5d 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -6,7 +6,7 @@
#We #undef __x86_64__ for kernelspace, not for userspace where
#it's needed for headers to work!
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin
USER_CFLAGS += -fno-builtin
ELF_ARCH := i386:x86-64
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index de17d4c..783e18c 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -13,7 +13,7 @@
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o
-ubd-objs := ubd_kern.o ubd_user.o
+ubd-objs := ubd_kern.o
port-objs := port_kern.o port_user.o
harddog-objs := harddog_kern.o harddog_user.o
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 5d37681..de3bce7 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -63,7 +63,7 @@
*
* SIGWINCH can't be received synchronously, so you have to set up to receive it
* as a signal. That being the case, if you are going to wait for it, it is
- * convenient to sit in a pause() and wait for the signal to bounce you out of
+ * convenient to sit in sigsuspend() and wait for the signal to bounce you out of
* it (see below for how we make sure to exit only on SIGWINCH).
*/
@@ -94,18 +94,19 @@
"byte, err = %d\n", -count);
/* We are not using SIG_IGN on purpose, so don't fix it as I thought to
- * do! If using SIG_IGN, the pause() call below would not stop on
+ * do! If using SIG_IGN, the sigsuspend() call below would not stop on
* SIGWINCH. */
signal(SIGWINCH, winch_handler);
sigfillset(&sigs);
- sigdelset(&sigs, SIGWINCH);
- /* Block anything else than SIGWINCH. */
+ /* Block all signals possible. */
if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
printk("winch_thread : sigprocmask failed, errno = %d\n",
errno);
exit(1);
}
+ /* In sigsuspend(), block anything else than SIGWINCH. */
+ sigdelset(&sigs, SIGWINCH);
if(setsid() < 0){
printk("winch_thread : setsid failed, errno = %d\n", errno);
@@ -130,7 +131,7 @@
while(1){
/* This will be interrupted by SIGWINCH only, since other signals
* are blocked.*/
- pause();
+ sigsuspend(&sigs);
count = os_write_file(pipe_fd, &c, sizeof(c));
if(count != sizeof(c))
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 344b24d..e77a38d 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -35,6 +35,7 @@
#include "linux/blkpg.h"
#include "linux/genhd.h"
#include "linux/spinlock.h"
+#include "asm/atomic.h"
#include "asm/segment.h"
#include "asm/uaccess.h"
#include "asm/irq.h"
@@ -53,20 +54,21 @@
#include "mem.h"
#include "mem_kern.h"
#include "cow.h"
+#include "aio.h"
enum ubd_req { UBD_READ, UBD_WRITE };
struct io_thread_req {
- enum ubd_req op;
+ enum aio_type op;
int fds[2];
unsigned long offsets[2];
unsigned long long offset;
unsigned long length;
char *buffer;
int sectorsize;
- unsigned long sector_mask;
- unsigned long long cow_offset;
- unsigned long bitmap_words[2];
+ int bitmap_offset;
+ long bitmap_start;
+ long bitmap_end;
int error;
};
@@ -80,28 +82,31 @@
unsigned long *bitmap_len_out,
int *data_offset_out);
extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
-extern void do_io(struct io_thread_req *req);
+extern void do_io(struct io_thread_req *req, struct request *r,
+ unsigned long *bitmap);
-static inline int ubd_test_bit(__u64 bit, unsigned char *data)
+static inline int ubd_test_bit(__u64 bit, void *data)
{
+ unsigned char *buffer = data;
__u64 n;
int bits, off;
- bits = sizeof(data[0]) * 8;
+ bits = sizeof(buffer[0]) * 8;
n = bit / bits;
off = bit % bits;
- return((data[n] & (1 << off)) != 0);
+ return((buffer[n] & (1 << off)) != 0);
}
-static inline void ubd_set_bit(__u64 bit, unsigned char *data)
+static inline void ubd_set_bit(__u64 bit, void *data)
{
+ unsigned char *buffer = data;
__u64 n;
int bits, off;
- bits = sizeof(data[0]) * 8;
+ bits = sizeof(buffer[0]) * 8;
n = bit / bits;
off = bit % bits;
- data[n] |= (1 << off);
+ buffer[n] |= (1 << off);
}
/*End stuff from ubd_user.h*/
@@ -110,8 +115,6 @@
static DEFINE_SPINLOCK(ubd_io_lock);
static DEFINE_SPINLOCK(ubd_lock);
-static void (*do_ubd)(void);
-
static int ubd_open(struct inode * inode, struct file * filp);
static int ubd_release(struct inode * inode, struct file * file);
static int ubd_ioctl(struct inode * inode, struct file * file,
@@ -158,6 +161,8 @@
int data_offset;
};
+#define MAX_SG 64
+
struct ubd {
char *file;
int count;
@@ -168,6 +173,7 @@
int no_cow;
struct cow cow;
struct platform_device pdev;
+ struct scatterlist sg[MAX_SG];
};
#define DEFAULT_COW { \
@@ -460,81 +466,114 @@
);
static void do_ubd_request(request_queue_t * q);
-
-/* Only changed by ubd_init, which is an initcall. */
-int thread_fd = -1;
+static int in_ubd;
/* Changed by ubd_handler, which is serialized because interrupts only
* happen on CPU 0.
*/
int intr_count = 0;
+static void ubd_end_request(struct request *req, int bytes, int uptodate)
+{
+ if (!end_that_request_first(req, uptodate, bytes >> 9)) {
+ add_disk_randomness(req->rq_disk);
+ end_that_request_last(req);
+ }
+}
+
/* call ubd_finish if you need to serialize */
-static void __ubd_finish(struct request *req, int error)
+static void __ubd_finish(struct request *req, int bytes)
{
- int nsect;
+ if(bytes < 0){
+ ubd_end_request(req, 0, 0);
+ return;
+ }
- if(error){
- end_request(req, 0);
- return;
- }
- nsect = req->current_nr_sectors;
- req->sector += nsect;
- req->buffer += nsect << 9;
- req->errors = 0;
- req->nr_sectors -= nsect;
- req->current_nr_sectors = 0;
- end_request(req, 1);
+ ubd_end_request(req, bytes, 1);
}
-static inline void ubd_finish(struct request *req, int error)
+static inline void ubd_finish(struct request *req, int bytes)
{
- spin_lock(&ubd_io_lock);
- __ubd_finish(req, error);
- spin_unlock(&ubd_io_lock);
+ spin_lock(&ubd_io_lock);
+ __ubd_finish(req, bytes);
+ spin_unlock(&ubd_io_lock);
}
-/* Called without ubd_io_lock held */
-static void ubd_handler(void)
-{
- struct io_thread_req req;
- struct request *rq = elv_next_request(ubd_queue);
- int n;
+struct bitmap_io {
+ atomic_t count;
+ struct aio_context aio;
+};
- do_ubd = NULL;
- intr_count++;
- n = os_read_file(thread_fd, &req, sizeof(req));
- if(n != sizeof(req)){
- printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
- "err = %d\n", os_getpid(), -n);
- spin_lock(&ubd_io_lock);
- end_request(rq, 0);
- spin_unlock(&ubd_io_lock);
- return;
- }
-
- ubd_finish(rq, req.error);
- reactivate_fd(thread_fd, UBD_IRQ);
- do_ubd_request(ubd_queue);
-}
+struct ubd_aio {
+ struct aio_context aio;
+ struct request *req;
+ int len;
+ struct bitmap_io *bitmap;
+ void *bitmap_buf;
+};
+
+static int ubd_reply_fd = -1;
static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
{
- ubd_handler();
+ struct aio_thread_reply reply;
+ struct ubd_aio *aio;
+ struct request *req;
+ int err, n, fd = (int) (long) dev;
+
+ while(1){
+ err = os_read_file(fd, &reply, sizeof(reply));
+ if(err == -EAGAIN)
+ break;
+ if(err < 0){
+ printk("ubd_aio_handler - read returned err %d\n",
+ -err);
+ break;
+ }
+
+ aio = container_of(reply.data, struct ubd_aio, aio);
+ n = reply.err;
+
+ if(n == 0){
+ req = aio->req;
+ req->nr_sectors -= aio->len >> 9;
+
+ if((aio->bitmap != NULL) &&
+ (atomic_dec_and_test(&aio->bitmap->count))){
+ aio->aio = aio->bitmap->aio;
+ aio->len = 0;
+ kfree(aio->bitmap);
+ aio->bitmap = NULL;
+ submit_aio(&aio->aio);
+ }
+ else {
+ if((req->nr_sectors == 0) &&
+ (aio->bitmap == NULL)){
+ int len = req->hard_nr_sectors << 9;
+ ubd_finish(req, len);
+ }
+
+ if(aio->bitmap_buf != NULL)
+ kfree(aio->bitmap_buf);
+ kfree(aio);
+ }
+ }
+ else if(n < 0){
+ ubd_finish(aio->req, n);
+ if(aio->bitmap != NULL)
+ kfree(aio->bitmap);
+ if(aio->bitmap_buf != NULL)
+ kfree(aio->bitmap_buf);
+ kfree(aio);
+ }
+ }
+ reactivate_fd(fd, UBD_IRQ);
+
+ do_ubd_request(ubd_queue);
+
return(IRQ_HANDLED);
}
-/* Only changed by ubd_init, which is an initcall. */
-static int io_pid = -1;
-
-void kill_io_thread(void)
-{
- if(io_pid != -1)
- os_kill_process(io_pid, 1);
-}
-
-__uml_exitcall(kill_io_thread);
-
static int ubd_file_size(struct ubd *dev, __u64 *size_out)
{
char *file;
@@ -569,7 +608,7 @@
&dev->cow.data_offset, create_ptr);
if((dev->fd == -ENOENT) && create_cow){
- dev->fd = create_cow_file(dev->file, dev->cow.file,
+ dev->fd = create_cow_file(dev->file, dev->cow.file,
dev->openflags, 1 << 9, PAGE_SIZE,
&dev->cow.bitmap_offset,
&dev->cow.bitmap_len,
@@ -668,21 +707,22 @@
struct ubd *dev = &ubd_dev[n];
int err;
+ err = -ENODEV;
if(dev->file == NULL)
- return(-ENODEV);
+ goto out;
if (ubd_open_dev(dev))
- return(-ENODEV);
+ goto out;
err = ubd_file_size(dev, &dev->size);
if(err < 0)
- return(err);
+ goto out_close;
dev->size = ROUND_BLOCK(dev->size);
err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
if(err)
- return(err);
+ goto out_close;
if(fake_major != MAJOR_NR)
ubd_new_disk(fake_major, dev->size, n,
@@ -693,8 +733,11 @@
if (fake_ide)
make_ide_entries(ubd_gendisk[n]->disk_name);
+ err = 0;
+out_close:
ubd_close(dev);
- return 0;
+out:
+ return err;
}
static int ubd_config(char *str)
@@ -827,6 +870,10 @@
{
int i;
+ ubd_reply_fd = init_aio_irq(UBD_IRQ, "ubd", ubd_intr);
+ if(ubd_reply_fd < 0)
+ printk("Setting up ubd AIO failed, err = %d\n", ubd_reply_fd);
+
devfs_mk_dir("ubd");
if (register_blkdev(MAJOR_NR, "ubd"))
return -1;
@@ -837,6 +884,7 @@
return -1;
}
+ blk_queue_max_hw_segments(ubd_queue, MAX_SG);
if (fake_major != MAJOR_NR) {
char name[sizeof("ubd_nnn\0")];
@@ -848,40 +896,12 @@
driver_register(&ubd_driver);
for (i = 0; i < MAX_DEV; i++)
ubd_add(i);
+
return 0;
}
late_initcall(ubd_init);
-int ubd_driver_init(void){
- unsigned long stack;
- int err;
-
- /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
- if(global_openflags.s){
- printk(KERN_INFO "ubd: Synchronous mode\n");
- /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
- * enough. So use anyway the io thread. */
- }
- stack = alloc_stack(0, 0);
- io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
- &thread_fd);
- if(io_pid < 0){
- printk(KERN_ERR
- "ubd : Failed to start I/O thread (errno = %d) - "
- "falling back to synchronous I/O\n", -io_pid);
- io_pid = -1;
- return(0);
- }
- err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
- SA_INTERRUPT, "ubd", ubd_dev);
- if(err != 0)
- printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
- return(err);
-}
-
-device_initcall(ubd_driver_init);
-
static int ubd_open(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
@@ -919,105 +939,55 @@
return(0);
}
-static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
- __u64 *cow_offset, unsigned long *bitmap,
- __u64 bitmap_offset, unsigned long *bitmap_words,
- __u64 bitmap_len)
+static void cowify_bitmap(struct io_thread_req *req, unsigned long *bitmap)
{
- __u64 sector = io_offset >> 9;
- int i, update_bitmap = 0;
+ __u64 sector = req->offset / req->sectorsize;
+ int i;
- for(i = 0; i < length >> 9; i++){
- if(cow_mask != NULL)
- ubd_set_bit(i, (unsigned char *) cow_mask);
- if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
- continue;
+ for(i = 0; i < req->length / req->sectorsize; i++){
+ if(ubd_test_bit(sector + i, bitmap))
+ continue;
- update_bitmap = 1;
- ubd_set_bit(sector + i, (unsigned char *) bitmap);
- }
+ if(req->bitmap_start == -1)
+ req->bitmap_start = sector + i;
+ req->bitmap_end = sector + i + 1;
- if(!update_bitmap)
- return;
-
- *cow_offset = sector / (sizeof(unsigned long) * 8);
-
- /* This takes care of the case where we're exactly at the end of the
- * device, and *cow_offset + 1 is off the end. So, just back it up
- * by one word. Thanks to Lynn Kerby for the fix and James McMechan
- * for the original diagnosis.
- */
- if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
- sizeof(unsigned long) - 1))
- (*cow_offset)--;
-
- bitmap_words[0] = bitmap[*cow_offset];
- bitmap_words[1] = bitmap[*cow_offset + 1];
-
- *cow_offset *= sizeof(unsigned long);
- *cow_offset += bitmap_offset;
-}
-
-static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
- __u64 bitmap_offset, __u64 bitmap_len)
-{
- __u64 sector = req->offset >> 9;
- int i;
-
- if(req->length > (sizeof(req->sector_mask) * 8) << 9)
- panic("Operation too long");
-
- if(req->op == UBD_READ) {
- for(i = 0; i < req->length >> 9; i++){
- if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
- ubd_set_bit(i, (unsigned char *)
- &req->sector_mask);
- }
- }
- else cowify_bitmap(req->offset, req->length, &req->sector_mask,
- &req->cow_offset, bitmap, bitmap_offset,
- req->bitmap_words, bitmap_len);
+ ubd_set_bit(sector + i, bitmap);
+ }
}
/* Called with ubd_io_lock held */
-static int prepare_request(struct request *req, struct io_thread_req *io_req)
+static int prepare_request(struct request *req, struct io_thread_req *io_req,
+ unsigned long long offset, int page_offset,
+ int len, struct page *page)
{
struct gendisk *disk = req->rq_disk;
struct ubd *dev = disk->private_data;
- __u64 offset;
- int len;
-
- if(req->rq_status == RQ_INACTIVE) return(1);
/* This should be impossible now */
if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
printk("Write attempted on readonly ubd device %s\n",
disk->disk_name);
- end_request(req, 0);
+ ubd_end_request(req, 0, 0);
return(1);
}
- offset = ((__u64) req->sector) << 9;
- len = req->current_nr_sectors << 9;
-
io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
io_req->fds[1] = dev->fd;
- io_req->cow_offset = -1;
io_req->offset = offset;
io_req->length = len;
io_req->error = 0;
- io_req->sector_mask = 0;
-
- io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
+ io_req->op = (rq_data_dir(req) == READ) ? AIO_READ : AIO_WRITE;
io_req->offsets[0] = 0;
io_req->offsets[1] = dev->cow.data_offset;
- io_req->buffer = req->buffer;
+ io_req->buffer = page_address(page) + page_offset;
io_req->sectorsize = 1 << 9;
+ io_req->bitmap_offset = dev->cow.bitmap_offset;
+ io_req->bitmap_start = -1;
+ io_req->bitmap_end = -1;
- if(dev->cow.file != NULL)
- cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
- dev->cow.bitmap_len);
-
+ if((dev->cow.file != NULL) && (io_req->op == UBD_WRITE))
+ cowify_bitmap(io_req, dev->cow.bitmap);
return(0);
}
@@ -1026,30 +996,36 @@
{
struct io_thread_req io_req;
struct request *req;
- int err, n;
+ __u64 sector;
+ int err;
- if(thread_fd == -1){
- while((req = elv_next_request(q)) != NULL){
- err = prepare_request(req, &io_req);
- if(!err){
- do_io(&io_req);
- __ubd_finish(req, io_req.error);
- }
+ if(in_ubd)
+ return;
+ in_ubd = 1;
+ while((req = elv_next_request(q)) != NULL){
+ struct gendisk *disk = req->rq_disk;
+ struct ubd *dev = disk->private_data;
+ int n, i;
+
+ blkdev_dequeue_request(req);
+
+ sector = req->sector;
+ n = blk_rq_map_sg(q, req, dev->sg);
+
+ for(i = 0; i < n; i++){
+ struct scatterlist *sg = &dev->sg[i];
+
+ err = prepare_request(req, &io_req, sector << 9,
+ sg->offset, sg->length,
+ sg->page);
+ if(err)
+ continue;
+
+ sector += sg->length >> 9;
+ do_io(&io_req, req, dev->cow.bitmap);
}
}
- else {
- if(do_ubd || (req = elv_next_request(q)) == NULL)
- return;
- err = prepare_request(req, &io_req);
- if(!err){
- do_ubd = ubd_handler;
- n = os_write_file(thread_fd, (char *) &io_req,
- sizeof(io_req));
- if(n != sizeof(io_req))
- printk("write to io thread failed, "
- "errno = %d\n", -n);
- }
- }
+ in_ubd = 0;
}
static int ubd_ioctl(struct inode * inode, struct file * file,
@@ -1265,131 +1241,95 @@
return(err);
}
-static int update_bitmap(struct io_thread_req *req)
+void do_io(struct io_thread_req *req, struct request *r, unsigned long *bitmap)
{
- int n;
+ struct ubd_aio *aio;
+ struct bitmap_io *bitmap_io = NULL;
+ char *buf;
+ void *bitmap_buf = NULL;
+ unsigned long len, sector;
+ int nsectors, start, end, bit, err;
+ __u64 off;
- if(req->cow_offset == -1)
- return(0);
+ if(req->bitmap_start != -1){
+ /* Round up to the nearest word */
+ int round = sizeof(unsigned long);
+ len = (req->bitmap_end - req->bitmap_start +
+ round * 8 - 1) / (round * 8);
+ len *= round;
- n = os_seek_file(req->fds[1], req->cow_offset);
- if(n < 0){
- printk("do_io - bitmap lseek failed : err = %d\n", -n);
- return(1);
- }
+ off = req->bitmap_start / (8 * round);
+ off *= round;
- n = os_write_file(req->fds[1], &req->bitmap_words,
- sizeof(req->bitmap_words));
- if(n != sizeof(req->bitmap_words)){
- printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
- req->fds[1]);
- return(1);
- }
+ bitmap_io = kmalloc(sizeof(*bitmap_io), GFP_KERNEL);
+ if(bitmap_io == NULL){
+ printk("Failed to kmalloc bitmap IO\n");
+ req->error = 1;
+ return;
+ }
- return(0);
+ bitmap_buf = kmalloc(len, GFP_KERNEL);
+ if(bitmap_buf == NULL){
+ printk("do_io : kmalloc of bitmap chunk "
+ "failed\n");
+ kfree(bitmap_io);
+ req->error = 1;
+ return;
+ }
+ memcpy(bitmap_buf, &bitmap[off / sizeof(bitmap[0])], len);
+
+ *bitmap_io = ((struct bitmap_io)
+ { .count = ATOMIC_INIT(0),
+ .aio = INIT_AIO(AIO_WRITE, req->fds[1],
+ bitmap_buf, len,
+ req->bitmap_offset + off,
+ ubd_reply_fd) } );
+ }
+
+ nsectors = req->length / req->sectorsize;
+ start = 0;
+ end = nsectors;
+ bit = 0;
+ do {
+ if(bitmap != NULL){
+ sector = req->offset / req->sectorsize;
+ bit = ubd_test_bit(sector + start, bitmap);
+ end = start;
+ while((end < nsectors) &&
+ (ubd_test_bit(sector + end, bitmap) == bit))
+ end++;
+ }
+
+ off = req->offsets[bit] + req->offset +
+ start * req->sectorsize;
+ len = (end - start) * req->sectorsize;
+ buf = &req->buffer[start * req->sectorsize];
+
+ aio = kmalloc(sizeof(*aio), GFP_KERNEL);
+ if(aio == NULL){
+ req->error = 1;
+ return;
+ }
+
+ *aio = ((struct ubd_aio)
+ { .aio = INIT_AIO(req->op, req->fds[bit], buf,
+ len, off, ubd_reply_fd),
+ .len = len,
+ .req = r,
+ .bitmap = bitmap_io,
+ .bitmap_buf = bitmap_buf });
+
+ if(aio->bitmap != NULL)
+ atomic_inc(&aio->bitmap->count);
+
+ err = submit_aio(&aio->aio);
+ if(err){
+ printk("do_io - submit_aio failed, "
+ "err = %d\n", err);
+ req->error = 1;
+ return;
+ }
+
+ start = end;
+ } while(start < nsectors);
}
-
-void do_io(struct io_thread_req *req)
-{
- char *buf;
- unsigned long len;
- int n, nsectors, start, end, bit;
- int err;
- __u64 off;
-
- nsectors = req->length / req->sectorsize;
- start = 0;
- do {
- bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
- end = start;
- while((end < nsectors) &&
- (ubd_test_bit(end, (unsigned char *)
- &req->sector_mask) == bit))
- end++;
-
- off = req->offset + req->offsets[bit] +
- start * req->sectorsize;
- len = (end - start) * req->sectorsize;
- buf = &req->buffer[start * req->sectorsize];
-
- err = os_seek_file(req->fds[bit], off);
- if(err < 0){
- printk("do_io - lseek failed : err = %d\n", -err);
- req->error = 1;
- return;
- }
- if(req->op == UBD_READ){
- n = 0;
- do {
- buf = &buf[n];
- len -= n;
- n = os_read_file(req->fds[bit], buf, len);
- if (n < 0) {
- printk("do_io - read failed, err = %d "
- "fd = %d\n", -n, req->fds[bit]);
- req->error = 1;
- return;
- }
- } while((n < len) && (n != 0));
- if (n < len) memset(&buf[n], 0, len - n);
- } else {
- n = os_write_file(req->fds[bit], buf, len);
- if(n != len){
- printk("do_io - write failed err = %d "
- "fd = %d\n", -n, req->fds[bit]);
- req->error = 1;
- return;
- }
- }
-
- start = end;
- } while(start < nsectors);
-
- req->error = update_bitmap(req);
-}
-
-/* Changed in start_io_thread, which is serialized by being called only
- * from ubd_init, which is an initcall.
- */
-int kernel_fd = -1;
-
-/* Only changed by the io thread */
-int io_count = 0;
-
-int io_thread(void *arg)
-{
- struct io_thread_req req;
- int n;
-
- ignore_sigwinch_sig();
- while(1){
- n = os_read_file(kernel_fd, &req, sizeof(req));
- if(n != sizeof(req)){
- if(n < 0)
- printk("io_thread - read failed, fd = %d, "
- "err = %d\n", kernel_fd, -n);
- else {
- printk("io_thread - short read, fd = %d, "
- "length = %d\n", kernel_fd, n);
- }
- continue;
- }
- io_count++;
- do_io(&req);
- n = os_write_file(kernel_fd, &req, sizeof(req));
- if(n != sizeof(req))
- printk("io_thread - write failed, fd = %d, err = %d\n",
- kernel_fd, -n);
- }
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/aio.h b/arch/um/include/aio.h
new file mode 100644
index 0000000..83f1687
--- /dev/null
+++ b/arch/um/include/aio.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef AIO_H__
+#define AIO_H__
+
+enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP };
+
+struct aio_thread_reply {
+ void *data;
+ int err;
+};
+
+struct aio_context {
+ enum aio_type type;
+ int fd;
+ void *data;
+ int len;
+ unsigned long long offset;
+ int reply_fd;
+ struct aio_context *next;
+};
+
+#define INIT_AIO(aio_type, aio_fd, aio_data, aio_len, aio_offset, \
+ aio_reply_fd) \
+ { .type = aio_type, \
+ .fd = aio_fd, \
+ .data = aio_data, \
+ .len = aio_len, \
+ .offset = aio_offset, \
+ .reply_fd = aio_reply_fd }
+
+#define INIT_AIO_CONTEXT { .reply_fd = -1, \
+ .next = NULL }
+
+extern int submit_aio(struct aio_context *aio);
+
+#endif
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index d705daa..0aa6209 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -12,3 +12,4 @@
DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
DEFINE_STR(UM_KERN_INFO, KERN_INFO);
DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+DEFINE(HOST_ELF_CLASS, ELF_CLASS);
diff --git a/arch/um/include/init.h b/arch/um/include/init.h
index 55c2693..cbd79a8 100644
--- a/arch/um/include/init.h
+++ b/arch/um/include/init.h
@@ -111,7 +111,15 @@
#ifndef __KERNEL__
-#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn
+#define __define_initcall(level,fn) \
+ static initcall_t __initcall_##fn __attribute_used__ \
+ __attribute__((__section__(".initcall" level ".init"))) = fn
+
+/* Userspace initcalls shouldn't depend on anything in the kernel, so we'll
+ * make them run first.
+ */
+#define __initcall(fn) __define_initcall("1", fn)
+
#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h
index 3af52a6..c222d56 100644
--- a/arch/um/include/irq_kern.h
+++ b/arch/um/include/irq_kern.h
@@ -7,12 +7,15 @@
#define __IRQ_KERN_H__
#include "linux/interrupt.h"
+#include "asm/ptrace.h"
extern int um_request_irq(unsigned int irq, int fd, int type,
irqreturn_t (*handler)(int, void *,
struct pt_regs *),
unsigned long irqflags, const char * devname,
void *dev_id);
+extern int init_aio_irq(int irq, char *name,
+ irqreturn_t (*handler)(int, void *, struct pt_regs *));
#endif
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 881d298..4c36245 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -153,6 +153,11 @@
extern int os_file_mode(char *file, struct openflags *mode_out);
extern int os_lock_file(int fd, int excl);
+/* start_up.c */
+extern void os_early_checks(void);
+extern int can_do_skas(void);
+
+/* process.c */
extern unsigned long os_process_pc(int pid);
extern int os_process_parent(int pid);
extern void os_stop_process(int pid);
@@ -161,6 +166,9 @@
extern void os_usr1_process(int pid);
extern int os_getpid(void);
extern int os_getpgrp(void);
+extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
+extern void init_new_thread_signals(int altstack);
+extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
extern int os_map_memory(void *virt, int fd, unsigned long long off,
unsigned long len, int r, int w, int x);
@@ -170,6 +178,13 @@
extern void os_flush_stdout(void);
extern unsigned long long os_usecs(void);
+/* tt.c
+ * for tt mode only (will be deleted in future...)
+ */
+extern void forward_pending_sigio(int target);
+extern int start_fork_tramp(void *arg, unsigned long temp_stack,
+ int clone_flags, int (*tramp)(void *));
+
#endif
/*
diff --git a/arch/um/include/syscall.h b/arch/um/include/syscall.h
new file mode 100644
index 0000000..dda1df9
--- /dev/null
+++ b/arch/um/include/syscall.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSCALL_USER_H
+#define __SYSCALL_USER_H
+
+extern int record_syscall_start(int syscall);
+extern void record_syscall_end(int index, long result);
+
+#endif
diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h
deleted file mode 100644
index 811d0ec..0000000
--- a/arch/um/include/syscall_user.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SYSCALL_USER_H
-#define __SYSCALL_USER_H
-
-extern int record_syscall_start(int syscall);
-extern void record_syscall_end(int index, long result);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h
index be0a3e3..a0d5b74 100644
--- a/arch/um/include/sysdep-i386/syscalls.h
+++ b/arch/um/include/sysdep-i386/syscalls.h
@@ -16,6 +16,8 @@
extern syscall_handler_t old_mmap_i386;
+extern syscall_handler_t *sys_call_table[];
+
#define EXECUTE_SYSCALL(syscall, regs) \
((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs))
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
index be8acd5..331aa2d 100644
--- a/arch/um/include/sysdep-x86_64/ptrace.h
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -227,7 +227,7 @@
panic("Bad register in UPT_SET : %d\n", reg); \
break; \
} \
- val; \
+ __upt_val; \
})
#define UPT_SET_SYSCALL_RETURN(r, res) \
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h
index 67923cc..e06f83e 100644
--- a/arch/um/include/sysdep-x86_64/syscalls.h
+++ b/arch/um/include/sysdep-x86_64/syscalls.h
@@ -14,6 +14,8 @@
extern syscall_handler_t *ia32_sys_call_table[];
+extern syscall_handler_t *sys_call_table[];
+
#define EXECUTE_SYSCALL(syscall, regs) \
(((long (*)(long, long, long, long, long, long)) \
(*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(®s->regs), \
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index c6f9628..45d7da6 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -9,7 +9,7 @@
#include "um_mmu.h"
struct host_vm_op {
- enum { MMAP, MUNMAP, MPROTECT } type;
+ enum { NONE, MMAP, MUNMAP, MPROTECT } type;
union {
struct {
unsigned long addr;
@@ -38,24 +38,10 @@
extern void force_flush_all(void);
extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force,
- void (*do_ops)(union mm_context *,
- struct host_vm_op *, int));
+ int (*do_ops)(union mm_context *,
+ struct host_vm_op *, int, int,
+ void **));
extern int flush_tlb_kernel_range_common(unsigned long start,
unsigned long end);
-extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, union mm_context *mmu,
- void (*do_ops)(union mm_context *, struct host_vm_op *,
- int));
-extern int add_munmap(unsigned long addr, unsigned long len,
- struct host_vm_op *ops, int index, int last_filled,
- union mm_context *mmu,
- void (*do_ops)(union mm_context *, struct host_vm_op *,
- int));
-extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
- int x, struct host_vm_op *ops, int index,
- int last_filled, union mm_context *mmu,
- void (*do_ops)(union mm_context *, struct host_vm_op *,
- int));
#endif
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index 6e348cb..84c0868 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -20,13 +20,6 @@
#define access_ok(type, addr, size) \
CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
-{
- return (CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
- size));
-}
-
static inline int copy_from_user(void *to, const void __user *from, int n)
{
return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index 7b6a24d..bb505e0 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -54,8 +54,6 @@
extern void task_protections(unsigned long address);
extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern void *add_signal_handler(int sig, void (*handler)(int));
-extern int start_fork_tramp(void *arg, unsigned long temp_stack,
- int clone_flags, int (*tramp)(void *));
extern int linux_main(int argc, char **argv);
extern void set_cmdline(char *cmd);
extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
@@ -64,8 +62,6 @@
extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
-extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
-extern void init_new_thread_signals(int altstack);
extern void do_exec(int old_pid, int new_pid);
extern void tracer_panic(char *msg, ...);
extern char *get_umid(int only_if_set);
@@ -74,16 +70,12 @@
extern int attach(int pid);
extern void kill_child_dead(int pid);
extern int cont(int pid);
-extern void check_ptrace(void);
extern void check_sigio(void);
-extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
extern void write_sigio_workaround(void);
extern void arch_check_bugs(void);
extern int cpu_feature(char *what, char *buf, int len);
extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
extern int arch_fixup(unsigned long address, void *sc_ptr);
-extern void forward_pending_sigio(int target);
-extern int can_do_skas(void);
extern void arch_init_thread(void);
extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
extern int raw(int fd);
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index a8918e80..614b8eb 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -8,25 +8,24 @@
obj-y = config.o exec_kern.o exitcode.o \
helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \
- physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
- sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
- syscall_kern.o sysrq.o tempfile.o time.o time_kern.o \
- tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \
- user_util.o
+ physmem.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
+ sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o \
+ tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o \
+ uaccess_user.o um_arch.o umid.o user_util.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_TTY_LOG) += tty_log.o
-obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o
+obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o
obj-$(CONFIG_MODE_TT) += tt/
obj-$(CONFIG_MODE_SKAS) += skas/
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \
- time.o tty_log.o umid.o user_util.o
+USER_OBJS := $(user-objs-y) config.o helper.o main.o tempfile.o time.o \
+ tty_log.o umid.o user_util.o
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 9f18061..dcd8149 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -31,7 +31,7 @@
#include "kern_util.h"
#include "irq_user.h"
#include "irq_kern.h"
-
+#include "os.h"
/*
* Generic, controller-independent functions:
@@ -168,13 +168,32 @@
}
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *,
+ struct pt_regs *))
+{
+ int fds[2], err;
+
+ err = os_pipe(fds, 1, 1);
+ if(err){
+ printk("init_aio_irq - os_pipe failed, err = %d\n", -err);
+ goto out;
+ }
+
+ err = um_request_irq(irq, fds[0], IRQ_READ, handler,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM, name,
+ (void *) (long) fds[0]);
+ if(err){
+ printk("init_aio_irq - : um_request_irq failed, err = %d\n",
+ err);
+ goto out_close;
+ }
+
+ err = fds[1];
+ goto out;
+
+ out_close:
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ out:
+ return(err);
+}
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 99439fa..32d3076 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -114,22 +114,3 @@
EXPORT_SYMBOL(__read_lock_failed);
#endif
-
-#ifdef CONFIG_HIGHMEM
-EXPORT_SYMBOL(kmap);
-EXPORT_SYMBOL(kunmap);
-EXPORT_SYMBOL(kmap_atomic);
-EXPORT_SYMBOL(kunmap_atomic);
-EXPORT_SYMBOL(kmap_atomic_to_page);
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
index 1e1a87f..d31027f 100644
--- a/arch/um/kernel/main.c
+++ b/arch/um/kernel/main.c
@@ -97,7 +97,7 @@
exit(1);
}
-#ifdef UML_CONFIG_MODE_TT
+#ifdef UML_CONFIG_CMDLINE_ON_HOST
/* Allocate memory for thread command lines */
if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 5597bd3..64fa062 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -196,7 +196,7 @@
static void __init fixaddr_user_init( void)
{
-#if CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
+#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
long size = FIXADDR_USER_END - FIXADDR_USER_START;
pgd_t *pgd;
pud_t *pud;
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index d296d55..db36c7c 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -4,7 +4,7 @@
#
obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
- syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
+ syscall.o tlb.o trap_user.o uaccess.o
subdir- := util
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 278b72f..09536f8 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,11 +6,15 @@
#ifndef __SKAS_MMU_H
#define __SKAS_MMU_H
+#include "linux/config.h"
#include "mm_id.h"
struct mmu_context_skas {
struct mm_id id;
unsigned long last_page_table;
+#ifdef CONFIG_3_LEVEL_PGTABLES
+ unsigned long last_pmd;
+#endif
};
extern void switch_mm_skas(struct mm_id * mm_idp);
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index d983ea8..0609347 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -24,28 +24,26 @@
extern void remove_sigstack(void);
extern void new_thread_handler(int sig);
extern void handle_syscall(union uml_pt_regs *regs);
-extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
- int r, int w, int x, int phys_fd, unsigned long long offset);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int map(struct mm_id * mm_idp, unsigned long virt,
+ unsigned long len, int r, int w, int x, int phys_fd,
+ unsigned long long offset, int done, void **data);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
+ int done, void **data);
extern int protect(struct mm_id * mm_idp, unsigned long addr,
- unsigned long len, int r, int w, int x);
+ unsigned long len, int r, int w, int x, int done,
+ void **data);
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
-extern int new_mm(int from);
+extern int new_mm(int from, unsigned long stack);
extern int start_userspace(unsigned long stub_stack);
extern int copy_context_skas0(unsigned long stack, int pid);
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
extern long execute_syscall_skas(void *r);
extern unsigned long current_stub_stack(void);
+extern long run_syscall_stub(struct mm_id * mm_idp,
+ int syscall, unsigned long *args, long expected,
+ void **addr, int done);
+extern long syscall_stub_data(struct mm_id * mm_idp,
+ unsigned long *data, int data_count,
+ void **addr, void **stub_addr);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index b0980ff..1d89640 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -5,13 +5,14 @@
#include <signal.h>
#include <errno.h>
+#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <asm/page.h>
#include <asm/unistd.h>
#include "mem_user.h"
#include "mem.h"
-#include "mm_id.h"
+#include "skas.h"
#include "user.h"
#include "os.h"
#include "proc_mm.h"
@@ -23,46 +24,155 @@
#include "uml-config.h"
#include "sysdep/ptrace.h"
#include "sysdep/stub.h"
-#include "skas.h"
-extern unsigned long syscall_stub, __syscall_stub_start;
+extern unsigned long batch_syscall_stub, __syscall_stub_start;
extern void wait_stub_done(int pid, int sig, char * fname);
-static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
- unsigned long *args)
+static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
+ unsigned long *stack)
{
+ if(stack == NULL){
+ stack = (unsigned long *) mm_idp->stack + 2;
+ *stack = 0;
+ }
+ return stack;
+}
+
+extern int proc_mm;
+
+int single_count = 0;
+int multi_count = 0;
+int multi_op_count = 0;
+
+static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
+{
+ unsigned long regs[MAX_REG_NR];
+ unsigned long *data;
+ unsigned long *syscall;
+ long ret, offset;
int n, pid = mm_idp->u.pid;
- unsigned long regs[MAX_REG_NR];
+
+ if(proc_mm)
+#warning Need to look up userspace_pid by cpu
+ pid = userspace_pid[0];
+
+ multi_count++;
get_safe_registers(regs);
regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
- ((unsigned long) &syscall_stub -
+ ((unsigned long) &batch_syscall_stub -
(unsigned long) &__syscall_stub_start);
- /* XXX Don't have a define for starting a syscall */
- regs[REGS_SYSCALL_NR] = syscall;
- regs[REGS_SYSCALL_ARG1] = args[0];
- regs[REGS_SYSCALL_ARG2] = args[1];
- regs[REGS_SYSCALL_ARG3] = args[2];
- regs[REGS_SYSCALL_ARG4] = args[3];
- regs[REGS_SYSCALL_ARG5] = args[4];
- regs[REGS_SYSCALL_ARG6] = args[5];
- n = ptrace_setregs(pid, regs);
- if(n < 0){
- printk("run_syscall_stub : PTRACE_SETREGS failed, "
- "errno = %d\n", n);
- return(n);
- }
+ n = ptrace_setregs(pid, regs);
+ if(n < 0)
+ panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
+ n);
- wait_stub_done(pid, 0, "run_syscall_stub");
+ wait_stub_done(pid, 0, "do_syscall_stub");
- return(*((unsigned long *) mm_idp->stack));
+ /* When the stub stops, we find the following values on the
+ * beginning of the stack:
+ * (long )return_value
+ * (long )offset to failed sycall-data (0, if no error)
+ */
+ ret = *((unsigned long *) mm_idp->stack);
+ offset = *((unsigned long *) mm_idp->stack + 1);
+ if (offset) {
+ data = (unsigned long *)(mm_idp->stack +
+ offset - UML_CONFIG_STUB_DATA);
+ syscall = (unsigned long *)((unsigned long)data + data[0]);
+ printk("do_syscall_stub: syscall %ld failed, return value = "
+ "0x%lx, expected return value = 0x%lx\n",
+ syscall[0], ret, syscall[7]);
+ printk(" syscall parameters: "
+ "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+ syscall[1], syscall[2], syscall[3],
+ syscall[4], syscall[5], syscall[6]);
+ for(n = 1; n < data[0]/sizeof(long); n++) {
+ if(n == 1)
+ printk(" additional syscall data:");
+ if(n % 4 == 1)
+ printk("\n ");
+ printk(" 0x%lx", data[n]);
+ }
+ if(n > 1)
+ printk("\n");
+ }
+ else ret = 0;
+
+ *addr = check_init_stack(mm_idp, NULL);
+
+ return ret;
}
-int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
- int r, int w, int x, int phys_fd, unsigned long long offset)
+long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+ unsigned long *args, long expected, void **addr,
+ int done)
{
- int prot, n;
+ unsigned long *stack = check_init_stack(mm_idp, *addr);
+
+ if(done && *addr == NULL)
+ single_count++;
+
+ *stack += sizeof(long);
+ stack += *stack / sizeof(long);
+
+ *stack++ = syscall;
+ *stack++ = args[0];
+ *stack++ = args[1];
+ *stack++ = args[2];
+ *stack++ = args[3];
+ *stack++ = args[4];
+ *stack++ = args[5];
+ *stack++ = expected;
+ *stack = 0;
+ multi_op_count++;
+
+ if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
+ PAGE_SIZE - 10 * sizeof(long))){
+ *addr = stack;
+ return 0;
+ }
+
+ return do_syscall_stub(mm_idp, addr);
+}
+
+long syscall_stub_data(struct mm_id * mm_idp,
+ unsigned long *data, int data_count,
+ void **addr, void **stub_addr)
+{
+ unsigned long *stack;
+ int ret = 0;
+
+ /* If *addr still is uninitialized, it *must* contain NULL.
+ * Thus in this case do_syscall_stub correctly won't be called.
+ */
+ if((((unsigned long) *addr) & ~PAGE_MASK) >=
+ PAGE_SIZE - (10 + data_count) * sizeof(long)) {
+ ret = do_syscall_stub(mm_idp, addr);
+ /* in case of error, don't overwrite data on stack */
+ if(ret)
+ return ret;
+ }
+
+ stack = check_init_stack(mm_idp, *addr);
+ *addr = stack;
+
+ *stack = data_count * sizeof(long);
+
+ memcpy(stack + 1, data, data_count * sizeof(long));
+
+ *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) +
+ UML_CONFIG_STUB_DATA);
+
+ return 0;
+}
+
+int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset,
+ int done, void **data)
+{
+ int prot, ret;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
@@ -70,6 +180,7 @@
if(proc_mm){
struct proc_mm_op map;
int fd = mm_idp->u.mm_fd;
+
map = ((struct proc_mm_op) { .op = MM_MMAP,
.u =
{ .mmap =
@@ -81,63 +192,61 @@
.fd = phys_fd,
.offset= offset
} } } );
- n = os_write_file(fd, &map, sizeof(map));
- if(n != sizeof(map))
- printk("map : /proc/mm map failed, err = %d\n", -n);
+ ret = os_write_file(fd, &map, sizeof(map));
+ if(ret != sizeof(map))
+ printk("map : /proc/mm map failed, err = %d\n", -ret);
+ else ret = 0;
}
else {
- long res;
unsigned long args[] = { virt, len, prot,
MAP_SHARED | MAP_FIXED, phys_fd,
MMAP_OFFSET(offset) };
- res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
- if((void *) res == MAP_FAILED)
- printk("mmap stub failed, errno = %d\n", res);
+ ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
+ data, done);
}
- return 0;
+ return ret;
}
-int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
+int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
+ void **data)
{
- int n;
+ int ret;
if(proc_mm){
struct proc_mm_op unmap;
int fd = mm_idp->u.mm_fd;
+
unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
.u =
{ .munmap =
{ .addr =
(unsigned long) addr,
.len = len } } } );
- n = os_write_file(fd, &unmap, sizeof(unmap));
- if(n != sizeof(unmap)) {
- if(n < 0)
- return(n);
- else if(n > 0)
- return(-EIO);
- }
+ ret = os_write_file(fd, &unmap, sizeof(unmap));
+ if(ret != sizeof(unmap))
+ printk("unmap - proc_mm write returned %d\n", ret);
+ else ret = 0;
}
else {
- int res;
unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
0 };
- res = run_syscall_stub(mm_idp, __NR_munmap, args);
- if(res < 0)
- printk("munmap stub failed, errno = %d\n", res);
+ ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
+ data, done);
+ if(ret < 0)
+ printk("munmap stub failed, errno = %d\n", ret);
}
- return(0);
+ return ret;
}
-int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
- int r, int w, int x)
+int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
+ int r, int w, int x, int done, void **data)
{
struct proc_mm_op protect;
- int prot, n;
+ int prot, ret;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
@@ -152,20 +261,19 @@
.len = len,
.prot = prot } } } );
- n = os_write_file(fd, &protect, sizeof(protect));
- if(n != sizeof(protect))
- panic("protect failed, err = %d", -n);
+ ret = os_write_file(fd, &protect, sizeof(protect));
+ if(ret != sizeof(protect))
+ printk("protect failed, err = %d", -ret);
+ else ret = 0;
}
else {
- int res;
unsigned long args[] = { addr, len, prot, 0, 0, 0 };
- res = run_syscall_stub(mm_idp, __NR_mprotect, args);
- if(res < 0)
- panic("mprotect stub failed, errno = %d\n", res);
+ ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
+ data, done);
}
- return(0);
+ return ret;
}
void before_mem_skas(unsigned long unused)
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index d232daa..240143b 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -56,6 +56,9 @@
*/
mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+#ifdef CONFIG_3_LEVEL_PGTABLES
+ mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud));
+#endif
*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
*pte = pte_mkexec(*pte);
@@ -77,23 +80,14 @@
struct mm_struct *cur_mm = current->mm;
struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
struct mm_id *mm_id = &mm->context.skas.id;
- unsigned long stack;
- int from, ret;
+ unsigned long stack = 0;
+ int from, ret = -ENOMEM;
- if(proc_mm){
- if((cur_mm != NULL) && (cur_mm != &init_mm))
- from = cur_mm->context.skas.id.u.mm_fd;
- else from = -1;
+ if(!proc_mm || !ptrace_faultinfo){
+ stack = get_zeroed_page(GFP_KERNEL);
+ if(stack == 0)
+ goto out;
- ret = new_mm(from);
- if(ret < 0){
- printk("init_new_context_skas - new_mm failed, "
- "errno = %d\n", ret);
- return ret;
- }
- mm_id->u.mm_fd = ret;
- }
- else {
/* This zeros the entry that pgd_alloc didn't, needed since
* we are about to reinitialize it, and want mm.nr_ptes to
* be accurate.
@@ -103,20 +97,30 @@
ret = init_stub_pte(mm, CONFIG_STUB_CODE,
(unsigned long) &__syscall_stub_start);
if(ret)
- goto out;
-
- ret = -ENOMEM;
- stack = get_zeroed_page(GFP_KERNEL);
- if(stack == 0)
- goto out;
- mm_id->stack = stack;
+ goto out_free;
ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
if(ret)
goto out_free;
mm->nr_ptes--;
+ }
+ mm_id->stack = stack;
+ if(proc_mm){
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ from = cur_mm_id->u.mm_fd;
+ else from = -1;
+
+ ret = new_mm(from, stack);
+ if(ret < 0){
+ printk("init_new_context_skas - new_mm failed, "
+ "errno = %d\n", ret);
+ goto out_free;
+ }
+ mm_id->u.mm_fd = ret;
+ }
+ else {
if((cur_mm != NULL) && (cur_mm != &init_mm))
mm_id->u.pid = copy_context_skas0(stack,
cur_mm_id->u.pid);
@@ -126,7 +130,8 @@
return 0;
out_free:
- free_page(mm_id->stack);
+ if(mm_id->stack != 0)
+ free_page(mm_id->stack);
out:
return ret;
}
@@ -137,9 +142,15 @@
if(proc_mm)
os_close_file(mmu->id.u.mm_fd);
- else {
+ else
os_kill_ptraced_process(mmu->id.u.pid, 1);
+
+ if(!proc_mm || !ptrace_faultinfo){
free_page(mmu->id.stack);
- free_page(mmu->last_page_table);
+ pte_free_kernel((pte_t *) mmu->last_page_table);
+ dec_page_state(nr_page_table_pages);
+#ifdef CONFIG_3_LEVEL_PGTABLES
+ pmd_free((pmd_t *) mmu->last_pmd);
+#endif
}
}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index f228f8b..5cd0e99 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -138,6 +138,8 @@
}
extern int __syscall_stub_start;
+int stub_code_fd = -1;
+__u64 stub_code_offset;
static int userspace_tramp(void *stack)
{
@@ -152,31 +154,31 @@
/* This has a pte, but it can't be mapped in with the usual
* tlb_flush mechanism because this is part of that mechanism
*/
- int fd;
- __u64 offset;
-
- fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
- PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+ PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
+ stub_code_fd, stub_code_offset);
if(addr == MAP_FAILED){
- printk("mapping mmap stub failed, errno = %d\n",
+ printk("mapping stub code failed, errno = %d\n",
errno);
exit(1);
}
if(stack != NULL){
+ int fd;
+ __u64 offset;
+
fd = phys_mapping(to_phys(stack), &offset);
addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, offset);
if(addr == MAP_FAILED){
- printk("mapping segfault stack failed, "
+ printk("mapping stub stack failed, "
"errno = %d\n", errno);
exit(1);
}
}
}
- if(!ptrace_faultinfo && (stack != NULL)){
+ if(!ptrace_faultinfo){
unsigned long v = UML_CONFIG_STUB_CODE +
(unsigned long) stub_segv_handler -
(unsigned long) &__syscall_stub_start;
@@ -202,6 +204,10 @@
unsigned long sp;
int pid, status, n, flags;
+ if ( stub_code_fd == -1 )
+ stub_code_fd = phys_mapping(to_phys(&__syscall_stub_start),
+ &stub_code_offset);
+
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(stack == MAP_FAILED)
@@ -363,6 +369,53 @@
return pid;
}
+/*
+ * This is used only, if proc_mm is available, while PTRACE_FAULTINFO
+ * isn't. Opening /proc/mm creates a new mm_context, which lacks the stub-pages
+ * Thus, we map them using /proc/mm-fd
+ */
+void map_stub_pages(int fd, unsigned long code,
+ unsigned long data, unsigned long stack)
+{
+ struct proc_mm_op mmop;
+ int n;
+
+ mmop = ((struct proc_mm_op) { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = code,
+ .len = PAGE_SIZE,
+ .prot = PROT_EXEC,
+ .flags = MAP_FIXED | MAP_PRIVATE,
+ .fd = stub_code_fd,
+ .offset = stub_code_offset
+ } } });
+ n = os_write_file(fd, &mmop, sizeof(mmop));
+ if(n != sizeof(mmop))
+ panic("map_stub_pages : /proc/mm map for code failed, "
+ "err = %d\n", -n);
+
+ if ( stack ) {
+ __u64 map_offset;
+ int map_fd = phys_mapping(to_phys((void *)stack), &map_offset);
+ mmop = ((struct proc_mm_op)
+ { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = data,
+ .len = PAGE_SIZE,
+ .prot = PROT_READ | PROT_WRITE,
+ .flags = MAP_FIXED | MAP_SHARED,
+ .fd = map_fd,
+ .offset = map_offset
+ } } });
+ n = os_write_file(fd, &mmop, sizeof(mmop));
+ if(n != sizeof(mmop))
+ panic("map_stub_pages : /proc/mm map for data failed, "
+ "err = %d\n", -n);
+ }
+}
+
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int))
{
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index cbabab1..3d1b227 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -129,7 +129,9 @@
return(0);
}
-int new_mm(int from)
+extern void map_stub_pages(int fd, unsigned long code,
+ unsigned long data, unsigned long stack);
+int new_mm(int from, unsigned long stack)
{
struct proc_mm_op copy;
int n, fd;
@@ -148,6 +150,9 @@
"err = %d\n", -n);
}
+ if(!ptrace_faultinfo)
+ map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
+
return(fd);
}
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
new file mode 100644
index 0000000..51fb940
--- /dev/null
+++ b/arch/um/kernel/skas/syscall.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sys.h"
+#include "linux/ptrace.h"
+#include "asm/errno.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/current.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+#include "syscall.h"
+
+void handle_syscall(union uml_pt_regs *r)
+{
+ struct pt_regs *regs = container_of(r, struct pt_regs, regs);
+ long result;
+ int syscall;
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+ int index;
+
+ index = record_syscall_start(UPT_SYSCALL_NR(r));
+#endif
+ syscall_trace(r, 0);
+
+ current->thread.nsyscalls++;
+ nsyscalls++;
+
+ /* This should go in the declaration of syscall, but when I do that,
+ * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
+ * children at all, sometimes hanging when bash doesn't see the first
+ * ls exit.
+ * The assembly looks functionally the same to me. This is
+ * gcc version 4.0.1 20050727 (Red Hat 4.0.1-5)
+ * in case it's a compiler bug.
+ */
+ syscall = UPT_SYSCALL_NR(r);
+ if((syscall >= NR_syscalls) || (syscall < 0))
+ result = -ENOSYS;
+ else result = EXECUTE_SYSCALL(syscall, regs);
+
+ REGS_SET_SYSCALL_RETURN(r->skas.regs, result);
+
+ syscall_trace(r, 1);
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+ record_syscall_end(index, result);
+#endif
+}
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
deleted file mode 100644
index bdf040c..0000000
--- a/arch/um/kernel/skas/syscall_kern.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include "linux/sys.h"
-#include "linux/ptrace.h"
-#include "asm/errno.h"
-#include "asm/unistd.h"
-#include "asm/ptrace.h"
-#include "asm/current.h"
-#include "sysdep/syscalls.h"
-#include "kern_util.h"
-
-extern syscall_handler_t *sys_call_table[];
-
-long execute_syscall_skas(void *r)
-{
- struct pt_regs *regs = r;
- long res;
- int syscall;
-
- current->thread.nsyscalls++;
- nsyscalls++;
- syscall = UPT_SYSCALL_NR(®s->regs);
-
- if((syscall >= NR_syscalls) || (syscall < 0))
- res = -ENOSYS;
- else res = EXECUTE_SYSCALL(syscall, regs);
-
- return(res);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
deleted file mode 100644
index 6b06649..0000000
--- a/arch/um/kernel/skas/syscall_user.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <signal.h>
-#include "kern_util.h"
-#include "uml-config.h"
-#include "syscall_user.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
-#include "skas.h"
-
-void handle_syscall(union uml_pt_regs *regs)
-{
- long result;
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- int index;
-
- index = record_syscall_start(UPT_SYSCALL_NR(regs));
-#endif
-
- syscall_trace(regs, 0);
- result = execute_syscall_skas(regs);
-
- REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
-
- syscall_trace(regs, 1);
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- record_syscall_end(index, result);
-#endif
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 6230999..6e84963 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -18,33 +18,39 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
+static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
+ int finished, void **flush)
{
struct host_vm_op *op;
- int i;
+ int i, ret = 0;
- for(i = 0; i <= last; i++){
+ for(i = 0; i <= last && !ret; i++){
op = &ops[i];
switch(op->type){
case MMAP:
- map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
- op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
- op->u.mmap.fd, op->u.mmap.offset);
+ ret = map(&mmu->skas.id, op->u.mmap.addr,
+ op->u.mmap.len, op->u.mmap.r, op->u.mmap.w,
+ op->u.mmap.x, op->u.mmap.fd,
+ op->u.mmap.offset, finished, flush);
break;
case MUNMAP:
- unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
- op->u.munmap.len);
+ ret = unmap(&mmu->skas.id,
+ (void *) op->u.munmap.addr,
+ op->u.munmap.len, finished, flush);
break;
case MPROTECT:
- protect(&mmu->skas.id, op->u.mprotect.addr,
- op->u.mprotect.len, op->u.mprotect.r,
- op->u.mprotect.w, op->u.mprotect.x);
+ ret = protect(&mmu->skas.id, op->u.mprotect.addr,
+ op->u.mprotect.len, op->u.mprotect.r,
+ op->u.mprotect.w, op->u.mprotect.x,
+ finished, flush);
break;
default:
printk("Unknown op type %d in do_ops\n", op->type);
break;
}
}
+
+ return ret;
}
extern int proc_mm;
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
new file mode 100644
index 0000000..1429c13
--- /dev/null
+++ b/arch/um/kernel/syscall.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "kern_util.h"
+#include "syscall.h"
+#include "os.h"
+
+struct {
+ int syscall;
+ int pid;
+ long result;
+ unsigned long long start;
+ unsigned long long end;
+} syscall_record[1024];
+
+int record_syscall_start(int syscall)
+{
+ int max, index;
+
+ max = sizeof(syscall_record)/sizeof(syscall_record[0]);
+ index = next_syscall_index(max);
+
+ syscall_record[index].syscall = syscall;
+ syscall_record[index].pid = current_pid();
+ syscall_record[index].result = 0xdeadbeef;
+ syscall_record[index].start = os_usecs();
+ return(index);
+}
+
+void record_syscall_end(int index, long result)
+{
+ syscall_record[index].result = result;
+ syscall_record[index].end = os_usecs();
+}
diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
deleted file mode 100644
index 01b711e..0000000
--- a/arch/um/kernel/syscall_user.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <sys/time.h>
-#include "kern_util.h"
-#include "syscall_user.h"
-
-struct {
- int syscall;
- int pid;
- long result;
- struct timeval start;
- struct timeval end;
-} syscall_record[1024];
-
-int record_syscall_start(int syscall)
-{
- int max, index;
-
- max = sizeof(syscall_record)/sizeof(syscall_record[0]);
- index = next_syscall_index(max);
-
- syscall_record[index].syscall = syscall;
- syscall_record[index].pid = current_pid();
- syscall_record[index].result = 0xdeadbeef;
- gettimeofday(&syscall_record[index].start, NULL);
- return(index);
-}
-
-void record_syscall_end(int index, long result)
-{
- syscall_record[index].result = result;
- gettimeofday(&syscall_record[index].end, NULL);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 83ec8d47..80ed618 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -15,12 +15,118 @@
#include "mem_user.h"
#include "os.h"
+static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
+ int r, int w, int x, struct host_vm_op *ops, int *index,
+ int last_filled, union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
+{
+ __u64 offset;
+ struct host_vm_op *last;
+ int fd, ret = 0;
+
+ fd = phys_mapping(phys, &offset);
+ if(*index != -1){
+ last = &ops[*index];
+ if((last->type == MMAP) &&
+ (last->u.mmap.addr + last->u.mmap.len == virt) &&
+ (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
+ (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
+ (last->u.mmap.offset + last->u.mmap.len == offset)){
+ last->u.mmap.len += len;
+ return 0;
+ }
+ }
+
+ if(*index == last_filled){
+ ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
+ *index = -1;
+ }
+
+ ops[++*index] = ((struct host_vm_op) { .type = MMAP,
+ .u = { .mmap = {
+ .addr = virt,
+ .len = len,
+ .r = r,
+ .w = w,
+ .x = x,
+ .fd = fd,
+ .offset = offset }
+ } });
+ return ret;
+}
+
+static int add_munmap(unsigned long addr, unsigned long len,
+ struct host_vm_op *ops, int *index, int last_filled,
+ union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
+{
+ struct host_vm_op *last;
+ int ret = 0;
+
+ if(*index != -1){
+ last = &ops[*index];
+ if((last->type == MUNMAP) &&
+ (last->u.munmap.addr + last->u.mmap.len == addr)){
+ last->u.munmap.len += len;
+ return 0;
+ }
+ }
+
+ if(*index == last_filled){
+ ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
+ *index = -1;
+ }
+
+ ops[++*index] = ((struct host_vm_op) { .type = MUNMAP,
+ .u = { .munmap = {
+ .addr = addr,
+ .len = len } } });
+ return ret;
+}
+
+static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
+ int x, struct host_vm_op *ops, int *index,
+ int last_filled, union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
+{
+ struct host_vm_op *last;
+ int ret = 0;
+
+ if(*index != -1){
+ last = &ops[*index];
+ if((last->type == MPROTECT) &&
+ (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
+ (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
+ (last->u.mprotect.x == x)){
+ last->u.mprotect.len += len;
+ return 0;
+ }
+ }
+
+ if(*index == last_filled){
+ ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
+ *index = -1;
+ }
+
+ ops[++*index] = ((struct host_vm_op) { .type = MPROTECT,
+ .u = { .mprotect = {
+ .addr = addr,
+ .len = len,
+ .r = r,
+ .w = w,
+ .x = x } } });
+ return ret;
+}
+
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force,
- void (*do_ops)(union mm_context *, struct host_vm_op *,
- int))
+ int (*do_ops)(union mm_context *, struct host_vm_op *,
+ int, int, void **))
{
pgd_t *npgd;
pud_t *npud;
@@ -29,21 +135,24 @@
union mm_context *mmu = &mm->context;
unsigned long addr, end;
int r, w, x;
- struct host_vm_op ops[16];
+ struct host_vm_op ops[1];
+ void *flush = NULL;
int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
+ int ret = 0;
if(mm == NULL) return;
- for(addr = start_addr; addr < end_addr;){
+ ops[0].type = NONE;
+ for(addr = start_addr; addr < end_addr && !ret;){
npgd = pgd_offset(mm, addr);
if(!pgd_present(*npgd)){
end = ADD_ROUND(addr, PGDIR_SIZE);
if(end > end_addr)
end = end_addr;
if(force || pgd_newpage(*npgd)){
- op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, mmu,
- do_ops);
+ ret = add_munmap(addr, end - addr, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
pgd_mkuptodate(*npgd);
}
addr = end;
@@ -56,9 +165,9 @@
if(end > end_addr)
end = end_addr;
if(force || pud_newpage(*npud)){
- op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, mmu,
- do_ops);
+ ret = add_munmap(addr, end - addr, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
pud_mkuptodate(*npud);
}
addr = end;
@@ -71,9 +180,9 @@
if(end > end_addr)
end = end_addr;
if(force || pmd_newpage(*npmd)){
- op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, mmu,
- do_ops);
+ ret = add_munmap(addr, end - addr, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
pmd_mkuptodate(*npmd);
}
addr = end;
@@ -92,24 +201,32 @@
}
if(force || pte_newpage(*npte)){
if(pte_present(*npte))
- op_index = add_mmap(addr,
- pte_val(*npte) & PAGE_MASK,
- PAGE_SIZE, r, w, x, ops,
- op_index, last_op, mmu,
- do_ops);
- else op_index = add_munmap(addr, PAGE_SIZE, ops,
- op_index, last_op, mmu,
- do_ops);
+ ret = add_mmap(addr,
+ pte_val(*npte) & PAGE_MASK,
+ PAGE_SIZE, r, w, x, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
+ else ret = add_munmap(addr, PAGE_SIZE, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
}
else if(pte_newprot(*npte))
- op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
- op_index, last_op, mmu,
- do_ops);
+ ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
+ &op_index, last_op, mmu,
+ &flush, do_ops);
*npte = pte_mkuptodate(*npte);
addr += PAGE_SIZE;
}
- (*do_ops)(mmu, ops, op_index);
+
+ if(!ret)
+ ret = (*do_ops)(mmu, ops, op_index, 1, &flush);
+
+ /* This is not an else because ret is modified above */
+ if(ret) {
+ printk("fix_range_common: failed, killing current process\n");
+ force_sig(SIGKILL, current);
+ }
}
int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -226,106 +343,6 @@
return(pte_offset_map(pmd, addr));
}
-int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, union mm_context *mmu,
- void (*do_ops)(union mm_context *, struct host_vm_op *, int))
-{
- __u64 offset;
- struct host_vm_op *last;
- int fd;
-
- fd = phys_mapping(phys, &offset);
- if(index != -1){
- last = &ops[index];
- if((last->type == MMAP) &&
- (last->u.mmap.addr + last->u.mmap.len == virt) &&
- (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
- (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
- (last->u.mmap.offset + last->u.mmap.len == offset)){
- last->u.mmap.len += len;
- return(index);
- }
- }
-
- if(index == last_filled){
- (*do_ops)(mmu, ops, last_filled);
- index = -1;
- }
-
- ops[++index] = ((struct host_vm_op) { .type = MMAP,
- .u = { .mmap = {
- .addr = virt,
- .len = len,
- .r = r,
- .w = w,
- .x = x,
- .fd = fd,
- .offset = offset }
- } });
- return(index);
-}
-
-int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
- int index, int last_filled, union mm_context *mmu,
- void (*do_ops)(union mm_context *, struct host_vm_op *, int))
-{
- struct host_vm_op *last;
-
- if(index != -1){
- last = &ops[index];
- if((last->type == MUNMAP) &&
- (last->u.munmap.addr + last->u.mmap.len == addr)){
- last->u.munmap.len += len;
- return(index);
- }
- }
-
- if(index == last_filled){
- (*do_ops)(mmu, ops, last_filled);
- index = -1;
- }
-
- ops[++index] = ((struct host_vm_op) { .type = MUNMAP,
- .u = { .munmap = {
- .addr = addr,
- .len = len } } });
- return(index);
-}
-
-int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
- struct host_vm_op *ops, int index, int last_filled,
- union mm_context *mmu,
- void (*do_ops)(union mm_context *, struct host_vm_op *, int))
-{
- struct host_vm_op *last;
-
- if(index != -1){
- last = &ops[index];
- if((last->type == MPROTECT) &&
- (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
- (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
- (last->u.mprotect.x == x)){
- last->u.mprotect.len += len;
- return(index);
- }
- }
-
- if(index == last_filled){
- (*do_ops)(mmu, ops, last_filled);
- index = -1;
- }
-
- ops[++index] = ((struct host_vm_op) { .type = MPROTECT,
- .u = { .mprotect = {
- .addr = addr,
- .len = len,
- .r = r,
- .w = w,
- .x = x } } });
- return(index);
-}
-
void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
{
address &= PAGE_MASK;
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index c20aef1..b5fc89f 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -26,6 +26,7 @@
#include "mem.h"
#include "mem_kern.h"
+/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
int handle_page_fault(unsigned long address, unsigned long ip,
int is_write, int is_user, int *code_out)
{
@@ -35,7 +36,6 @@
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- unsigned long page;
int err = -EFAULT;
*code_out = SEGV_MAPERR;
@@ -52,7 +52,7 @@
else if(expand_stack(vma, address))
goto out;
- good_area:
+good_area:
*code_out = SEGV_ACCERR;
if(is_write && !(vma->vm_flags & VM_WRITE))
goto out;
@@ -60,9 +60,8 @@
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto out;
- page = address & PAGE_MASK;
do {
- survive:
+survive:
switch (handle_mm_fault(mm, vma, address, is_write)){
case VM_FAULT_MINOR:
current->min_flt++;
@@ -79,16 +78,16 @@
default:
BUG();
}
- pgd = pgd_offset(mm, page);
- pud = pud_offset(pgd, page);
- pmd = pmd_offset(pud, page);
- pte = pte_offset_kernel(pmd, page);
+ pgd = pgd_offset(mm, address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
} while(!pte_present(*pte));
err = 0;
*pte = pte_mkyoung(*pte);
if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
- flush_tlb_page(vma, page);
- out:
+ flush_tlb_page(vma, address);
+out:
up_read(&mm->mmap_sem);
return(err);
@@ -144,19 +143,18 @@
panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
address, ip);
- if(err == -EACCES){
+ if (err == -EACCES) {
si.si_signo = SIGBUS;
si.si_errno = 0;
si.si_code = BUS_ADRERR;
si.si_addr = (void *)address;
current->thread.arch.faultinfo = fi;
force_sig_info(SIGBUS, &si, current);
- }
- else if(err == -ENOMEM){
+ } else if (err == -ENOMEM) {
printk("VM: killing process %s\n", current->comm);
do_exit(SIGKILL);
- }
- else {
+ } else {
+ BUG_ON(err != -EFAULT);
si.si_signo = SIGSEGV;
si.si_addr = (void *) address;
current->thread.arch.faultinfo = fi;
@@ -200,30 +198,3 @@
void trap_init(void)
{
}
-
-DEFINE_SPINLOCK(trap_lock);
-
-static int trap_index = 0;
-
-int next_trap_index(int limit)
-{
- int ret;
-
- spin_lock(&trap_lock);
- ret = trap_index;
- if(++trap_index == limit)
- trap_index = 0;
- spin_unlock(&trap_lock);
- return(ret);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
index f825a6e..e9ccd6b 100644
--- a/arch/um/kernel/trap_user.c
+++ b/arch/um/kernel/trap_user.c
@@ -40,35 +40,14 @@
} while(1);
}
-/* Unlocked - don't care if this is a bit off */
-int nsegfaults = 0;
-
-struct {
- unsigned long address;
- int is_write;
- int pid;
- unsigned long sp;
- int is_user;
-} segfault_record[1024];
-
void segv_handler(int sig, union uml_pt_regs *regs)
{
- int index, max;
struct faultinfo * fi = UPT_FAULTINFO(regs);
if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
bad_segv(*fi, UPT_IP(regs));
return;
}
- max = sizeof(segfault_record)/sizeof(segfault_record[0]);
- index = next_trap_index(max);
-
- nsegfaults++;
- segfault_record[index].address = FAULT_ADDRESS(*fi);
- segfault_record[index].pid = os_getpid();
- segfault_record[index].is_write = FAULT_WRITE(*fi);
- segfault_record[index].sp = UPT_SP(regs);
- segfault_record[index].is_user = UPT_IS_USER(regs);
segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
}
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
index 2650a62..3d29c90 100644
--- a/arch/um/kernel/tt/syscall_kern.c
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -12,36 +12,41 @@
#include "asm/uaccess.h"
#include "asm/stat.h"
#include "sysdep/syscalls.h"
+#include "sysdep/sigcontext.h"
#include "kern_util.h"
+#include "syscall.h"
-extern syscall_handler_t *sys_call_table[];
-
-long execute_syscall_tt(void *r)
+void syscall_handler_tt(int sig, struct pt_regs *regs)
{
- struct pt_regs *regs = r;
- long res;
+ void *sc;
+ long result;
int syscall;
-
#ifdef CONFIG_SYSCALL_DEBUG
+ int index;
+ index = record_syscall_start(syscall);
+#endif
+ sc = UPT_SC(®s->regs);
+ SC_START_SYSCALL(sc);
+
+ syscall_trace(®s->regs, 0);
+
current->thread.nsyscalls++;
nsyscalls++;
-#endif
syscall = UPT_SYSCALL_NR(®s->regs);
if((syscall >= NR_syscalls) || (syscall < 0))
- res = -ENOSYS;
- else res = EXECUTE_SYSCALL(syscall, regs);
+ result = -ENOSYS;
+ else result = EXECUTE_SYSCALL(syscall, regs);
- return(res);
+ /* regs->sc may have changed while the system call ran (there may
+ * have been an interrupt or segfault), so it needs to be refreshed.
+ */
+ UPT_SC(®s->regs) = sc;
+
+ SC_SET_SYSCALL_RETURN(sc, result);
+
+ syscall_trace(®s->regs, 1);
+#ifdef CONFIG_SYSCALL_DEBUG
+ record_syscall_end(index, result);
+#endif
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
index b218316..902987b 100644
--- a/arch/um/kernel/tt/syscall_user.c
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -13,42 +13,9 @@
#include "task.h"
#include "user_util.h"
#include "kern_util.h"
-#include "syscall_user.h"
+#include "syscall.h"
#include "tt.h"
-
-void syscall_handler_tt(int sig, union uml_pt_regs *regs)
-{
- void *sc;
- long result;
- int syscall;
-#ifdef UML_CONFIG_DEBUG_SYSCALL
- int index;
-#endif
-
- syscall = UPT_SYSCALL_NR(regs);
- sc = UPT_SC(regs);
- SC_START_SYSCALL(sc);
-
-#ifdef UML_CONFIG_DEBUG_SYSCALL
- index = record_syscall_start(syscall);
-#endif
- syscall_trace(regs, 0);
- result = execute_syscall_tt(regs);
-
- /* regs->sc may have changed while the system call ran (there may
- * have been an interrupt or segfault), so it needs to be refreshed.
- */
- UPT_SC(regs) = sc;
-
- SC_SET_SYSCALL_RETURN(sc, result);
-
- syscall_trace(regs, 1);
-#ifdef UML_CONFIG_DEBUG_SYSCALL
- record_syscall_end(index, result);
-#endif
-}
-
void do_sigtrap(void *task)
{
UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 2eefb43..f1d85db 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,25 +17,31 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
+static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
+ int finished, void **flush)
{
struct host_vm_op *op;
- int i;
+ int i, ret=0;
- for(i = 0; i <= last; i++){
+ for(i = 0; i <= last && !ret; i++){
op = &ops[i];
switch(op->type){
case MMAP:
- os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
- op->u.mmap.offset, op->u.mmap.len,
- op->u.mmap.r, op->u.mmap.w,
- op->u.mmap.x);
+ ret = os_map_memory((void *) op->u.mmap.addr,
+ op->u.mmap.fd, op->u.mmap.offset,
+ op->u.mmap.len, op->u.mmap.r,
+ op->u.mmap.w, op->u.mmap.x);
break;
case MUNMAP:
- os_unmap_memory((void *) op->u.munmap.addr,
- op->u.munmap.len);
+ ret = os_unmap_memory((void *) op->u.munmap.addr,
+ op->u.munmap.len);
break;
case MPROTECT:
+ ret = protect_memory(op->u.mprotect.addr,
+ op->u.munmap.len,
+ op->u.mprotect.r,
+ op->u.mprotect.w,
+ op->u.mprotect.x, 1);
protect_memory(op->u.mprotect.addr, op->u.munmap.len,
op->u.mprotect.r, op->u.mprotect.w,
op->u.mprotect.x, 1);
@@ -45,6 +51,8 @@
break;
}
}
+
+ return ret;
}
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index ca2bb6f..09f6f7c 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -126,7 +126,7 @@
unsigned long end_vm;
int ncpus = 1;
-#ifdef CONFIG_MODE_TT
+#ifdef CONFIG_CMDLINE_ON_HOST
/* Pointer set in linux_main, the array itself is private to each thread,
* and changed at address space creation time so this poses no concurrency
* problems.
@@ -141,7 +141,7 @@
void set_cmdline(char *cmd)
{
-#ifdef CONFIG_MODE_TT
+#ifdef CONFIG_CMDLINE_ON_HOST
char *umid, *ptr;
if(CHOOSE_MODE(honeypot, 0)) return;
@@ -333,6 +333,7 @@
if(have_root == 0)
add_arg(DEFAULT_COMMAND_LINE);
+ os_early_checks();
mode_tt = force_tt ? 1 : !can_do_skas();
#ifndef CONFIG_MODE_TT
if (mode_tt) {
@@ -385,7 +386,7 @@
setup_machinename(system_utsname.machine);
-#ifdef CONFIG_MODE_TT
+#ifdef CONFIG_CMDLINE_ON_HOST
argv1_begin = argv[1];
argv1_end = &argv[1][strlen(argv[1])];
#endif
@@ -470,7 +471,6 @@
void __init check_bugs(void)
{
arch_check_bugs();
- check_ptrace();
check_sigio();
check_devanon();
}
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 4ddf540..7a16624 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -3,11 +3,19 @@
# Licensed under the GPL
#
-obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \
- sys-$(SUBARCH)/
+obj-y = aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \
+ tty.o user_syms.o drivers/ sys-$(SUBARCH)/
-USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
+USER_OBJS := aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \
+ tty.o
+
+elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
+CFLAGS_elf_aux.o += -I$(objtree)/arch/um
CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
+HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \
+ echo -DHAVE_AIO_ABI )
+CFLAGS_aio.o += $(HAVE_AIO_ABI)
+
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
new file mode 100644
index 0000000..b04897c
--- /dev/null
+++ b/arch/um/os-Linux/aio.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include "os.h"
+#include "helper.h"
+#include "aio.h"
+#include "init.h"
+#include "user.h"
+#include "mode.h"
+
+static int aio_req_fd_r = -1;
+static int aio_req_fd_w = -1;
+
+static int update_aio(struct aio_context *aio, int res)
+{
+ if(res < 0)
+ aio->len = res;
+ else if((res == 0) && (aio->type == AIO_READ)){
+ /* This is the EOF case - we have hit the end of the file
+ * and it ends in a partial block, so we fill the end of
+ * the block with zeros and claim success.
+ */
+ memset(aio->data, 0, aio->len);
+ aio->len = 0;
+ }
+ else if(res > 0){
+ aio->len -= res;
+ aio->data += res;
+ aio->offset += res;
+ return aio->len;
+ }
+
+ return 0;
+}
+
+#if defined(HAVE_AIO_ABI)
+#include <linux/aio_abi.h>
+
+/* If we have the headers, we are going to build with AIO enabled.
+ * If we don't have aio in libc, we define the necessary stubs here.
+ */
+
+#if !defined(HAVE_AIO_LIBC)
+
+static long io_setup(int n, aio_context_t *ctxp)
+{
+ return syscall(__NR_io_setup, n, ctxp);
+}
+
+static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
+{
+ return syscall(__NR_io_submit, ctx, nr, iocbpp);
+}
+
+static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
+ struct io_event *events, struct timespec *timeout)
+{
+ return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
+}
+
+#endif
+
+/* The AIO_MMAP cases force the mmapped page into memory here
+ * rather than in whatever place first touches the data. I used
+ * to do this by touching the page, but that's delicate because
+ * gcc is prone to optimizing that away. So, what's done here
+ * is we read from the descriptor from which the page was
+ * mapped. The caller is required to pass an offset which is
+ * inside the page that was mapped. Thus, when the read
+ * returns, we know that the page is in the page cache, and
+ * that it now backs the mmapped area.
+ */
+
+static int do_aio(aio_context_t ctx, struct aio_context *aio)
+{
+ struct iocb iocb, *iocbp = &iocb;
+ char c;
+ int err;
+
+ iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
+ .aio_reqprio = 0,
+ .aio_fildes = aio->fd,
+ .aio_buf = (unsigned long) aio->data,
+ .aio_nbytes = aio->len,
+ .aio_offset = aio->offset,
+ .aio_reserved1 = 0,
+ .aio_reserved2 = 0,
+ .aio_reserved3 = 0 });
+
+ switch(aio->type){
+ case AIO_READ:
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ break;
+ case AIO_WRITE:
+ iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
+ break;
+ case AIO_MMAP:
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb.aio_buf = (unsigned long) &c;
+ iocb.aio_nbytes = sizeof(c);
+ break;
+ default:
+ printk("Bogus op in do_aio - %d\n", aio->type);
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = io_submit(ctx, 1, &iocbp);
+ if(err > 0)
+ err = 0;
+
+ out:
+ return err;
+}
+
+static aio_context_t ctx = 0;
+
+static int aio_thread(void *arg)
+{
+ struct aio_thread_reply reply;
+ struct aio_context *aio;
+ struct io_event event;
+ int err, n;
+
+ signal(SIGWINCH, SIG_IGN);
+
+ while(1){
+ n = io_getevents(ctx, 1, 1, &event, NULL);
+ if(n < 0){
+ if(errno == EINTR)
+ continue;
+ printk("aio_thread - io_getevents failed, "
+ "errno = %d\n", errno);
+ }
+ else {
+ aio = (struct aio_context *) event.data;
+ if(update_aio(aio, event.res)){
+ do_aio(ctx, aio);
+ continue;
+ }
+
+ reply = ((struct aio_thread_reply)
+ { .data = aio,
+ .err = aio->len });
+ err = os_write_file(aio->reply_fd, &reply,
+ sizeof(reply));
+ if(err != sizeof(reply))
+ printk("aio_thread - write failed, "
+ "fd = %d, err = %d\n", aio->reply_fd,
+ -err);
+ }
+ }
+ return 0;
+}
+
+#endif
+
+static int do_not_aio(struct aio_context *aio)
+{
+ char c;
+ int err;
+
+ switch(aio->type){
+ case AIO_READ:
+ err = os_seek_file(aio->fd, aio->offset);
+ if(err)
+ goto out;
+
+ err = os_read_file(aio->fd, aio->data, aio->len);
+ break;
+ case AIO_WRITE:
+ err = os_seek_file(aio->fd, aio->offset);
+ if(err)
+ goto out;
+
+ err = os_write_file(aio->fd, aio->data, aio->len);
+ break;
+ case AIO_MMAP:
+ err = os_seek_file(aio->fd, aio->offset);
+ if(err)
+ goto out;
+
+ err = os_read_file(aio->fd, &c, sizeof(c));
+ break;
+ default:
+ printk("do_not_aio - bad request type : %d\n", aio->type);
+ err = -EINVAL;
+ break;
+ }
+
+ out:
+ return err;
+}
+
+static int not_aio_thread(void *arg)
+{
+ struct aio_context *aio;
+ struct aio_thread_reply reply;
+ int err;
+
+ signal(SIGWINCH, SIG_IGN);
+ while(1){
+ err = os_read_file(aio_req_fd_r, &aio, sizeof(aio));
+ if(err != sizeof(aio)){
+ if(err < 0)
+ printk("not_aio_thread - read failed, "
+ "fd = %d, err = %d\n", aio_req_fd_r,
+ -err);
+ else {
+ printk("not_aio_thread - short read, fd = %d, "
+ "length = %d\n", aio_req_fd_r, err);
+ }
+ continue;
+ }
+ again:
+ err = do_not_aio(aio);
+
+ if(update_aio(aio, err))
+ goto again;
+
+ reply = ((struct aio_thread_reply) { .data = aio,
+ .err = aio->len });
+ err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply))
+ printk("not_aio_thread - write failed, fd = %d, "
+ "err = %d\n", aio_req_fd_r, -err);
+ }
+}
+
+static int submit_aio_24(struct aio_context *aio)
+{
+ int err;
+
+ err = os_write_file(aio_req_fd_w, &aio, sizeof(aio));
+ if(err == sizeof(aio))
+ err = 0;
+
+ return err;
+}
+
+static int aio_pid = -1;
+static int (*submit_proc)(struct aio_context *aio);
+
+static int init_aio_24(void)
+{
+ unsigned long stack;
+ int fds[2], err;
+
+ err = os_pipe(fds, 1, 1);
+ if(err)
+ goto out;
+
+ aio_req_fd_w = fds[0];
+ aio_req_fd_r = fds[1];
+ err = run_helper_thread(not_aio_thread, NULL,
+ CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ if(err < 0)
+ goto out_close_pipe;
+
+ aio_pid = err;
+ goto out;
+
+ out_close_pipe:
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ aio_req_fd_w = -1;
+ aio_req_fd_r = -1;
+ out:
+#ifndef HAVE_AIO_ABI
+ printk("/usr/include/linux/aio_abi.h not present during build\n");
+#endif
+ printk("2.6 host AIO support not used - falling back to I/O "
+ "thread\n");
+
+ submit_proc = submit_aio_24;
+
+ return 0;
+}
+
+#ifdef HAVE_AIO_ABI
+#define DEFAULT_24_AIO 0
+static int submit_aio_26(struct aio_context *aio)
+{
+ struct aio_thread_reply reply;
+ int err;
+
+ err = do_aio(ctx, aio);
+ if(err){
+ reply = ((struct aio_thread_reply) { .data = aio,
+ .err = err });
+ err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply))
+ printk("submit_aio_26 - write failed, "
+ "fd = %d, err = %d\n", aio->reply_fd, -err);
+ else err = 0;
+ }
+
+ return err;
+}
+
+static int init_aio_26(void)
+{
+ unsigned long stack;
+ int err;
+
+ if(io_setup(256, &ctx)){
+ printk("aio_thread failed to initialize context, err = %d\n",
+ errno);
+ return -errno;
+ }
+
+ err = run_helper_thread(aio_thread, NULL,
+ CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ if(err < 0)
+ return -errno;
+
+ aio_pid = err;
+
+ printk("Using 2.6 host AIO\n");
+
+ submit_proc = submit_aio_26;
+
+ return 0;
+}
+
+#else
+#define DEFAULT_24_AIO 1
+static int submit_aio_26(struct aio_context *aio)
+{
+ return -ENOSYS;
+}
+
+static int init_aio_26(void)
+{
+ submit_proc = submit_aio_26;
+ return -ENOSYS;
+}
+#endif
+
+static int aio_24 = DEFAULT_24_AIO;
+
+static int __init set_aio_24(char *name, int *add)
+{
+ aio_24 = 1;
+ return 0;
+}
+
+__uml_setup("aio=2.4", set_aio_24,
+"aio=2.4\n"
+" This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
+" available. 2.4 AIO is a single thread that handles one request at a\n"
+" time, synchronously. 2.6 AIO is a thread which uses the 2.6 AIO \n"
+" interface to handle an arbitrary number of pending requests. 2.6 AIO \n"
+" is not available in tt mode, on 2.4 hosts, or when UML is built with\n"
+" /usr/include/linux/aio_abi.h not available. Many distributions don't\n"
+" include aio_abi.h, so you will need to copy it from a kernel tree to\n"
+" your /usr/include/linux in order to build an AIO-capable UML\n\n"
+);
+
+static int init_aio(void)
+{
+ int err;
+
+ CHOOSE_MODE(({
+ if(!aio_24){
+ printk("Disabling 2.6 AIO in tt mode\n");
+ aio_24 = 1;
+ } }), (void) 0);
+
+ if(!aio_24){
+ err = init_aio_26();
+ if(err && (errno == ENOSYS)){
+ printk("2.6 AIO not supported on the host - "
+ "reverting to 2.4 AIO\n");
+ aio_24 = 1;
+ }
+ else return err;
+ }
+
+ if(aio_24)
+ return init_aio_24();
+
+ return 0;
+}
+
+/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
+ * needs to be called when the kernel is running because it calls run_helper,
+ * which needs get_free_page. exit_aio is a __uml_exitcall because the generic
+ * kernel does not run __exitcalls on shutdown, and can't because many of them
+ * break when called outside of module unloading.
+ */
+__initcall(init_aio);
+
+static void exit_aio(void)
+{
+ if(aio_pid != -1)
+ os_kill_process(aio_pid, 1);
+}
+
+__uml_exitcall(exit_aio);
+
+int submit_aio(struct aio_context *aio)
+{
+ return (*submit_proc)(aio);
+}
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
index 4cca3e9..1399520 100644
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -12,8 +12,9 @@
#include "init.h"
#include "elf_user.h"
#include "mem_user.h"
+#include <kernel-offsets.h>
-#if ELF_CLASS == ELFCLASS32
+#if HOST_ELF_CLASS == ELFCLASS32
typedef Elf32_auxv_t elf_auxv_t;
#else
typedef Elf64_auxv_t elf_auxv_t;
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 1e126bf..d32413e 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -3,10 +3,10 @@
* Licensed under the GPL
*/
-#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
+#include <setjmp.h>
#include <linux/unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
@@ -14,6 +14,10 @@
#include "os.h"
#include "user.h"
#include "user_util.h"
+#include "signal_user.h"
+#include "process.h"
+#include "irq_user.h"
+#include "kern_util.h"
#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
@@ -114,8 +118,10 @@
kill(pid, SIGUSR1);
}
-/*Don't use the glibc version, which caches the result in TLS. It misses some
- * syscalls, and also breaks with clone(), which does not unshare the TLS.*/
+/* Don't use the glibc version, which caches the result in TLS. It misses some
+ * syscalls, and also breaks with clone(), which does not unshare the TLS.
+ */
+
inline _syscall0(pid_t, getpid)
int os_getpid(void)
@@ -164,6 +170,52 @@
return(0);
}
+void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
+{
+ int flags = 0, pages;
+
+ if(sig_stack != NULL){
+ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
+ set_sigstack(sig_stack, pages * page_size());
+ flags = SA_ONSTACK;
+ }
+ if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
+}
+
+void init_new_thread_signals(int altstack)
+{
+ int flags = altstack ? SA_ONSTACK : 0;
+
+ set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
+ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+ set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
+ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+ set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
+ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+ set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
+ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+ set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
+ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+ set_handler(SIGUSR2, (__sighandler_t) sig_handler,
+ flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+ signal(SIGHUP, SIG_IGN);
+
+ init_irq_signals(altstack);
+}
+
+int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+{
+ sigjmp_buf buf;
+ int n;
+
+ *jmp_ptr = &buf;
+ n = sigsetjmp(buf, 1);
+ if(n != 0)
+ return(n);
+ (*fn)(arg);
+ return(0);
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/process.c b/arch/um/os-Linux/start_up.c
similarity index 61%
rename from arch/um/kernel/process.c
rename to arch/um/os-Linux/start_up.c
index 67acd92..040cc14 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/os-Linux/start_up.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -19,7 +19,6 @@
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
-#include "process.h"
#include "signal_kern.h"
#include "signal_user.h"
#include "sysdep/ptrace.h"
@@ -39,98 +38,6 @@
#include "registers.h"
#endif
-void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
-{
- int flags = 0, pages;
-
- if(sig_stack != NULL){
- pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
- set_sigstack(sig_stack, pages * page_size());
- flags = SA_ONSTACK;
- }
- if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
-}
-
-void init_new_thread_signals(int altstack)
-{
- int flags = altstack ? SA_ONSTACK : 0;
-
- set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- set_handler(SIGUSR2, (__sighandler_t) sig_handler,
- flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- signal(SIGHUP, SIG_IGN);
-
- init_irq_signals(altstack);
-}
-
-struct tramp {
- int (*tramp)(void *);
- void *tramp_data;
- unsigned long temp_stack;
- int flags;
- int pid;
-};
-
-/* See above for why sigkill is here */
-
-int sigkill = SIGKILL;
-
-int outer_tramp(void *arg)
-{
- struct tramp *t;
- int sig = sigkill;
-
- t = arg;
- t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
- t->flags, t->tramp_data);
- if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
- kill(os_getpid(), sig);
- _exit(0);
-}
-
-int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
- int clone_flags, int (*tramp)(void *))
-{
- struct tramp arg;
- unsigned long sp;
- int new_pid, status, err;
-
- /* The trampoline will run on the temporary stack */
- sp = stack_sp(temp_stack);
-
- clone_flags |= CLONE_FILES | SIGCHLD;
-
- arg.tramp = tramp;
- arg.tramp_data = thread_arg;
- arg.temp_stack = temp_stack;
- arg.flags = clone_flags;
-
- /* Start the process and wait for it to kill itself */
- new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
- if(new_pid < 0)
- return(new_pid);
-
- CATCH_EINTR(err = waitpid(new_pid, &status, 0));
- if(err < 0)
- panic("Waiting for outer trampoline failed - errno = %d",
- errno);
-
- if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
- panic("outer trampoline didn't exit with SIGKILL, "
- "status = %d", status);
-
- return(arg.pid);
-}
-
static int ptrace_child(void *arg)
{
int ret;
@@ -165,7 +72,7 @@
void *stack;
unsigned long sp;
int pid, n, status;
-
+
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(stack == MAP_FAILED)
@@ -173,10 +80,10 @@
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
if(pid < 0)
- panic("check_ptrace : clone failed, errno = %d", errno);
+ panic("start_ptraced_child : clone failed, errno = %d", errno);
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
- panic("check_ptrace : wait failed, errno = %d", errno);
+ panic("check_ptrace : clone failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
panic("check_ptrace : expected SIGSTOP, got status = %d",
status);
@@ -185,11 +92,14 @@
return(pid);
}
-/* When testing for SYSEMU support, if it is one of the broken versions, we must
- * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
+/* When testing for SYSEMU support, if it is one of the broken versions, we
+ * must just avoid using sysemu, not panic, but only if SYSEMU features are
+ * broken.
* So only for SYSEMU features we test mustpanic, while normal host features
- * must work anyway!*/
-static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
+ * must work anyway!
+ */
+static int stop_ptraced_child(int pid, void *stack, int exitcode,
+ int mustpanic)
{
int status, n, ret = 0;
@@ -217,8 +127,6 @@
return ret;
}
-static int force_sysemu_disabled = 0;
-
int ptrace_faultinfo = 1;
int proc_mm = 1;
@@ -228,29 +136,32 @@
return 0;
}
+__uml_setup("skas0", skas0_cmd_param,
+ "skas0\n"
+ " Disables SKAS3 usage, so that SKAS0 is used, unless \n"
+ " you specify mode=tt.\n\n");
+
+static int force_sysemu_disabled = 0;
+
static int __init nosysemu_cmd_param(char *str, int* add)
{
force_sysemu_disabled = 1;
return 0;
}
-__uml_setup("skas0", skas0_cmd_param,
- "skas0\n"
- " Disables SKAS3 usage, so that SKAS0 is used, unless you \n"
- " specify mode=tt.\n\n");
-
__uml_setup("nosysemu", nosysemu_cmd_param,
- "nosysemu\n"
- " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
- " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
- " behaviour of ptrace() and helps reducing host context switch rate.\n"
- " To make it working, you need a kernel patch for your host, too.\n"
- " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n");
+"nosysemu\n"
+" Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
+" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
+" behaviour of ptrace() and helps reducing host context switch rate.\n"
+" To make it working, you need a kernel patch for your host, too.\n"
+" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
+" information.\n\n");
static void __init check_sysemu(void)
{
void *stack;
- int pid, syscall, n, status, count=0;
+ int pid, n, status, count=0;
printk("Checking syscall emulation patch for ptrace...");
sysemu_supported = 0;
@@ -281,6 +192,12 @@
printk("Checking advanced syscall emulation patch for ptrace...");
pid = start_ptraced_child(&stack);
+
+ if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
+ (void *) PTRACE_O_TRACESYSGOOD) < 0)
+ panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d",
+ errno);
+
while(1){
count++;
if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
@@ -288,15 +205,10 @@
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
- if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
- panic("check_ptrace : expected (SIGTRAP|SYSCALL_TRAP), "
- "got status = %d", status);
-
- syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
- 0);
- if(syscall == __NR_getpid){
+ if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){
if (!count)
- panic("check_ptrace : SYSEMU_SINGLESTEP doesn't singlestep");
+ panic("check_ptrace : SYSEMU_SINGLESTEP "
+ "doesn't singlestep");
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
os_getpid());
if(n < 0)
@@ -304,6 +216,11 @@
"call return, errno = %d", errno);
break;
}
+ else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
+ count++;
+ else
+ panic("check_ptrace : expected SIGTRAP or "
+ "(SIGTRAP|0x80), got status = %d", status);
}
if (stop_ptraced_child(pid, stack, 0, 0) < 0)
goto fail_stopped;
@@ -321,7 +238,7 @@
printk("missing\n");
}
-void __init check_ptrace(void)
+static void __init check_ptrace(void)
{
void *stack;
int pid, syscall, n, status;
@@ -329,20 +246,20 @@
printk("Checking that ptrace can change system call numbers...");
pid = start_ptraced_child(&stack);
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
- panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
+ if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+ panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno);
while(1){
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
- panic("check_ptrace : ptrace failed, errno = %d",
+ panic("check_ptrace : ptrace failed, errno = %d",
errno);
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
- if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80))
- panic("check_ptrace : expected SIGTRAP + 0x80, "
+ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80)))
+ panic("check_ptrace : expected (SIGTRAP|0x80), "
"got status = %d", status);
-
+
syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
0);
if(syscall == __NR_getpid){
@@ -359,33 +276,36 @@
check_sysemu();
}
-int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+void os_early_checks(void)
{
- sigjmp_buf buf;
- int n;
-
- *jmp_ptr = &buf;
- n = sigsetjmp(buf, 1);
- if(n != 0)
- return(n);
- (*fn)(arg);
- return(0);
+ check_ptrace();
}
-void forward_pending_sigio(int target)
+static int __init noprocmm_cmd_param(char *str, int* add)
{
- sigset_t sigs;
-
- if(sigpending(&sigs))
- panic("forward_pending_sigio : sigpending failed");
- if(sigismember(&sigs, SIGIO))
- kill(target, SIGIO);
+ proc_mm = 0;
+ return 0;
}
-extern void *__syscall_stub_start, __syscall_stub_end;
+__uml_setup("noprocmm", noprocmm_cmd_param,
+"noprocmm\n"
+" Turns off usage of /proc/mm, even if host supports it.\n"
+" To support /proc/mm, the host needs to be patched using\n"
+" the current skas3 patch.\n\n");
+
+static int __init noptracefaultinfo_cmd_param(char *str, int* add)
+{
+ ptrace_faultinfo = 0;
+ return 0;
+}
+
+__uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param,
+"noptracefaultinfo\n"
+" Turns off usage of PTRACE_FAULTINFO, even if host supports\n"
+" it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
+" using the current skas3 patch.\n\n");
#ifdef UML_CONFIG_MODE_SKAS
-
static inline void check_skas3_ptrace_support(void)
{
struct ptrace_faultinfo fi;
@@ -400,9 +320,8 @@
ptrace_faultinfo = 0;
if(errno == EIO)
printf("not found\n");
- else {
+ else
perror("not found");
- }
}
else {
if (!ptrace_faultinfo)
@@ -419,9 +338,10 @@
{
printf("Checking for /proc/mm...");
if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
- proc_mm = 0;
+ proc_mm = 0;
printf("not found\n");
- } else {
+ }
+ else {
if (!proc_mm)
printf("found but disabled on command line\n");
else
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
new file mode 100644
index 0000000..5b047ab
--- /dev/null
+++ b/arch/um/os-Linux/tt.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "irq_user.h"
+#include "ptrace_user.h"
+#include "time_user.h"
+#include "init.h"
+#include "os.h"
+#include "uml-config.h"
+#include "choose-mode.h"
+#include "mode.h"
+#include "tempfile.h"
+
+/*
+ *-------------------------
+ * only for tt mode (will be deleted in future...)
+ *-------------------------
+ */
+
+struct tramp {
+ int (*tramp)(void *);
+ void *tramp_data;
+ unsigned long temp_stack;
+ int flags;
+ int pid;
+};
+
+/* See above for why sigkill is here */
+
+int sigkill = SIGKILL;
+
+int outer_tramp(void *arg)
+{
+ struct tramp *t;
+ int sig = sigkill;
+
+ t = arg;
+ t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
+ t->flags, t->tramp_data);
+ if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
+ kill(os_getpid(), sig);
+ _exit(0);
+}
+
+int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
+ int clone_flags, int (*tramp)(void *))
+{
+ struct tramp arg;
+ unsigned long sp;
+ int new_pid, status, err;
+
+ /* The trampoline will run on the temporary stack */
+ sp = stack_sp(temp_stack);
+
+ clone_flags |= CLONE_FILES | SIGCHLD;
+
+ arg.tramp = tramp;
+ arg.tramp_data = thread_arg;
+ arg.temp_stack = temp_stack;
+ arg.flags = clone_flags;
+
+ /* Start the process and wait for it to kill itself */
+ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
+ if(new_pid < 0)
+ return(new_pid);
+
+ CATCH_EINTR(err = waitpid(new_pid, &status, 0));
+ if(err < 0)
+ panic("Waiting for outer trampoline failed - errno = %d",
+ errno);
+
+ if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
+ panic("outer trampoline didn't exit with SIGKILL, "
+ "status = %d", status);
+
+ return(arg.pid);
+}
+
+void forward_pending_sigio(int target)
+{
+ sigset_t sigs;
+
+ if(sigpending(&sigs))
+ panic("forward_pending_sigio : sigpending failed");
+ if(sigismember(&sigs, SIGIO))
+ kill(target, SIGIO);
+}
+
diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap
index 802d027..b216518 100644
--- a/arch/um/scripts/Makefile.unmap
+++ b/arch/um/scripts/Makefile.unmap
@@ -12,7 +12,7 @@
quiet_cmd_wrapld = LD $@
define cmd_wrapld
- $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) $(CFLAGS) -print-file-name=libc.a); \
+ $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \
$(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo
endef
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 77c3c4d..4ca2a22 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -16,13 +16,7 @@
highmem.c-dir = mm
module.c-dir = kernel
-STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
-
-# _cflags works with kernel files, not with userspace ones, but c_flags does,
-# why ask why?
-$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
-
-$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS))
subdir- := util
diff --git a/arch/um/sys-i386/kernel-offsets.c b/arch/um/sys-i386/kernel-offsets.c
index 9f8ecd1..a1070af 100644
--- a/arch/um/sys-i386/kernel-offsets.c
+++ b/arch/um/sys-i386/kernel-offsets.c
@@ -2,6 +2,7 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/time.h>
+#include <linux/elf.h>
#include <asm/page.h>
#define DEFINE(sym, val) \
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 4efc69a..16bc1992 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -122,9 +122,9 @@
int err;
to_fp = to->fpstate;
- from_fp = from->fpstate;
sigs = to->oldmask;
err = copy_from_user(to, from, sizeof(*to));
+ from_fp = to->fpstate;
to->oldmask = sigs;
to->fpstate = to_fp;
if(to_fp != NULL)
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
index 2f2c70a..6a70d9a 100644
--- a/arch/um/sys-i386/stub.S
+++ b/arch/um/sys-i386/stub.S
@@ -2,7 +2,50 @@
.globl syscall_stub
.section .__syscall_stub, "x"
-syscall_stub:
- int $0x80
+
+ .globl batch_syscall_stub
+batch_syscall_stub:
+ /* load pointer to first operation */
+ mov $(UML_CONFIG_STUB_DATA+8), %esp
+
+again:
+ /* load length of additional data */
+ mov 0x0(%esp), %eax
+
+ /* if(length == 0) : end of list */
+ /* write possible 0 to header */
+ mov %eax, UML_CONFIG_STUB_DATA+4
+ cmpl $0, %eax
+ jz done
+
+ /* save current pointer */
+ mov %esp, UML_CONFIG_STUB_DATA+4
+
+ /* skip additional data */
+ add %eax, %esp
+
+ /* load syscall-# */
+ pop %eax
+
+ /* load syscall params */
+ pop %ebx
+ pop %ecx
+ pop %edx
+ pop %esi
+ pop %edi
+ pop %ebp
+
+ /* execute syscall */
+ int $0x80
+
+ /* check return value */
+ pop %ebx
+ cmp %ebx, %eax
+ je again
+
+done:
+ /* save return value */
mov %eax, UML_CONFIG_STUB_DATA
+
+ /* stop */
int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
index 68aeabe..1e88b27 100644
--- a/arch/um/sys-i386/stub_segv.c
+++ b/arch/um/sys-i386/stub_segv.c
@@ -3,8 +3,7 @@
* Licensed under the GPL
*/
-#include <signal.h>
-#include <asm/sigcontext.h>
+#include <asm/signal.h>
#include <asm/unistd.h>
#include "uml-config.h"
#include "sysdep/sigcontext.h"
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 7488206..f0ab574d 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,7 +6,7 @@
#XXX: why into lib-y?
lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
- ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+ ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \
stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
obj-y := ksyms.o
@@ -15,7 +15,7 @@
USER_OBJS := ptrace_user.o sigcontext.o
SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \
- semaphore.c thunk.S module.c
+ thunk.S module.c
include arch/um/scripts/Makefile.rules
@@ -24,17 +24,10 @@
csum-partial.c-dir = lib
csum-wrappers.c-dir = lib
memcpy.S-dir = lib
-semaphore.c-dir = kernel
thunk.S-dir = lib
module.c-dir = kernel
-STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
-
-# _cflags works with kernel files, not with userspace ones, but c_flags does,
-# why ask why?
-$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
-
-$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS))
subdir- := util
diff --git a/arch/um/sys-x86_64/kernel-offsets.c b/arch/um/sys-x86_64/kernel-offsets.c
index 220e875..998541e 100644
--- a/arch/um/sys-x86_64/kernel-offsets.c
+++ b/arch/um/sys-x86_64/kernel-offsets.c
@@ -2,6 +2,7 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/time.h>
+#include <linux/elf.h>
#include <asm/page.h>
#define DEFINE(sym, val) \
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 8fdaed0..fe1d065 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -104,28 +104,35 @@
int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
int fpsize)
{
- struct _fpstate *to_fp, *from_fp;
- unsigned long sigs;
- int err;
+ struct _fpstate *to_fp, *from_fp;
+ unsigned long sigs;
+ int err;
- to_fp = to->fpstate;
- from_fp = from->fpstate;
- sigs = to->oldmask;
- err = copy_from_user(to, from, sizeof(*to));
- to->oldmask = sigs;
- return(err);
+ to_fp = to->fpstate;
+ sigs = to->oldmask;
+ err = copy_from_user(to, from, sizeof(*to));
+ from_fp = to->fpstate;
+ to->fpstate = to_fp;
+ to->oldmask = sigs;
+ if(to_fp != NULL)
+ err |= copy_from_user(to_fp, from_fp, fpsize);
+ return(err);
}
int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
struct sigcontext *from, int fpsize)
{
- struct _fpstate *to_fp, *from_fp;
- int err;
+ struct _fpstate *to_fp, *from_fp;
+ int err;
- to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
- from_fp = from->fpstate;
- err = copy_to_user(to, from, sizeof(*to));
- return(err);
+ to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
+ from_fp = from->fpstate;
+ err = copy_to_user(to, from, sizeof(*to));
+ if(from_fp != NULL){
+ err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
+ err |= copy_to_user(to_fp, from_fp, fpsize);
+ }
+ return(err);
}
#endif
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
index 31c1492..03c2797 100644
--- a/arch/um/sys-x86_64/stub.S
+++ b/arch/um/sys-x86_64/stub.S
@@ -13,3 +13,54 @@
or %rcx, %rbx
movq %rax, (%rbx)
int3
+
+ .globl batch_syscall_stub
+batch_syscall_stub:
+ mov $(UML_CONFIG_STUB_DATA >> 32), %rbx
+ sal $32, %rbx
+ mov $(UML_CONFIG_STUB_DATA & 0xffffffff), %rax
+ or %rax, %rbx
+ /* load pointer to first operation */
+ mov %rbx, %rsp
+ add $0x10, %rsp
+again:
+ /* load length of additional data */
+ mov 0x0(%rsp), %rax
+
+ /* if(length == 0) : end of list */
+ /* write possible 0 to header */
+ mov %rax, 8(%rbx)
+ cmp $0, %rax
+ jz done
+
+ /* save current pointer */
+ mov %rsp, 8(%rbx)
+
+ /* skip additional data */
+ add %rax, %rsp
+
+ /* load syscall-# */
+ pop %rax
+
+ /* load syscall params */
+ pop %rdi
+ pop %rsi
+ pop %rdx
+ pop %r10
+ pop %r8
+ pop %r9
+
+ /* execute syscall */
+ syscall
+
+ /* check return value */
+ pop %rcx
+ cmp %rcx, %rax
+ je again
+
+done:
+ /* save return value */
+ mov %rax, (%rbx)
+
+ /* stop */
+ int3
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
index 161d1fe..65a131b 100644
--- a/arch/um/sys-x86_64/stub_segv.c
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -3,9 +3,10 @@
* Licensed under the GPL
*/
-#include <signal.h>
+#include <asm/signal.h>
#include <linux/compiler.h>
#include <asm/unistd.h>
+#include <asm/ucontext.h>
#include "uml-config.h"
#include "sysdep/sigcontext.h"
#include "sysdep/faultinfo.h"
diff --git a/arch/v850/configs/rte-ma1-cb_defconfig b/arch/v850/configs/rte-ma1-cb_defconfig
index 1b5ca3c..1a5beda 100644
--- a/arch/v850/configs/rte-ma1-cb_defconfig
+++ b/arch/v850/configs/rte-ma1-cb_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:08:27 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep 2 13:54:27 2005
#
# CONFIG_MMU is not set
# CONFIG_UID16 is not set
@@ -44,6 +44,8 @@
# CONFIG_V850E_HIGHRES_TIMER is not set
# CONFIG_RESET_GUARD is not set
CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Code maturity level options
@@ -111,6 +113,52 @@
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER 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_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE 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
+
+#
# Generic Driver Options
#
CONFIG_STANDALONE=y
@@ -158,6 +206,7 @@
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -232,6 +281,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -244,53 +294,8 @@
# CONFIG_I2O is not set
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_UNIX is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -372,6 +377,8 @@
# CONFIG_FDDI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -472,6 +479,7 @@
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -479,6 +487,8 @@
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -524,9 +534,11 @@
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
diff --git a/arch/v850/configs/rte-me2-cb_defconfig b/arch/v850/configs/rte-me2-cb_defconfig
index 44becc0..15e6664 100644
--- a/arch/v850/configs/rte-me2-cb_defconfig
+++ b/arch/v850/configs/rte-me2-cb_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:30:08 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep 2 13:47:50 2005
#
# CONFIG_MMU is not set
# CONFIG_UID16 is not set
@@ -41,6 +41,8 @@
# CONFIG_V850E_HIGHRES_TIMER is not set
# CONFIG_RESET_GUARD is not set
CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Code maturity level options
@@ -56,7 +58,6 @@
CONFIG_LOCALVERSION=""
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
@@ -104,6 +105,11 @@
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
# Generic Driver Options
#
CONFIG_STANDALONE=y
@@ -151,6 +157,7 @@
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -218,6 +225,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -228,9 +236,8 @@
#
#
-# Networking support
+# Network device support
#
-# CONFIG_NET is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
@@ -311,7 +318,6 @@
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
@@ -335,6 +341,7 @@
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -342,6 +349,8 @@
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
diff --git a/arch/v850/configs/sim_defconfig b/arch/v850/configs/sim_defconfig
index d73f5f9..f31ba73 100644
--- a/arch/v850/configs/sim_defconfig
+++ b/arch/v850/configs/sim_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:29:27 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep 2 13:36:43 2005
#
# CONFIG_MMU is not set
# CONFIG_UID16 is not set
@@ -36,6 +36,8 @@
CONFIG_ZERO_BSS=y
# CONFIG_RESET_GUARD is not set
CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Code maturity level options
@@ -51,7 +53,6 @@
CONFIG_LOCALVERSION=""
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
@@ -99,6 +100,11 @@
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
# Generic Driver Options
#
CONFIG_STANDALONE=y
@@ -146,6 +152,7 @@
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -213,6 +220,7 @@
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -223,9 +231,8 @@
#
#
-# Networking support
+# Network device support
#
-# CONFIG_NET is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
@@ -300,7 +307,6 @@
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
@@ -324,6 +330,7 @@
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -331,6 +338,8 @@
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c
index c41d72b..abd4840 100644
--- a/arch/v850/kernel/setup.c
+++ b/arch/v850/kernel/setup.c
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/setup.c -- Arch-dependent initialization functions
*
- * Copyright (C) 2001,02,03 NEC Electronics Corporation
- * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03,05 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03,05 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -98,10 +98,20 @@
}
#ifdef CONFIG_MTD
+
+/* From drivers/mtd/devices/slram.c */
+#define SLRAM_BLK_SZ 0x4000
+
/* Set the root filesystem to be the given memory region.
Some parameter may be appended to CMD_LINE. */
void set_mem_root (void *addr, size_t len, char *cmd_line)
{
+ /* Some sort of idiocy in MTD means we must supply a length that's
+ a multiple of SLRAM_BLK_SZ. We just round up the real length,
+ as the file system shouldn't attempt to access anything beyond
+ the end of the image anyway. */
+ len = (((len - 1) + SLRAM_BLK_SZ) / SLRAM_BLK_SZ) * SLRAM_BLK_SZ;
+
/* The only way to pass info to the MTD slram driver is via
the command line. */
if (*cmd_line) {
@@ -284,3 +294,33 @@
free_area_init_node (0, NODE_DATA(0), zones_size,
ADDR_TO_PAGE (PAGE_OFFSET), 0);
}
+
+
+
+/* Taken from m68knommu */
+void show_mem(void)
+{
+ unsigned long i;
+ int free = 0, total = 0, reserved = 0, shared = 0;
+ int cached = 0;
+
+ printk(KERN_INFO "\nMem-info:\n");
+ show_free_areas();
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
+ else if (!page_count(mem_map+i))
+ free++;
+ else
+ shared += page_count(mem_map+i) - 1;
+ }
+ printk(KERN_INFO "%d pages of RAM\n",total);
+ printk(KERN_INFO "%d free pages\n",free);
+ printk(KERN_INFO "%d reserved pages\n",reserved);
+ printk(KERN_INFO "%d pages shared\n",shared);
+ printk(KERN_INFO "%d pages swap cached\n",cached);
+}
diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
index f722a26..ea3fd88 100644
--- a/arch/v850/kernel/time.c
+++ b/arch/v850/kernel/time.c
@@ -66,7 +66,7 @@
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
@@ -169,10 +169,7 @@
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_nsec;
- time_adjust = 0; /* stop active adjtime () */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq (&xtime_lock);
clock_was_set();
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 660a03a..8f868b6 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -24,6 +24,10 @@
bool
default y
+config SEMAPHORE_SLEEPERS
+ bool
+ default y
+
config MMU
bool
default y
@@ -61,6 +65,10 @@
bool
default y
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ default y
+
source "init/Kconfig"
@@ -437,6 +445,11 @@
bool
default y
+config GENERIC_PENDING_IRQ
+ bool
+ depends on GENERIC_HARDIRQS && SMP
+ default y
+
menu "Power management options"
source kernel/power/Kconfig
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
index ff58b28..12ea0b6 100644
--- a/arch/x86_64/boot/setup.S
+++ b/arch/x86_64/boot/setup.S
@@ -81,7 +81,7 @@
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
.ascii "HdrS" # header signature
- .word 0x0203 # header version number (>= 0x0105)
+ .word 0x0204 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
start_sys_seg: .word SYSSEG
diff --git a/arch/x86_64/boot/tools/build.c b/arch/x86_64/boot/tools/build.c
index 18b5bac..c44f5e2 100644
--- a/arch/x86_64/boot/tools/build.c
+++ b/arch/x86_64/boot/tools/build.c
@@ -178,7 +178,9 @@
die("Output: seek failed");
buf[0] = (sys_size & 0xff);
buf[1] = ((sys_size >> 8) & 0xff);
- if (write(1, buf, 2) != 2)
+ buf[2] = ((sys_size >> 16) & 0xff);
+ buf[3] = ((sys_size >> 24) & 0xff);
+ if (write(1, buf, 4) != 4)
die("Write of image length failed");
return 0; /* Everything is OK */
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index c45d6a0..f174083 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -307,7 +307,7 @@
.quad stub32_fork
.quad sys_read
.quad sys_write
- .quad sys32_open /* 5 */
+ .quad compat_sys_open /* 5 */
.quad sys_close
.quad sys32_waitpid
.quad sys_creat
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index be996d1b..04d8040 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -969,32 +969,6 @@
return sys_kill(pid, sig);
}
-asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
-{
- char * tmp;
- int fd, error;
-
- /* don't force O_LARGEFILE */
- tmp = getname(filename);
- fd = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
- if (fd >= 0) {
- struct file *f = filp_open(tmp, flags, mode);
- error = PTR_ERR(f);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = error;
- } else {
- fsnotify_open(f->f_dentry);
- fd_install(fd, f);
- }
- }
- putname(tmp);
- }
- return fd;
-}
-
extern asmlinkage long
sys_timer_create(clockid_t which_clock,
struct sigevent __user *timer_event_spec,
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index 48f9e2c..c32e198 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -4,10 +4,10 @@
extra-y := head.o head64.o init_task.o vmlinux.lds
EXTRA_AFLAGS := -traditional
-obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
+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
+ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o
obj-$(CONFIG_X86_MCE) += mce.o
obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o
@@ -45,3 +45,4 @@
microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o
intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o
quirks-y += ../../i386/kernel/quirks.o
+i8237-y += ../../i386/kernel/i8237.o
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index b548dea..116ac5f 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -85,7 +85,7 @@
struct e820entry *ei = &e820.map[i];
if (type && ei->type != type)
continue;
- if (ei->addr >= end || ei->addr + ei->size < start)
+ if (ei->addr >= end || ei->addr + ei->size <= start)
continue;
return 1;
}
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 096d470..be51dbe 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -784,8 +784,9 @@
ret
CFI_ENDPROC
-ENTRY(page_fault)
+KPROBE_ENTRY(page_fault)
errorentry do_page_fault
+ .previous .text
ENTRY(coprocessor_error)
zeroentry do_coprocessor_error
@@ -797,13 +798,14 @@
zeroentry math_state_restore
/* runs on exception stack */
-ENTRY(debug)
+KPROBE_ENTRY(debug)
CFI_STARTPROC
pushq $0
CFI_ADJUST_CFA_OFFSET 8
paranoidentry do_debug
jmp paranoid_exit
CFI_ENDPROC
+ .previous .text
/* runs on exception stack */
ENTRY(nmi)
@@ -854,8 +856,9 @@
jmp paranoid_userspace
CFI_ENDPROC
-ENTRY(int3)
+KPROBE_ENTRY(int3)
zeroentry do_int3
+ .previous .text
ENTRY(overflow)
zeroentry do_overflow
@@ -892,8 +895,9 @@
jmp paranoid_exit
CFI_ENDPROC
-ENTRY(general_protection)
+KPROBE_ENTRY(general_protection)
errorentry do_general_protection
+ .previous .text
ENTRY(alignment_check)
errorentry do_alignment_check
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
index 30c843a..f062aa0 100644
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -25,7 +25,7 @@
#endif
/* which logical CPU number maps to which CPU (physical APIC ID) */
-u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
EXPORT_SYMBOL(x86_cpu_to_apicid);
u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c
index 9703da7..f6523dd 100644
--- a/arch/x86_64/kernel/genapic_cluster.c
+++ b/arch/x86_64/kernel/genapic_cluster.c
@@ -72,10 +72,14 @@
static void cluster_send_IPI_allbutself(int vector)
{
cpumask_t mask = cpu_online_map;
- cpu_clear(smp_processor_id(), mask);
+ int me = get_cpu(); /* Ensure we are not preempted when we clear */
+
+ cpu_clear(me, mask);
if (!cpus_empty(mask))
cluster_send_IPI_mask(mask, vector);
+
+ put_cpu();
}
static void cluster_send_IPI_all(int vector)
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index d206d7e..ba1a744 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -70,7 +70,7 @@
short apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
#ifdef CONFIG_PCI_MSI
#define vector_to_irq(vector) \
(platform_legacy_irq(vector) ? vector : vector_irq[vector])
@@ -78,6 +78,54 @@
#define vector_to_irq(vector) (vector)
#endif
+#define __DO_ACTION(R, ACTION, FINAL) \
+ \
+{ \
+ int pin; \
+ struct irq_pin_list *entry = irq_2_pin + irq; \
+ \
+ for (;;) { \
+ unsigned int reg; \
+ pin = entry->pin; \
+ if (pin == -1) \
+ break; \
+ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
+ reg ACTION; \
+ io_apic_modify(entry->apic, reg); \
+ if (!entry->next) \
+ break; \
+ entry = irq_2_pin + entry->next; \
+ } \
+ FINAL; \
+}
+
+#ifdef CONFIG_SMP
+static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+ unsigned long flags;
+ unsigned int dest;
+ cpumask_t tmp;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ dest = cpu_mask_to_apicid(mask);
+
+ /*
+ * Only the high 8 bits are valid.
+ */
+ dest = SET_APIC_LOGICAL_ID(dest);
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __DO_ACTION(1, = dest, )
+ set_irq_info(irq, mask);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+#endif
+
/*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
* shared ISA-space IRQs, so we have to support them. We are super
@@ -101,26 +149,6 @@
entry->pin = pin;
}
-#define __DO_ACTION(R, ACTION, FINAL) \
- \
-{ \
- int pin; \
- struct irq_pin_list *entry = irq_2_pin + irq; \
- \
- for (;;) { \
- unsigned int reg; \
- pin = entry->pin; \
- if (pin == -1) \
- break; \
- reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
- reg ACTION; \
- io_apic_modify(entry->apic, reg); \
- if (!entry->next) \
- break; \
- entry = irq_2_pin + entry->next; \
- } \
- FINAL; \
-}
#define DO_ACTION(name,R,ACTION, FINAL) \
\
@@ -655,7 +683,7 @@
}
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
int assign_irq_vector(int irq)
{
@@ -767,6 +795,7 @@
spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+ set_native_irq_info(irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
}
@@ -1314,6 +1343,7 @@
*/
static void ack_edge_ioapic_irq(unsigned int irq)
{
+ move_irq(irq);
if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
== (IRQ_PENDING | IRQ_DISABLED))
mask_IO_APIC_irq(irq);
@@ -1343,26 +1373,10 @@
static void end_level_ioapic_irq (unsigned int irq)
{
+ move_irq(irq);
ack_APIC_irq();
}
-static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
-{
- unsigned long flags;
- unsigned int dest;
-
- dest = cpu_mask_to_apicid(mask);
-
- /*
- * Only the high 8 bits are valid.
- */
- dest = SET_APIC_LOGICAL_ID(dest);
-
- spin_lock_irqsave(&ioapic_lock, flags);
- __DO_ACTION(1, = dest, )
- spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
#ifdef CONFIG_PCI_MSI
static unsigned int startup_edge_ioapic_vector(unsigned int vector)
{
@@ -1375,6 +1389,7 @@
{
int irq = vector_to_irq(vector);
+ move_native_irq(vector);
ack_edge_ioapic_irq(irq);
}
@@ -1389,6 +1404,7 @@
{
int irq = vector_to_irq(vector);
+ move_native_irq(vector);
end_level_ioapic_irq(irq);
}
@@ -1406,14 +1422,17 @@
unmask_IO_APIC_irq(irq);
}
+#ifdef CONFIG_SMP
static void set_ioapic_affinity_vector (unsigned int vector,
cpumask_t cpu_mask)
{
int irq = vector_to_irq(vector);
+ set_native_irq_info(vector, cpu_mask);
set_ioapic_affinity_irq(irq, cpu_mask);
}
-#endif
+#endif // CONFIG_SMP
+#endif // CONFIG_PCI_MSI
/*
* Level and edge triggered IO-APIC interrupts need different handling,
@@ -1424,7 +1443,7 @@
* races.
*/
-static struct hw_interrupt_type ioapic_edge_type = {
+static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
.typename = "IO-APIC-edge",
.startup = startup_edge_ioapic,
.shutdown = shutdown_edge_ioapic,
@@ -1432,10 +1451,12 @@
.disable = disable_edge_ioapic,
.ack = ack_edge_ioapic,
.end = end_edge_ioapic,
+#ifdef CONFIG_SMP
.set_affinity = set_ioapic_affinity,
+#endif
};
-static struct hw_interrupt_type ioapic_level_type = {
+static struct hw_interrupt_type ioapic_level_type __read_mostly = {
.typename = "IO-APIC-level",
.startup = startup_level_ioapic,
.shutdown = shutdown_level_ioapic,
@@ -1443,7 +1464,9 @@
.disable = disable_level_ioapic,
.ack = mask_and_ack_level_ioapic,
.end = end_level_ioapic,
+#ifdef CONFIG_SMP
.set_affinity = set_ioapic_affinity,
+#endif
};
static inline void init_IO_APIC_traps(void)
@@ -1506,7 +1529,7 @@
static void end_lapic_irq (unsigned int i) { /* nothing */ }
-static struct hw_interrupt_type lapic_irq_type = {
+static struct hw_interrupt_type lapic_irq_type __read_mostly = {
.typename = "local-APIC-edge",
.startup = NULL, /* startup_irq() not used for IRQ0 */
.shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
@@ -1918,6 +1941,7 @@
spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+ set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
@@ -1931,6 +1955,7 @@
* we need to reprogram the ioredtbls to cater for the cpus which have come online
* so mask in all cases should simply be TARGET_CPUS
*/
+#ifdef CONFIG_SMP
void __init setup_ioapic_dest(void)
{
int pin, ioapic, irq, irq_entry;
@@ -1949,3 +1974,4 @@
}
}
+#endif
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 5c6dc70..df08c43 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -74,7 +74,7 @@
return 0;
}
-int arch_prepare_kprobe(struct kprobe *p)
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
/* insn: must be on special executable page on x86_64. */
up(&kprobe_mutex);
@@ -189,7 +189,7 @@
return NULL;
}
-void arch_copy_kprobe(struct kprobe *p)
+void __kprobes arch_copy_kprobe(struct kprobe *p)
{
s32 *ripdisp;
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
@@ -215,21 +215,21 @@
p->opcode = *p->addr;
}
-void arch_arm_kprobe(struct kprobe *p)
+void __kprobes arch_arm_kprobe(struct kprobe *p)
{
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
-void arch_disarm_kprobe(struct kprobe *p)
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
-void arch_remove_kprobe(struct kprobe *p)
+void __kprobes arch_remove_kprobe(struct kprobe *p)
{
up(&kprobe_mutex);
free_insn_slot(p->ainsn.insn);
@@ -261,7 +261,7 @@
kprobe_saved_rflags &= ~IF_MASK;
}
-static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
regs->eflags |= TF_MASK;
regs->eflags &= ~IF_MASK;
@@ -272,7 +272,8 @@
regs->rip = (unsigned long)p->ainsn.insn;
}
-void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+ struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)regs->rsp;
struct kretprobe_instance *ri;
@@ -295,7 +296,7 @@
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
* remain disabled thorough out this function.
*/
-int kprobe_handler(struct pt_regs *regs)
+int __kprobes kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
int ret = 0;
@@ -310,7 +311,8 @@
Disarm the probe we just hit, and ignore it. */
p = get_kprobe(addr);
if (p) {
- if (kprobe_status == KPROBE_HIT_SS) {
+ if (kprobe_status == KPROBE_HIT_SS &&
+ *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
regs->eflags &= ~TF_MASK;
regs->eflags |= kprobe_saved_rflags;
unlock_kprobes();
@@ -360,7 +362,10 @@
* either a probepoint or a debugger breakpoint
* at this address. In either case, no further
* handling of this interrupt is appropriate.
+ * Back up over the (now missing) int3 and run
+ * the original instruction.
*/
+ regs->rip = (unsigned long)addr;
ret = 1;
}
/* Not one of ours: let kernel handle it */
@@ -399,7 +404,7 @@
/*
* Called when we hit the probe point at kretprobe_trampoline
*/
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head;
@@ -478,7 +483,7 @@
* that is atop the stack is the address following the copied instruction.
* We need to make it the address following the original instruction.
*/
-static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
unsigned long *tos = (unsigned long *)regs->rsp;
unsigned long next_rip = 0;
@@ -536,7 +541,7 @@
* Interrupts are disabled on entry as trap1 is an interrupt gate and they
* remain disabled thoroughout this function. And we hold kprobe lock.
*/
-int post_kprobe_handler(struct pt_regs *regs)
+int __kprobes post_kprobe_handler(struct pt_regs *regs)
{
if (!kprobe_running())
return 0;
@@ -571,7 +576,7 @@
}
/* Interrupts disabled, kprobe_lock held. */
-int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
if (current_kprobe->fault_handler
&& current_kprobe->fault_handler(current_kprobe, regs, trapnr))
@@ -590,8 +595,8 @@
/*
* Wrapper routine for handling exceptions.
*/
-int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
- void *data)
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
switch (val) {
@@ -619,7 +624,7 @@
return NOTIFY_DONE;
}
-int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
unsigned long addr;
@@ -640,7 +645,7 @@
return 1;
}
-void jprobe_return(void)
+void __kprobes jprobe_return(void)
{
preempt_enable_no_resched();
asm volatile (" xchg %%rbx,%%rsp \n"
@@ -651,7 +656,7 @@
(jprobe_saved_rsp):"memory");
}
-int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
u8 *addr = (u8 *) (regs->rip - 1);
unsigned long stack_addr = (unsigned long)jprobe_saved_rsp;
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 4e44d6e..caf1649 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -290,7 +290,7 @@
static int nmi_pm_active; /* nmi_active before suspend */
-static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
+static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
{
nmi_pm_active = nmi_active;
disable_lapic_nmi_watchdog();
@@ -463,6 +463,8 @@
*/
for (i = 0; i < NR_CPUS; i++)
per_cpu(nmi_touch, i) = 1;
+
+ touch_softlockup_watchdog();
}
void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
@@ -522,14 +524,14 @@
nmi_enter();
add_pda(__nmi_count,1);
- if (!nmi_callback(regs, cpu))
+ if (!rcu_dereference(nmi_callback)(regs, cpu))
default_do_nmi(regs);
nmi_exit();
}
void set_nmi_callback(nmi_callback_t callback)
{
- nmi_callback = callback;
+ rcu_assign_pointer(nmi_callback, callback);
}
void unset_nmi_callback(void)
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 7577f9d..8661f82 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -310,6 +310,7 @@
void show_regs(struct pt_regs *regs)
{
+ printk("CPU %d:", smp_processor_id());
__show_regs(regs);
show_trace(®s->rsp);
}
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 116a491..b356f8e 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -65,7 +65,7 @@
* Machine setup..
*/
-struct cpuinfo_x86 boot_cpu_data;
+struct cpuinfo_x86 boot_cpu_data __read_mostly;
unsigned long mmu_cr4_features;
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 34082c1..e3ffcac 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -36,7 +36,7 @@
char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
-unsigned long __supported_pte_mask = ~0UL;
+unsigned long __supported_pte_mask __read_mostly = ~0UL;
static int do_not_nx __initdata = 0;
/* noexec=on|off
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index fa25e39..90aeccd 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -62,13 +62,13 @@
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
/* Package ID of each logical CPU */
-u8 phys_proc_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
-u8 cpu_core_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
EXPORT_SYMBOL(phys_proc_id);
EXPORT_SYMBOL(cpu_core_id);
/* Bitmask of currently online CPUs */
-cpumask_t cpu_online_map;
+cpumask_t cpu_online_map __read_mostly;
EXPORT_SYMBOL(cpu_online_map);
@@ -88,8 +88,8 @@
/* Set when the idlers are all forked */
int smp_threads_ready;
-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
-cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map);
/*
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 66bf6dd..7b6abe0 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -176,10 +176,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
@@ -471,7 +468,7 @@
* off) isn't likely to go away much sooner anyway.
*/
- if ((~time_status & STA_UNSYNC) && xtime.tv_sec > rtc_update &&
+ if (ntp_synced() && xtime.tv_sec > rtc_update &&
abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
set_rtc_mmss(xtime.tv_sec);
rtc_update = xtime.tv_sec + 660;
@@ -1041,6 +1038,7 @@
write_sequnlock_irqrestore(&xtime_lock,flags);
jiffies += sleep_length;
wall_jiffies += sleep_length;
+ touch_softlockup_watchdog();
return 0;
}
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 6ead433..f238d60 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/nmi.h>
+#include <linux/kprobes.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -419,8 +420,9 @@
do_exit(SIGSEGV);
}
-static void do_trap(int trapnr, int signr, char *str,
- struct pt_regs * regs, long error_code, siginfo_t *info)
+static void __kprobes do_trap(int trapnr, int signr, char *str,
+ struct pt_regs * regs, long error_code,
+ siginfo_t *info)
{
conditional_sti(regs);
@@ -504,7 +506,8 @@
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
+ long error_code)
{
conditional_sti(regs);
@@ -622,7 +625,7 @@
io_check_error(reason, regs);
}
-asmlinkage void do_int3(struct pt_regs * regs, long error_code)
+asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
{
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
return;
@@ -653,7 +656,8 @@
}
/* runs on IST stack. */
-asmlinkage void do_debug(struct pt_regs * regs, unsigned long error_code)
+asmlinkage void __kprobes do_debug(struct pt_regs * regs,
+ unsigned long error_code)
{
unsigned long condition;
struct task_struct *tsk = current;
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 2a94f9b..d4abb07 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -21,6 +21,7 @@
*(.text)
SCHED_TEXT
LOCK_TEXT
+ KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
} = 0x9090
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index ca914c3..816732d 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -23,6 +23,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/compiler.h>
#include <linux/module.h>
+#include <linux/kprobes.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -294,7 +295,8 @@
* bit 2 == 0 means kernel, 1 means user-mode
* bit 3 == 1 means fault was an instruction fetch
*/
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+ unsigned long error_code)
{
struct task_struct *tsk;
struct mm_struct *mm;
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 6a156f5..04f7a33 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -22,14 +22,14 @@
#define Dprintk(x...)
#endif
-struct pglist_data *node_data[MAX_NUMNODES];
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
bootmem_data_t plat_node_bdata[MAX_NUMNODES];
int memnode_shift;
u8 memnodemap[NODEMAPSIZE];
-unsigned char cpu_to_node[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
-cpumask_t node_to_cpumask[MAX_NUMNODES];
+unsigned char cpu_to_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
+cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly;
int numa_off __initdata;
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index e07287d..1ac7d5c 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -122,10 +122,7 @@
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
+ ntp_clear();
write_sequnlock_irq(&xtime_lock);
return 0;
}
@@ -184,7 +181,7 @@
next += CCOUNT_PER_JIFFY;
do_timer (regs); /* Linux handler in kernel/timer.c */
- if ((time_status & STA_UNSYNC) == 0 &&
+ if (ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
jiffies - wall_jiffies == 1) {
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 256c0b1..89299f4 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -219,7 +219,7 @@
described in RFC2612.
config CRYPTO_TEA
- tristate "TEA and XTEA cipher algorithms"
+ tristate "TEA, XTEA and XETA cipher algorithms"
depends on CRYPTO
help
TEA cipher algorithm.
@@ -232,6 +232,9 @@
the TEA algorithm to address a potential key weakness
in the TEA algorithm.
+ Xtendend Encryption Tiny Algorithm is a mis-implementation
+ of the XTEA algorithm for compatibility purposes.
+
config CRYPTO_ARC4
tristate "ARC4 cipher algorithm"
depends on CRYPTO
diff --git a/crypto/api.c b/crypto/api.c
index b472881..959c4e5 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -66,7 +66,8 @@
static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
{
- tfm->crt_flags = 0;
+ tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK;
+ flags &= ~CRYPTO_TFM_REQ_MASK;
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 8da6443..dfd4bcf 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -191,6 +191,8 @@
u8 *iv = desc->info;
unsigned int done = 0;
+ nbytes -= bsize;
+
do {
xor(iv, src);
fn(crypto_tfm_ctx(tfm), dst, iv);
@@ -198,7 +200,7 @@
src += bsize;
dst += bsize;
- } while ((done += bsize) < nbytes);
+ } while ((done += bsize) <= nbytes);
return done;
}
@@ -219,6 +221,8 @@
u8 *iv = desc->info;
unsigned int done = 0;
+ nbytes -= bsize;
+
do {
u8 *tmp_dst = *dst_p;
@@ -230,7 +234,7 @@
src += bsize;
dst += bsize;
- } while ((done += bsize) < nbytes);
+ } while ((done += bsize) <= nbytes);
return done;
}
@@ -243,12 +247,14 @@
void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
unsigned int done = 0;
+ nbytes -= bsize;
+
do {
fn(crypto_tfm_ctx(tfm), dst, src);
src += bsize;
dst += bsize;
- } while ((done += bsize) < nbytes);
+ } while ((done += bsize) <= nbytes);
return done;
}
@@ -377,11 +383,7 @@
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
{
u32 mode = flags & CRYPTO_TFM_MODE_MASK;
-
tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
- if (flags & CRYPTO_TFM_REQ_WEAK_KEY)
- tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY;
-
return 0;
}
diff --git a/crypto/internal.h b/crypto/internal.h
index 37515be..37aa652 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <asm/kmap_types.h>
extern enum km_type crypto_km_types[];
@@ -38,7 +39,7 @@
static inline void crypto_yield(struct crypto_tfm *tfm)
{
- if (!in_atomic())
+ if (tfm->crt_flags & CRYPTO_TFM_REQ_MAY_SLEEP)
cond_resched();
}
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index bd7524c..6863941 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -72,7 +72,7 @@
"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
"arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
- "khazad", "wp512", "wp384", "wp256", "tnepres", NULL
+ "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL
};
static void hexdump(unsigned char *buf, unsigned int len)
@@ -859,6 +859,10 @@
test_cipher ("anubis", MODE_CBC, ENCRYPT, anubis_cbc_enc_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
test_cipher ("anubis", MODE_CBC, DECRYPT, anubis_cbc_dec_tv_template, ANUBIS_CBC_ENC_TEST_VECTORS);
+ //XETA
+ test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS);
+ test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS);
+
test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
@@ -1016,6 +1020,11 @@
case 29:
test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
break;
+
+ case 30:
+ test_cipher ("xeta", MODE_ECB, ENCRYPT, xeta_enc_tv_template, XETA_ENC_TEST_VECTORS);
+ test_cipher ("xeta", MODE_ECB, DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS);
+ break;
#ifdef CONFIG_CRYPTO_HMAC
case 100:
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index c01a0ce9..522ffd4 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -2211,7 +2211,7 @@
.klen = 16,
.input = { [0 ... 8] = 0x00 },
.ilen = 8,
- .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+ .result = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 },
.rlen = 8,
}, {
.key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
@@ -2219,31 +2219,31 @@
.klen = 16,
.input = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
.ilen = 8,
- .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+ .result = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 },
.rlen = 8,
}, {
.key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
.klen = 16,
- .input = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
+ .input = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d,
0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
.ilen = 16,
- .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
+ .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
.rlen = 16,
}, {
.key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
.klen = 16,
- .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
- 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
- 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
+ .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
+ 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
+ 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
.ilen = 32,
- .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1,
- 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4,
- 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f,
- 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+ .result = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a,
+ 0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07,
+ 0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4,
+ 0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 },
.rlen = 32,
}
};
@@ -2252,7 +2252,7 @@
{
.key = { [0 ... 15] = 0x00 },
.klen = 16,
- .input = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+ .input = { 0xd8, 0xd4, 0xe9, 0xde, 0xd9, 0x1e, 0x13, 0xf7 },
.ilen = 8,
.result = { [0 ... 8] = 0x00 },
.rlen = 8,
@@ -2260,7 +2260,7 @@
.key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
.klen = 16,
- .input = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+ .input = { 0x94, 0xeb, 0xc8, 0x96, 0x84, 0x6a, 0x49, 0xa8 },
.ilen = 8,
.result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
.rlen = 8,
@@ -2268,24 +2268,24 @@
.key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
.klen = 16,
- .input = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
- 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+ .input = { 0x3e, 0xce, 0xae, 0x22, 0x60, 0x56, 0xa8, 0x9d,
+ 0x77, 0x4d, 0xd4, 0xb4, 0x87, 0x24, 0xe3, 0x9a },
.ilen = 16,
- .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
+ .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
.rlen = 16,
}, {
.key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
.klen = 16,
- .input = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1,
- 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4,
- 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f,
- 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+ .input = { 0x99, 0x81, 0x9f, 0x5d, 0x6f, 0x4b, 0x31, 0x3a,
+ 0x86, 0xff, 0x6f, 0xd0, 0xe3, 0x87, 0x70, 0x07,
+ 0x4d, 0xb8, 0xcf, 0xf3, 0x99, 0x50, 0xb3, 0xd4,
+ 0x73, 0xa2, 0xfa, 0xc9, 0x16, 0x59, 0x5d, 0x81 },
.ilen = 32,
- .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
- 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
- 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
+ .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
+ 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
+ 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
.rlen = 32,
}
@@ -2594,6 +2594,98 @@
},
};
+/*
+ * XETA test vectors
+ */
+#define XETA_ENC_TEST_VECTORS 4
+#define XETA_DEC_TEST_VECTORS 4
+
+static struct cipher_testvec xeta_enc_tv_template[] = {
+ {
+ .key = { [0 ... 15] = 0x00 },
+ .klen = 16,
+ .input = { [0 ... 8] = 0x00 },
+ .ilen = 8,
+ .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+ .rlen = 8,
+ }, {
+ .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
+ 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
+ .klen = 16,
+ .input = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
+ .ilen = 8,
+ .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+ .rlen = 8,
+ }, {
+ .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
+ 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
+ .klen = 16,
+ .input = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
+ 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
+ .ilen = 16,
+ .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
+ 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+ .rlen = 16,
+ }, {
+ .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
+ 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
+ .klen = 16,
+ .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
+ 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
+ 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
+ 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
+ .ilen = 32,
+ .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1,
+ 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4,
+ 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f,
+ 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+ .rlen = 32,
+ }
+};
+
+static struct cipher_testvec xeta_dec_tv_template[] = {
+ {
+ .key = { [0 ... 15] = 0x00 },
+ .klen = 16,
+ .input = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 },
+ .ilen = 8,
+ .result = { [0 ... 8] = 0x00 },
+ .rlen = 8,
+ }, {
+ .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76,
+ 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 },
+ .klen = 16,
+ .input = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 },
+ .ilen = 8,
+ .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e },
+ .rlen = 8,
+ }, {
+ .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25,
+ 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e },
+ .klen = 16,
+ .input = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea,
+ 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c },
+ .ilen = 16,
+ .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74,
+ 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 },
+ .rlen = 16,
+ }, {
+ .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c,
+ 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f },
+ .klen = 16,
+ .input = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1,
+ 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4,
+ 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f,
+ 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 },
+ .ilen = 32,
+ .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67,
+ 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20,
+ 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72,
+ 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 },
+ .rlen = 32,
+ }
+};
+
/*
* Compression stuff.
*/
diff --git a/crypto/tea.c b/crypto/tea.c
index 03c23cb..5924efd 100644
--- a/crypto/tea.c
+++ b/crypto/tea.c
@@ -1,11 +1,15 @@
/*
* Cryptographic API.
*
- * TEA and Xtended TEA Algorithms
+ * TEA, XTEA, and XETA crypto alogrithms
*
* The TEA and Xtended TEA algorithms were developed by David Wheeler
* and Roger Needham at the Computer Laboratory of Cambridge University.
*
+ * Due to the order of evaluation in XTEA many people have incorrectly
+ * implemented it. XETA (XTEA in the wrong order), exists for
+ * compatibility with these implementations.
+ *
* Copyright (c) 2004 Aaron Grothe ajgrothe@yahoo.com
*
* This program is free software; you can redistribute it and/or modify
@@ -153,9 +157,9 @@
z = u32_in (src + 4);
while (sum != limit) {
- y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3];
+ y += ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum&3]);
sum += XTEA_DELTA;
- z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3];
+ z += ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 &3]);
}
u32_out (dst, y);
@@ -175,6 +179,51 @@
sum = XTEA_DELTA * XTEA_ROUNDS;
while (sum) {
+ z -= ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 & 3]);
+ sum -= XTEA_DELTA;
+ y -= ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum & 3]);
+ }
+
+ u32_out (dst, y);
+ u32_out (dst + 4, z);
+
+}
+
+
+static void xeta_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{
+
+ u32 y, z, sum = 0;
+ u32 limit = XTEA_DELTA * XTEA_ROUNDS;
+
+ struct xtea_ctx *ctx = ctx_arg;
+
+ y = u32_in (src);
+ z = u32_in (src + 4);
+
+ while (sum != limit) {
+ y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3];
+ sum += XTEA_DELTA;
+ z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3];
+ }
+
+ u32_out (dst, y);
+ u32_out (dst + 4, z);
+
+}
+
+static void xeta_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{
+
+ u32 y, z, sum;
+ struct tea_ctx *ctx = ctx_arg;
+
+ y = u32_in (src);
+ z = u32_in (src + 4);
+
+ sum = XTEA_DELTA * XTEA_ROUNDS;
+
+ while (sum) {
z -= (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 & 3];
sum -= XTEA_DELTA;
y -= (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum & 3];
@@ -215,6 +264,21 @@
.cia_decrypt = xtea_decrypt } }
};
+static struct crypto_alg xeta_alg = {
+ .cra_name = "xeta",
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = XTEA_BLOCK_SIZE,
+ .cra_ctxsize = sizeof (struct xtea_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list),
+ .cra_u = { .cipher = {
+ .cia_min_keysize = XTEA_KEY_SIZE,
+ .cia_max_keysize = XTEA_KEY_SIZE,
+ .cia_setkey = xtea_setkey,
+ .cia_encrypt = xeta_encrypt,
+ .cia_decrypt = xeta_decrypt } }
+};
+
static int __init init(void)
{
int ret = 0;
@@ -229,6 +293,13 @@
goto out;
}
+ ret = crypto_register_alg(&xeta_alg);
+ if (ret < 0) {
+ crypto_unregister_alg(&tea_alg);
+ crypto_unregister_alg(&xtea_alg);
+ goto out;
+ }
+
out:
return ret;
}
@@ -237,12 +308,14 @@
{
crypto_unregister_alg(&tea_alg);
crypto_unregister_alg(&xtea_alg);
+ crypto_unregister_alg(&xeta_alg);
}
MODULE_ALIAS("xtea");
+MODULE_ALIAS("xeta");
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("TEA & XTEA Cryptographic Algorithms");
+MODULE_DESCRIPTION("TEA, XTEA & XETA Cryptographic Algorithms");
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index c4b75ec..55959e4 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -417,9 +417,9 @@
chan = (here[3] & uPD98401_AAL5_CHAN) >>
uPD98401_AAL5_CHAN_SHIFT;
if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) {
- int pos = ZATM_VCC(vcc)->pool;
-
+ int pos;
vcc = zatm_dev->rx_map[chan];
+ pos = ZATM_VCC(vcc)->pool;
if (skb == zatm_dev->last_free[pos])
zatm_dev->last_free[pos] = NULL;
skb_unlink(skb, zatm_dev->pool + pos);
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index ec615d8..373e7b7 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -22,11 +22,26 @@
/* This is a private structure used to tie the classdev and the
* container .. it should never be visible outside this file */
struct internal_container {
- struct list_head node;
+ struct klist_node node;
struct attribute_container *cont;
struct class_device classdev;
};
+static void internal_container_klist_get(struct klist_node *n)
+{
+ struct internal_container *ic =
+ container_of(n, struct internal_container, node);
+ class_device_get(&ic->classdev);
+}
+
+static void internal_container_klist_put(struct klist_node *n)
+{
+ struct internal_container *ic =
+ container_of(n, struct internal_container, node);
+ class_device_put(&ic->classdev);
+}
+
+
/**
* attribute_container_classdev_to_container - given a classdev, return the container
*
@@ -57,7 +72,8 @@
attribute_container_register(struct attribute_container *cont)
{
INIT_LIST_HEAD(&cont->node);
- INIT_LIST_HEAD(&cont->containers);
+ klist_init(&cont->containers,internal_container_klist_get,
+ internal_container_klist_put);
down(&attribute_container_mutex);
list_add_tail(&cont->node, &attribute_container_list);
@@ -77,11 +93,13 @@
{
int retval = -EBUSY;
down(&attribute_container_mutex);
- if (!list_empty(&cont->containers))
+ spin_lock(&cont->containers.k_lock);
+ if (!list_empty(&cont->containers.k_list))
goto out;
retval = 0;
list_del(&cont->node);
out:
+ spin_unlock(&cont->containers.k_lock);
up(&attribute_container_mutex);
return retval;
@@ -140,7 +158,6 @@
continue;
}
memset(ic, 0, sizeof(struct internal_container));
- INIT_LIST_HEAD(&ic->node);
ic->cont = cont;
class_device_initialize(&ic->classdev);
ic->classdev.dev = get_device(dev);
@@ -151,11 +168,22 @@
fn(cont, dev, &ic->classdev);
else
attribute_container_add_class_device(&ic->classdev);
- list_add_tail(&ic->node, &cont->containers);
+ klist_add_tail(&ic->node, &cont->containers);
}
up(&attribute_container_mutex);
}
+/* FIXME: can't break out of this unless klist_iter_exit is also
+ * called before doing the break
+ */
+#define klist_for_each_entry(pos, head, member, iter) \
+ for (klist_iter_init(head, iter); (pos = ({ \
+ struct klist_node *n = klist_next(iter); \
+ n ? container_of(n, typeof(*pos), member) : \
+ ({ klist_iter_exit(iter) ; NULL; }); \
+ }) ) != NULL; )
+
+
/**
* attribute_container_remove_device - make device eligible for removal.
*
@@ -182,17 +210,19 @@
down(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) {
- struct internal_container *ic, *tmp;
+ struct internal_container *ic;
+ struct klist_iter iter;
if (attribute_container_no_classdevs(cont))
continue;
if (!cont->match(cont, dev))
continue;
- list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
+
+ klist_for_each_entry(ic, &cont->containers, node, &iter) {
if (dev != ic->classdev.dev)
continue;
- list_del(&ic->node);
+ klist_del(&ic->node);
if (fn)
fn(cont, dev, &ic->classdev);
else {
@@ -225,12 +255,18 @@
down(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) {
- struct internal_container *ic, *tmp;
+ struct internal_container *ic;
+ struct klist_iter iter;
if (!cont->match(cont, dev))
continue;
- list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
+ if (attribute_container_no_classdevs(cont)) {
+ fn(cont, dev, NULL);
+ continue;
+ }
+
+ klist_for_each_entry(ic, &cont->containers, node, &iter) {
if (dev == ic->classdev.dev)
fn(cont, dev, &ic->classdev);
}
@@ -368,6 +404,36 @@
}
EXPORT_SYMBOL_GPL(attribute_container_class_device_del);
+/**
+ * attribute_container_find_class_device - find the corresponding class_device
+ *
+ * @cont: the container
+ * @dev: the generic device
+ *
+ * Looks up the device in the container's list of class devices and returns
+ * the corresponding class_device.
+ */
+struct class_device *
+attribute_container_find_class_device(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct class_device *cdev = NULL;
+ struct internal_container *ic;
+ struct klist_iter iter;
+
+ klist_for_each_entry(ic, &cont->containers, node, &iter) {
+ if (ic->classdev.dev == dev) {
+ cdev = &ic->classdev;
+ /* FIXME: must exit iterator then break */
+ klist_iter_exit(&iter);
+ break;
+ }
+ }
+
+ return cdev;
+}
+EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
+
int __init
attribute_container_init(void)
{
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index ab53832..03204bf 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -156,7 +156,9 @@
device_release_driver(dev);
err = count;
}
- return err;
+ if (err)
+ return err;
+ return count;
}
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -358,7 +360,7 @@
if (bus) {
pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
device_attach(dev);
- klist_add_tail(&bus->klist_devices, &dev->knode_bus);
+ klist_add_tail(&dev->knode_bus, &bus->klist_devices);
error = device_add_attrs(bus, dev);
if (!error) {
sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
@@ -446,7 +448,7 @@
}
driver_attach(drv);
- klist_add_tail(&bus->klist_drivers, &drv->knode_bus);
+ klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
driver_add_attrs(bus, drv);
@@ -566,6 +568,36 @@
}
}
+static void klist_devices_get(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_bus);
+
+ get_device(dev);
+}
+
+static void klist_devices_put(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_bus);
+
+ put_device(dev);
+}
+
+static void klist_drivers_get(struct klist_node *n)
+{
+ struct device_driver *drv = container_of(n, struct device_driver,
+ knode_bus);
+
+ get_driver(drv);
+}
+
+static void klist_drivers_put(struct klist_node *n)
+{
+ struct device_driver *drv = container_of(n, struct device_driver,
+ knode_bus);
+
+ put_driver(drv);
+}
+
/**
* bus_register - register a bus with the system.
* @bus: bus.
@@ -600,8 +632,8 @@
if (retval)
goto bus_drivers_fail;
- klist_init(&bus->klist_devices);
- klist_init(&bus->klist_drivers);
+ klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
+ klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put);
bus_add_attrs(bus);
pr_debug("bus type '%s' registered\n", bus->name);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 0154a16..d164c32 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -299,10 +299,8 @@
pr_debug("device class '%s': release.\n", cd->class_id);
- if (cd->devt_attr) {
- kfree(cd->devt_attr);
- cd->devt_attr = NULL;
- }
+ kfree(cd->devt_attr);
+ cd->devt_attr = NULL;
if (cls->release)
cls->release(cd);
@@ -452,10 +450,29 @@
INIT_LIST_HEAD(&class_dev->node);
}
+static char *make_class_name(struct class_device *class_dev)
+{
+ char *name;
+ int size;
+
+ size = strlen(class_dev->class->name) +
+ strlen(kobject_name(&class_dev->kobj)) + 2;
+
+ name = kmalloc(size, GFP_KERNEL);
+ if (!name)
+ return ERR_PTR(-ENOMEM);
+
+ strcpy(name, class_dev->class->name);
+ strcat(name, ":");
+ strcat(name, kobject_name(&class_dev->kobj));
+ return name;
+}
+
int class_device_add(struct class_device *class_dev)
{
struct class * parent = NULL;
struct class_interface * class_intf;
+ char *class_name = NULL;
int error;
class_dev = class_device_get(class_dev);
@@ -500,9 +517,13 @@
}
class_device_add_attrs(class_dev);
- if (class_dev->dev)
+ if (class_dev->dev) {
+ class_name = make_class_name(class_dev);
sysfs_create_link(&class_dev->kobj,
&class_dev->dev->kobj, "device");
+ sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+ class_name);
+ }
/* notify any interfaces this device is now here */
if (parent) {
@@ -519,6 +540,7 @@
if (error && parent)
class_put(parent);
class_device_put(class_dev);
+ kfree(class_name);
return error;
}
@@ -584,6 +606,7 @@
{
struct class * parent = class_dev->class;
struct class_interface * class_intf;
+ char *class_name = NULL;
if (parent) {
down(&parent->sem);
@@ -594,8 +617,11 @@
up(&parent->sem);
}
- if (class_dev->dev)
+ if (class_dev->dev) {
+ class_name = make_class_name(class_dev);
sysfs_remove_link(&class_dev->kobj, "device");
+ sysfs_remove_link(&class_dev->dev->kobj, class_name);
+ }
if (class_dev->devt_attr)
class_device_remove_file(class_dev, class_dev->devt_attr);
class_device_remove_attrs(class_dev);
@@ -605,6 +631,7 @@
if (parent)
class_put(parent);
+ kfree(class_name);
}
void class_device_unregister(struct class_device *class_dev)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index efe03a0..6ab73f5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -191,6 +191,20 @@
}
}
+static void klist_children_get(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_parent);
+
+ get_device(dev);
+}
+
+static void klist_children_put(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_parent);
+
+ put_device(dev);
+}
+
/**
* device_initialize - init device structure.
@@ -207,7 +221,8 @@
{
kobj_set_kset_s(dev, devices_subsys);
kobject_init(&dev->kobj);
- klist_init(&dev->klist_children);
+ klist_init(&dev->klist_children, klist_children_get,
+ klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
}
@@ -249,7 +264,7 @@
if ((error = bus_add_device(dev)))
goto BusError;
if (parent)
- klist_add_tail(&parent->klist_children, &dev->knode_parent);
+ klist_add_tail(&dev->knode_parent, &parent->klist_children);
/* notify platform of device entry */
if (platform_notify)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 16323f9..d5bbce3 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -42,7 +42,7 @@
{
pr_debug("bound device '%s' to driver '%s'\n",
dev->bus_id, dev->driver->name);
- klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver);
+ klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
sysfs_create_link(&dev->driver->kobj, &dev->kobj,
kobject_name(&dev->kobj));
sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 291c595..ef3fe51 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -142,6 +142,19 @@
kobject_put(&drv->kobj);
}
+static void klist_devices_get(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_driver);
+
+ get_device(dev);
+}
+
+static void klist_devices_put(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_driver);
+
+ put_device(dev);
+}
/**
* driver_register - register driver with bus
@@ -157,7 +170,7 @@
*/
int driver_register(struct device_driver * drv)
{
- klist_init(&drv->klist_devices);
+ klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);
init_completion(&drv->unloaded);
return bus_add_driver(drv);
}
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6522814..5bfa2e9 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -28,6 +28,7 @@
FW_STATUS_DONE,
FW_STATUS_ABORT,
FW_STATUS_READY,
+ FW_STATUS_READY_NOHOTPLUG,
};
static int loading_timeout = 10; /* In seconds */
@@ -344,7 +345,7 @@
static int
fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
- const char *fw_name, struct device *device)
+ const char *fw_name, struct device *device, int hotplug)
{
struct class_device *class_dev;
struct firmware_priv *fw_priv;
@@ -376,7 +377,10 @@
goto error_unreg;
}
- set_bit(FW_STATUS_READY, &fw_priv->status);
+ if (hotplug)
+ set_bit(FW_STATUS_READY, &fw_priv->status);
+ else
+ set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
*class_dev_p = class_dev;
goto out;
@@ -386,21 +390,9 @@
return retval;
}
-/**
- * request_firmware: - request firmware to hotplug and wait for it
- * Description:
- * @firmware will be used to return a firmware image by the name
- * of @name for device @device.
- *
- * Should be called from user context where sleeping is allowed.
- *
- * @name will be use as $FIRMWARE in the hotplug environment and
- * should be distinctive enough not to be confused with any other
- * firmware image for this or any other device.
- **/
-int
-request_firmware(const struct firmware **firmware_p, const char *name,
- struct device *device)
+static int
+_request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device, int hotplug)
{
struct class_device *class_dev;
struct firmware_priv *fw_priv;
@@ -419,22 +411,25 @@
}
memset(firmware, 0, sizeof (*firmware));
- retval = fw_setup_class_device(firmware, &class_dev, name, device);
+ retval = fw_setup_class_device(firmware, &class_dev, name, device,
+ hotplug);
if (retval)
goto error_kfree_fw;
fw_priv = class_get_devdata(class_dev);
- if (loading_timeout > 0) {
- fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
- add_timer(&fw_priv->timeout);
- }
+ if (hotplug) {
+ if (loading_timeout > 0) {
+ fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+ add_timer(&fw_priv->timeout);
+ }
- kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
- wait_for_completion(&fw_priv->completion);
- set_bit(FW_STATUS_DONE, &fw_priv->status);
-
- del_timer_sync(&fw_priv->timeout);
+ kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+ wait_for_completion(&fw_priv->completion);
+ set_bit(FW_STATUS_DONE, &fw_priv->status);
+ del_timer_sync(&fw_priv->timeout);
+ } else
+ wait_for_completion(&fw_priv->completion);
down(&fw_lock);
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
@@ -455,6 +450,26 @@
}
/**
+ * request_firmware: - request firmware to hotplug and wait for it
+ * Description:
+ * @firmware will be used to return a firmware image by the name
+ * of @name for device @device.
+ *
+ * Should be called from user context where sleeping is allowed.
+ *
+ * @name will be use as $FIRMWARE in the hotplug environment and
+ * should be distinctive enough not to be confused with any other
+ * firmware image for this or any other device.
+ **/
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device)
+{
+ int hotplug = 1;
+ return _request_firmware(firmware_p, name, device, hotplug);
+}
+
+/**
* release_firmware: - release the resource associated with a firmware image
**/
void
@@ -491,6 +506,7 @@
struct device *device;
void *context;
void (*cont)(const struct firmware *fw, void *context);
+ int hotplug;
};
static int
@@ -503,7 +519,8 @@
return 0;
}
daemonize("%s/%s", "firmware", fw_work->name);
- request_firmware(&fw, fw_work->name, fw_work->device);
+ _request_firmware(&fw, fw_work->name, fw_work->device,
+ fw_work->hotplug);
fw_work->cont(fw, fw_work->context);
release_firmware(fw);
module_put(fw_work->module);
@@ -518,6 +535,9 @@
* Asynchronous variant of request_firmware() for contexts where
* it is not possible to sleep.
*
+ * @hotplug invokes hotplug event to copy the firmware image if this flag
+ * is non-zero else the firmware copy must be done manually.
+ *
* @cont will be called asynchronously when the firmware request is over.
*
* @context will be passed over to @cont.
@@ -527,7 +547,7 @@
**/
int
request_firmware_nowait(
- struct module *module,
+ struct module *module, int hotplug,
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context))
{
@@ -548,6 +568,7 @@
.device = device,
.context = context,
.cont = cont,
+ .hotplug = hotplug,
};
ret = kernel_thread(request_firmware_work_func, fw_work,
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 904b27c..16c513a 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -39,13 +39,25 @@
int n;
int nid = dev->id;
struct sysinfo i;
+ struct page_state ps;
unsigned long inactive;
unsigned long active;
unsigned long free;
si_meminfo_node(&i, nid);
+ get_page_state_node(&ps, nid);
__get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
+ /* Check for negative values in these approximate counters */
+ if ((long)ps.nr_dirty < 0)
+ ps.nr_dirty = 0;
+ if ((long)ps.nr_writeback < 0)
+ ps.nr_writeback = 0;
+ if ((long)ps.nr_mapped < 0)
+ ps.nr_mapped = 0;
+ if ((long)ps.nr_slab < 0)
+ ps.nr_slab = 0;
+
n = sprintf(buf, "\n"
"Node %d MemTotal: %8lu kB\n"
"Node %d MemFree: %8lu kB\n"
@@ -55,7 +67,11 @@
"Node %d HighTotal: %8lu kB\n"
"Node %d HighFree: %8lu kB\n"
"Node %d LowTotal: %8lu kB\n"
- "Node %d LowFree: %8lu kB\n",
+ "Node %d LowFree: %8lu kB\n"
+ "Node %d Dirty: %8lu kB\n"
+ "Node %d Writeback: %8lu kB\n"
+ "Node %d Mapped: %8lu kB\n"
+ "Node %d Slab: %8lu kB\n",
nid, K(i.totalram),
nid, K(i.freeram),
nid, K(i.totalram - i.freeram),
@@ -64,7 +80,11 @@
nid, K(i.totalhigh),
nid, K(i.freehigh),
nid, K(i.totalram - i.totalhigh),
- nid, K(i.freeram - i.freehigh));
+ nid, K(i.freeram - i.freehigh),
+ nid, K(ps.nr_dirty),
+ nid, K(ps.nr_writeback),
+ nid, K(ps.nr_mapped),
+ nid, K(ps.nr_slab));
n += hugetlb_report_node_meminfo(nid, buf + n);
return n;
}
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index bdd96b0..0a7aa07 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -26,11 +26,11 @@
down(&dev->sem);
if (dev->power.pm_parent
- && dev->power.pm_parent->power.power_state) {
+ && dev->power.pm_parent->power.power_state.event) {
dev_err(dev, "PM: resume from %d, parent %s still %d\n",
- dev->power.power_state,
+ dev->power.power_state.event,
dev->power.pm_parent->bus_id,
- dev->power.pm_parent->power.power_state);
+ dev->power.pm_parent->power.power_state.event);
}
if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n");
@@ -54,7 +54,7 @@
list_add_tail(entry, &dpm_active);
up(&dpm_list_sem);
- if (!dev->power.prev_state)
+ if (!dev->power.prev_state.event)
resume_device(dev);
down(&dpm_list_sem);
put_device(dev);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 325962d..e8f0519 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -13,10 +13,10 @@
static void runtime_resume(struct device * dev)
{
dev_dbg(dev, "resuming\n");
- if (!dev->power.power_state)
+ if (!dev->power.power_state.event)
return;
if (!resume_device(dev))
- dev->power.power_state = 0;
+ dev->power.power_state = PMSG_ON;
}
@@ -49,10 +49,10 @@
int error = 0;
down(&dpm_sem);
- if (dev->power.power_state == state)
+ if (dev->power.power_state.event == state.event)
goto Done;
- if (dev->power.power_state)
+ if (dev->power.power_state.event)
runtime_resume(dev);
if (!(error = suspend_device(dev, state)))
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 2ccee37..5050176 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -40,22 +40,22 @@
int error = 0;
down(&dev->sem);
- if (dev->power.power_state) {
+ if (dev->power.power_state.event) {
dev_dbg(dev, "PM: suspend %d-->%d\n",
- dev->power.power_state, state);
+ dev->power.power_state.event, state.event);
}
if (dev->power.pm_parent
- && dev->power.pm_parent->power.power_state) {
+ && dev->power.pm_parent->power.power_state.event) {
dev_err(dev,
"PM: suspend %d->%d, parent %s already %d\n",
- dev->power.power_state, state,
+ dev->power.power_state.event, state.event,
dev->power.pm_parent->bus_id,
- dev->power.pm_parent->power.power_state);
+ dev->power.pm_parent->power.power_state.event);
}
dev->power.prev_state = dev->power.power_state;
- if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
+ if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
dev_dbg(dev, "suspending\n");
error = dev->bus->suspend(dev, state);
}
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index f82b3df..8d04fb4 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -26,19 +26,19 @@
static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
{
- return sprintf(buf, "%u\n", dev->power.power_state);
+ return sprintf(buf, "%u\n", dev->power.power_state.event);
}
static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
{
- u32 state;
+ pm_message_t state;
char * rest;
int error = 0;
- state = simple_strtoul(buf, &rest, 10);
+ state.event = simple_strtoul(buf, &rest, 10);
if (*rest)
return -EINVAL;
- if (state)
+ if (state.event)
error = dpm_runtime_suspend(dev, state);
else
dpm_runtime_resume(dev);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 214b964..3431eb6 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -288,6 +288,27 @@
up(&sysdev_drivers_lock);
}
+static void __sysdev_resume(struct sys_device *dev)
+{
+ struct sysdev_class *cls = dev->cls;
+ struct sysdev_driver *drv;
+
+ /* First, call the class-specific one */
+ if (cls->resume)
+ cls->resume(dev);
+
+ /* Call auxillary drivers next. */
+ list_for_each_entry(drv, &cls->drivers, entry) {
+ if (drv->resume)
+ drv->resume(dev);
+ }
+
+ /* Call global drivers. */
+ list_for_each_entry(drv, &sysdev_drivers, entry) {
+ if (drv->resume)
+ drv->resume(dev);
+ }
+}
/**
* sysdev_suspend - Suspend all system devices.
@@ -305,38 +326,93 @@
int sysdev_suspend(pm_message_t state)
{
struct sysdev_class * cls;
+ struct sys_device *sysdev, *err_dev;
+ struct sysdev_driver *drv, *err_drv;
+ int ret;
pr_debug("Suspending System Devices\n");
list_for_each_entry_reverse(cls, &system_subsys.kset.list,
kset.kobj.entry) {
- struct sys_device * sysdev;
pr_debug("Suspending type '%s':\n",
kobject_name(&cls->kset.kobj));
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
- struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
/* Call global drivers first. */
list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->suspend)
- drv->suspend(sysdev, state);
+ if (drv->suspend) {
+ ret = drv->suspend(sysdev, state);
+ if (ret)
+ goto gbl_driver;
+ }
}
/* Call auxillary drivers next. */
list_for_each_entry(drv, &cls->drivers, entry) {
- if (drv->suspend)
- drv->suspend(sysdev, state);
+ if (drv->suspend) {
+ ret = drv->suspend(sysdev, state);
+ if (ret)
+ goto aux_driver;
+ }
}
/* Now call the generic one */
- if (cls->suspend)
- cls->suspend(sysdev, state);
+ if (cls->suspend) {
+ ret = cls->suspend(sysdev, state);
+ if (ret)
+ goto cls_driver;
+ }
}
}
return 0;
+ /* resume current sysdev */
+cls_driver:
+ drv = NULL;
+ printk(KERN_ERR "Class suspend failed for %s\n",
+ kobject_name(&sysdev->kobj));
+
+aux_driver:
+ if (drv)
+ printk(KERN_ERR "Class driver suspend failed for %s\n",
+ kobject_name(&sysdev->kobj));
+ list_for_each_entry(err_drv, &cls->drivers, entry) {
+ if (err_drv == drv)
+ break;
+ if (err_drv->resume)
+ err_drv->resume(sysdev);
+ }
+ drv = NULL;
+
+gbl_driver:
+ if (drv)
+ printk(KERN_ERR "sysdev driver suspend failed for %s\n",
+ kobject_name(&sysdev->kobj));
+ list_for_each_entry(err_drv, &sysdev_drivers, entry) {
+ if (err_drv == drv)
+ break;
+ if (err_drv->resume)
+ err_drv->resume(sysdev);
+ }
+ /* resume other sysdevs in current class */
+ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
+ if (err_dev == sysdev)
+ break;
+ pr_debug(" %s\n", kobject_name(&err_dev->kobj));
+ __sysdev_resume(err_dev);
+ }
+
+ /* resume other classes */
+ list_for_each_entry_continue(cls, &system_subsys.kset.list,
+ kset.kobj.entry) {
+ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
+ pr_debug(" %s\n", kobject_name(&err_dev->kobj));
+ __sysdev_resume(err_dev);
+ }
+ }
+ return ret;
}
@@ -362,25 +438,9 @@
kobject_name(&cls->kset.kobj));
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
- struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* First, call the class-specific one */
- if (cls->resume)
- cls->resume(sysdev);
-
- /* Call auxillary drivers next. */
- list_for_each_entry(drv, &cls->drivers, entry) {
- if (drv->resume)
- drv->resume(sysdev);
- }
-
- /* Call global drivers. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->resume)
- drv->resume(sysdev);
- }
-
+ __sysdev_resume(sysdev);
}
}
return 0;
diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c
index 6c2b447..f25e7c6 100644
--- a/drivers/base/transport_class.c
+++ b/drivers/base/transport_class.c
@@ -7,7 +7,7 @@
* This file is licensed under GPLv2
*
* The basic idea here is to allow any "device controller" (which
- * would most often be a Host Bus Adapter" to use the services of one
+ * would most often be a Host Bus Adapter to use the services of one
* or more tranport classes for performing transport specific
* services. Transport specific services are things that the generic
* command layer doesn't want to know about (speed settings, line
@@ -64,7 +64,9 @@
}
EXPORT_SYMBOL_GPL(transport_class_unregister);
-static int anon_transport_dummy_function(struct device *dev)
+static int anon_transport_dummy_function(struct transport_container *tc,
+ struct device *dev,
+ struct class_device *cdev)
{
/* do nothing */
return 0;
@@ -115,9 +117,10 @@
struct class_device *classdev)
{
struct transport_class *tclass = class_to_transport_class(cont->class);
+ struct transport_container *tcont = attribute_container_to_transport_container(cont);
if (tclass->setup)
- tclass->setup(dev);
+ tclass->setup(tcont, dev, classdev);
return 0;
}
@@ -178,12 +181,14 @@
EXPORT_SYMBOL_GPL(transport_add_device);
static int transport_configure(struct attribute_container *cont,
- struct device *dev)
+ struct device *dev,
+ struct class_device *cdev)
{
struct transport_class *tclass = class_to_transport_class(cont->class);
+ struct transport_container *tcont = attribute_container_to_transport_container(cont);
if (tclass->configure)
- tclass->configure(dev);
+ tclass->configure(tcont, dev, cdev);
return 0;
}
@@ -202,7 +207,7 @@
*/
void transport_configure_device(struct device *dev)
{
- attribute_container_trigger(dev, transport_configure);
+ attribute_container_device_trigger(dev, transport_configure);
}
EXPORT_SYMBOL_GPL(transport_configure_device);
@@ -215,7 +220,7 @@
struct transport_class *tclass = class_to_transport_class(cont->class);
if (tclass->remove)
- tclass->remove(dev);
+ tclass->remove(tcont, dev, classdev);
if (tclass->remove != anon_transport_dummy_function) {
if (tcont->statistics)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index b594768..51b0af1 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -6,7 +6,7 @@
config BLK_DEV_FD
tristate "Normal floppy disk support"
- depends on (!ARCH_S390 && !M68K && !IA64 && !UML && !ARM) || Q40 || (SUN3X && BROKEN) || ARCH_RPC || ARCH_EBSA285
+ depends on ARCH_MAY_HAVE_PC_FDC
---help---
If you want to use the floppy disk drive(s) of your PC under Linux,
say Y. Information about this driver, especially important for IBM
@@ -408,54 +408,12 @@
"real" root file system, etc. See <file:Documentation/initrd.txt>
for details.
-config INITRAMFS_SOURCE
- string "Initramfs source file(s)"
- default ""
- help
- This can be either a single cpio archive with a .cpio suffix or a
- space-separated list of directories and files for building the
- initramfs image. A cpio archive should contain a filesystem archive
- to be used as an initramfs image. Directories should contain a
- filesystem layout to be included in the initramfs image. Files
- should contain entries according to the format described by the
- "usr/gen_init_cpio" program in the kernel tree.
-
- When multiple directories and files are specified then the
- initramfs image will be the aggregate of all of them.
-
- See <file:Documentation/early-userspace/README for more details.
-
- If you are not sure, leave it blank.
-
-config INITRAMFS_ROOT_UID
- int "User ID to map to 0 (user root)"
- depends on INITRAMFS_SOURCE!=""
- default "0"
- help
- This setting is only meaningful if the INITRAMFS_SOURCE is
- contains a directory. Setting this user ID (UID) to something
- other than "0" will cause all files owned by that UID to be
- owned by user root in the initial ramdisk image.
-
- If you are not sure, leave it set to "0".
-
-config INITRAMFS_ROOT_GID
- int "Group ID to map to 0 (group root)"
- depends on INITRAMFS_SOURCE!=""
- default "0"
- help
- This setting is only meaningful if the INITRAMFS_SOURCE is
- contains a directory. Setting this group ID (GID) to something
- other than "0" will cause all files owned by that GID to be
- owned by group root in the initial ramdisk image.
-
- If you are not sure, leave it set to "0".
#XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64
#for instance.
config LBD
bool "Support for Large Block Devices"
- depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || UML
+ depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML
help
Say Y here if you want to attach large (bigger than 2TB) discs to
your machine, or if you want to have a raid or loopback device
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 6e231c5..ded33ba 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -35,7 +35,7 @@
struct aoedev *d;
struct frame *f, *e;
- d = kcalloc(1, sizeof *d, GFP_ATOMIC);
+ d = kzalloc(sizeof *d, GFP_ATOMIC);
if (d == NULL)
return NULL;
f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index cd056e7..30c0903 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -2260,8 +2260,6 @@
if (!atomic_dec_and_test(&cfqd->ref))
return;
- blk_put_queue(q);
-
cfq_shutdown_timer_wq(cfqd);
q->elevator->elevator_data = NULL;
@@ -2318,7 +2316,6 @@
e->elevator_data = cfqd;
cfqd->queue = q;
- atomic_inc(&q->refcnt);
cfqd->max_queued = q->nr_requests / 4;
q->nr_batching = cfq_queued;
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
index 5be6f99..3d4261c 100644
--- a/drivers/block/cryptoloop.c
+++ b/drivers/block/cryptoloop.c
@@ -57,9 +57,11 @@
mode = strsep(&cmsp, "-");
if (mode == NULL || strcmp(mode, "cbc") == 0)
- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC);
+ tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC |
+ CRYPTO_TFM_REQ_MAY_SLEEP);
else if (strcmp(mode, "ecb") == 0)
- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB);
+ tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB |
+ CRYPTO_TFM_REQ_MAY_SLEEP);
if (tfm == NULL)
return -EINVAL;
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index ff5201e..24594c5 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -507,18 +507,12 @@
const int reads = !list_empty(&dd->fifo_list[READ]);
const int writes = !list_empty(&dd->fifo_list[WRITE]);
struct deadline_rq *drq;
- int data_dir, other_dir;
+ int data_dir;
/*
* batches are currently reads XOR writes
*/
- drq = NULL;
-
- if (dd->next_drq[READ])
- drq = dd->next_drq[READ];
-
- if (dd->next_drq[WRITE])
- drq = dd->next_drq[WRITE];
+ drq = dd->next_drq[WRITE] ? : dd->next_drq[READ];
if (drq) {
/* we have a "next request" */
@@ -544,7 +538,6 @@
goto dispatch_writes;
data_dir = READ;
- other_dir = WRITE;
goto dispatch_find_request;
}
@@ -560,7 +553,6 @@
dd->starved = 0;
data_dir = WRITE;
- other_dir = READ;
goto dispatch_find_request;
}
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index f0c1084..888dad5 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -493,6 +493,8 @@
static sector_t floppy_sizes[256];
+static char floppy_device_name[] = "floppy";
+
/*
* The driver is trying to determine the correct media format
* while probing is set. rw_interrupt() clears it after a
@@ -4191,18 +4193,24 @@
static int have_no_fdc = -ENODEV;
+static ssize_t floppy_cmos_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *p;
+ int drive;
+
+ p = container_of(dev, struct platform_device,dev);
+ drive = p->id;
+ return sprintf(buf, "%X\n", UDP->cmos);
+}
+DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
+
static void floppy_device_release(struct device *dev)
{
complete(&device_release);
}
-static struct platform_device floppy_device = {
- .name = "floppy",
- .id = 0,
- .dev = {
- .release = floppy_device_release,
- }
-};
+static struct platform_device floppy_device[N_DRIVE];
static struct kobject *floppy_find(dev_t dev, int *part, void *data)
{
@@ -4370,20 +4378,26 @@
goto out_flush_work;
}
- err = platform_device_register(&floppy_device);
- if (err)
- goto out_flush_work;
-
for (drive = 0; drive < N_DRIVE; drive++) {
if (!(allowed_drive_mask & (1 << drive)))
continue;
if (fdc_state[FDC(drive)].version == FDC_NONE)
continue;
+
+ floppy_device[drive].name = floppy_device_name;
+ floppy_device[drive].id = drive;
+ floppy_device[drive].dev.release = floppy_device_release;
+
+ err = platform_device_register(&floppy_device[drive]);
+ if (err)
+ goto out_flush_work;
+
+ device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
/* to be cleaned up... */
disks[drive]->private_data = (void *)(long)drive;
disks[drive]->queue = floppy_queue;
disks[drive]->flags |= GENHD_FL_REMOVABLE;
- disks[drive]->driverfs_dev = &floppy_device.dev;
+ disks[drive]->driverfs_dev = &floppy_device[drive].dev;
add_disk(disks[drive]);
}
@@ -4603,10 +4617,11 @@
fdc_state[FDC(drive)].version != FDC_NONE) {
del_gendisk(disks[drive]);
unregister_devfs_entries(drive);
+ device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
+ platform_device_unregister(&floppy_device[drive]);
}
put_disk(disks[drive]);
}
- platform_device_unregister(&floppy_device);
devfs_remove("floppy");
del_timer_sync(&fd_timeout);
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 47fd365..d42840c 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -45,7 +45,7 @@
struct blk_major_name *n;
int i, len;
- len = sprintf(p, "\nBlock devices:\n");
+ len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n");
down(&block_subsys_sem);
for (i = 0; i < ARRAY_SIZE(major_names); i++) {
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 3c81854..483d71b 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -235,8 +235,8 @@
* set defaults
*/
q->nr_requests = BLKDEV_MAX_RQ;
- q->max_phys_segments = MAX_PHYS_SEGMENTS;
- q->max_hw_segments = MAX_HW_SEGMENTS;
+ blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+ blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
q->make_request_fn = mfn;
q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
q->backing_dev_info.state = 0;
@@ -284,6 +284,7 @@
rq->special = NULL;
rq->data_len = 0;
rq->data = NULL;
+ rq->nr_phys_segments = 0;
rq->sense = NULL;
rq->end_io = NULL;
rq->end_io_data = NULL;
@@ -2115,7 +2116,7 @@
/**
* blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage
* @q: request queue where request should be inserted
- * @rw: READ or WRITE data
+ * @rq: request structure to fill
* @ubuf: the user buffer
* @len: length of user data
*
@@ -2132,21 +2133,19 @@
* original bio must be passed back in to blk_rq_unmap_user() for proper
* unmapping.
*/
-struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf,
- unsigned int len)
+int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,
+ unsigned int len)
{
unsigned long uaddr;
- struct request *rq;
struct bio *bio;
+ int reading;
if (len > (q->max_sectors << 9))
- return ERR_PTR(-EINVAL);
- if ((!len && ubuf) || (len && !ubuf))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
+ if (!len || !ubuf)
+ return -EINVAL;
- rq = blk_get_request(q, rw, __GFP_WAIT);
- if (!rq)
- return ERR_PTR(-ENOMEM);
+ reading = rq_data_dir(rq) == READ;
/*
* if alignment requirement is satisfied, map in user pages for
@@ -2154,9 +2153,9 @@
*/
uaddr = (unsigned long) ubuf;
if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q)))
- bio = bio_map_user(q, NULL, uaddr, len, rw == READ);
+ bio = bio_map_user(q, NULL, uaddr, len, reading);
else
- bio = bio_copy_user(q, uaddr, len, rw == READ);
+ bio = bio_copy_user(q, uaddr, len, reading);
if (!IS_ERR(bio)) {
rq->bio = rq->biotail = bio;
@@ -2164,28 +2163,70 @@
rq->buffer = rq->data = NULL;
rq->data_len = len;
- return rq;
+ return 0;
}
/*
* bio is the err-ptr
*/
- blk_put_request(rq);
- return (struct request *) bio;
+ return PTR_ERR(bio);
}
EXPORT_SYMBOL(blk_rq_map_user);
/**
+ * blk_rq_map_user_iov - map user data to a request, for REQ_BLOCK_PC usage
+ * @q: request queue where request should be inserted
+ * @rq: request to map data to
+ * @iov: pointer to the iovec
+ * @iov_count: number of elements in the iovec
+ *
+ * Description:
+ * Data will be mapped directly for zero copy io, if possible. Otherwise
+ * a kernel bounce buffer is used.
+ *
+ * A matching blk_rq_unmap_user() must be issued at the end of io, while
+ * still in process context.
+ *
+ * Note: The mapped bio may need to be bounced through blk_queue_bounce()
+ * before being submitted to the device, as pages mapped may be out of
+ * reach. It's the callers responsibility to make sure this happens. The
+ * original bio must be passed back in to blk_rq_unmap_user() for proper
+ * unmapping.
+ */
+int blk_rq_map_user_iov(request_queue_t *q, struct request *rq,
+ struct sg_iovec *iov, int iov_count)
+{
+ struct bio *bio;
+
+ if (!iov || iov_count <= 0)
+ return -EINVAL;
+
+ /* we don't allow misaligned data like bio_map_user() does. If the
+ * user is using sg, they're expected to know the alignment constraints
+ * and respect them accordingly */
+ bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ);
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
+
+ rq->bio = rq->biotail = bio;
+ blk_rq_bio_prep(q, rq, bio);
+ rq->buffer = rq->data = NULL;
+ rq->data_len = bio->bi_size;
+ return 0;
+}
+
+EXPORT_SYMBOL(blk_rq_map_user_iov);
+
+/**
* blk_rq_unmap_user - unmap a request with user data
- * @rq: request to be unmapped
- * @bio: bio for the request
+ * @bio: bio to be unmapped
* @ulen: length of user buffer
*
* Description:
- * Unmap a request previously mapped by blk_rq_map_user().
+ * Unmap a bio previously mapped by blk_rq_map_user().
*/
-int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen)
+int blk_rq_unmap_user(struct bio *bio, unsigned int ulen)
{
int ret = 0;
@@ -2196,31 +2237,89 @@
ret = bio_uncopy_user(bio);
}
- blk_put_request(rq);
- return ret;
+ return 0;
}
EXPORT_SYMBOL(blk_rq_unmap_user);
/**
+ * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage
+ * @q: request queue where request should be inserted
+ * @rq: request to fill
+ * @kbuf: the kernel buffer
+ * @len: length of user data
+ * @gfp_mask: memory allocation flags
+ */
+int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,
+ unsigned int len, unsigned int gfp_mask)
+{
+ struct bio *bio;
+
+ if (len > (q->max_sectors << 9))
+ return -EINVAL;
+ if (!len || !kbuf)
+ return -EINVAL;
+
+ bio = bio_map_kern(q, kbuf, len, gfp_mask);
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
+
+ if (rq_data_dir(rq) == WRITE)
+ bio->bi_rw |= (1 << BIO_RW);
+
+ rq->bio = rq->biotail = bio;
+ blk_rq_bio_prep(q, rq, bio);
+
+ rq->buffer = rq->data = NULL;
+ rq->data_len = len;
+ return 0;
+}
+
+EXPORT_SYMBOL(blk_rq_map_kern);
+
+/**
+ * blk_execute_rq_nowait - insert a request into queue for execution
+ * @q: queue to insert the request in
+ * @bd_disk: matching gendisk
+ * @rq: request to insert
+ * @at_head: insert request at head or tail of queue
+ * @done: I/O completion handler
+ *
+ * Description:
+ * Insert a fully prepared request at the back of the io scheduler queue
+ * for execution. Don't wait for completion.
+ */
+void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk,
+ struct request *rq, int at_head,
+ void (*done)(struct request *))
+{
+ int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
+
+ rq->rq_disk = bd_disk;
+ rq->flags |= REQ_NOMERGE;
+ rq->end_io = done;
+ elv_add_request(q, rq, where, 1);
+ generic_unplug_device(q);
+}
+
+/**
* blk_execute_rq - insert a request into queue for execution
* @q: queue to insert the request in
* @bd_disk: matching gendisk
* @rq: request to insert
+ * @at_head: insert request at head or tail of queue
*
* Description:
* Insert a fully prepared request at the back of the io scheduler queue
- * for execution.
+ * for execution and wait for completion.
*/
int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk,
- struct request *rq)
+ struct request *rq, int at_head)
{
DECLARE_COMPLETION(wait);
char sense[SCSI_SENSE_BUFFERSIZE];
int err = 0;
- rq->rq_disk = bd_disk;
-
/*
* we need an extra reference to the request, so we can look at
* it after io completion
@@ -2233,11 +2332,8 @@
rq->sense_len = 0;
}
- rq->flags |= REQ_NOMERGE;
rq->waiting = &wait;
- rq->end_io = blk_end_sync_rq;
- elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
- generic_unplug_device(q);
+ blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
wait_for_completion(&wait);
rq->waiting = NULL;
@@ -2277,6 +2373,44 @@
EXPORT_SYMBOL(blkdev_issue_flush);
+/**
+ * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices
+ * @q: device queue
+ * @disk: gendisk
+ * @error_sector: error offset
+ *
+ * Description:
+ * Devices understanding the SCSI command set, can use this function as
+ * a helper for issuing a cache flush. Note: driver is required to store
+ * the error offset (in case of error flushing) in ->sector of struct
+ * request.
+ */
+int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
+ sector_t *error_sector)
+{
+ struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ int ret;
+
+ rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+ rq->sector = 0;
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+ rq->cmd[0] = 0x35;
+ rq->cmd_len = 12;
+ rq->data = NULL;
+ rq->data_len = 0;
+ rq->timeout = 60 * HZ;
+
+ ret = blk_execute_rq(q, disk, rq, 0);
+
+ if (ret && error_sector)
+ *error_sector = rq->sector;
+
+ blk_put_request(rq);
+ return ret;
+}
+
+EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn);
+
static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
{
int rw = rq_data_dir(rq);
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
index 681871c..abb2df2 100644
--- a/drivers/block/scsi_ioctl.c
+++ b/drivers/block/scsi_ioctl.c
@@ -216,7 +216,7 @@
struct gendisk *bd_disk, struct sg_io_hdr *hdr)
{
unsigned long start_time;
- int reading, writing;
+ int writing = 0, ret = 0;
struct request *rq;
struct bio *bio;
char sense[SCSI_SENSE_BUFFERSIZE];
@@ -231,38 +231,48 @@
if (verify_command(file, cmd))
return -EPERM;
- /*
- * we'll do that later
- */
- if (hdr->iovec_count)
- return -EOPNOTSUPP;
-
if (hdr->dxfer_len > (q->max_sectors << 9))
return -EIO;
- reading = writing = 0;
- if (hdr->dxfer_len) {
+ if (hdr->dxfer_len)
switch (hdr->dxfer_direction) {
default:
return -EINVAL;
case SG_DXFER_TO_FROM_DEV:
- reading = 1;
- /* fall through */
case SG_DXFER_TO_DEV:
writing = 1;
break;
case SG_DXFER_FROM_DEV:
- reading = 1;
break;
}
- rq = blk_rq_map_user(q, writing ? WRITE : READ, hdr->dxferp,
- hdr->dxfer_len);
+ rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
+ if (!rq)
+ return -ENOMEM;
- if (IS_ERR(rq))
- return PTR_ERR(rq);
- } else
- rq = blk_get_request(q, READ, __GFP_WAIT);
+ if (hdr->iovec_count) {
+ const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
+ struct sg_iovec *iov;
+
+ iov = kmalloc(size, GFP_KERNEL);
+ if (!iov) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(iov, hdr->dxferp, size)) {
+ kfree(iov);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count);
+ kfree(iov);
+ } else if (hdr->dxfer_len)
+ ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len);
+
+ if (ret)
+ goto out;
/*
* fill in request structure
@@ -298,7 +308,7 @@
* (if he doesn't check that is his problem).
* N.B. a non-zero SCSI status is _not_ necessarily an error.
*/
- blk_execute_rq(q, bd_disk, rq);
+ blk_execute_rq(q, bd_disk, rq, 0);
/* write to all output members */
hdr->status = 0xff & rq->errors;
@@ -320,12 +330,14 @@
hdr->sb_len_wr = len;
}
- if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len))
- return -EFAULT;
+ if (blk_rq_unmap_user(bio, hdr->dxfer_len))
+ ret = -EFAULT;
/* may not have succeeded, but output values written to control
* structure (struct sg_io_hdr). */
- return 0;
+out:
+ blk_put_request(rq);
+ return ret;
}
#define OMAX_SB_LEN 16 /* For backward compatibility */
@@ -408,7 +420,7 @@
rq->data_len = bytes;
rq->flags |= REQ_BLOCK_PC;
- blk_execute_rq(q, bd_disk, rq);
+ blk_execute_rq(q, bd_disk, rq, 0);
err = rq->errors & 0xff; /* only 8 bit SCSI status */
if (err) {
if (rq->sense_len && rq->sense) {
@@ -561,7 +573,7 @@
rq->cmd[0] = GPCMD_START_STOP_UNIT;
rq->cmd[4] = 0x02 + (close != 0);
rq->cmd_len = 6;
- err = blk_execute_rq(q, bd_disk, rq);
+ err = blk_execute_rq(q, bd_disk, rq, 0);
blk_put_request(rq);
break;
default:
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index beaa561..1539603 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2097,6 +2097,10 @@
if (!q)
return -ENXIO;
+ rq = blk_get_request(q, READ, GFP_KERNEL);
+ if (!rq)
+ return -ENOMEM;
+
cdi->last_sense = 0;
while (nframes) {
@@ -2108,9 +2112,9 @@
len = nr * CD_FRAMESIZE_RAW;
- rq = blk_rq_map_user(q, READ, ubuf, len);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
+ ret = blk_rq_map_user(q, rq, ubuf, len);
+ if (ret)
+ break;
memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = GPCMD_READ_CD;
@@ -2132,13 +2136,13 @@
if (rq->bio)
blk_queue_bounce(q, &rq->bio);
- if (blk_execute_rq(q, cdi->disk, rq)) {
+ if (blk_execute_rq(q, cdi->disk, rq, 0)) {
struct request_sense *s = rq->sense;
ret = -EIO;
cdi->last_sense = s->sense_key;
}
- if (blk_rq_unmap_user(rq, bio, len))
+ if (blk_rq_unmap_user(bio, len))
ret = -EFAULT;
if (ret)
@@ -2149,6 +2153,7 @@
ubuf += len;
}
+ blk_put_request(rq);
return ret;
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7333b41..2bc9d64 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -138,7 +138,7 @@
config DIGIEPCA
tristate "Digiboard Intelligent Async Support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN)
+ depends on SERIAL_NONSTANDARD
---help---
This is a driver for Digi International's Xx, Xeve, and Xem series
of cards which provide multiple serial ports. You would need
@@ -735,7 +735,7 @@
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32
+ depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -842,8 +842,7 @@
config TANBAC_TB0219
tristate "TANBAC TB0219 base board support"
- depends TANBAC_TB0229
-
+ depends TANBAC_TB022X
menu "Ftape, the floppy tape device driver"
diff --git a/drivers/char/digi1.h b/drivers/char/digi1.h
index 184378d..94d4eab 100644
--- a/drivers/char/digi1.h
+++ b/drivers/char/digi1.h
@@ -1,46 +1,46 @@
/* Definitions for DigiBoard ditty(1) command. */
#if !defined(TIOCMODG)
-#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
-#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
+#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
#endif
#if !defined(TIOCMSET)
-#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
-#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
+#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
#endif
#if !defined(TIOCMBIC)
-#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
-#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
+#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
#endif
#if !defined(TIOCSDTR)
-#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
-#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
+#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
#endif
/************************************************************************
* Ioctl command arguments for DIGI parameters.
************************************************************************/
-#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+#define DIGI_GETA (('e'<<8) | 94) /* Read params */
-#define DIGI_SETA ('e'<<8) | 95 /* Set params */
-#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
-#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+#define DIGI_SETA (('e'<<8) | 95) /* Set params */
+#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
+#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
-#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
/* control characters */
-#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
/* control characters */
-#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
/* flow control chars */
-#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
/* flow control chars */
-#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */
-#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */
-#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */
+#define DIGI_GETINFO (('e'<<8) | 103) /* Fill in digi_info */
+#define DIGI_POLLER (('e'<<8) | 104) /* Turn on/off poller */
+#define DIGI_INIT (('e'<<8) | 105) /* Allow things to run. */
struct digiflow_struct
{
diff --git a/drivers/char/digiFep1.h b/drivers/char/digiFep1.h
index c47d7fc..3c1f192 100644
--- a/drivers/char/digiFep1.h
+++ b/drivers/char/digiFep1.h
@@ -13,88 +13,88 @@
struct global_data
{
- volatile ushort cin;
- volatile ushort cout;
- volatile ushort cstart;
- volatile ushort cmax;
- volatile ushort ein;
- volatile ushort eout;
- volatile ushort istart;
- volatile ushort imax;
+ u16 cin;
+ u16 cout;
+ u16 cstart;
+ u16 cmax;
+ u16 ein;
+ u16 eout;
+ u16 istart;
+ u16 imax;
};
struct board_chan
{
- int filler1;
- int filler2;
- volatile ushort tseg;
- volatile ushort tin;
- volatile ushort tout;
- volatile ushort tmax;
-
- volatile ushort rseg;
- volatile ushort rin;
- volatile ushort rout;
- volatile ushort rmax;
-
- volatile ushort tlow;
- volatile ushort rlow;
- volatile ushort rhigh;
- volatile ushort incr;
-
- volatile ushort etime;
- volatile ushort edelay;
- volatile unchar *dev;
-
- volatile ushort iflag;
- volatile ushort oflag;
- volatile ushort cflag;
- volatile ushort gmask;
-
- volatile ushort col;
- volatile ushort delay;
- volatile ushort imask;
- volatile ushort tflush;
+ u32 filler1;
+ u32 filler2;
+ u16 tseg;
+ u16 tin;
+ u16 tout;
+ u16 tmax;
- int filler3;
- int filler4;
- int filler5;
- int filler6;
-
- volatile unchar num;
- volatile unchar ract;
- volatile unchar bstat;
- volatile unchar tbusy;
- volatile unchar iempty;
- volatile unchar ilow;
- volatile unchar idata;
- volatile unchar eflag;
-
- volatile unchar tflag;
- volatile unchar rflag;
- volatile unchar xmask;
- volatile unchar xval;
- volatile unchar mstat;
- volatile unchar mchange;
- volatile unchar mint;
- volatile unchar lstat;
+ u16 rseg;
+ u16 rin;
+ u16 rout;
+ u16 rmax;
- volatile unchar mtran;
- volatile unchar orun;
- volatile unchar startca;
- volatile unchar stopca;
- volatile unchar startc;
- volatile unchar stopc;
- volatile unchar vnext;
- volatile unchar hflow;
+ u16 tlow;
+ u16 rlow;
+ u16 rhigh;
+ u16 incr;
- volatile unchar fillc;
- volatile unchar ochar;
- volatile unchar omask;
+ u16 etime;
+ u16 edelay;
+ unchar *dev;
- unchar filler7;
- unchar filler8[28];
+ u16 iflag;
+ u16 oflag;
+ u16 cflag;
+ u16 gmask;
+
+ u16 col;
+ u16 delay;
+ u16 imask;
+ u16 tflush;
+
+ u32 filler3;
+ u32 filler4;
+ u32 filler5;
+ u32 filler6;
+
+ u8 num;
+ u8 ract;
+ u8 bstat;
+ u8 tbusy;
+ u8 iempty;
+ u8 ilow;
+ u8 idata;
+ u8 eflag;
+
+ u8 tflag;
+ u8 rflag;
+ u8 xmask;
+ u8 xval;
+ u8 mstat;
+ u8 mchange;
+ u8 mint;
+ u8 lstat;
+
+ u8 mtran;
+ u8 orun;
+ u8 startca;
+ u8 stopca;
+ u8 startc;
+ u8 stopc;
+ u8 vnext;
+ u8 hflow;
+
+ u8 fillc;
+ u8 ochar;
+ u8 omask;
+
+ u8 filler7;
+ u8 filler8[28];
};
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index e0743eb..f28e70a 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -48,8 +48,8 @@
}
EXPORT_SYMBOL(drm_get_resource_len);
-static drm_local_map_t *drm_find_matching_map(drm_device_t *dev,
- drm_local_map_t *map)
+static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
+ drm_local_map_t *map)
{
struct list_head *list;
@@ -57,7 +57,7 @@
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
if (entry->map && map->type == entry->map->type &&
entry->map->offset == map->offset) {
- return entry->map;
+ return entry;
}
}
@@ -114,14 +114,13 @@
* type. Adds the map to the map list drm_device::maplist. Adds MTRR's where
* applicable and if supported by the kernel.
*/
-int drm_addmap(drm_device_t * dev, unsigned int offset,
- unsigned int size, drm_map_type_t type,
- drm_map_flags_t flags, drm_local_map_t ** map_ptr)
+int drm_addmap_core(drm_device_t * dev, unsigned int offset,
+ unsigned int size, drm_map_type_t type,
+ drm_map_flags_t flags, drm_map_list_t **maplist)
{
drm_map_t *map;
drm_map_list_t *list;
drm_dma_handle_t *dmah;
- drm_local_map_t *found_map;
map = drm_alloc( sizeof(*map), DRM_MEM_MAPS );
if ( !map )
@@ -166,17 +165,17 @@
* needing to be aware of it. Therefore, we just return success
* when the server tries to create a duplicate map.
*/
- found_map = drm_find_matching_map(dev, map);
- if (found_map != NULL) {
- if (found_map->size != map->size) {
+ list = drm_find_matching_map(dev, map);
+ if (list != NULL) {
+ if (list->map->size != map->size) {
DRM_DEBUG("Matching maps of type %d with "
"mismatched sizes, (%ld vs %ld)\n",
- map->type, map->size, found_map->size);
- found_map->size = map->size;
+ map->type, map->size, list->map->size);
+ list->map->size = map->size;
}
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- *map_ptr = found_map;
+ *maplist = list;
return 0;
}
@@ -264,9 +263,22 @@
: map->offset, dev);
up(&dev->struct_sem);
- *map_ptr = map;
+ *maplist = list;
return 0;
}
+
+int drm_addmap(drm_device_t *dev, unsigned int offset,
+ unsigned int size, drm_map_type_t type,
+ drm_map_flags_t flags, drm_local_map_t **map_ptr)
+{
+ drm_map_list_t *list;
+ int rc;
+
+ rc = drm_addmap_core(dev, offset, size, type, flags, &list);
+ if (!rc)
+ *map_ptr = list->map;
+ return rc;
+}
EXPORT_SYMBOL(drm_addmap);
int drm_addmap_ioctl(struct inode *inode, struct file *filp,
@@ -275,10 +287,9 @@
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
drm_map_t map;
- drm_map_t *map_ptr;
+ drm_map_list_t *maplist;
drm_map_t __user *argp = (void __user *)arg;
int err;
- unsigned long handle = 0;
if (!(filp->f_mode & 3))
return -EACCES; /* Require read/write */
@@ -287,26 +298,15 @@
return -EFAULT;
}
- err = drm_addmap(dev, map.offset, map.size, map.type, map.flags,
- &map_ptr);
+ err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags,
+ &maplist);
- if (err) {
+ if (err)
return err;
- }
- {
- drm_map_list_t *_entry;
- list_for_each_entry(_entry, &dev->maplist->head, head) {
- if (_entry->map == map_ptr)
- handle = _entry->user_token;
- }
- if (!handle)
- return -EFAULT;
- }
-
- if (copy_to_user(argp, map_ptr, sizeof(*map_ptr)))
+ if (copy_to_user(argp, maplist->map, sizeof(drm_map_t)))
return -EFAULT;
- if (put_user(handle, &argp->handle))
+ if (put_user(maplist->user_token, &argp->handle))
return -EFAULT;
return 0;
}
@@ -1041,7 +1041,7 @@
return 0;
}
-int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request)
+static int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request)
{
drm_device_dma_t *dma = dev->dma;
drm_buf_entry_t *entry;
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index f515567..5028927 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -308,7 +308,7 @@
*
* Attempt to set drm_device::context_flag.
*/
-int drm_context_switch( drm_device_t *dev, int old, int new )
+static int drm_context_switch( drm_device_t *dev, int old, int new )
{
if ( test_and_set_bit( 0, &dev->context_flag ) ) {
DRM_ERROR( "Reentering -- FIXME\n" );
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 2fc10c4..475cc5e 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include "drm_core.h"
+#include "drmP.h"
struct drm_sysfs_class {
struct class_device_attribute attr;
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
index 567b425..fc7d4a5 100644
--- a/drivers/char/drm/mga_dma.c
+++ b/drivers/char/drm/mga_dma.c
@@ -417,6 +417,7 @@
return 0;
}
+#if __OS_HAS_AGP
/**
* Bootstrap the driver for AGP DMA.
*
@@ -560,6 +561,13 @@
DRM_INFO("Initialized card for AGP DMA.\n");
return 0;
}
+#else
+static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
+ drm_mga_dma_bootstrap_t * dma_bs)
+{
+ return -EINVAL;
+}
+#endif
/**
* Bootstrap the driver for PCI DMA.
@@ -697,7 +705,6 @@
* carve off portions of it for internal uses. The remaining memory
* is returned to user-mode to be used for AGP textures.
*/
-
if (is_agp) {
err = mga_do_agp_dma_bootstrap(dev, dma_bs);
}
@@ -932,6 +939,7 @@
drm_core_ioremapfree(dev->agp_buffer_map, dev);
if (dev_priv->used_new_dma_init) {
+#if __OS_HAS_AGP
if (dev_priv->agp_mem != NULL) {
dev_priv->agp_textures = NULL;
drm_unbind_agp(dev_priv->agp_mem);
@@ -944,7 +952,7 @@
if ((dev->agp != NULL) && dev->agp->acquired) {
err = drm_agp_release(dev);
}
-
+#endif
dev_priv->used_new_dma_init = 0;
}
@@ -965,7 +973,7 @@
}
}
- return 0;
+ return err;
}
int mga_dma_init( DRM_IOCTL_ARGS )
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 6025e18..58d3738 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -6,6 +6,8 @@
For technical support please email digiLinux@dgii.com or
call Digi tech support at (612) 912-3456
+ ** This driver is no longer supported by Digi **
+
Much of this design and code came from epca.c which was
copyright (C) 1994, 1995 Troy De Jongh, and subsquently
modified by David Nugent, Christoph Lameter, Mike McLagan.
@@ -43,31 +45,19 @@
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif /* CONFIG_PCI */
-
-#define putUser(arg1, arg2) put_user(arg1, (unsigned long __user *)arg2)
-#define getUser(arg1, arg2) get_user(arg1, (unsigned __user *)arg2)
-
-#ifdef ENABLE_PCI
+#include <linux/spinlock.h>
#include <linux/pci.h>
#include "digiPCI.h"
-#endif /* ENABLE_PCI */
+
#include "digi1.h"
#include "digiFep1.h"
#include "epca.h"
#include "epcaconfig.h"
-#if BITS_PER_LONG != 32
-# error FIXME: this driver only works on 32-bit platforms
-#endif
-
/* ---------------------- Begin defines ------------------------ */
-#define VERSION "1.3.0.1-LK"
+#define VERSION "1.3.0.1-LK2.6"
/* This major needs to be submitted to Linux to join the majors list */
@@ -81,13 +71,17 @@
/* ----------------- Begin global definitions ------------------- */
-static char mesg[100];
static int nbdevs, num_cards, liloconfig;
static int digi_poller_inhibited = 1 ;
static int setup_error_code;
static int invalid_lilo_config;
+/* The ISA boards do window flipping into the same spaces so its only sane
+ with a single lock. It's still pretty efficient */
+
+static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED;
+
/* -----------------------------------------------------------------------
MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
7 below.
@@ -129,58 +123,58 @@
configured.
----------------------------------------------------------------------- */
-static inline void memwinon(struct board_info *b, unsigned int win);
-static inline void memwinoff(struct board_info *b, unsigned int win);
-static inline void globalwinon(struct channel *ch);
-static inline void rxwinon(struct channel *ch);
-static inline void txwinon(struct channel *ch);
-static inline void memoff(struct channel *ch);
-static inline void assertgwinon(struct channel *ch);
-static inline void assertmemoff(struct channel *ch);
+static void memwinon(struct board_info *b, unsigned int win);
+static void memwinoff(struct board_info *b, unsigned int win);
+static void globalwinon(struct channel *ch);
+static void rxwinon(struct channel *ch);
+static void txwinon(struct channel *ch);
+static void memoff(struct channel *ch);
+static void assertgwinon(struct channel *ch);
+static void assertmemoff(struct channel *ch);
/* ---- Begin more 'specific' memory functions for cx_like products --- */
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxem_globalwinon(struct channel *ch);
-static inline void pcxem_rxwinon(struct channel *ch);
-static inline void pcxem_txwinon(struct channel *ch);
-static inline void pcxem_memoff(struct channel *ch);
+static void pcxem_memwinon(struct board_info *b, unsigned int win);
+static void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static void pcxem_globalwinon(struct channel *ch);
+static void pcxem_rxwinon(struct channel *ch);
+static void pcxem_txwinon(struct channel *ch);
+static void pcxem_memoff(struct channel *ch);
/* ------ Begin more 'specific' memory functions for the pcxe ------- */
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxe_globalwinon(struct channel *ch);
-static inline void pcxe_rxwinon(struct channel *ch);
-static inline void pcxe_txwinon(struct channel *ch);
-static inline void pcxe_memoff(struct channel *ch);
+static void pcxe_memwinon(struct board_info *b, unsigned int win);
+static void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static void pcxe_globalwinon(struct channel *ch);
+static void pcxe_rxwinon(struct channel *ch);
+static void pcxe_txwinon(struct channel *ch);
+static void pcxe_memoff(struct channel *ch);
/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
/* Note : pc64xe and pcxi share the same windowing routines */
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxi_globalwinon(struct channel *ch);
-static inline void pcxi_rxwinon(struct channel *ch);
-static inline void pcxi_txwinon(struct channel *ch);
-static inline void pcxi_memoff(struct channel *ch);
+static void pcxi_memwinon(struct board_info *b, unsigned int win);
+static void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static void pcxi_globalwinon(struct channel *ch);
+static void pcxi_rxwinon(struct channel *ch);
+static void pcxi_txwinon(struct channel *ch);
+static void pcxi_memoff(struct channel *ch);
/* - Begin 'specific' do nothing memory functions needed for some cards - */
-static inline void dummy_memwinon(struct board_info *b, unsigned int win);
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
-static inline void dummy_globalwinon(struct channel *ch);
-static inline void dummy_rxwinon(struct channel *ch);
-static inline void dummy_txwinon(struct channel *ch);
-static inline void dummy_memoff(struct channel *ch);
-static inline void dummy_assertgwinon(struct channel *ch);
-static inline void dummy_assertmemoff(struct channel *ch);
+static void dummy_memwinon(struct board_info *b, unsigned int win);
+static void dummy_memwinoff(struct board_info *b, unsigned int win);
+static void dummy_globalwinon(struct channel *ch);
+static void dummy_rxwinon(struct channel *ch);
+static void dummy_txwinon(struct channel *ch);
+static void dummy_memoff(struct channel *ch);
+static void dummy_assertgwinon(struct channel *ch);
+static void dummy_assertmemoff(struct channel *ch);
/* ------------------- Begin declare functions ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *);
-static inline void pc_sched_event(struct channel *, int);
+static struct channel *verifyChannel(struct tty_struct *);
+static void pc_sched_event(struct channel *, int);
static void epca_error(int, char *);
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
@@ -215,15 +209,11 @@
static void digi_send_break(struct channel *ch, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
void epca_setup(char *, int *);
-void console_print(const char *);
static int get_termio(struct tty_struct *, struct termio __user *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
-int pc_init(void);
-
-#ifdef ENABLE_PCI
+static int pc_init(void);
static int init_PCI(void);
-#endif /* ENABLE_PCI */
/* ------------------------------------------------------------------
@@ -237,41 +227,41 @@
making direct calls deserves what they get.
-------------------------------------------------------------------- */
-static inline void memwinon(struct board_info *b, unsigned int win)
+static void memwinon(struct board_info *b, unsigned int win)
{
(b->memwinon)(b, win);
}
-static inline void memwinoff(struct board_info *b, unsigned int win)
+static void memwinoff(struct board_info *b, unsigned int win)
{
(b->memwinoff)(b, win);
}
-static inline void globalwinon(struct channel *ch)
+static void globalwinon(struct channel *ch)
{
(ch->board->globalwinon)(ch);
}
-static inline void rxwinon(struct channel *ch)
+static void rxwinon(struct channel *ch)
{
(ch->board->rxwinon)(ch);
}
-static inline void txwinon(struct channel *ch)
+static void txwinon(struct channel *ch)
{
(ch->board->txwinon)(ch);
}
-static inline void memoff(struct channel *ch)
+static void memoff(struct channel *ch)
{
(ch->board->memoff)(ch);
}
-static inline void assertgwinon(struct channel *ch)
+static void assertgwinon(struct channel *ch)
{
(ch->board->assertgwinon)(ch);
}
-static inline void assertmemoff(struct channel *ch)
+static void assertmemoff(struct channel *ch)
{
(ch->board->assertmemoff)(ch);
}
@@ -281,66 +271,66 @@
and CX series cards.
------------------------------------------------------------ */
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN|win, (int)b->port + 1);
+ outb_p(FEPWIN|win, b->port + 1);
}
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+static void pcxem_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(0, (int)b->port + 1);
+ outb_p(0, b->port + 1);
}
-static inline void pcxem_globalwinon(struct channel *ch)
+static void pcxem_globalwinon(struct channel *ch)
{
outb_p( FEPWIN, (int)ch->board->port + 1);
}
-static inline void pcxem_rxwinon(struct channel *ch)
+static void pcxem_rxwinon(struct channel *ch)
{
outb_p(ch->rxwin, (int)ch->board->port + 1);
}
-static inline void pcxem_txwinon(struct channel *ch)
+static void pcxem_txwinon(struct channel *ch)
{
outb_p(ch->txwin, (int)ch->board->port + 1);
}
-static inline void pcxem_memoff(struct channel *ch)
+static void pcxem_memoff(struct channel *ch)
{
outb_p(0, (int)ch->board->port + 1);
}
/* ----------------- Begin pcxe memory window stuff ------------------ */
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+static void pcxe_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN | win, (int)b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+static void pcxe_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) & ~FEPMEM,
- (int)b->port + 1);
- outb_p(0, (int)b->port + 1);
+ outb_p(inb(b->port) & ~FEPMEM,
+ b->port + 1);
+ outb_p(0, b->port + 1);
}
-static inline void pcxe_globalwinon(struct channel *ch)
+static void pcxe_globalwinon(struct channel *ch)
{
outb_p( FEPWIN, (int)ch->board->port + 1);
}
-static inline void pcxe_rxwinon(struct channel *ch)
+static void pcxe_rxwinon(struct channel *ch)
{
outb_p(ch->rxwin, (int)ch->board->port + 1);
}
-static inline void pcxe_txwinon(struct channel *ch)
+static void pcxe_txwinon(struct channel *ch)
{
outb_p(ch->txwin, (int)ch->board->port + 1);
}
-static inline void pcxe_memoff(struct channel *ch)
+static void pcxe_memoff(struct channel *ch)
{
outb_p(0, (int)ch->board->port);
outb_p(0, (int)ch->board->port + 1);
@@ -348,44 +338,44 @@
/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+static void pcxi_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+ outb_p(inb(b->port) | FEPMEM, b->port);
}
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+static void pcxi_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+ outb_p(inb(b->port) & ~FEPMEM, b->port);
}
-static inline void pcxi_globalwinon(struct channel *ch)
+static void pcxi_globalwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_rxwinon(struct channel *ch)
+static void pcxi_rxwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_txwinon(struct channel *ch)
+static void pcxi_txwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_memoff(struct channel *ch)
+static void pcxi_memoff(struct channel *ch)
{
- outb_p(0, (int)ch->board->port);
+ outb_p(0, ch->board->port);
}
-static inline void pcxi_assertgwinon(struct channel *ch)
+static void pcxi_assertgwinon(struct channel *ch)
{
- epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+ epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
}
-static inline void pcxi_assertmemoff(struct channel *ch)
+static void pcxi_assertmemoff(struct channel *ch)
{
- epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+ epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
}
@@ -398,185 +388,143 @@
may or may not do anything.
---------------------------------------------------------------------------*/
-static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+static void dummy_memwinon(struct board_info *b, unsigned int win)
{
}
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+static void dummy_memwinoff(struct board_info *b, unsigned int win)
{
}
-static inline void dummy_globalwinon(struct channel *ch)
+static void dummy_globalwinon(struct channel *ch)
{
}
-static inline void dummy_rxwinon(struct channel *ch)
+static void dummy_rxwinon(struct channel *ch)
{
}
-static inline void dummy_txwinon(struct channel *ch)
+static void dummy_txwinon(struct channel *ch)
{
}
-static inline void dummy_memoff(struct channel *ch)
+static void dummy_memoff(struct channel *ch)
{
}
-static inline void dummy_assertgwinon(struct channel *ch)
+static void dummy_assertgwinon(struct channel *ch)
{
}
-static inline void dummy_assertmemoff(struct channel *ch)
+static void dummy_assertmemoff(struct channel *ch)
{
}
/* ----------------- Begin verifyChannel function ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *tty)
+static struct channel *verifyChannel(struct tty_struct *tty)
{ /* Begin verifyChannel */
-
/* --------------------------------------------------------------------
This routine basically provides a sanity check. It insures that
the channel returned is within the proper range of addresses as
well as properly initialized. If some bogus info gets passed in
through tty->driver_data this should catch it.
- --------------------------------------------------------------------- */
-
- if (tty)
- { /* Begin if tty */
-
- register struct channel *ch = (struct channel *)tty->driver_data;
-
- if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs]))
- {
+ --------------------------------------------------------------------- */
+ if (tty) {
+ struct channel *ch = (struct channel *)tty->driver_data;
+ if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
if (ch->magic == EPCA_MAGIC)
return ch;
}
-
- } /* End if tty */
-
- /* Else return a NULL for invalid */
+ }
return NULL;
} /* End verifyChannel */
/* ------------------ Begin pc_sched_event ------------------------- */
-static inline void pc_sched_event(struct channel *ch, int event)
-{ /* Begin pc_sched_event */
-
-
+static void pc_sched_event(struct channel *ch, int event)
+{
/* ----------------------------------------------------------------------
We call this to schedule interrupt processing on some event. The
kernel sees our request and calls the related routine in OUR driver.
-------------------------------------------------------------------------*/
-
ch->event |= 1 << event;
schedule_work(&ch->tqueue);
-
-
} /* End pc_sched_event */
/* ------------------ Begin epca_error ------------------------- */
static void epca_error(int line, char *msg)
-{ /* Begin epca_error */
-
+{
printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
- return;
-
-} /* End epca_error */
+}
/* ------------------ Begin pc_close ------------------------- */
static void pc_close(struct tty_struct * tty, struct file * filp)
-{ /* Begin pc_close */
-
+{
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if ch != NULL */
-
- save_flags(flags);
- cli();
-
- if (tty_hung_up_p(filp))
- {
- restore_flags(flags);
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
+ spin_lock_irqsave(&epca_lock, flags);
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&epca_lock, flags);
return;
}
-
/* Check to see if the channel is open more than once */
- if (ch->count-- > 1)
- { /* Begin channel is open more than once */
-
+ if (ch->count-- > 1) {
+ /* Begin channel is open more than once */
/* -------------------------------------------------------------
Return without doing anything. Someone might still be using
the channel.
---------------------------------------------------------------- */
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
return;
} /* End channel is open more than once */
/* Port open only once go ahead with shutdown & reset */
-
- if (ch->count < 0)
- {
- ch->count = 0;
- }
+ if (ch->count < 0)
+ BUG();
/* ---------------------------------------------------------------
Let the rest of the driver know the channel is being closed.
This becomes important if an open is attempted before close
is finished.
------------------------------------------------------------------ */
-
ch->asyncflags |= ASYNC_CLOSING;
-
tty->closing = 1;
- if (ch->asyncflags & ASYNC_INITIALIZED)
- {
+ spin_unlock_irqrestore(&epca_lock, flags);
+
+ if (ch->asyncflags & ASYNC_INITIALIZED) {
/* Setup an event to indicate when the transmit buffer empties */
setup_empty_event(tty, ch);
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
}
-
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
+
+ spin_lock_irqsave(&epca_lock, flags);
tty->closing = 0;
ch->event = 0;
ch->tty = NULL;
+ spin_unlock_irqrestore(&epca_lock, flags);
- if (ch->blocked_open)
- { /* Begin if blocked_open */
-
+ if (ch->blocked_open) { /* Begin if blocked_open */
if (ch->close_delay)
- {
msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
-
wake_up_interruptible(&ch->open_wait);
-
} /* End if blocked_open */
-
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
-
-
- restore_flags(flags);
-
} /* End if ch != NULL */
-
} /* End pc_close */
/* ------------------ Begin shutdown ------------------------- */
@@ -586,15 +534,14 @@
unsigned long flags;
struct tty_struct *tty;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
- save_flags(flags);
- cli();
- globalwinon(ch);
+ spin_lock_irqsave(&epca_lock, flags);
+ globalwinon(ch);
bc = ch->brdchan;
/* ------------------------------------------------------------------
@@ -604,20 +551,17 @@
--------------------------------------------------------------------- */
if (bc)
- bc->idata = 0;
-
+ writeb(0, &bc->idata);
tty = ch->tty;
/* ----------------------------------------------------------------
If we're a modem control device and HUPCL is on, drop RTS & DTR.
------------------------------------------------------------------ */
- if (tty->termios->c_cflag & HUPCL)
- {
+ if (tty->termios->c_cflag & HUPCL) {
ch->omodem &= ~(ch->m_rts | ch->m_dtr);
fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
}
-
memoff(ch);
/* ------------------------------------------------------------------
@@ -628,7 +572,7 @@
/* Prevent future Digi programmed interrupts from coming active */
ch->asyncflags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End shutdown */
@@ -636,7 +580,6 @@
static void pc_hangup(struct tty_struct *tty)
{ /* Begin pc_hangup */
-
struct channel *ch;
/* ---------------------------------------------------------
@@ -644,25 +587,21 @@
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if ch != NULL */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
unsigned long flags;
- save_flags(flags);
- cli();
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
+ spin_lock_irqsave(&epca_lock, flags);
ch->tty = NULL;
ch->event = 0;
ch->count = 0;
- restore_flags(flags);
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
+ spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&ch->open_wait);
-
} /* End if ch != NULL */
} /* End pc_hangup */
@@ -672,18 +611,14 @@
static int pc_write(struct tty_struct * tty,
const unsigned char *buf, int bytesAvailable)
{ /* Begin pc_write */
-
- register unsigned int head, tail;
- register int dataLen;
- register int size;
- register int amountCopied;
-
-
+ unsigned int head, tail;
+ int dataLen;
+ int size;
+ int amountCopied;
struct channel *ch;
unsigned long flags;
int remain;
- volatile struct board_chan *bc;
-
+ struct board_chan *bc;
/* ----------------------------------------------------------------
pc_write is primarily called directly by the kernel routine
@@ -706,24 +641,20 @@
bc = ch->brdchan;
size = ch->txbufsize;
-
amountCopied = 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- head = bc->tin & (size - 1);
- tail = bc->tout;
+ head = readw(&bc->tin) & (size - 1);
+ tail = readw(&bc->tout);
- if (tail != bc->tout)
- tail = bc->tout;
+ if (tail != readw(&bc->tout))
+ tail = readw(&bc->tout);
tail &= (size - 1);
/* If head >= tail, head has not wrapped around. */
- if (head >= tail)
- { /* Begin head has not wrapped */
-
+ if (head >= tail) { /* Begin head has not wrapped */
/* ---------------------------------------------------------------
remain (much like dataLen above) represents the total amount of
space available on the card for data. Here dataLen represents
@@ -731,26 +662,19 @@
buffer. This is important because a memcpy cannot be told to
automatically wrap around when it hits the buffer end.
------------------------------------------------------------------ */
-
dataLen = size - head;
remain = size - (head - tail) - 1;
-
- } /* End head has not wrapped */
- else
- { /* Begin head has wrapped around */
+ } else { /* Begin head has wrapped around */
remain = tail - head - 1;
dataLen = remain;
} /* End head has wrapped around */
-
/* -------------------------------------------------------------------
Check the space on the card. If we have more data than
space; reduce the amount of data to fit the space.
---------------------------------------------------------------------- */
-
bytesAvailable = min(remain, bytesAvailable);
-
txwinon(ch);
while (bytesAvailable > 0)
{ /* Begin while there is data to copy onto card */
@@ -767,26 +691,21 @@
amountCopied += dataLen;
bytesAvailable -= dataLen;
- if (head >= size)
- {
+ if (head >= size) {
head = 0;
dataLen = tail;
}
-
} /* End while there is data to copy onto card */
-
ch->statusflags |= TXBUSY;
globalwinon(ch);
- bc->tin = head;
+ writew(head, &bc->tin);
- if ((ch->statusflags & LOWWAIT) == 0)
- {
+ if ((ch->statusflags & LOWWAIT) == 0) {
ch->statusflags |= LOWWAIT;
- bc->ilow = 1;
+ writeb(1, &bc->ilow);
}
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
return(amountCopied);
} /* End pc_write */
@@ -795,11 +714,7 @@
static void pc_put_char(struct tty_struct *tty, unsigned char c)
{ /* Begin pc_put_char */
-
-
pc_write(tty, &c, 1);
- return;
-
} /* End pc_put_char */
/* ------------------ Begin pc_write_room ------------------------- */
@@ -811,7 +726,7 @@
struct channel *ch;
unsigned long flags;
unsigned int head, tail;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
remain = 0;
@@ -820,33 +735,29 @@
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL)
- {
- save_flags(flags);
- cli();
+ if ((ch = verifyChannel(tty)) != NULL) {
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
bc = ch->brdchan;
- head = bc->tin & (ch->txbufsize - 1);
- tail = bc->tout;
+ head = readw(&bc->tin) & (ch->txbufsize - 1);
+ tail = readw(&bc->tout);
- if (tail != bc->tout)
- tail = bc->tout;
+ if (tail != readw(&bc->tout))
+ tail = readw(&bc->tout);
/* Wrap tail if necessary */
tail &= (ch->txbufsize - 1);
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
- if (remain && (ch->statusflags & LOWWAIT) == 0)
- {
+ if (remain && (ch->statusflags & LOWWAIT) == 0) {
ch->statusflags |= LOWWAIT;
- bc->ilow = 1;
+ writeb(1, &bc->ilow);
}
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
}
-
/* Return how much room is left on card */
return remain;
@@ -862,8 +773,7 @@
int remain;
unsigned long flags;
struct channel *ch;
- volatile struct board_chan *bc;
-
+ struct board_chan *bc;
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
@@ -873,34 +783,27 @@
if ((ch = verifyChannel(tty)) == NULL)
return(0);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
bc = ch->brdchan;
- tail = bc->tout;
- head = bc->tin;
- ctail = ch->mailbox->cout;
+ tail = readw(&bc->tout);
+ head = readw(&bc->tin);
+ ctail = readw(&ch->mailbox->cout);
- if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+ if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
chars = 0;
- else
- { /* Begin if some space on the card has been used */
-
- head = bc->tin & (ch->txbufsize - 1);
+ else { /* Begin if some space on the card has been used */
+ head = readw(&bc->tin) & (ch->txbufsize - 1);
tail &= (ch->txbufsize - 1);
-
/* --------------------------------------------------------------
The logic here is basically opposite of the above pc_write_room
here we are finding the amount of bytes in the buffer filled.
Not the amount of bytes empty.
------------------------------------------------------------------- */
-
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
-
chars = (int)(ch->txbufsize - remain);
-
/* -------------------------------------------------------------
Make it possible to wakeup anything waiting for output
in tty_ioctl.c, etc.
@@ -908,15 +811,12 @@
If not already set. Setup an event to indicate when the
transmit buffer empties
----------------------------------------------------------------- */
-
if (!(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
} /* End if some space on the card has been used */
-
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
/* Return number of characters residing on card. */
return(chars);
@@ -930,67 +830,46 @@
unsigned int tail;
unsigned long flags;
struct channel *ch;
- volatile struct board_chan *bc;
-
-
+ struct board_chan *bc;
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
if ((ch = verifyChannel(tty)) == NULL)
return;
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
-
bc = ch->brdchan;
- tail = bc->tout;
-
+ tail = readw(&bc->tout);
/* Have FEP move tout pointer; effectively flushing transmit buffer */
-
fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
-
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
-
} /* End pc_flush_buffer */
/* ------------------ Begin pc_flush_chars ---------------------- */
static void pc_flush_chars(struct tty_struct *tty)
{ /* Begin pc_flush_chars */
-
struct channel * ch;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- {
+ if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* ----------------------------------------------------------------
If not already set and the transmitter is busy setup an event
to indicate when the transmit empties.
------------------------------------------------------------------- */
-
if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
}
-
} /* End pc_flush_chars */
/* ------------------ Begin block_til_ready ---------------------- */
@@ -998,14 +877,11 @@
static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch)
{ /* Begin block_til_ready */
-
DECLARE_WAITQUEUE(wait,current);
int retval, do_clocal = 0;
unsigned long flags;
-
- if (tty_hung_up_p(filp))
- {
+ if (tty_hung_up_p(filp)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
@@ -1017,8 +893,7 @@
If the device is in the middle of being closed, then block
until it's done, and then try again.
-------------------------------------------------------------------- */
- if (ch->asyncflags & ASYNC_CLOSING)
- {
+ if (ch->asyncflags & ASYNC_CLOSING) {
interruptible_sleep_on(&ch->close_wait);
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
@@ -1027,43 +902,29 @@
return -ERESTARTSYS;
}
- if (filp->f_flags & O_NONBLOCK)
- {
+ if (filp->f_flags & O_NONBLOCK) {
/* -----------------------------------------------------------------
If non-blocking mode is set, then make the check up front
and then exit.
-------------------------------------------------------------------- */
-
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
return 0;
}
-
-
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
-
- /* Block waiting for the carrier detect and the line to become free */
+ /* Block waiting for the carrier detect and the line to become free */
retval = 0;
add_wait_queue(&ch->open_wait, &wait);
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* We dec count so that pc_close will know when to free things */
if (!tty_hung_up_p(filp))
ch->count--;
-
- restore_flags(flags);
-
ch->blocked_open++;
-
while(1)
{ /* Begin forever while */
-
set_current_state(TASK_INTERRUPTIBLE);
-
if (tty_hung_up_p(filp) ||
!(ch->asyncflags & ASYNC_INITIALIZED))
{
@@ -1073,17 +934,14 @@
retval = -ERESTARTSYS;
break;
}
-
if (!(ch->asyncflags & ASYNC_CLOSING) &&
(do_clocal || (ch->imodem & ch->dcd)))
break;
-
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
-
+ spin_unlock_irqrestore(&epca_lock, flags);
/* ---------------------------------------------------------------
Allow someone else to be scheduled. We will occasionally go
through this loop until one of the above conditions change.
@@ -1091,25 +949,23 @@
prevent this loop from hogging the cpu.
------------------------------------------------------------------ */
schedule();
+ spin_lock_irqsave(&epca_lock, flags);
} /* End forever while */
current->state = TASK_RUNNING;
remove_wait_queue(&ch->open_wait, &wait);
- cli();
if (!tty_hung_up_p(filp))
ch->count++;
- restore_flags(flags);
-
ch->blocked_open--;
+ spin_unlock_irqrestore(&epca_lock, flags);
+
if (retval)
return retval;
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
return 0;
-
} /* End block_til_ready */
/* ------------------ Begin pc_open ---------------------- */
@@ -1120,17 +976,12 @@
struct channel *ch;
unsigned long flags;
int line, retval, boardnum;
- volatile struct board_chan *bc;
- volatile unsigned int head;
+ struct board_chan *bc;
+ unsigned int head;
line = tty->index;
- if (line < 0 || line >= nbdevs)
- {
- printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
- tty->driver_data = NULL;
- return(-ENODEV);
- }
-
+ if (line < 0 || line >= nbdevs)
+ return -ENODEV;
ch = &digi_channels[line];
boardnum = ch->boardnum;
@@ -1143,66 +994,49 @@
goes here.
---------------------------------------------------------------------- */
- if (invalid_lilo_config)
- {
+ if (invalid_lilo_config) {
if (setup_error_code & INVALID_BOARD_TYPE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
if (setup_error_code & INVALID_NUM_PORTS)
- printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
if (setup_error_code & INVALID_MEM_BASE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
if (setup_error_code & INVALID_PORT_BASE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
-
+ printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
if (setup_error_code & INVALID_BOARD_STATUS)
- printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
if (setup_error_code & INVALID_ALTPIN)
- printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
tty->driver_data = NULL; /* Mark this device as 'down' */
- return(-ENODEV);
+ return -ENODEV;
}
-
- if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED))
- {
+ if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
tty->driver_data = NULL; /* Mark this device as 'down' */
return(-ENODEV);
}
- if (( bc = ch->brdchan) == 0)
- {
+ if ((bc = ch->brdchan) == 0) {
tty->driver_data = NULL;
- return(-ENODEV);
+ return -ENODEV;
}
+ spin_lock_irqsave(&epca_lock, flags);
/* ------------------------------------------------------------------
Every time a channel is opened, increment a counter. This is
necessary because we do not wish to flush and shutdown the channel
until the last app holding the channel open, closes it.
--------------------------------------------------------------------- */
-
ch->count++;
-
/* ----------------------------------------------------------------
Set a kernel structures pointer to our local channel
structure. This way we can get to it when passed only
a tty struct.
------------------------------------------------------------------ */
-
tty->driver_data = ch;
-
/* ----------------------------------------------------------------
If this is the first time the channel has been opened, initialize
the tty->termios struct otherwise let pc_close handle it.
-------------------------------------------------------------------- */
-
- save_flags(flags);
- cli();
-
globalwinon(ch);
ch->statusflags = 0;
@@ -1213,8 +1047,8 @@
Set receive head and tail ptrs to each other. This indicates
no data available to read.
----------------------------------------------------------------- */
- head = bc->rin;
- bc->rout = head;
+ head = readw(&bc->rin);
+ writew(head, &bc->rout);
/* Set the channels associated tty structure */
ch->tty = tty;
@@ -1224,122 +1058,74 @@
issues, etc.... It effect both control flags and input flags.
-------------------------------------------------------------------- */
epcaparam(tty,ch);
-
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
retval = block_til_ready(tty, filp, ch);
if (retval)
- {
return retval;
- }
-
/* -------------------------------------------------------------
Set this again in case a hangup set it to zero while this
open() was waiting for the line...
--------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
ch->tty = tty;
-
- save_flags(flags);
- cli();
globalwinon(ch);
-
/* Enable Digi Data events */
- bc->idata = 1;
-
+ writeb(1, &bc->idata);
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
return 0;
-
} /* End pc_open */
-#ifdef MODULE
static int __init epca_module_init(void)
{ /* Begin init_module */
-
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- pc_init();
-
- restore_flags(flags);
-
- return(0);
+ return pc_init();
}
module_init(epca_module_init);
-#endif
-#ifdef ENABLE_PCI
static struct pci_driver epca_driver;
-#endif
-
-#ifdef MODULE
-/* -------------------- Begin cleanup_module ---------------------- */
static void __exit epca_module_exit(void)
{
-
int count, crd;
struct board_info *bd;
struct channel *ch;
- unsigned long flags;
del_timer_sync(&epca_timer);
- save_flags(flags);
- cli();
-
if ((tty_unregister_driver(pc_driver)) ||
(tty_unregister_driver(pc_info)))
{
- printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
- restore_flags(flags);
+ printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
}
put_tty_driver(pc_driver);
put_tty_driver(pc_info);
- for (crd = 0; crd < num_cards; crd++)
- { /* Begin for each card */
-
+ for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */
bd = &boards[crd];
-
if (!bd)
{ /* Begin sanity check */
printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
return;
} /* End sanity check */
-
- ch = card_ptr[crd];
-
+ ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++)
{ /* Begin for each port */
-
- if (ch)
- {
+ if (ch) {
if (ch->tty)
tty_hangup(ch->tty);
kfree(ch->tmp_buf);
}
-
} /* End for each port */
} /* End for each card */
-
-#ifdef ENABLE_PCI
pci_unregister_driver (&epca_driver);
-#endif
-
- restore_flags(flags);
-
}
+
module_exit(epca_module_exit);
-#endif /* MODULE */
static struct tty_operations pc_ops = {
.open = pc_open,
@@ -1371,34 +1157,15 @@
/* ------------------ Begin pc_init ---------------------- */
-int __init pc_init(void)
+static int __init pc_init(void)
{ /* Begin pc_init */
-
- /* ----------------------------------------------------------------
- pc_init is called by the operating system during boot up prior to
- any open calls being made. In the older versions of Linux (Prior
- to 2.0.0) an entry is made into tty_io.c. A pointer to the last
- memory location (from kernel space) used (kmem_start) is passed
- to pc_init. It is pc_inits responsibility to modify this value
- for any memory that the Digi driver might need and then return
- this value to the operating system. For example if the driver
- wishes to allocate 1K of kernel memory, pc_init would return
- (kmem_start + 1024). This memory (Between kmem_start and kmem_start
- + 1024) would then be available for use exclusively by the driver.
- In this case our driver does not allocate any of this kernel
- memory.
- ------------------------------------------------------------------*/
-
- ulong flags;
int crd;
struct board_info *bd;
unsigned char board_id = 0;
-#ifdef ENABLE_PCI
int pci_boards_found, pci_count;
pci_count = 0;
-#endif /* ENABLE_PCI */
pc_driver = alloc_tty_driver(MAX_ALLOC);
if (!pc_driver)
@@ -1416,8 +1183,7 @@
Note : If LILO has ran epca_setup then epca_setup will handle defining
num_cards as well as copying the data into the board structure.
-------------------------------------------------------------------------- */
- if (!liloconfig)
- { /* Begin driver has been configured via. epcaconfig */
+ if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */
nbdevs = NBDEVS;
num_cards = NUMCARDS;
@@ -1440,8 +1206,6 @@
printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
-#ifdef ENABLE_PCI
-
/* ------------------------------------------------------------------
NOTE : This code assumes that the number of ports found in
the boards array is correct. This could be wrong if
@@ -1467,8 +1231,6 @@
pci_boards_found += init_PCI();
num_cards += pci_boards_found;
-#endif /* ENABLE_PCI */
-
pc_driver->owner = THIS_MODULE;
pc_driver->name = "ttyD";
pc_driver->devfs_name = "tts/D";
@@ -1499,9 +1261,6 @@
tty_set_operations(pc_info, &info_ops);
- save_flags(flags);
- cli();
-
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
@@ -1610,11 +1369,7 @@
if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000;
- } /* End it is an XI card */
- else
- {
- printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
- }
+ } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
break;
} /* End switch on bd->type */
@@ -1634,9 +1389,6 @@
init_timer(&epca_timer);
epca_timer.function = epcapoll;
mod_timer(&epca_timer, jiffies + HZ/25);
-
- restore_flags(flags);
-
return 0;
} /* End pc_init */
@@ -1647,10 +1399,10 @@
{ /* Begin post_fep_init */
int i;
- unchar *memaddr;
- volatile struct global_data *gd;
+ unsigned char *memaddr;
+ struct global_data *gd;
struct board_info *bd;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
struct channel *ch;
int shrinkmem = 0, lowwater ;
@@ -1669,9 +1421,7 @@
after DIGI_INIT has been called will return the proper values.
------------------------------------------------------------------- */
- if (bd->type >= PCIXEM) /* If the board in question is PCI */
- { /* Begin get PCI number of ports */
-
+ if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
/* --------------------------------------------------------------------
Below we use XEMPORTS as a memory offset regardless of which PCI
card it is. This is because all of the supported PCI cards have
@@ -1685,15 +1435,15 @@
(FYI - The id should be located at 0x1ac (And may use up to 4 bytes
if the box in question is a XEM or CX)).
------------------------------------------------------------------------ */
-
- bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
- (bd->re_map_membase + XEMPORTS));
-
-
+ /* PCI cards are already remapped at this point ISA are not */
+ bd->numports = readw(bd->re_map_membase + XEMPORTS);
epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
nbdevs += (bd->numports);
-
- } /* End get PCI number of ports */
+ } else {
+ /* Fix up the mappings for ISA/EISA etc */
+ /* FIXME: 64K - can we be smarter ? */
+ bd->re_map_membase = ioremap(bd->membase, 0x10000);
+ }
if (crd != 0)
card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
@@ -1701,19 +1451,9 @@
card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
ch = card_ptr[crd];
-
-
epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
- memaddr = (unchar *)bd->re_map_membase;
-
- /*
- The below command is necessary because newer kernels (2.1.x and
- up) do not have a 1:1 virtual to physical mapping. The below
- call adjust for that.
- */
-
- memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+ memaddr = bd->re_map_membase;
/* -----------------------------------------------------------------
The below assignment will set bc to point at the BEGINING of
@@ -1721,7 +1461,7 @@
8 and 64 of these structures.
-------------------------------------------------------------------- */
- bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+ bc = (struct board_chan *)(memaddr + CHANSTRUCT);
/* -------------------------------------------------------------------
The below assignment will set gd to point at the BEGINING of
@@ -1730,20 +1470,18 @@
pointer begins at 0xd10.
---------------------------------------------------------------------- */
- gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+ gd = (struct global_data *)(memaddr + GLOBAL);
/* --------------------------------------------------------------------
XEPORTS (address 0xc22) points at the number of channels the
card supports. (For 64XE, XI, XEM, and XR use 0xc02)
----------------------------------------------------------------------- */
- if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
- (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+ if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1;
if (bd->type < PCIXEM)
if (!request_region((int)bd->port, 4, board_desc[bd->type]))
return;
-
memwinon(bd, 0);
/* --------------------------------------------------------------------
@@ -1753,17 +1491,16 @@
/* For every port on the card do ..... */
- for (i = 0; i < bd->numports; i++, ch++, bc++)
- { /* Begin for each port */
+ for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */
+ unsigned long flags;
ch->brdchan = bc;
ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint, ch);
ch->board = &boards[crd];
- switch (bd->type)
- { /* Begin switch bd->type */
-
+ spin_lock_irqsave(&epca_lock, flags);
+ switch (bd->type) {
/* ----------------------------------------------------------------
Since some of the boards use different bitmaps for their
control signals we cannot hard code these values and retain
@@ -1796,14 +1533,12 @@
} /* End switch bd->type */
- if (boards[crd].altpin)
- {
+ if (boards[crd].altpin) {
ch->dsr = ch->m_dcd;
ch->dcd = ch->m_dsr;
ch->digiext.digi_flags |= DIGI_ALTPIN;
}
- else
- {
+ else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
@@ -1813,14 +1548,12 @@
ch->magic = EPCA_MAGIC;
ch->tty = NULL;
- if (shrinkmem)
- {
+ if (shrinkmem) {
fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
shrinkmem = 0;
}
- switch (bd->type)
- { /* Begin switch bd->type */
+ switch (bd->type) {
case PCIXEM:
case PCIXRJ:
@@ -1878,13 +1611,13 @@
fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
- bc->edelay = 100;
- bc->idata = 1;
+ writew(100, &bc->edelay);
+ writeb(1, &bc->idata);
- ch->startc = bc->startc;
- ch->stopc = bc->stopc;
- ch->startca = bc->startca;
- ch->stopca = bc->stopca;
+ ch->startc = readb(&bc->startc);
+ ch->stopc = readb(&bc->stopc);
+ ch->startca = readb(&bc->startca);
+ ch->stopca = readb(&bc->stopca);
ch->fepcflag = 0;
ch->fepiflag = 0;
@@ -1899,27 +1632,23 @@
ch->blocked_open = 0;
init_waitqueue_head(&ch->open_wait);
init_waitqueue_head(&ch->close_wait);
+
+ spin_unlock_irqrestore(&epca_lock, flags);
+
ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
- if (!(ch->tmp_buf))
- {
+ if (!ch->tmp_buf) {
printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
release_region((int)bd->port, 4);
while(i-- > 0)
kfree((ch--)->tmp_buf);
return;
- }
- else
+ } else
memset((void *)ch->tmp_buf,0,ch->txbufsize);
} /* End for each port */
printk(KERN_INFO
"Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
- sprintf(mesg,
- "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
- VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
- console_print(mesg);
-
memwinoff(bd, 0);
} /* End post_fep_init */
@@ -1943,9 +1672,6 @@
buffer empty) and acts on those events.
----------------------------------------------------------------------- */
- save_flags(flags);
- cli();
-
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
@@ -1961,6 +1687,8 @@
some legacy boards.
---------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
+
assertmemoff(ch);
globalwinon(ch);
@@ -1970,21 +1698,19 @@
the transmit or receive queue.
------------------------------------------------------------------- */
- head = ch->mailbox->ein;
- tail = ch->mailbox->eout;
+ head = readw(&ch->mailbox->ein);
+ tail = readw(&ch->mailbox->eout);
/* If head isn't equal to tail we have an event */
if (head != tail)
doevent(crd);
-
memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+
} /* End for each card */
-
mod_timer(&epca_timer, jiffies + (HZ / 25));
-
- restore_flags(flags);
} /* End epcapoll */
/* --------------------- Begin doevent ------------------------ */
@@ -1992,53 +1718,42 @@
static void doevent(int crd)
{ /* Begin doevent */
- volatile unchar *eventbuf;
+ void *eventbuf;
struct channel *ch, *chan0;
static struct tty_struct *tty;
- volatile struct board_info *bd;
- volatile struct board_chan *bc;
- register volatile unsigned int tail, head;
- register int event, channel;
- register int mstat, lstat;
+ struct board_info *bd;
+ struct board_chan *bc;
+ unsigned int tail, head;
+ int event, channel;
+ int mstat, lstat;
/* -------------------------------------------------------------------
This subroutine is called by epcapoll when an event is detected
in the event queue. This routine responds to those events.
--------------------------------------------------------------------- */
-
bd = &boards[crd];
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
-
assertgwinon(chan0);
-
- while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein))
+ while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein)))
{ /* Begin while something in event queue */
-
assertgwinon(chan0);
-
- eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
-
+ eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
- channel = eventbuf[0];
-
+ channel = readb(eventbuf);
/* Get the actual event code that occurred */
- event = eventbuf[1];
-
+ event = readb(eventbuf + 1);
/* ----------------------------------------------------------------
The two assignments below get the current modem status (mstat)
and the previous modem status (lstat). These are useful becuase
an event could signal a change in modem signals itself.
------------------------------------------------------------------- */
-
- mstat = eventbuf[2];
- lstat = eventbuf[3];
+ mstat = readb(eventbuf + 2);
+ lstat = readb(eventbuf + 3);
ch = chan0 + channel;
-
- if ((unsigned)channel >= bd->numports || !ch)
- {
+ if ((unsigned)channel >= bd->numports || !ch) {
if (channel >= bd->numports)
ch = chan0;
bc = ch->brdchan;
@@ -2048,97 +1763,53 @@
if ((bc = ch->brdchan) == NULL)
goto next;
- if (event & DATA_IND)
- { /* Begin DATA_IND */
-
+ if (event & DATA_IND) { /* Begin DATA_IND */
receive_data(ch);
assertgwinon(ch);
-
} /* End DATA_IND */
/* else *//* Fix for DCD transition missed bug */
- if (event & MODEMCHG_IND)
- { /* Begin MODEMCHG_IND */
-
+ if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */
/* A modem signal change has been indicated */
-
ch->imodem = mstat;
-
- if (ch->asyncflags & ASYNC_CHECK_CD)
- {
+ if (ch->asyncflags & ASYNC_CHECK_CD) {
if (mstat & ch->dcd) /* We are now receiving dcd */
wake_up_interruptible(&ch->open_wait);
else
pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
}
-
} /* End MODEMCHG_IND */
-
tty = ch->tty;
- if (tty)
- { /* Begin if valid tty */
-
- if (event & BREAK_IND)
- { /* Begin if BREAK_IND */
-
+ if (tty) { /* Begin if valid tty */
+ if (event & BREAK_IND) { /* Begin if BREAK_IND */
/* A break has been indicated */
-
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
-
*tty->flip.char_buf_ptr++ = 0;
-
tty_schedule_flip(tty);
-
- } /* End if BREAK_IND */
- else
- if (event & LOWTX_IND)
- { /* Begin LOWTX_IND */
-
+ } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */
if (ch->statusflags & LOWWAIT)
{ /* Begin if LOWWAIT */
-
ch->statusflags &= ~LOWWAIT;
tty_wakeup(tty);
wake_up_interruptible(&tty->write_wait);
-
} /* End if LOWWAIT */
-
- } /* End LOWTX_IND */
- else
- if (event & EMPTYTX_IND)
- { /* Begin EMPTYTX_IND */
-
+ } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */
/* This event is generated by setup_empty_event */
-
ch->statusflags &= ~TXBUSY;
- if (ch->statusflags & EMPTYWAIT)
- { /* Begin if EMPTYWAIT */
-
+ if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(tty);
-
wake_up_interruptible(&tty->write_wait);
-
} /* End if EMPTYWAIT */
-
} /* End EMPTYTX_IND */
-
} /* End if valid tty */
-
-
next:
globalwinon(ch);
-
- if (!bc)
- printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
- else
- bc->idata = 1;
-
- chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+ BUG_ON(!bc);
+ writew(1, &bc->idata);
+ writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
globalwinon(chan0);
-
} /* End while something in event queue */
-
} /* End doevent */
/* --------------------- Begin fepcmd ------------------------ */
@@ -2146,7 +1817,6 @@
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
int byte2, int ncmds, int bytecmd)
{ /* Begin fepcmd */
-
unchar *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
long count;
@@ -2155,93 +1825,57 @@
/* This is the routine in which commands may be passed to the card. */
if (ch->board->status == DISABLED)
- {
return;
- }
-
assertgwinon(ch);
-
/* Remember head (As well as max) is just an offset not a base addr */
- head = ch->mailbox->cin;
-
+ head = readw(&ch->mailbox->cin);
/* cmdStart is a base address */
- cmdStart = ch->mailbox->cstart;
-
+ cmdStart = readw(&ch->mailbox->cstart);
/* ------------------------------------------------------------------
We do the addition below because we do not want a max pointer
relative to cmdStart. We want a max pointer that points at the
physical end of the command queue.
-------------------------------------------------------------------- */
-
- cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
-
+ cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
memaddr = ch->board->re_map_membase;
- /*
- The below command is necessary because newer kernels (2.1.x and
- up) do not have a 1:1 virtual to physical mapping. The below
- call adjust for that.
- */
-
- memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
-
- if (head >= (cmdMax - cmdStart) || (head & 03))
- {
- printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__,
- cmd, head);
- printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__,
- cmdMax, cmdStart);
+ if (head >= (cmdMax - cmdStart) || (head & 03)) {
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart);
return;
}
-
- if (bytecmd)
- {
- *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
-
- *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ if (bytecmd) {
+ writeb(cmd, memaddr + head + cmdStart + 0);
+ writeb(ch->channelnum, memaddr + head + cmdStart + 1);
/* Below word_or_byte is bits to set */
- *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+ writeb(word_or_byte, memaddr + head + cmdStart + 2);
/* Below byte2 is bits to reset */
- *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
-
- }
- else
- {
- *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
- *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
- *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+ writeb(byte2, memaddr + head + cmdStart + 3);
+ } else {
+ writeb(cmd, memaddr + head + cmdStart + 0);
+ writeb(ch->channelnum, memaddr + head + cmdStart + 1);
+ writeb(word_or_byte, memaddr + head + cmdStart + 2);
}
-
head = (head + 4) & (cmdMax - cmdStart - 4);
- ch->mailbox->cin = head;
-
+ writew(head, &ch->mailbox->cin);
count = FEPTIMEOUT;
- for (;;)
- { /* Begin forever loop */
-
+ for (;;) { /* Begin forever loop */
count--;
- if (count == 0)
- {
+ if (count == 0) {
printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
return;
}
-
- head = ch->mailbox->cin;
- cmdTail = ch->mailbox->cout;
-
+ head = readw(&ch->mailbox->cin);
+ cmdTail = readw(&ch->mailbox->cout);
n = (head - cmdTail) & (cmdMax - cmdStart - 4);
-
/* ----------------------------------------------------------
Basically this will break when the FEP acknowledges the
command by incrementing cmdTail (Making it equal to head).
------------------------------------------------------------- */
-
if (n <= ncmds * (sizeof(short) * 4))
break; /* Well nearly forever :-) */
-
} /* End forever loop */
-
} /* End fepcmd */
/* ---------------------------------------------------------------------
@@ -2255,11 +1889,9 @@
static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_h */
-
unsigned res = 0;
- if (cflag & CRTSCTS)
- {
+ if (cflag & CRTSCTS) {
ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
res |= ((ch->m_cts) | (ch->m_rts));
}
@@ -2295,7 +1927,6 @@
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
INPCK | ISTRIP|IXON|IXANY|IXOFF);
-
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
@@ -2308,28 +1939,15 @@
{ /* Begin termios2digi_c */
unsigned res = 0;
-
-#ifdef SPEED_HACK
- /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
- if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
- if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
-#endif /* SPEED_HACK */
-
- if (cflag & CBAUDEX)
- { /* Begin detected CBAUDEX */
-
+ if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */
ch->digiext.digi_flags |= DIGI_FAST;
-
/* -------------------------------------------------------------
HUPCL bit is used by FEP to indicate fast baud
table is to be used.
----------------------------------------------------------------- */
-
res |= FEP_HUPCL;
-
} /* End detected CBAUDEX */
else ch->digiext.digi_flags &= ~DIGI_FAST;
-
/* -------------------------------------------------------------------
CBAUD has bit position 0x1000 set these days to indicate Linux
baud rate remap. Digi hardware can't handle the bit assignment.
@@ -2337,7 +1955,6 @@
bit out.
---------------------------------------------------------------------- */
res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
-
/* -------------------------------------------------------------
This gets a little confusing. The Digi cards have their own
representation of c_cflags controling baud rate. For the most
@@ -2357,10 +1974,8 @@
should be checked for a screened out prior to termios2digi_c
returning. Since CLOCAL isn't used by the board this can be
ignored as long as the returned value is used only by Digi hardware.
- ----------------------------------------------------------------- */
-
- if (cflag & CBAUDEX)
- {
+ ----------------------------------------------------------------- */
+ if (cflag & CBAUDEX) {
/* -------------------------------------------------------------
The below code is trying to guarantee that only baud rates
115200 and 230400 are remapped. We use exclusive or because
@@ -2371,138 +1986,96 @@
if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
(!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
- {
res += 1;
- }
}
-
return res;
} /* End termios2digi_c */
/* --------------------- Begin epcaparam ----------------------- */
+/* Caller must hold the locks */
static void epcaparam(struct tty_struct *tty, struct channel *ch)
{ /* Begin epcaparam */
unsigned int cmdHead;
struct termios *ts;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
unsigned mval, hflow, cflag, iflag;
bc = ch->brdchan;
epcaassert(bc !=0, "bc out of range");
assertgwinon(ch);
-
ts = tty->termios;
-
- if ((ts->c_cflag & CBAUD) == 0)
- { /* Begin CBAUD detected */
-
- cmdHead = bc->rin;
+ if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
+ cmdHead = readw(&bc->rin);
bc->rout = cmdHead;
- cmdHead = bc->tin;
-
+ cmdHead = readw(&bc->tin);
/* Changing baud in mid-stream transmission can be wonderful */
/* ---------------------------------------------------------------
Flush current transmit buffer by setting cmdTail pointer (tout)
to cmdHead pointer (tin). Hopefully the transmit buffer is empty.
----------------------------------------------------------------- */
-
fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
mval = 0;
-
- } /* End CBAUD detected */
- else
- { /* Begin CBAUD not detected */
-
+ } else { /* Begin CBAUD not detected */
/* -------------------------------------------------------------------
c_cflags have changed but that change had nothing to do with BAUD.
Propagate the change to the card.
---------------------------------------------------------------------- */
-
cflag = termios2digi_c(ch, ts->c_cflag);
-
- if (cflag != ch->fepcflag)
- {
+ if (cflag != ch->fepcflag) {
ch->fepcflag = cflag;
/* Set baud rate, char size, stop bits, parity */
fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
}
-
-
/* ----------------------------------------------------------------
If the user has not forced CLOCAL and if the device is not a
CALLOUT device (Which is always CLOCAL) we set flags such that
the driver will wait on carrier detect.
------------------------------------------------------------------- */
-
if (ts->c_cflag & CLOCAL)
- { /* Begin it is a cud device or a ttyD device with CLOCAL on */
ch->asyncflags &= ~ASYNC_CHECK_CD;
- } /* End it is a cud device or a ttyD device with CLOCAL on */
else
- { /* Begin it is a ttyD device */
ch->asyncflags |= ASYNC_CHECK_CD;
- } /* End it is a ttyD device */
-
mval = ch->m_dtr | ch->m_rts;
-
} /* End CBAUD not detected */
-
iflag = termios2digi_i(ch, ts->c_iflag);
-
/* Check input mode flags */
-
- if (iflag != ch->fepiflag)
- {
+ if (iflag != ch->fepiflag) {
ch->fepiflag = iflag;
-
/* ---------------------------------------------------------------
Command sets channels iflag structure on the board. Such things
as input soft flow control, handling of parity errors, and
break handling are all set here.
------------------------------------------------------------------- */
-
/* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
-
/* ---------------------------------------------------------------
Set the board mint value for this channel. This will cause hardware
events to be generated each time the DCD signal (Described in mint)
changes.
------------------------------------------------------------------- */
- bc->mint = ch->dcd;
-
+ writeb(ch->dcd, &bc->mint);
if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
if (ch->digiext.digi_flags & DIGI_FORCEDCD)
- bc->mint = 0;
-
- ch->imodem = bc->mstat;
-
+ writeb(0, &bc->mint);
+ ch->imodem = readb(&bc->mstat);
hflow = termios2digi_h(ch, ts->c_cflag);
-
- if (hflow != ch->hflow)
- {
+ if (hflow != ch->hflow) {
ch->hflow = hflow;
-
/* --------------------------------------------------------------
Hard flow control has been selected but the board is not
using it. Activate hard flow control now.
----------------------------------------------------------------- */
-
fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
}
-
-
mval ^= ch->modemfake & (mval ^ ch->modem);
- if (ch->omodem ^ mval)
- {
+ if (ch->omodem ^ mval) {
ch->omodem = mval;
-
/* --------------------------------------------------------------
The below command sets the DTR and RTS mstat structure. If
hard flow control is NOT active these changes will drive the
@@ -2514,87 +2087,65 @@
/* First reset DTR & RTS; then set them */
fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
fepcmd(ch, SETMODEM, mval, 0, 0, 1);
-
}
-
- if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc)
- {
+ if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
ch->fepstartc = ch->startc;
ch->fepstopc = ch->stopc;
-
/* ------------------------------------------------------------
The XON / XOFF characters have changed; propagate these
changes to the card.
--------------------------------------------------------------- */
-
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
}
-
- if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca)
- {
+ if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
ch->fepstartca = ch->startca;
ch->fepstopca = ch->stopca;
-
/* ---------------------------------------------------------------
Similar to the above, this time the auxilarly XON / XOFF
characters have changed; propagate these changes to the card.
------------------------------------------------------------------ */
-
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
-
} /* End epcaparam */
/* --------------------- Begin receive_data ----------------------- */
-
+/* Caller holds lock */
static void receive_data(struct channel *ch)
{ /* Begin receive_data */
unchar *rptr;
struct termios *ts = NULL;
struct tty_struct *tty;
- volatile struct board_chan *bc;
- register int dataToRead, wrapgap, bytesAvailable;
- register unsigned int tail, head;
+ struct board_chan *bc;
+ int dataToRead, wrapgap, bytesAvailable;
+ unsigned int tail, head;
unsigned int wrapmask;
int rc;
-
/* ---------------------------------------------------------------
This routine is called by doint when a receive data event
has taken place.
------------------------------------------------------------------- */
globalwinon(ch);
-
if (ch->statusflags & RXSTOPPED)
return;
-
tty = ch->tty;
if (tty)
ts = tty->termios;
-
bc = ch->brdchan;
-
- if (!bc)
- {
- printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
- return;
- }
-
+ BUG_ON(!bc);
wrapmask = ch->rxbufsize - 1;
/* ---------------------------------------------------------------------
Get the head and tail pointers to the receiver queue. Wrap the
head pointer if it has reached the end of the buffer.
------------------------------------------------------------------------ */
-
- head = bc->rin;
+ head = readw(&bc->rin);
head &= wrapmask;
- tail = bc->rout & wrapmask;
+ tail = readw(&bc->rout) & wrapmask;
bytesAvailable = (head - tail) & wrapmask;
-
if (bytesAvailable == 0)
return;
@@ -2602,8 +2153,7 @@
If CREAD bit is off or device not open, set TX tail to head
--------------------------------------------------------------------- */
- if (!tty || !ts || !(ts->c_cflag & CREAD))
- {
+ if (!tty || !ts || !(ts->c_cflag & CREAD)) {
bc->rout = head;
return;
}
@@ -2611,64 +2161,45 @@
if (tty->flip.count == TTY_FLIPBUF_SIZE)
return;
- if (bc->orun)
- {
- bc->orun = 0;
- printk(KERN_WARNING "overrun! DigiBoard device %s\n",tty->name);
+ if (readb(&bc->orun)) {
+ writeb(0, &bc->orun);
+ printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
}
-
rxwinon(ch);
rptr = tty->flip.char_buf_ptr;
rc = tty->flip.count;
-
- while (bytesAvailable > 0)
- { /* Begin while there is data on the card */
-
+ while (bytesAvailable > 0) { /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
-
/* ---------------------------------------------------------------
Even if head has wrapped around only report the amount of
data to be equal to the size - tail. Remember memcpy can't
automaticly wrap around the receive buffer.
----------------------------------------------------------------- */
-
dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
-
/* --------------------------------------------------------------
Make sure we don't overflow the buffer
----------------------------------------------------------------- */
-
if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
dataToRead = TTY_FLIPBUF_SIZE - rc;
-
if (dataToRead == 0)
break;
-
/* ---------------------------------------------------------------
Move data read from our card into the line disciplines buffer
for translation if necessary.
------------------------------------------------------------------ */
-
- if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
- printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
-
+ memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
rc += dataToRead;
rptr += dataToRead;
tail = (tail + dataToRead) & wrapmask;
bytesAvailable -= dataToRead;
-
} /* End while there is data on the card */
-
-
tty->flip.count = rc;
tty->flip.char_buf_ptr = rptr;
globalwinon(ch);
- bc->rout = tail;
-
+ writew(tail, &bc->rout);
/* Must be called with global data */
tty_schedule_flip(ch->tty);
return;
-
} /* End receive_data */
static int info_ioctl(struct tty_struct *tty, struct file * file,
@@ -2676,17 +2207,15 @@
{
switch (cmd)
{ /* Begin switch cmd */
-
case DIGI_GETINFO:
{ /* Begin case DIGI_GETINFO */
-
struct digi_info di ;
int brd;
- getUser(brd, (unsigned int __user *)arg);
-
- if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
- return (-ENODEV);
+ if(get_user(brd, (unsigned int __user *)arg))
+ return -EFAULT;
+ if (brd < 0 || brd >= num_cards || num_cards == 0)
+ return -ENODEV;
memset(&di, 0, sizeof(di));
@@ -2694,8 +2223,9 @@
di.status = boards[brd].status;
di.type = boards[brd].type ;
di.numports = boards[brd].numports ;
- di.port = boards[brd].port ;
- di.membase = boards[brd].membase ;
+ /* Legacy fixups - just move along nothing to see */
+ di.port = (unsigned char *)boards[brd].port ;
+ di.membase = (unsigned char *)boards[brd].membase ;
if (copy_to_user((void __user *)arg, &di, sizeof (di)))
return -EFAULT;
@@ -2709,39 +2239,29 @@
int brd = arg & 0xff000000 >> 16 ;
unsigned char state = arg & 0xff ;
- if ((brd < 0) || (brd >= num_cards))
- {
- printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+ if (brd < 0 || brd >= num_cards) {
+ printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
return (-ENODEV);
}
-
digi_poller_inhibited = state ;
break ;
-
} /* End case DIGI_POLLER */
case DIGI_INIT:
{ /* Begin case DIGI_INIT */
-
/* ------------------------------------------------------------
This call is made by the apps to complete the initilization
of the board(s). This routine is responsible for setting
the card to its initial state and setting the drivers control
fields to the sutianle settings for the card in question.
---------------------------------------------------------------- */
-
int crd ;
for (crd = 0; crd < num_cards; crd++)
post_fep_init (crd);
-
break ;
-
} /* End case DIGI_INIT */
-
-
default:
- return -ENOIOCTLCMD;
-
+ return -ENOTTY;
} /* End switch cmd */
return (0) ;
}
@@ -2750,43 +2270,33 @@
static int pc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct channel *ch = (struct channel *) tty->driver_data;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
unsigned int mstat, mflag = 0;
unsigned long flags;
if (ch)
bc = ch->brdchan;
else
- {
- printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmget!\n");
- return(-EINVAL);
- }
+ return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- mstat = bc->mstat;
+ mstat = readb(&bc->mstat);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
if (mstat & ch->m_dtr)
mflag |= TIOCM_DTR;
-
if (mstat & ch->m_rts)
mflag |= TIOCM_RTS;
-
if (mstat & ch->m_cts)
mflag |= TIOCM_CTS;
-
if (mstat & ch->dsr)
mflag |= TIOCM_DSR;
-
if (mstat & ch->m_ri)
mflag |= TIOCM_RI;
-
if (mstat & ch->dcd)
mflag |= TIOCM_CD;
-
return mflag;
}
@@ -2796,13 +2306,10 @@
struct channel *ch = (struct channel *) tty->driver_data;
unsigned long flags;
- if (!ch) {
- printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmset!\n");
- return(-EINVAL);
- }
+ if (!ch)
+ return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
/*
* I think this modemfake stuff is broken. It doesn't
* correctly reflect the behaviour desired by the TIOCM*
@@ -2824,17 +2331,14 @@
ch->modemfake |= ch->m_dtr;
ch->modem &= ~ch->m_dtr;
}
-
globalwinon(ch);
-
/* --------------------------------------------------------------
The below routine generally sets up parity, baud, flow control
issues, etc.... It effect both control flags and input flags.
------------------------------------------------------------------ */
-
epcaparam(tty,ch);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
return 0;
}
@@ -2847,19 +2351,14 @@
unsigned long flags;
unsigned int mflag, mstat;
unsigned char startc, stopc;
- volatile struct board_chan *bc;
+ struct board_chan *bc;
struct channel *ch = (struct channel *) tty->driver_data;
void __user *argp = (void __user *)arg;
if (ch)
bc = ch->brdchan;
else
- {
- printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
- return(-EINVAL);
- }
-
- save_flags(flags);
+ return -EINVAL;
/* -------------------------------------------------------------------
For POSIX compliance we need to add more ioctls. See tty_ioctl.c
@@ -2871,46 +2370,39 @@
{ /* Begin switch cmd */
case TCGETS:
- if (copy_to_user(argp,
- tty->termios, sizeof(struct termios)))
+ if (copy_to_user(argp, tty->termios, sizeof(struct termios)))
return -EFAULT;
- return(0);
-
+ return 0;
case TCGETA:
return get_termio(tty, argp);
-
case TCSBRK: /* SVID version: non-zero arg --> no break */
-
retval = tty_check_change(tty);
if (retval)
return retval;
-
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
if (!arg)
digi_send_break(ch, HZ/4); /* 1/4 second */
return 0;
-
case TCSBRKP: /* support for POSIX tcsendbreak() */
-
retval = tty_check_change(tty);
if (retval)
return retval;
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
return 0;
-
case TIOCGSOFTCAR:
if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
return -EFAULT;
return 0;
-
case TIOCSSOFTCAR:
{
unsigned int value;
@@ -2922,75 +2414,63 @@
(value ? CLOCAL : 0));
return 0;
}
-
case TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
return -EFAULT;
break;
-
case TIOCMODS:
if (get_user(mstat, (unsigned __user *)argp))
return -EFAULT;
return pc_tiocmset(tty, file, mstat, ~mstat);
-
case TIOCSDTR:
+ spin_lock_irqsave(&epca_lock, flags);
ch->omodem |= ch->m_dtr;
- cli();
globalwinon(ch);
fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
case TIOCCDTR:
+ spin_lock_irqsave(&epca_lock, flags);
ch->omodem &= ~ch->m_dtr;
- cli();
globalwinon(ch);
fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
-
case DIGI_GETA:
if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
return -EFAULT;
break;
-
case DIGI_SETAW:
case DIGI_SETAF:
- if ((cmd) == (DIGI_SETAW))
- {
+ if (cmd == DIGI_SETAW) {
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
- }
- else
- {
+ } else {
/* ldisc lock already held in ioctl */
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
}
-
/* Fall Thru */
-
case DIGI_SETA:
if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
return -EFAULT;
- if (ch->digiext.digi_flags & DIGI_ALTPIN)
- {
+ if (ch->digiext.digi_flags & DIGI_ALTPIN) {
ch->dcd = ch->m_dsr;
ch->dsr = ch->m_dcd;
- }
- else
- {
+ } else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
/* -----------------------------------------------------------------
@@ -3000,25 +2480,22 @@
epcaparam(tty,ch);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
case DIGI_GETFLOW:
case DIGI_GETAFLOW:
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if ((cmd) == (DIGI_GETFLOW))
- {
- dflow.startc = bc->startc;
- dflow.stopc = bc->stopc;
- }
- else
- {
- dflow.startc = bc->startca;
- dflow.stopc = bc->stopca;
+ if (cmd == DIGI_GETFLOW) {
+ dflow.startc = readb(&bc->startc);
+ dflow.stopc = readb(&bc->stopc);
+ } else {
+ dflow.startc = readb(&bc->startca);
+ dflow.stopc = readb(&bc->stopca);
}
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
if (copy_to_user(argp, &dflow, sizeof(dflow)))
return -EFAULT;
@@ -3026,13 +2503,10 @@
case DIGI_SETAFLOW:
case DIGI_SETFLOW:
- if ((cmd) == (DIGI_SETFLOW))
- {
+ if (cmd == DIGI_SETFLOW) {
startc = ch->startc;
stopc = ch->stopc;
- }
- else
- {
+ } else {
startc = ch->startca;
stopc = ch->stopca;
}
@@ -3040,40 +2514,31 @@
if (copy_from_user(&dflow, argp, sizeof(dflow)))
return -EFAULT;
- if (dflow.startc != startc || dflow.stopc != stopc)
- { /* Begin if setflow toggled */
- cli();
+ if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if ((cmd) == (DIGI_SETFLOW))
- {
+ if (cmd == DIGI_SETFLOW) {
ch->fepstartc = ch->startc = dflow.startc;
ch->fepstopc = ch->stopc = dflow.stopc;
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
- }
- else
- {
+ } else {
ch->fepstartca = ch->startca = dflow.startc;
ch->fepstopca = ch->stopca = dflow.stopc;
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
- if (ch->statusflags & TXSTOPPED)
+ if (ch->statusflags & TXSTOPPED)
pc_start(tty);
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if setflow toggled */
break;
-
default:
return -ENOIOCTLCMD;
-
} /* End switch cmd */
-
return 0;
-
} /* End pc_ioctl */
/* --------------------- Begin pc_set_termios ----------------------- */
@@ -3083,20 +2548,16 @@
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
- save_flags(flags);
- cli();
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
epcaparam(tty, ch);
memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
((tty->termios->c_cflag & CRTSCTS) == 0))
@@ -3106,8 +2567,6 @@
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&ch->open_wait);
- restore_flags(flags);
-
} /* End if channel valid */
} /* End pc_set_termios */
@@ -3116,29 +2575,18 @@
static void do_softint(void *private_)
{ /* Begin do_softint */
-
struct channel *ch = (struct channel *) private_;
-
-
/* Called in response to a modem change event */
-
- if (ch && ch->magic == EPCA_MAGIC)
- { /* Begin EPCA_MAGIC */
-
+ if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */
struct tty_struct *tty = ch->tty;
- if (tty && tty->driver_data)
- {
- if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event))
- { /* Begin if clear_bit */
-
+ if (tty && tty->driver_data) {
+ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-
} /* End if clear_bit */
}
-
} /* End EPCA_MAGIC */
} /* End do_softint */
@@ -3154,82 +2602,49 @@
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if valid channel */
-
- save_flags(flags);
- cli();
-
- if ((ch->statusflags & TXSTOPPED) == 0)
- { /* Begin if transmit stop requested */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */
+ spin_lock_irqsave(&epca_lock, flags);
+ if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
globalwinon(ch);
-
/* STOP transmitting now !! */
-
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
-
ch->statusflags |= TXSTOPPED;
memoff(ch);
-
} /* End if transmit stop requested */
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if valid channel */
-
} /* End pc_stop */
/* --------------------- Begin pc_start ----------------------- */
static void pc_start(struct tty_struct *tty)
{ /* Begin pc_start */
-
struct channel *ch;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* Just in case output was resumed because of a change in Digi-flow */
- if (ch->statusflags & TXSTOPPED)
- { /* Begin transmit resume requested */
-
- volatile struct board_chan *bc;
-
+ if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */
+ struct board_chan *bc;
globalwinon(ch);
bc = ch->brdchan;
if (ch->statusflags & LOWWAIT)
- bc->ilow = 1;
-
+ writeb(1, &bc->ilow);
/* Okay, you can start transmitting again... */
-
fepcmd(ch, RESUMETX, 0, 0, 0, 0);
-
ch->statusflags &= ~TXSTOPPED;
memoff(ch);
-
} /* End transmit resume requested */
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_start */
/* ------------------------------------------------------------------
@@ -3244,86 +2659,55 @@
static void pc_throttle(struct tty_struct * tty)
{ /* Begin pc_throttle */
-
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
-
- save_flags(flags);
- cli();
-
- if ((ch->statusflags & RXSTOPPED) == 0)
- {
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ spin_lock_irqsave(&epca_lock, flags);
+ if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
fepcmd(ch, PAUSERX, 0, 0, 0, 0);
-
ch->statusflags |= RXSTOPPED;
memoff(ch);
}
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_throttle */
/* --------------------- Begin unthrottle ----------------------- */
static void pc_unthrottle(struct tty_struct *tty)
{ /* Begin pc_unthrottle */
-
struct channel *ch;
unsigned long flags;
- volatile struct board_chan *bc;
-
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
/* Just in case output was resumed because of a change in Digi-flow */
- save_flags(flags);
- cli();
-
- if (ch->statusflags & RXSTOPPED)
- {
-
+ spin_lock_irqsave(&epca_lock, flags);
+ if (ch->statusflags & RXSTOPPED) {
globalwinon(ch);
- bc = ch->brdchan;
fepcmd(ch, RESUMERX, 0, 0, 0, 0);
-
ch->statusflags &= ~RXSTOPPED;
memoff(ch);
}
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_unthrottle */
/* --------------------- Begin digi_send_break ----------------------- */
void digi_send_break(struct channel *ch, int msec)
{ /* Begin digi_send_break */
-
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
-
/* --------------------------------------------------------------------
Maybe I should send an infinite break here, schedule() for
msec amount of time, and then stop the break. This way,
@@ -3331,36 +2715,28 @@
to be called (i.e. via an ioctl()) more than once in msec amount
of time. Try this for now...
------------------------------------------------------------------------ */
-
fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
memoff(ch);
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End digi_send_break */
/* --------------------- Begin setup_empty_event ----------------------- */
+/* Caller MUST hold the lock */
+
static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
{ /* Begin setup_empty_event */
- volatile struct board_chan *bc = ch->brdchan;
- unsigned long int flags;
+ struct board_chan *bc = ch->brdchan;
- save_flags(flags);
- cli();
globalwinon(ch);
ch->statusflags |= EMPTYWAIT;
-
/* ------------------------------------------------------------------
When set the iempty flag request a event to be generated when the
transmit buffer is empty (If there is no BREAK in progress).
--------------------------------------------------------------------- */
-
- bc->iempty = 1;
+ writeb(1, &bc->iempty);
memoff(ch);
- restore_flags(flags);
-
} /* End setup_empty_event */
/* --------------------- Begin get_termio ----------------------- */
@@ -3369,10 +2745,10 @@
{ /* Begin get_termio */
return kernel_termios_to_user_termio(termio, tty->termios);
} /* End get_termio */
+
/* ---------------------- Begin epca_setup -------------------------- */
void epca_setup(char *str, int *ints)
{ /* Begin epca_setup */
-
struct board_info board;
int index, loop, last;
char *temp, *t2;
@@ -3394,49 +2770,41 @@
for (last = 0, index = 1; index <= ints[0]; index++)
switch(index)
{ /* Begin parse switch */
-
case 1:
board.status = ints[index];
-
/* ---------------------------------------------------------
We check for 2 (As opposed to 1; because 2 is a flag
instructing the driver to ignore epcaconfig.) For this
reason we check for 2.
------------------------------------------------------------ */
- if (board.status == 2)
- { /* Begin ignore epcaconfig as well as lilo cmd line */
+ if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
nbdevs = 0;
num_cards = 0;
return;
} /* End ignore epcaconfig as well as lilo cmd line */
- if (board.status > 2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+ if (board.status > 2) {
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
}
last = index;
break;
-
case 2:
board.type = ints[index];
- if (board.type >= PCIXEM)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+ if (board.type >= PCIXEM) {
+ printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_TYPE;
return;
}
last = index;
break;
-
case 3:
board.altpin = ints[index];
- if (board.altpin > 1)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+ if (board.altpin > 1) {
+ printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
invalid_lilo_config = 1;
setup_error_code |= INVALID_ALTPIN;
return;
@@ -3446,9 +2814,8 @@
case 4:
board.numports = ints[index];
- if ((board.numports < 2) || (board.numports > 256))
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+ if (board.numports < 2 || board.numports > 256) {
+ printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
invalid_lilo_config = 1;
setup_error_code |= INVALID_NUM_PORTS;
return;
@@ -3458,10 +2825,9 @@
break;
case 5:
- board.port = (unsigned char *)ints[index];
- if (ints[index] <= 0)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+ board.port = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
invalid_lilo_config = 1;
setup_error_code |= INVALID_PORT_BASE;
return;
@@ -3470,10 +2836,9 @@
break;
case 6:
- board.membase = (unsigned char *)ints[index];
- if (ints[index] <= 0)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ board.membase = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -3487,21 +2852,16 @@
} /* End parse switch */
- while (str && *str)
- { /* Begin while there is a string arg */
-
+ while (str && *str) { /* Begin while there is a string arg */
/* find the next comma or terminator */
temp = str;
-
/* While string is not null, and a comma hasn't been found */
while (*temp && (*temp != ','))
temp++;
-
if (!*temp)
temp = NULL;
else
*temp++ = 0;
-
/* Set index to the number of args + 1 */
index = last + 1;
@@ -3511,12 +2871,10 @@
len = strlen(str);
if (strncmp("Disable", str, len) == 0)
board.status = 0;
- else
- if (strncmp("Enable", str, len) == 0)
+ else if (strncmp("Enable", str, len) == 0)
board.status = 1;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
@@ -3525,22 +2883,17 @@
break;
case 2:
-
for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
if (strcmp(board_desc[loop], str) == 0)
break;
-
-
/* ---------------------------------------------------------------
If the index incremented above refers to a legitamate board
type set it here.
------------------------------------------------------------------*/
-
if (index < EPCA_NUM_TYPES)
board.type = loop;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_TYPE;
return;
@@ -3552,12 +2905,10 @@
len = strlen(str);
if (strncmp("Disable", str, len) == 0)
board.altpin = 0;
- else
- if (strncmp("Enable", str, len) == 0)
+ else if (strncmp("Enable", str, len) == 0)
board.altpin = 1;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_ALTPIN;
return;
@@ -3570,9 +2921,8 @@
while (isdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_NUM_PORTS;
return;
@@ -3601,15 +2951,14 @@
while (isxdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_PORT_BASE;
return;
}
- board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+ board.port = simple_strtoul(str, NULL, 16);
last = index;
break;
@@ -3618,52 +2967,38 @@
while (isxdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
}
-
- board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+ board.membase = simple_strtoul(str, NULL, 16);
last = index;
break;
-
default:
- printk(KERN_ERR "PC/Xx: Too many string parms\n");
+ printk(KERN_ERR "epca: Too many string parms\n");
return;
}
str = temp;
-
} /* End while there is a string arg */
-
- if (last < 6)
- {
- printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+ if (last < 6) {
+ printk(KERN_ERR "epca: Insufficient parms specified\n");
return;
}
/* I should REALLY validate the stuff here */
-
/* Copies our local copy of board into boards */
memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
-
-
/* Does this get called once per lilo arg are what ? */
-
printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
num_cards, board_desc[board.type],
board.numports, (int)board.port, (unsigned int) board.membase);
-
num_cards++;
-
} /* End epca_setup */
-
-#ifdef ENABLE_PCI
/* ------------------------ Begin init_PCI --------------------------- */
enum epic_board_types {
@@ -3685,7 +3020,6 @@
{ PCIXRJ, 2, },
};
-
static int __devinit epca_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -3711,10 +3045,8 @@
boards[board_idx].status = ENABLED;
boards[board_idx].type = epca_info_tbl[info_idx].board_type;
boards[board_idx].numports = 0x0;
- boards[board_idx].port =
- (unsigned char *)((char *) addr + PCI_IO_OFFSET);
- boards[board_idx].membase =
- (unsigned char *)((char *) addr);
+ boards[board_idx].port = addr + PCI_IO_OFFSET;
+ boards[board_idx].membase = addr;
if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
@@ -3775,15 +3107,13 @@
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
int __init init_PCI (void)
-{ /* Begin init_PCI */
+{ /* Begin init_PCI */
memset (&epca_driver, 0, sizeof (epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
epca_driver.probe = epca_init_one;
return pci_register_driver(&epca_driver);
-} /* End init_PCI */
-
-#endif /* ENABLE_PCI */
+}
MODULE_LICENSE("GPL");
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 52205ef..20eeb5a 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -85,73 +85,73 @@
struct channel
{
long magic;
- unchar boardnum;
- unchar channelnum;
- unchar omodem; /* FEP output modem status */
- unchar imodem; /* FEP input modem status */
- unchar modemfake; /* Modem values to be forced */
- unchar modem; /* Force values */
- unchar hflow;
- unchar dsr;
- unchar dcd;
- unchar m_rts ; /* The bits used in whatever FEP */
- unchar m_dcd ; /* is indiginous to this board to */
- unchar m_dsr ; /* represent each of the physical */
- unchar m_cts ; /* handshake lines */
- unchar m_ri ;
- unchar m_dtr ;
- unchar stopc;
- unchar startc;
- unchar stopca;
- unchar startca;
- unchar fepstopc;
- unchar fepstartc;
- unchar fepstopca;
- unchar fepstartca;
- unchar txwin;
- unchar rxwin;
- ushort fepiflag;
- ushort fepcflag;
- ushort fepoflag;
- ushort txbufhead;
- ushort txbufsize;
- ushort rxbufhead;
- ushort rxbufsize;
+ unsigned char boardnum;
+ unsigned char channelnum;
+ unsigned char omodem; /* FEP output modem status */
+ unsigned char imodem; /* FEP input modem status */
+ unsigned char modemfake; /* Modem values to be forced */
+ unsigned char modem; /* Force values */
+ unsigned char hflow;
+ unsigned char dsr;
+ unsigned char dcd;
+ unsigned char m_rts ; /* The bits used in whatever FEP */
+ unsigned char m_dcd ; /* is indiginous to this board to */
+ unsigned char m_dsr ; /* represent each of the physical */
+ unsigned char m_cts ; /* handshake lines */
+ unsigned char m_ri ;
+ unsigned char m_dtr ;
+ unsigned char stopc;
+ unsigned char startc;
+ unsigned char stopca;
+ unsigned char startca;
+ unsigned char fepstopc;
+ unsigned char fepstartc;
+ unsigned char fepstopca;
+ unsigned char fepstartca;
+ unsigned char txwin;
+ unsigned char rxwin;
+ unsigned short fepiflag;
+ unsigned short fepcflag;
+ unsigned short fepoflag;
+ unsigned short txbufhead;
+ unsigned short txbufsize;
+ unsigned short rxbufhead;
+ unsigned short rxbufsize;
int close_delay;
int count;
int blocked_open;
- ulong event;
+ unsigned long event;
int asyncflags;
uint dev;
- ulong statusflags;
- ulong c_iflag;
- ulong c_cflag;
- ulong c_lflag;
- ulong c_oflag;
- unchar *txptr;
- unchar *rxptr;
- unchar *tmp_buf;
+ unsigned long statusflags;
+ unsigned long c_iflag;
+ unsigned long c_cflag;
+ unsigned long c_lflag;
+ unsigned long c_oflag;
+ unsigned char *txptr;
+ unsigned char *rxptr;
+ unsigned char *tmp_buf;
struct board_info *board;
- volatile struct board_chan *brdchan;
+ struct board_chan *brdchan;
struct digi_struct digiext;
struct tty_struct *tty;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
- struct work_struct tqueue;
- volatile struct global_data *mailbox;
+ struct work_struct tqueue;
+ struct global_data *mailbox;
};
struct board_info
{
- unchar status;
- unchar type;
- unchar altpin;
- ushort numports;
- unchar *port;
- unchar *membase;
- unchar __iomem *re_map_port;
- unchar *re_map_membase;
- ulong memory_seg;
+ unsigned char status;
+ unsigned char type;
+ unsigned char altpin;
+ unsigned short numports;
+ unsigned long port;
+ unsigned long membase;
+ unsigned char __iomem *re_map_port;
+ unsigned char *re_map_membase;
+ unsigned long memory_seg;
void ( * memwinon ) (struct board_info *, unsigned int) ;
void ( * memwinoff ) (struct board_info *, unsigned int) ;
void ( * globalwinon ) (struct channel *) ;
@@ -160,6 +160,6 @@
void ( * memoff ) (struct channel *) ;
void ( * assertgwinon ) (struct channel *) ;
void ( * assertmemoff ) (struct channel *) ;
- unchar poller_inhibited ;
+ unsigned char poller_inhibited ;
};
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 762fa43..a695f25 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -44,7 +44,7 @@
/*
* The High Precision Event Timer driver.
* This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ * http://www.intel.com/hardwaredesign/hpetspec.htm
*/
#define HPET_USER_FREQ (64)
#define HPET_DRIFT (500)
@@ -712,7 +712,7 @@
ti->shift = 10;
ti->addr = &hpetp->hp_hpet->hpet_mc;
ti->frequency = hpet_time_div(hpets->hp_period);
- ti->drift = ti->frequency * HPET_DRIFT / 1000000;
+ ti->drift = HPET_DRIFT;
ti->mask = -1;
hpetp->hp_interpolator = ti;
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 5ce9c62..3386267 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -31,8 +31,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_BT_VERSION "v33"
-
static int bt_debug = 0x00; /* Production value 0, see following flags */
#define BT_DEBUG_ENABLE 1
@@ -163,7 +161,8 @@
{
unsigned int i;
- if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
+ if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH))
+ return -1;
if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
return -2;
@@ -171,7 +170,8 @@
if (bt_debug & BT_DEBUG_MSG) {
printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
- for (i = 0; i < size; i ++) printk (" %02x", data[i]);
+ for (i = 0; i < size; i ++)
+ printk (" %02x", data[i]);
printk("\n");
}
bt->write_data[0] = size + 1; /* all data plus seq byte */
@@ -210,15 +210,18 @@
} else {
data[0] = bt->read_data[1];
data[1] = bt->read_data[3];
- if (length < msg_len) bt->truncated = 1;
+ if (length < msg_len)
+ bt->truncated = 1;
if (bt->truncated) { /* can be set in read_all_bytes() */
data[2] = IPMI_ERR_MSG_TRUNCATED;
msg_len = 3;
- } else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
+ } else
+ memcpy(data + 2, bt->read_data + 4, msg_len - 2);
if (bt_debug & BT_DEBUG_MSG) {
printk (KERN_WARNING "BT: res (raw)");
- for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
+ for (i = 0; i < msg_len; i++)
+ printk(" %02x", data[i]);
printk ("\n");
}
}
@@ -231,8 +234,10 @@
static void reset_flags(struct si_sm_data *bt)
{
- if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
- if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
+ if (BT_STATUS & BT_H_BUSY)
+ BT_CONTROL(BT_H_BUSY);
+ if (BT_STATUS & BT_B_BUSY)
+ BT_CONTROL(BT_B_BUSY);
BT_CONTROL(BT_CLR_WR_PTR);
BT_CONTROL(BT_SMS_ATN);
#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
@@ -241,7 +246,8 @@
BT_CONTROL(BT_H_BUSY);
BT_CONTROL(BT_B2H_ATN);
BT_CONTROL(BT_CLR_RD_PTR);
- for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
+ for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++)
+ BMC2HOST;
BT_CONTROL(BT_H_BUSY);
}
#endif
@@ -258,7 +264,8 @@
printk (" %02x", bt->write_data[i]);
printk ("\n");
}
- for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
+ for (i = 0; i < bt->write_count; i++)
+ HOST2BMC(bt->write_data[i]);
}
static inline int read_all_bytes(struct si_sm_data *bt)
@@ -278,7 +285,8 @@
bt->truncated = 1;
return 1; /* let next XACTION START clean it up */
}
- for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;
+ for (i = 1; i <= bt->read_count; i++)
+ bt->read_data[i] = BMC2HOST;
bt->read_count++; /* account for the length byte */
if (bt_debug & BT_DEBUG_MSG) {
@@ -295,7 +303,8 @@
((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
return 1;
- if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
+ if (bt_debug & BT_DEBUG_MSG)
+ printk(KERN_WARNING "BT: bad packet: "
"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
bt->write_data[1], bt->write_data[2], bt->write_data[3],
bt->read_data[1], bt->read_data[2], bt->read_data[3]);
@@ -359,7 +368,8 @@
time);
bt->last_state = bt->state;
- if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
+ if (bt->state == BT_STATE_HOSED)
+ return SI_SM_HOSED;
if (bt->state != BT_STATE_IDLE) { /* do timeout test */
@@ -371,7 +381,8 @@
/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
(noticed in ipmi_smic_sm.c January 2004) */
- if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
+ if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT))
+ time = 100;
bt->timeout -= time;
if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
error_recovery(bt, "timed out");
@@ -393,12 +404,14 @@
BT_CONTROL(BT_H_BUSY);
break;
}
- if (status & BT_B2H_ATN) break;
+ if (status & BT_B2H_ATN)
+ break;
bt->state = BT_STATE_WRITE_BYTES;
return SI_SM_CALL_WITHOUT_DELAY; /* for logging */
case BT_STATE_WRITE_BYTES:
- if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
+ if (status & (BT_B_BUSY | BT_H2B_ATN))
+ break;
BT_CONTROL(BT_CLR_WR_PTR);
write_all_bytes(bt);
BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */
@@ -406,7 +419,8 @@
return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
- if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
+ if (status & (BT_H2B_ATN | BT_B_BUSY))
+ break;
bt->state = BT_STATE_B2H_WAIT;
/* fall through with status */
@@ -415,15 +429,18 @@
generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
case BT_STATE_B2H_WAIT:
- if (!(status & BT_B2H_ATN)) break;
+ if (!(status & BT_B2H_ATN))
+ break;
/* Assume ordered, uncached writes: no need to wait */
- if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
+ if (!(status & BT_H_BUSY))
+ BT_CONTROL(BT_H_BUSY); /* set */
BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */
BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */
i = read_all_bytes(bt);
BT_CONTROL(BT_H_BUSY); /* clear */
- if (!i) break; /* Try this state again */
+ if (!i) /* Try this state again */
+ break;
bt->state = BT_STATE_READ_END;
return SI_SM_CALL_WITHOUT_DELAY; /* for logging */
@@ -436,7 +453,8 @@
#ifdef MAKE_THIS_TRUE_IF_NECESSARY
- if (status & BT_H_BUSY) break;
+ if (status & BT_H_BUSY)
+ break;
#endif
bt->seq++;
bt->state = BT_STATE_IDLE;
@@ -459,7 +477,8 @@
break;
case BT_STATE_RESET3:
- if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
+ if (bt->timeout > 0)
+ return SI_SM_CALL_WITH_DELAY;
bt->state = BT_STATE_RESTART; /* printk in debug modes */
break;
@@ -485,7 +504,8 @@
but that's what you get from reading a bogus address, so we
test that first. The calling routine uses negative logic. */
- if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
+ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
+ return 1;
reset_flags(bt);
return 0;
}
@@ -501,7 +521,6 @@
struct si_sm_handlers bt_smi_handlers =
{
- .version = IPMI_BT_VERSION,
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index e0a5357..883ac43 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -47,8 +47,6 @@
#include <linux/device.h>
#include <linux/compat.h>
-#define IPMI_DEVINTF_VERSION "v33"
-
struct ipmi_file_private
{
ipmi_user_t user;
@@ -411,6 +409,7 @@
break;
}
+ /* The next four are legacy, not per-channel. */
case IPMICTL_SET_MY_ADDRESS_CMD:
{
unsigned int val;
@@ -420,22 +419,25 @@
break;
}
- ipmi_set_my_address(priv->user, val);
- rv = 0;
+ rv = ipmi_set_my_address(priv->user, 0, val);
break;
}
case IPMICTL_GET_MY_ADDRESS_CMD:
{
- unsigned int val;
+ unsigned int val;
+ unsigned char rval;
- val = ipmi_get_my_address(priv->user);
+ rv = ipmi_get_my_address(priv->user, 0, &rval);
+ if (rv)
+ break;
+
+ val = rval;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
- rv = 0;
break;
}
@@ -448,24 +450,94 @@
break;
}
- ipmi_set_my_LUN(priv->user, val);
- rv = 0;
+ rv = ipmi_set_my_LUN(priv->user, 0, val);
break;
}
case IPMICTL_GET_MY_LUN_CMD:
{
- unsigned int val;
+ unsigned int val;
+ unsigned char rval;
- val = ipmi_get_my_LUN(priv->user);
+ rv = ipmi_get_my_LUN(priv->user, 0, &rval);
+ if (rv)
+ break;
+
+ val = rval;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
- rv = 0;
break;
}
+
+ case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ return ipmi_set_my_address(priv->user, val.channel, val.value);
+ break;
+ }
+
+ case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
+ if (rv)
+ break;
+
+ if (copy_to_user(arg, &val, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
+ break;
+ }
+
+ case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
+ if (rv)
+ break;
+
+ if (copy_to_user(arg, &val, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+ break;
+ }
+
case IPMICTL_SET_TIMING_PARMS_CMD:
{
struct ipmi_timing_parms parms;
@@ -748,8 +820,7 @@
if (ipmi_major < 0)
return -EINVAL;
- printk(KERN_INFO "ipmi device interface version "
- IPMI_DEVINTF_VERSION "\n");
+ printk(KERN_INFO "ipmi device interface\n");
ipmi_class = class_create(THIS_MODULE, "ipmi");
if (IS_ERR(ipmi_class)) {
@@ -792,3 +863,5 @@
module_exit(cleanup_ipmi);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index 48cce24..d21853a 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -42,8 +42,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_KCS_VERSION "v33"
-
/* Set this if you want a printout of why the state machine was hosed
when it gets hosed. */
#define DEBUG_HOSED_REASON
@@ -489,7 +487,6 @@
struct si_sm_handlers kcs_smi_handlers =
{
- .version = IPMI_KCS_VERSION,
.init_data = init_kcs_data,
.start_transaction = start_kcs_transaction,
.get_result = get_kcs_result,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index e16c13f..463351d 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -47,7 +47,8 @@
#include <linux/proc_fs.h>
#define PFX "IPMI message handler: "
-#define IPMI_MSGHANDLER_VERSION "v33"
+
+#define IPMI_DRIVER_VERSION "36.0"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
@@ -116,7 +117,7 @@
do { \
seq = ((msgid >> 26) & 0x3f); \
seqid = (msgid & 0x3fffff); \
- } while(0)
+ } while (0)
#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
@@ -124,6 +125,14 @@
{
unsigned char medium;
unsigned char protocol;
+
+ /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
+ but may be changed by the user. */
+ unsigned char address;
+
+ /* My LUN. This should generally stay the SMS LUN, but just in
+ case... */
+ unsigned char lun;
};
#ifdef CONFIG_PROC_FS
@@ -135,7 +144,7 @@
#endif
#define IPMI_IPMB_NUM_SEQ 64
-#define IPMI_MAX_CHANNELS 8
+#define IPMI_MAX_CHANNELS 16
struct ipmi_smi
{
/* What interface number are we? */
@@ -193,20 +202,6 @@
struct list_head waiting_events;
unsigned int waiting_events_count; /* How many events in queue? */
- /* This will be non-null if someone registers to receive all
- IPMI commands (this is for interface emulation). There
- may not be any things in the cmd_rcvrs list above when
- this is registered. */
- ipmi_user_t all_cmd_rcvr;
-
- /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
- but may be changed by the user. */
- unsigned char my_address;
-
- /* My LUN. This should generally stay the SMS LUN, but just in
- case... */
- unsigned char my_lun;
-
/* The event receiver for my BMC, only really used at panic
shutdown as a place to store this. */
unsigned char event_receiver;
@@ -218,7 +213,7 @@
interface comes in with a NULL user, call this routine with
it. Note that the message will still be freed by the
caller. This only works on the system interface. */
- void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
+ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
/* When we are scanning the channels for an SMI, this will
tell which channel we are scanning. */
@@ -325,7 +320,7 @@
down_read(&interfaces_sem);
down_write(&smi_watchers_sem);
list_add(&(watcher->link), &smi_watchers);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] != NULL) {
watcher->new_smi(i);
}
@@ -458,7 +453,27 @@
static void deliver_response(struct ipmi_recv_msg *msg)
{
- msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+ if (! msg->user) {
+ ipmi_smi_t intf = msg->user_msg_data;
+ unsigned long flags;
+
+ /* Special handling for NULL users. */
+ if (intf->null_user_handler) {
+ intf->null_user_handler(intf, msg);
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->handled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ } else {
+ /* No handler, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ }
+ ipmi_free_recv_msg(msg);
+ } else {
+ msg->user->handler->ipmi_recv_hndl(msg,
+ msg->user->handler_data);
+ }
}
/* Find the next sequence number not being used and add the given
@@ -475,9 +490,9 @@
int rv = 0;
unsigned int i;
- for (i=intf->curr_seq;
+ for (i = intf->curr_seq;
(i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
- i=(i+1)%IPMI_IPMB_NUM_SEQ)
+ i = (i+1)%IPMI_IPMB_NUM_SEQ)
{
if (! intf->seq_table[i].inuse)
break;
@@ -712,7 +727,7 @@
/* Remove the user from the interfaces sequence table. */
spin_lock_irqsave(&(user->intf->seq_lock), flags);
- for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+ for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if (user->intf->seq_table[i].inuse
&& (user->intf->seq_table[i].recv_msg->user == user))
{
@@ -766,26 +781,44 @@
*minor = user->intf->version_minor;
}
-void ipmi_set_my_address(ipmi_user_t user,
- unsigned char address)
+int ipmi_set_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char address)
{
- user->intf->my_address = address;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ user->intf->channels[channel].address = address;
+ return 0;
}
-unsigned char ipmi_get_my_address(ipmi_user_t user)
+int ipmi_get_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address)
{
- return user->intf->my_address;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *address = user->intf->channels[channel].address;
+ return 0;
}
-void ipmi_set_my_LUN(ipmi_user_t user,
- unsigned char LUN)
+int ipmi_set_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char LUN)
{
- user->intf->my_lun = LUN & 0x3;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ user->intf->channels[channel].lun = LUN & 0x3;
+ return 0;
}
-unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+int ipmi_get_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address)
{
- return user->intf->my_lun;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *address = user->intf->channels[channel].lun;
+ return 0;
}
int ipmi_set_gets_events(ipmi_user_t user, int val)
@@ -828,11 +861,6 @@
read_lock(&(user->intf->users_lock));
write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
- if (user->intf->all_cmd_rcvr != NULL) {
- rv = -EBUSY;
- goto out_unlock;
- }
-
/* Make sure the command/netfn is not already registered. */
list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
@@ -847,7 +875,7 @@
rcvr->user = user;
list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
}
- out_unlock:
+
write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
read_unlock(&(user->intf->users_lock));
@@ -1213,7 +1241,7 @@
unsigned char ipmb_seq;
long seqid;
- if (addr->channel > IPMI_NUM_CHANNELS) {
+ if (addr->channel >= IPMI_NUM_CHANNELS) {
spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags);
@@ -1331,7 +1359,7 @@
#ifdef DEBUG_MSGING
{
int m;
- for (m=0; m<smi_msg->data_size; m++)
+ for (m = 0; m < smi_msg->data_size; m++)
printk(" %2.2x", smi_msg->data[m]);
printk("\n");
}
@@ -1346,6 +1374,18 @@
return rv;
}
+static int check_addr(ipmi_smi_t intf,
+ struct ipmi_addr *addr,
+ unsigned char *saddr,
+ unsigned char *lun)
+{
+ if (addr->channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *lun = intf->channels[addr->channel].lun;
+ *saddr = intf->channels[addr->channel].address;
+ return 0;
+}
+
int ipmi_request_settime(ipmi_user_t user,
struct ipmi_addr *addr,
long msgid,
@@ -1355,6 +1395,14 @@
int retries,
unsigned int retry_time_ms)
{
+ unsigned char saddr, lun;
+ int rv;
+
+ if (! user)
+ return -EINVAL;
+ rv = check_addr(user->intf, addr, &saddr, &lun);
+ if (rv)
+ return rv;
return i_ipmi_request(user,
user->intf,
addr,
@@ -1363,8 +1411,8 @@
user_msg_data,
NULL, NULL,
priority,
- user->intf->my_address,
- user->intf->my_lun,
+ saddr,
+ lun,
retries,
retry_time_ms);
}
@@ -1378,6 +1426,14 @@
struct ipmi_recv_msg *supplied_recv,
int priority)
{
+ unsigned char saddr, lun;
+ int rv;
+
+ if (! user)
+ return -EINVAL;
+ rv = check_addr(user->intf, addr, &saddr, &lun);
+ if (rv)
+ return rv;
return i_ipmi_request(user,
user->intf,
addr,
@@ -1387,8 +1443,8 @@
supplied_smi,
supplied_recv,
priority,
- user->intf->my_address,
- user->intf->my_lun,
+ saddr,
+ lun,
-1, 0);
}
@@ -1397,8 +1453,15 @@
{
char *out = (char *) page;
ipmi_smi_t intf = data;
+ int i;
+ int rv= 0;
- return sprintf(out, "%x\n", intf->my_address);
+ for (i = 0; i < IPMI_MAX_CHANNELS; i++)
+ rv += sprintf(out+rv, "%x ", intf->channels[i].address);
+ out[rv-1] = '\n'; /* Replace the final space with a newline */
+ out[rv] = '\0';
+ rv++;
+ return rv;
}
static int version_file_read_proc(char *page, char **start, off_t off,
@@ -1588,29 +1651,30 @@
(struct ipmi_addr *) &si,
0,
&msg,
- NULL,
+ intf,
NULL,
NULL,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
-1, 0);
}
static void
-channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
int rv = 0;
int chan;
- if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
{
/* It's the one we want */
- if (msg->rsp[2] != 0) {
+ if (msg->msg.data[0] != 0) {
/* Got an error from the channel, just go on. */
- if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
+ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
/* If the MC does not support this
command, that is legal. We just
assume it has one IPMB at channel
@@ -1627,13 +1691,13 @@
}
goto next_channel;
}
- if (msg->rsp_size < 6) {
+ if (msg->msg.data_len < 4) {
/* Message not big enough, just go on. */
goto next_channel;
}
chan = intf->curr_channel;
- intf->channels[chan].medium = msg->rsp[4] & 0x7f;
- intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
+ intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
+ intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
next_channel:
intf->curr_channel++;
@@ -1691,22 +1755,24 @@
rv = -ENOMEM;
down_write(&interfaces_sem);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == NULL) {
new_intf->intf_num = i;
new_intf->version_major = version_major;
new_intf->version_minor = version_minor;
- if (slave_addr == 0)
- new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
- else
- new_intf->my_address = slave_addr;
- new_intf->my_lun = 2; /* the SMS LUN. */
+ for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
+ new_intf->channels[j].address
+ = IPMI_BMC_SLAVE_ADDR;
+ new_intf->channels[j].lun = 2;
+ }
+ if (slave_addr != 0)
+ new_intf->channels[0].address = slave_addr;
rwlock_init(&(new_intf->users_lock));
INIT_LIST_HEAD(&(new_intf->users));
new_intf->handlers = handlers;
new_intf->send_info = send_info;
spin_lock_init(&(new_intf->seq_lock));
- for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+ for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
new_intf->seq_table[j].inuse = 0;
new_intf->seq_table[j].seqid = 0;
}
@@ -1722,7 +1788,6 @@
rwlock_init(&(new_intf->cmd_rcvr_lock));
init_waitqueue_head(&new_intf->waitq);
INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
- new_intf->all_cmd_rcvr = NULL;
spin_lock_init(&(new_intf->counter_lock));
@@ -1814,7 +1879,7 @@
free_recv_msg_list(&(intf->waiting_events));
free_cmd_rcvr_list(&(intf->cmd_rcvrs));
- for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+ for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if ((intf->seq_table[i].inuse)
&& (intf->seq_table[i].recv_msg))
{
@@ -1833,7 +1898,7 @@
down_write(&interfaces_sem);
if (list_empty(&(intf->users)))
{
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == intf) {
remove_proc_entries(intf);
spin_lock_irqsave(&interfaces_lock, flags);
@@ -1960,15 +2025,11 @@
read_lock(&(intf->cmd_rcvr_lock));
- if (intf->all_cmd_rcvr) {
- user = intf->all_cmd_rcvr;
- } else {
- /* Find the command/netfn. */
- list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
- user = rcvr->user;
- break;
- }
+ /* Find the command/netfn. */
+ list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ user = rcvr->user;
+ break;
}
}
read_unlock(&(intf->cmd_rcvr_lock));
@@ -1985,7 +2046,7 @@
msg->data[3] = msg->rsp[6];
msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
- msg->data[6] = intf->my_address;
+ msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
/* rqseq/lun */
msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
msg->data[8] = msg->rsp[8]; /* cmd */
@@ -1997,7 +2058,7 @@
{
int m;
printk("Invalid command:");
- for (m=0; m<msg->data_size; m++)
+ for (m = 0; m < msg->data_size; m++)
printk(" %2.2x", msg->data[m]);
printk("\n");
}
@@ -2145,15 +2206,11 @@
read_lock(&(intf->cmd_rcvr_lock));
- if (intf->all_cmd_rcvr) {
- user = intf->all_cmd_rcvr;
- } else {
- /* Find the command/netfn. */
- list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
- user = rcvr->user;
- break;
- }
+ /* Find the command/netfn. */
+ list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ user = rcvr->user;
+ break;
}
}
read_unlock(&(intf->cmd_rcvr_lock));
@@ -2330,6 +2387,14 @@
unsigned long flags;
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+ if (recv_msg == NULL)
+ {
+ printk(KERN_WARNING"IPMI message received with no owner. This\n"
+ "could be because of a malformed message, or\n"
+ "because of a hardware error. Contact your\n"
+ "hardware vender for assistance\n");
+ return 0;
+ }
/* Make sure the user still exists. */
list_for_each_entry(user, &(intf->users), link) {
@@ -2340,19 +2405,11 @@
}
}
- if (!found) {
- /* Special handling for NULL users. */
- if (!recv_msg->user && intf->null_user_handler){
- intf->null_user_handler(intf, msg);
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
- }else{
- /* The user for the message went away, so give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
- }
+ if ((! found) && recv_msg->user) {
+ /* The user for the message went away, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
@@ -2392,7 +2449,7 @@
#ifdef DEBUG_MSGING
int m;
printk("Recv:");
- for (m=0; m<msg->rsp_size; m++)
+ for (m = 0; m < msg->rsp_size; m++)
printk(" %2.2x", msg->rsp[m]);
printk("\n");
#endif
@@ -2626,7 +2683,7 @@
{
int m;
printk("Resend: ");
- for (m=0; m<smi_msg->data_size; m++)
+ for (m = 0; m < smi_msg->data_size; m++)
printk(" %2.2x", smi_msg->data[m]);
printk("\n");
}
@@ -2647,7 +2704,7 @@
INIT_LIST_HEAD(&timeouts);
spin_lock(&interfaces_lock);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2672,7 +2729,7 @@
have timed out, putting them in the timeouts
list. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+ for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
struct seq_table *ent = &(intf->seq_table[j]);
if (!ent->inuse)
continue;
@@ -2712,7 +2769,7 @@
spin_unlock(&intf->counter_lock);
smi_msg = smi_from_recv_msg(intf,
ent->recv_msg, j, ent->seqid);
- if(!smi_msg)
+ if (! smi_msg)
continue;
spin_unlock_irqrestore(&(intf->seq_lock),flags);
@@ -2743,7 +2800,7 @@
int i;
spin_lock(&interfaces_lock);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2838,28 +2895,30 @@
}
#ifdef CONFIG_IPMI_PANIC_STRING
-static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
- if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
- && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
{
/* A get event receiver command, save it. */
- intf->event_receiver = msg->rsp[3];
- intf->event_receiver_lun = msg->rsp[4] & 0x3;
+ intf->event_receiver = msg->msg.data[1];
+ intf->event_receiver_lun = msg->msg.data[2] & 0x3;
}
}
-static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
- if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
- && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
{
/* A get device id command, save if we are an event
receiver or generator. */
- intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
- intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
+ intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
}
}
#endif
@@ -2903,7 +2962,7 @@
recv_msg.done = dummy_recv_done_handler;
/* For every registered interface, send the event. */
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2915,12 +2974,12 @@
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
}
@@ -2930,7 +2989,7 @@
if (!str)
return;
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
char *p = str;
struct ipmi_ipmb_addr *ipmb;
int j;
@@ -2961,12 +3020,12 @@
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
if (intf->local_event_generator) {
@@ -2981,12 +3040,12 @@
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
intf->null_user_handler = NULL;
@@ -2996,7 +3055,7 @@
be zero, and it must not be my address. */
if (((intf->event_receiver & 1) == 0)
&& (intf->event_receiver != 0)
- && (intf->event_receiver != intf->my_address))
+ && (intf->event_receiver != intf->channels[0].address))
{
/* The event receiver is valid, send an IPMB
message. */
@@ -3031,7 +3090,7 @@
data[0] = 0;
data[1] = 0;
data[2] = 0xf0; /* OEM event without timestamp. */
- data[3] = intf->my_address;
+ data[3] = intf->channels[0].address;
data[4] = j++; /* sequence # */
/* Always give 11 bytes, so strncpy will fill
it with zeroes for me. */
@@ -3043,12 +3102,12 @@
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
}
@@ -3070,7 +3129,7 @@
has_paniced = 1;
/* For every registered interface, set it to run to completion. */
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -3099,9 +3158,9 @@
return 0;
printk(KERN_INFO "ipmi message handler version "
- IPMI_MSGHANDLER_VERSION "\n");
+ IPMI_DRIVER_VERSION "\n");
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
ipmi_interfaces[i] = NULL;
}
@@ -3171,6 +3230,9 @@
module_init(ipmi_init_msghandler_mod);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
+MODULE_VERSION(IPMI_DRIVER_VERSION);
EXPORT_SYMBOL(ipmi_create_user);
EXPORT_SYMBOL(ipmi_destroy_user);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index f951c30..e82a96b 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -42,7 +42,6 @@
#include <linux/ipmi_smi.h>
#define PFX "IPMI poweroff: "
-#define IPMI_POWEROFF_VERSION "v33"
/* Where to we insert our poweroff function? */
extern void (*pm_power_off)(void);
@@ -53,16 +52,17 @@
#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
/* the IPMI data command */
-static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+static int poweroff_powercycle;
/* parameter definition to allow user to flag power cycle */
-module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
-MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+module_param(poweroff_powercycle, int, 0);
+MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
/* Stuff from the get device id command. */
static unsigned int mfg_id;
static unsigned int prod_id;
static unsigned char capabilities;
+static unsigned char ipmi_version;
/* We use our own messages for this operation, we don't let the system
allocate them, since we may be in a panic situation. The whole
@@ -338,6 +338,25 @@
}
/*
+ * ipmi_dell_chassis_detect()
+ * Dell systems with IPMI < 1.5 don't set the chassis capability bit
+ * but they can handle a chassis poweroff or powercycle command.
+ */
+
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static int ipmi_dell_chassis_detect (ipmi_user_t user)
+{
+ const char ipmi_version_major = ipmi_version & 0xF;
+ const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
+ const char mfr[3]=DELL_IANA_MFR_ID;
+ if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
+ ipmi_version_major <= 1 &&
+ ipmi_version_minor < 5)
+ return 1;
+ return 0;
+}
+
+/*
* Standard chassis support
*/
@@ -366,37 +385,34 @@
powercyclefailed:
printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
- ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
+ (poweroff_powercycle ? "cycle" : "down"));
/*
* Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
- data[0] = poweroff_control;
+ if (poweroff_powercycle)
+ data[0] = IPMI_CHASSIS_POWER_CYCLE;
+ else
+ data[0] = IPMI_CHASSIS_POWER_DOWN;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
if (rv) {
- switch (poweroff_control) {
- case IPMI_CHASSIS_POWER_CYCLE:
- /* power cycle failed, default to power down */
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "cycle message, IPMI error 0x%x\n", rv);
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- goto powercyclefailed;
-
- case IPMI_CHASSIS_POWER_DOWN:
- default:
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "down message, IPMI error 0x%x\n", rv);
- break;
+ if (poweroff_powercycle) {
+ /* power cycle failed, default to power down */
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "cycle message, IPMI error 0x%x\n", rv);
+ poweroff_powercycle = 0;
+ goto powercyclefailed;
}
- }
- return;
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "down message, IPMI error 0x%x\n", rv);
+ }
}
@@ -414,6 +430,9 @@
{ .platform_type = "CPI1",
.detect = ipmi_cpi1_detect,
.poweroff_func = ipmi_poweroff_cpi1 },
+ { .platform_type = "chassis",
+ .detect = ipmi_dell_chassis_detect,
+ .poweroff_func = ipmi_poweroff_chassis },
/* Chassis should generally be last, other things should override
it. */
{ .platform_type = "chassis",
@@ -499,10 +518,11 @@
prod_id = (halt_recv_msg.msg.data[10]
| (halt_recv_msg.msg.data[11] << 8));
capabilities = halt_recv_msg.msg.data[6];
+ ipmi_version = halt_recv_msg.msg.data[5];
/* Scan for a poweroff method */
- for (i=0; i<NUM_PO_FUNCS; i++) {
+ for (i = 0; i < NUM_PO_FUNCS; i++) {
if (poweroff_functions[i].detect(ipmi_user))
goto found;
}
@@ -538,39 +558,35 @@
#ifdef CONFIG_PROC_FS
-/* displays properties to proc */
-static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
- poweroff_control);
-}
+#include <linux/sysctl.h>
-/* process property writes from proc */
-static int proc_write_chassctrl(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- int rv = count;
- unsigned int newval = 0;
+static ctl_table ipmi_table[] = {
+ { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE,
+ .procname = "poweroff_powercycle",
+ .data = &poweroff_powercycle,
+ .maxlen = sizeof(poweroff_powercycle),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec },
+ { }
+};
- sscanf(buffer, "%d", &newval);
- switch (newval) {
- case IPMI_CHASSIS_POWER_CYCLE:
- printk(KERN_INFO PFX "power cycle is now enabled\n");
- poweroff_control = newval;
- break;
+static ctl_table ipmi_dir_table[] = {
+ { .ctl_name = DEV_IPMI,
+ .procname = "ipmi",
+ .mode = 0555,
+ .child = ipmi_table },
+ { }
+};
- case IPMI_CHASSIS_POWER_DOWN:
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- break;
+static ctl_table ipmi_root_table[] = {
+ { .ctl_name = CTL_DEV,
+ .procname = "dev",
+ .mode = 0555,
+ .child = ipmi_dir_table },
+ { }
+};
- default:
- rv = -EINVAL;
- break;
- }
-
- return rv;
-}
+static struct ctl_table_header *ipmi_table_header;
#endif /* CONFIG_PROC_FS */
/*
@@ -578,42 +594,32 @@
*/
static int ipmi_poweroff_init (void)
{
- int rv;
- struct proc_dir_entry *file;
+ int rv;
printk ("Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot version "
- IPMI_POWEROFF_VERSION ".\n");
+ " IPMI Powerdown via sys_reboot.\n");
- switch (poweroff_control) {
- case IPMI_CHASSIS_POWER_CYCLE:
- printk(KERN_INFO PFX "Power cycle is enabled.\n");
- break;
+ if (poweroff_powercycle)
+ printk(KERN_INFO PFX "Power cycle is enabled.\n");
- case IPMI_CHASSIS_POWER_DOWN:
- default:
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- break;
+#ifdef CONFIG_PROC_FS
+ ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
+ if (!ipmi_table_header) {
+ printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
+ rv = -ENOMEM;
+ goto out_err;
}
+#endif
+#ifdef CONFIG_PROC_FS
rv = ipmi_smi_watcher_register(&smi_watcher);
+#endif
if (rv) {
+ unregister_sysctl_table(ipmi_table_header);
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
goto out_err;
}
-#ifdef CONFIG_PROC_FS
- file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
- if (!file) {
- printk(KERN_ERR PFX "Unable to create proc power control\n");
- } else {
- file->nlink = 1;
- file->read_proc = proc_read_chassctrl;
- file->write_proc = proc_write_chassctrl;
- file->owner = THIS_MODULE;
- }
-#endif
-
out_err:
return rv;
}
@@ -624,7 +630,7 @@
int rv;
#ifdef CONFIG_PROC_FS
- remove_proc_entry("poweroff_control", proc_ipmi_root);
+ unregister_sysctl_table(ipmi_table_header);
#endif
ipmi_smi_watcher_unregister(&smi_watcher);
@@ -642,3 +648,5 @@
module_init(ipmi_poweroff_init);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index a44b973..1abec68 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -61,11 +61,11 @@
# endif
static inline void add_usec_to_timer(struct timer_list *t, long v)
{
- t->sub_expires += nsec_to_arch_cycle(v * 1000);
- while (t->sub_expires >= arch_cycles_per_jiffy)
+ t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
+ while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
{
t->expires++;
- t->sub_expires -= arch_cycles_per_jiffy;
+ t->arch_cycle_expires -= arch_cycles_per_jiffy;
}
}
#endif
@@ -75,8 +75,7 @@
#include <asm/io.h>
#include "ipmi_si_sm.h"
#include <linux/init.h>
-
-#define IPMI_SI_VERSION "v33"
+#include <linux/dmi.h>
/* Measure times between events in the driver. */
#undef DEBUG_TIMING
@@ -109,6 +108,21 @@
SI_KCS, SI_SMIC, SI_BT
};
+struct ipmi_device_id {
+ unsigned char device_id;
+ unsigned char device_revision;
+ unsigned char firmware_revision_1;
+ unsigned char firmware_revision_2;
+ unsigned char ipmi_version;
+ unsigned char additional_device_support;
+ unsigned char manufacturer_id[3];
+ unsigned char product_id[2];
+ unsigned char aux_firmware_revision[4];
+} __attribute__((packed));
+
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
struct smi_info
{
ipmi_smi_t intf;
@@ -131,12 +145,24 @@
void (*irq_cleanup)(struct smi_info *info);
unsigned int io_size;
+ /* Per-OEM handler, called from handle_flags().
+ Returns 1 when handle_flags() needs to be re-run
+ or 0 indicating it set si_state itself.
+ */
+ int (*oem_data_avail_handler)(struct smi_info *smi_info);
+
/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
is set to hold the flags until we are done handling everything
from the flags. */
#define RECEIVE_MSG_AVAIL 0x01
#define EVENT_MSG_BUFFER_FULL 0x02
#define WDT_PRE_TIMEOUT_INT 0x08
+#define OEM0_DATA_AVAIL 0x20
+#define OEM1_DATA_AVAIL 0x40
+#define OEM2_DATA_AVAIL 0x80
+#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \
+ OEM1_DATA_AVAIL | \
+ OEM2_DATA_AVAIL)
unsigned char msg_flags;
/* If set to true, this will request events the next time the
@@ -175,11 +201,7 @@
interrupts. */
int interrupt_disabled;
- unsigned char ipmi_si_dev_rev;
- unsigned char ipmi_si_fw_rev_major;
- unsigned char ipmi_si_fw_rev_minor;
- unsigned char ipmi_version_major;
- unsigned char ipmi_version_minor;
+ struct ipmi_device_id device_id;
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
@@ -245,7 +267,7 @@
entry = smi_info->xmit_msgs.next;
}
- if (!entry) {
+ if (! entry) {
smi_info->curr_msg = NULL;
rv = SI_SM_IDLE;
} else {
@@ -306,7 +328,7 @@
memory, we will re-enable the interrupt. */
static inline void disable_si_irq(struct smi_info *smi_info)
{
- if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
+ if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
disable_irq_nosync(smi_info->irq);
smi_info->interrupt_disabled = 1;
}
@@ -322,6 +344,7 @@
static void handle_flags(struct smi_info *smi_info)
{
+ retry:
if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
/* Watchdog pre-timeout */
spin_lock(&smi_info->count_lock);
@@ -336,7 +359,7 @@
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
- if (!smi_info->curr_msg) {
+ if (! smi_info->curr_msg) {
disable_si_irq(smi_info);
smi_info->si_state = SI_NORMAL;
return;
@@ -355,7 +378,7 @@
} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
/* Events available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
- if (!smi_info->curr_msg) {
+ if (! smi_info->curr_msg) {
disable_si_irq(smi_info);
smi_info->si_state = SI_NORMAL;
return;
@@ -371,6 +394,10 @@
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
+ } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
+ if (smi_info->oem_data_avail_handler)
+ if (smi_info->oem_data_avail_handler(smi_info))
+ goto retry;
} else {
smi_info->si_state = SI_NORMAL;
}
@@ -387,7 +414,7 @@
#endif
switch (smi_info->si_state) {
case SI_NORMAL:
- if (!smi_info->curr_msg)
+ if (! smi_info->curr_msg)
break;
smi_info->curr_msg->rsp_size
@@ -761,18 +788,20 @@
#if defined(CONFIG_HIGH_RES_TIMERS)
unsigned long flags;
unsigned long jiffies_now;
+ unsigned long seq;
if (del_timer(&(smi_info->si_timer))) {
/* If we don't delete the timer, then it will go off
immediately, anyway. So we only process if we
actually delete the timer. */
- /* We already have irqsave on, so no need for it
- here. */
- read_lock(&xtime_lock);
- jiffies_now = jiffies;
- smi_info->si_timer.expires = jiffies_now;
- smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ jiffies_now = jiffies;
+ smi_info->si_timer.expires = jiffies_now;
+ smi_info->si_timer.arch_cycle_expires
+ = get_arch_cycles(jiffies_now);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
@@ -826,15 +855,19 @@
/* If the state machine asks for a short delay, then shorten
the timer timeout. */
if (smi_result == SI_SM_CALL_WITH_DELAY) {
+#if defined(CONFIG_HIGH_RES_TIMERS)
+ unsigned long seq;
+#endif
spin_lock_irqsave(&smi_info->count_lock, flags);
smi_info->short_timeouts++;
spin_unlock_irqrestore(&smi_info->count_lock, flags);
#if defined(CONFIG_HIGH_RES_TIMERS)
- read_lock(&xtime_lock);
- smi_info->si_timer.expires = jiffies;
- smi_info->si_timer.sub_expires
- = get_arch_cycles(smi_info->si_timer.expires);
- read_unlock(&xtime_lock);
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ smi_info->si_timer.expires = jiffies;
+ smi_info->si_timer.arch_cycle_expires
+ = get_arch_cycles(smi_info->si_timer.expires);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
#else
smi_info->si_timer.expires = jiffies + 1;
@@ -845,7 +878,7 @@
spin_unlock_irqrestore(&smi_info->count_lock, flags);
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
#if defined(CONFIG_HIGH_RES_TIMERS)
- smi_info->si_timer.sub_expires = 0;
+ smi_info->si_timer.arch_cycle_expires = 0;
#endif
}
@@ -1014,7 +1047,7 @@
{
int rv;
- if (!info->irq)
+ if (! info->irq)
return 0;
if (info->si_type == SI_BT) {
@@ -1023,7 +1056,7 @@
SA_INTERRUPT,
DEVICE_NAME,
info);
- if (!rv)
+ if (! rv)
/* Enable the interrupt in the BT interface. */
info->io.outputb(&info->io, IPMI_BT_INTMASK_REG,
IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
@@ -1048,7 +1081,7 @@
static void std_irq_cleanup(struct smi_info *info)
{
- if (!info->irq)
+ if (! info->irq)
return;
if (info->si_type == SI_BT)
@@ -1121,7 +1154,7 @@
unsigned int *addr = info->io.info;
int mapsize;
- if (!addr || (!*addr))
+ if (! addr || (! *addr))
return -ENODEV;
info->io_cleanup = port_cleanup;
@@ -1164,15 +1197,15 @@
{
struct smi_info *info;
- if (!ports[intf_num])
+ if (! ports[intf_num])
return -ENODEV;
- if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
+ if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
ports[intf_num]))
return -ENODEV;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
return -ENOMEM;
}
@@ -1182,10 +1215,10 @@
info->io.info = &(ports[intf_num]);
info->io.addr = NULL;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[intf_num];
- if (!info->io.regsize)
+ if (! info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
info->irq = 0;
@@ -1270,7 +1303,7 @@
unsigned long *addr = info->io.info;
int mapsize;
- if (!addr || (!*addr))
+ if (! addr || (! *addr))
return -ENODEV;
info->io_cleanup = mem_cleanup;
@@ -1325,15 +1358,15 @@
{
struct smi_info *info;
- if (!addrs[intf_num])
+ if (! addrs[intf_num])
return -ENODEV;
- if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
+ if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
addrs[intf_num]))
return -ENODEV;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
return -ENOMEM;
}
@@ -1343,10 +1376,10 @@
info->io.info = &addrs[intf_num];
info->io.addr = NULL;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[intf_num];
- if (!info->io.regsize)
+ if (! info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
info->irq = 0;
@@ -1404,7 +1437,7 @@
{
acpi_status status;
- if (!info->irq)
+ if (! info->irq)
return 0;
/* FIXME - is level triggered right? */
@@ -1428,7 +1461,7 @@
static void acpi_gpe_irq_cleanup(struct smi_info *info)
{
- if (!info->irq)
+ if (! info->irq)
return;
acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);
@@ -1504,10 +1537,10 @@
addr_space = IPMI_MEM_ADDR_SPACE;
else
addr_space = IPMI_IO_ADDR_SPACE;
- if (!is_new_interface(-1, addr_space, spmi->addr.address))
+ if (! is_new_interface(-1, addr_space, spmi->addr.address))
return -ENODEV;
- if (!spmi->addr.register_bit_width) {
+ if (! spmi->addr.register_bit_width) {
acpi_failure = 1;
return -ENODEV;
}
@@ -1534,7 +1567,7 @@
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
return -ENOMEM;
}
@@ -1610,22 +1643,15 @@
static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];
static int dmi_data_entries;
-typedef struct dmi_header
+static int __init decode_dmi(struct dmi_header *dm, int intf_num)
{
- u8 type;
- u8 length;
- u16 handle;
-} dmi_header_t;
-
-static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
-{
- u8 __iomem *data = (u8 __iomem *)dm;
+ u8 *data = (u8 *)dm;
unsigned long base_addr;
u8 reg_spacing;
- u8 len = readb(&dm->length);
+ u8 len = dm->length;
dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
- ipmi_data->type = readb(&data[4]);
+ ipmi_data->type = data[4];
memcpy(&base_addr, data+8, sizeof(unsigned long));
if (len >= 0x11) {
@@ -1640,12 +1666,12 @@
}
/* If bit 4 of byte 0x10 is set, then the lsb for the address
is odd. */
- ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4);
+ ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
- ipmi_data->irq = readb(&data[0x11]);
+ ipmi_data->irq = data[0x11];
/* The top two bits of byte 0x10 hold the register spacing. */
- reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6;
+ reg_spacing = (data[0x10] & 0xC0) >> 6;
switch(reg_spacing){
case 0x00: /* Byte boundaries */
ipmi_data->offset = 1;
@@ -1673,7 +1699,7 @@
ipmi_data->offset = 1;
}
- ipmi_data->slave_addr = readb(&data[6]);
+ ipmi_data->slave_addr = data[6];
if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {
dmi_data_entries++;
@@ -1685,94 +1711,29 @@
return -1;
}
-static int dmi_table(u32 base, int len, int num)
+static void __init dmi_find_bmc(void)
{
- u8 __iomem *buf;
- struct dmi_header __iomem *dm;
- u8 __iomem *data;
- int i=1;
- int status=-1;
+ struct dmi_device *dev = NULL;
int intf_num = 0;
- buf = ioremap(base, len);
- if(buf==NULL)
- return -1;
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
+ if (intf_num >= SI_MAX_DRIVERS)
+ break;
- data = buf;
-
- while(i<num && (data - buf) < len)
- {
- dm=(dmi_header_t __iomem *)data;
-
- if((data-buf+readb(&dm->length)) >= len)
- break;
-
- if (readb(&dm->type) == 38) {
- if (decode_dmi(dm, intf_num) == 0) {
- intf_num++;
- if (intf_num >= SI_MAX_DRIVERS)
- break;
- }
- }
-
- data+=readb(&dm->length);
- while((data-buf) < len && (readb(data)||readb(data+1)))
- data++;
- data+=2;
- i++;
+ decode_dmi((struct dmi_header *) dev->device_data, intf_num++);
}
- iounmap(buf);
-
- return status;
-}
-
-static inline int dmi_checksum(u8 *buf)
-{
- u8 sum=0;
- int a;
-
- for(a=0; a<15; a++)
- sum+=buf[a];
- return (sum==0);
-}
-
-static int dmi_decode(void)
-{
- u8 buf[15];
- u32 fp=0xF0000;
-
-#ifdef CONFIG_SIMNOW
- return -1;
-#endif
-
- while(fp < 0xFFFFF)
- {
- isa_memcpy_fromio(buf, fp, 15);
- if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
- {
- u16 num=buf[13]<<8|buf[12];
- u16 len=buf[7]<<8|buf[6];
- u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
-
- if(dmi_table(base, len, num) == 0)
- return 0;
- }
- fp+=16;
- }
-
- return -1;
}
static int try_init_smbios(int intf_num, struct smi_info **new_info)
{
- struct smi_info *info;
- dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
- char *io_type;
+ struct smi_info *info;
+ dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
+ char *io_type;
if (intf_num >= dmi_data_entries)
return -ENODEV;
- switch(ipmi_data->type) {
+ switch (ipmi_data->type) {
case 0x01: /* KCS */
si_type[intf_num] = "kcs";
break;
@@ -1787,7 +1748,7 @@
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
return -ENOMEM;
}
@@ -1811,7 +1772,7 @@
regspacings[intf_num] = ipmi_data->offset;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
@@ -1853,14 +1814,14 @@
pci_smic_checked = 1;
- if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
- NULL)))
- ;
- else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) &&
- pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
- fe_rmc = 1;
- else
- return -ENODEV;
+ pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL);
+ if (! pci_dev) {
+ pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL);
+ if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID))
+ fe_rmc = 1;
+ else
+ return -ENODEV;
+ }
error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
if (error)
@@ -1873,7 +1834,7 @@
}
/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
- if (!(base_addr & 0x0001))
+ if (! (base_addr & 0x0001))
{
pci_dev_put(pci_dev);
printk(KERN_ERR
@@ -1883,17 +1844,17 @@
}
base_addr &= 0xFFFE;
- if (!fe_rmc)
+ if (! fe_rmc)
/* Data register starts at base address + 1 in eRMC */
++base_addr;
- if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
+ if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
pci_dev_put(pci_dev);
return -ENODEV;
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
pci_dev_put(pci_dev);
printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
return -ENOMEM;
@@ -1904,7 +1865,7 @@
ports[intf_num] = base_addr;
info->io.info = &(ports[intf_num]);
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
@@ -1925,7 +1886,7 @@
static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
{
#ifdef CONFIG_PCI
- if (find_pci_smic(intf_num, new_info)==0)
+ if (find_pci_smic(intf_num, new_info) == 0)
return 0;
#endif
/* Include other methods here. */
@@ -1943,7 +1904,7 @@
int rv = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
- if (!resp)
+ if (! resp)
return -ENOMEM;
/* Do a Get Device ID command, since it comes back with some
@@ -1992,11 +1953,8 @@
}
/* Record info from the get device id, in case we need it. */
- smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
- smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
- smi_info->ipmi_si_fw_rev_minor = resp[6];
- smi_info->ipmi_version_major = resp[7] & 0xf;
- smi_info->ipmi_version_minor = resp[7] >> 4;
+ memcpy(&smi_info->device_id, &resp[3],
+ min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
out:
kfree(resp);
@@ -2028,7 +1986,7 @@
struct smi_info *smi = data;
out += sprintf(out, "interrupts_enabled: %d\n",
- smi->irq && !smi->interrupt_disabled);
+ smi->irq && ! smi->interrupt_disabled);
out += sprintf(out, "short_timeouts: %ld\n",
smi->short_timeouts);
out += sprintf(out, "long_timeouts: %ld\n",
@@ -2057,6 +2015,73 @@
return (out - ((char *) page));
}
+/*
+ * oem_data_avail_to_receive_msg_avail
+ * @info - smi_info structure with msg_flags set
+ *
+ * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL
+ * Returns 1 indicating need to re-run handle_flags().
+ */
+static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
+{
+ smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) |
+ RECEIVE_MSG_AVAIL);
+ return 1;
+}
+
+/*
+ * setup_dell_poweredge_oem_data_handler
+ * @info - smi_info.device_id must be populated
+ *
+ * Systems that match, but have firmware version < 1.40 may assert
+ * OEM0_DATA_AVAIL on their own, without being told via Set Flags that
+ * it's safe to do so. Such systems will de-assert OEM1_DATA_AVAIL
+ * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags
+ * as RECEIVE_MSG_AVAIL instead.
+ *
+ * As Dell has no plans to release IPMI 1.5 firmware that *ever*
+ * assert the OEM[012] bits, and if it did, the driver would have to
+ * change to handle that properly, we don't actually check for the
+ * firmware version.
+ * Device ID = 0x20 BMC on PowerEdge 8G servers
+ * Device Revision = 0x80
+ * Firmware Revision1 = 0x01 BMC version 1.40
+ * Firmware Revision2 = 0x40 BCD encoded
+ * IPMI Version = 0x51 IPMI 1.5
+ * Manufacturer ID = A2 02 00 Dell IANA
+ *
+ */
+#define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20
+#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80
+#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
+{
+ struct ipmi_device_id *id = &smi_info->device_id;
+ const char mfr[3]=DELL_IANA_MFR_ID;
+ if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))
+ && (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID)
+ && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV)
+ && (id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION))
+ {
+ smi_info->oem_data_avail_handler =
+ oem_data_avail_to_receive_msg_avail;
+ }
+}
+
+/*
+ * setup_oem_data_handler
+ * @info - smi_info.device_id must be filled in already
+ *
+ * Fills in smi_info.device_id.oem_data_available_handler
+ * when we know what function to use there.
+ */
+
+static void setup_oem_data_handler(struct smi_info *smi_info)
+{
+ setup_dell_poweredge_oem_data_handler(smi_info);
+}
+
/* Returns 0 if initialized, or negative on an error. */
static int init_one_smi(int intf_num, struct smi_info **smi)
{
@@ -2068,19 +2093,15 @@
if (rv)
rv = try_init_port(intf_num, &new_smi);
#ifdef CONFIG_ACPI_INTERPRETER
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_acpi(intf_num, &new_smi);
- }
#endif
#ifdef CONFIG_X86
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_smbios(intf_num, &new_smi);
- }
#endif
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_plug_and_play(intf_num, &new_smi);
- }
-
if (rv)
return rv;
@@ -2090,7 +2111,7 @@
new_smi->si_sm = NULL;
new_smi->handlers = NULL;
- if (!new_smi->irq_setup) {
+ if (! new_smi->irq_setup) {
new_smi->irq = irqs[intf_num];
new_smi->irq_setup = std_irq_setup;
new_smi->irq_cleanup = std_irq_cleanup;
@@ -2124,7 +2145,7 @@
/* Allocate the state machine's data and initialize it. */
new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
- if (!new_smi->si_sm) {
+ if (! new_smi->si_sm) {
printk(" Could not allocate state machine memory\n");
rv = -ENOMEM;
goto out_err;
@@ -2155,6 +2176,8 @@
if (rv)
goto out_err;
+ setup_oem_data_handler(new_smi);
+
/* Try to claim any interrupts. */
new_smi->irq_setup(new_smi);
@@ -2188,8 +2211,8 @@
rv = ipmi_register_smi(&handlers,
new_smi,
- new_smi->ipmi_version_major,
- new_smi->ipmi_version_minor,
+ ipmi_version_major(&new_smi->device_id),
+ ipmi_version_minor(&new_smi->device_id),
new_smi->slave_addr,
&(new_smi->intf));
if (rv) {
@@ -2230,7 +2253,7 @@
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
- while (!new_smi->timer_stopped) {
+ while (! new_smi->timer_stopped) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
@@ -2270,7 +2293,7 @@
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {
- for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) {
+ for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
si_type[i] = str;
str = strchr(str, ',');
if (str) {
@@ -2282,22 +2305,14 @@
}
}
- printk(KERN_INFO "IPMI System Interface driver version "
- IPMI_SI_VERSION);
- if (kcs_smi_handlers.version)
- printk(", KCS version %s", kcs_smi_handlers.version);
- if (smic_smi_handlers.version)
- printk(", SMIC version %s", smic_smi_handlers.version);
- if (bt_smi_handlers.version)
- printk(", BT version %s", bt_smi_handlers.version);
- printk("\n");
+ printk(KERN_INFO "IPMI System Interface driver.\n");
#ifdef CONFIG_X86
- dmi_decode();
+ dmi_find_bmc();
#endif
rv = init_one_smi(0, &(smi_infos[pos]));
- if (rv && !ports[0] && si_trydefaults) {
+ if (rv && ! ports[0] && si_trydefaults) {
/* If we are trying defaults and the initial port is
not set, then set it. */
si_type[0] = "kcs";
@@ -2319,7 +2334,7 @@
if (rv == 0)
pos++;
- for (i=1; i < SI_MAX_PARMS; i++) {
+ for (i = 1; i < SI_MAX_PARMS; i++) {
rv = init_one_smi(i, &(smi_infos[pos]));
if (rv == 0)
pos++;
@@ -2361,14 +2376,14 @@
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
- while (!to_clean->timer_stopped) {
+ while (! to_clean->timer_stopped) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
/* Interrupts and timeouts are stopped, now make sure the
interface is in a clean state. */
- while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
@@ -2392,13 +2407,15 @@
{
int i;
- if (!initialized)
+ if (! initialized)
return;
- for (i=0; i<SI_MAX_DRIVERS; i++) {
+ for (i = 0; i < SI_MAX_DRIVERS; i++) {
cleanup_one_si(smi_infos[i]);
}
}
module_exit(cleanup_ipmi_si);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces.");
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index ae18747..add2aa2 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -46,8 +46,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_SMIC_VERSION "v33"
-
/* smic_debug is a bit-field
* SMIC_DEBUG_ENABLE - turned on for now
* SMIC_DEBUG_MSG - commands and their responses
@@ -588,7 +586,6 @@
struct si_sm_handlers smic_smi_handlers =
{
- .version = IPMI_SMIC_VERSION,
.init_data = init_smic_data,
.start_transaction = start_smic_transaction,
.get_result = smic_get_result,
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index d35a953..e71aaae 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -53,8 +53,6 @@
#define PFX "IPMI Watchdog: "
-#define IPMI_WATCHDOG_VERSION "v33"
-
/*
* The IPMI command/response information for the watchdog timer.
*/
@@ -259,7 +257,7 @@
data[1] = 0;
WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
- if (pretimeout > 0) {
+ if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) {
WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
data[2] = pretimeout;
} else {
@@ -659,19 +657,18 @@
static int ipmi_open(struct inode *ino, struct file *filep)
{
- switch (iminor(ino))
- {
- case WATCHDOG_MINOR:
- if(test_and_set_bit(0, &ipmi_wdog_open))
+ switch (iminor(ino)) {
+ case WATCHDOG_MINOR:
+ if (test_and_set_bit(0, &ipmi_wdog_open))
return -EBUSY;
- /* Don't start the timer now, let it start on the
- first heartbeat. */
- ipmi_start_timer_on_heartbeat = 1;
- return nonseekable_open(ino, filep);
+ /* Don't start the timer now, let it start on the
+ first heartbeat. */
+ ipmi_start_timer_on_heartbeat = 1;
+ return nonseekable_open(ino, filep);
- default:
- return (-ENODEV);
+ default:
+ return (-ENODEV);
}
}
@@ -817,15 +814,19 @@
static int
ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
{
+ /* If we are not expecting a timeout, ignore it. */
+ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+ return NOTIFY_DONE;
+
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
- if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
+ if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+ /* On some machines, the heartbeat will give
+ an error and not work unless we re-enable
+ the timer. So do so. */
+ pretimeout_since_last_heartbeat = 1;
panic(PFX "pre-timeout");
-
- /* On some machines, the heartbeat will give
- an error and not work unless we re-enable
- the timer. So do so. */
- pretimeout_since_last_heartbeat = 1;
+ }
return NOTIFY_DONE;
}
@@ -924,9 +925,6 @@
{
int rv;
- printk(KERN_INFO PFX "driver version "
- IPMI_WATCHDOG_VERSION "\n");
-
if (strcmp(action, "reset") == 0) {
action_val = WDOG_TIMEOUT_RESET;
} else if (strcmp(action, "none") == 0) {
@@ -1011,6 +1009,8 @@
register_reboot_notifier(&wdog_reboot_notifier);
notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+ printk(KERN_INFO PFX "driver initialized\n");
+
return 0;
}
@@ -1062,3 +1062,5 @@
module_exit(ipmi_wdog_exit);
module_init(ipmi_wdog_init);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 115dbb3..3fa64c6 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -750,7 +750,7 @@
dev->soft = NULL;
- soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL);
+ soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);
if (soft == NULL)
return -ENOMEM;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 850a78c..f182752 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -35,10 +35,6 @@
# include <linux/efi.h>
#endif
-#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
-extern void tapechar_init(void);
-#endif
-
/*
* Architectures vary in how they handle caching for addresses
* outside of main memory.
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 931efd5..0c83751 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -63,8 +63,6 @@
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static unsigned char misc_minors[DYNAMIC_MINORS / 8];
-extern int rtc_DP8570A_init(void);
-extern int rtc_MK48T08_init(void);
extern int pmu_device_init(void);
#ifdef CONFIG_PROC_FS
@@ -303,12 +301,7 @@
misc_class = class_create(THIS_MODULE, "misc");
if (IS_ERR(misc_class))
return PTR_ERR(misc_class);
-#ifdef CONFIG_MVME16x
- rtc_MK48T08_init();
-#endif
-#ifdef CONFIG_BVME6000
- rtc_DP8570A_init();
-#endif
+
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 95f7046..79e490e 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -339,7 +339,7 @@
init_MUTEX(&moxaBuffSem);
moxaDriver->owner = THIS_MODULE;
- moxaDriver->name = "ttya";
+ moxaDriver->name = "ttyMX";
moxaDriver->devfs_name = "tts/a";
moxaDriver->major = ttymajor;
moxaDriver->minor_start = 0;
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index d568991..8666171 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -57,6 +57,7 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
+#include <linux/serial_8250.h>
#include "smapi.h"
#include "mwavedd.h"
#include "3780i.h"
@@ -410,8 +411,8 @@
static int register_serial_portandirq(unsigned int port, int irq)
{
- struct serial_struct serial;
-
+ struct uart_port uart;
+
switch ( port ) {
case 0x3f8:
case 0x2f8:
@@ -442,12 +443,14 @@
} /* switch */
/* irq is okay */
- memset(&serial, 0, sizeof(serial));
- serial.port = port;
- serial.irq = irq;
- serial.flags = ASYNC_SHARE_IRQ;
-
- return register_serial(&serial);
+ memset(&uart, 0, sizeof(struct uart_port));
+
+ uart.uartclk = 1843200;
+ uart.iobase = port;
+ uart.irq = irq;
+ uart.iotype = UPIO_PORT;
+ uart.flags = UPF_SHARE_IRQ;
+ return serial8250_register_port(&uart);
}
@@ -523,7 +526,7 @@
#endif
if ( pDrvData->sLine >= 0 ) {
- unregister_serial(pDrvData->sLine);
+ serial8250_unregister_port(pDrvData->sLine);
}
if (pDrvData->bMwaveDevRegistered) {
misc_deregister(&mwave_misc_dev);
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index f022f09..d0ef1ae 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -63,7 +63,6 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index cd4fe8b..63fff7c 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -938,10 +938,9 @@
/*
* XXX Interrupt pin #7 in Espresso is shared between RTC and
- * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here
- * is asking for trouble with add-on boards. Change to SA_SHIRQ.
+ * PCI Slot 2 INTA# (and some INTx# in Slot 1).
*/
- if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {
+ if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) {
/*
* Standard way for sparc to print irq's is to use
* __irq_itoa(). I think for EBus it's ok to use %d.
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index d692af5..baaa365 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -19,6 +19,7 @@
#include <linux/sched.h>
#include <linux/byteorder/generic.h>
#include <asm/sn/sn_sal.h>
+#include <asm/unaligned.h>
#include "snsc.h"
static struct subch_data_s *event_sd;
@@ -62,13 +63,16 @@
scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
{
char *desc_end;
+ __be32 from_buf;
/* record event source address */
- *src = be32_to_cpup((__be32 *)event);
+ from_buf = get_unaligned((__be32 *)event);
+ *src = be32_to_cpup(&from_buf);
event += 4; /* move on to event code */
/* record the system controller's event code */
- *code = be32_to_cpup((__be32 *)event);
+ from_buf = get_unaligned((__be32 *)event);
+ *code = be32_to_cpup(&from_buf);
event += 4; /* move on to event arguments */
/* how many arguments are in the packet? */
@@ -82,7 +86,8 @@
/* not an integer argument, so give up */
return -1;
}
- *esp_code = be32_to_cpup((__be32 *)event);
+ from_buf = get_unaligned((__be32 *)event);
+ *esp_code = be32_to_cpup(&from_buf);
event += 4;
/* parse out the event description */
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index cefbe98..36ae9ad 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -98,12 +98,13 @@
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE2 2
+#define SONYPI_DEVICE_MODEL_TYPE3 3
/* type1 models use those */
#define SONYPI_IRQ_PORT 0x8034
#define SONYPI_IRQ_SHIFT 22
-#define SONYPI_BASE 0x50
-#define SONYPI_G10A (SONYPI_BASE+0x14)
+#define SONYPI_TYPE1_BASE 0x50
+#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14)
#define SONYPI_TYPE1_REGION_SIZE 0x08
#define SONYPI_TYPE1_EVTYPE_OFFSET 0x04
@@ -114,6 +115,13 @@
#define SONYPI_TYPE2_REGION_SIZE 0x20
#define SONYPI_TYPE2_EVTYPE_OFFSET 0x12
+/* type3 series specifics */
+#define SONYPI_TYPE3_BASE 0x40
+#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */
+#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */
+#define SONYPI_TYPE3_REGION_SIZE 0x20
+#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12
+
/* battery / brightness addresses */
#define SONYPI_BAT_FLAGS 0x81
#define SONYPI_LCD_LIGHT 0x96
@@ -159,6 +167,10 @@
{ 0x0, 0x0 }
};
+/* same as in type 2 models */
+static struct sonypi_ioport_list *sonypi_type3_ioport_list =
+ sonypi_type2_ioport_list;
+
/* The set of possible interrupts */
struct sonypi_irq_list {
u16 irq;
@@ -180,6 +192,9 @@
{ 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */
};
+/* same as in type2 models */
+static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
+
#define SONYPI_CAMERA_BRIGHTNESS 0
#define SONYPI_CAMERA_CONTRAST 1
#define SONYPI_CAMERA_HUE 2
@@ -223,6 +238,7 @@
#define SONYPI_MEYE_MASK 0x00000400
#define SONYPI_MEMORYSTICK_MASK 0x00000800
#define SONYPI_BATTERY_MASK 0x00001000
+#define SONYPI_WIRELESS_MASK 0x00002000
struct sonypi_event {
u8 data;
@@ -305,6 +321,13 @@
{ 0, 0 }
};
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+ { 0x59, SONYPI_EVENT_WIRELESS_ON },
+ { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+ { 0, 0 }
+};
+
/* The set of possible back button events */
static struct sonypi_event sonypi_backev[] = {
{ 0x20, SONYPI_EVENT_BACK_PRESSED },
@@ -383,7 +406,6 @@
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
- { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
@@ -391,6 +413,12 @@
{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ 0 }
};
@@ -563,6 +591,23 @@
udelay(10);
}
+static void sonypi_type3_srs(void)
+{
+ u16 v16;
+ u8 v8;
+
+ /* This model type uses the same initialiazation of
+ * the embedded controller as the type2 models. */
+ sonypi_type2_srs();
+
+ /* Initialization of PCI config space of the LPC interface bridge. */
+ v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
+ pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
+ pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
+ v8 = (v8 & 0xCF) | 0x10;
+ pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
+}
+
/* Disables the device - this comes from the AML code in the ACPI bios */
static void sonypi_type1_dis(void)
{
@@ -587,6 +632,13 @@
printk(KERN_WARNING "ec_write failed\n");
}
+static void sonypi_type3_dis(void)
+{
+ sonypi_type2_dis();
+ udelay(10);
+ pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
+}
+
static u8 sonypi_call1(u8 dev)
{
u8 v1, v2;
@@ -1067,10 +1119,17 @@
static void sonypi_enable(unsigned int camera_on)
{
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
- sonypi_type2_srs();
- else
+ switch (sonypi_device.model) {
+ case SONYPI_DEVICE_MODEL_TYPE1:
sonypi_type1_srs();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE2:
+ sonypi_type2_srs();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE3:
+ sonypi_type3_srs();
+ break;
+ }
sonypi_call1(0x82);
sonypi_call2(0x81, 0xff);
@@ -1094,10 +1153,18 @@
if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
outb(0xf1, 0xb2);
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
- sonypi_type2_dis();
- else
+ switch (sonypi_device.model) {
+ case SONYPI_DEVICE_MODEL_TYPE1:
sonypi_type1_dis();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE2:
+ sonypi_type2_dis();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE3:
+ sonypi_type3_dis();
+ break;
+ }
+
return 0;
}
@@ -1143,12 +1210,16 @@
struct sonypi_irq_list *irq_list;
struct pci_dev *pcidev;
- pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+ else
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
sonypi_device.dev = pcidev;
- sonypi_device.model = pcidev ?
- SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2;
spin_lock_init(&sonypi_device.fifo_lock);
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
@@ -1176,16 +1247,22 @@
goto out_miscreg;
}
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
+
+ if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
+ ioport_list = sonypi_type1_ioport_list;
+ sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
+ sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
+ irq_list = sonypi_type1_irq_list;
+ } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
ioport_list = sonypi_type2_ioport_list;
sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
irq_list = sonypi_type2_irq_list;
} else {
- ioport_list = sonypi_type1_ioport_list;
- sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
- sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
- irq_list = sonypi_type1_irq_list;
+ ioport_list = sonypi_type3_ioport_list;
+ sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
+ sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
+ irq_list = sonypi_type3_irq_list;
}
for (i = 0; ioport_list[i].port1; i++) {
@@ -1274,11 +1351,10 @@
printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
"v%s.\n", SONYPI_DRIVER_VERSION);
- printk(KERN_INFO "sonypi: detected %s model, "
+ printk(KERN_INFO "sonypi: detected type%d model, "
"verbose = %d, fnkeyinit = %s, camera = %s, "
"compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
- (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
- "type1" : "type2",
+ sonypi_device.model,
verbose,
fnkeyinit ? "on" : "off",
camera ? "on" : "off",
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index cc2cc77..c0d6491 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -206,6 +206,9 @@
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
{0,}
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index dc8c540..939e51e 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -14,7 +14,6 @@
* License.
*/
-#include <acpi/acpi_bus.h>
#include <linux/pnp.h>
#include "tpm.h"
@@ -29,9 +28,10 @@
#define TPM_MAX_TRIES 5000
#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
-/* These values will be filled after ACPI-call */
+/* These values will be filled after PnP-call */
static int TPM_INF_DATA = 0;
static int TPM_INF_ADDR = 0;
+static int pnp_registered = 0;
/* TPM header definitions */
enum infineon_tpm_header {
@@ -356,24 +356,26 @@
{"IFX0102", 0},
{"", 0}
};
+MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
-static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev,
+static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
{
- TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff);
- TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff);
- tpm_inf.base = pnp_port_start(dev, 1);
- dev_info(&dev->dev, "Found %s with ID %s\n",
- dev->name, dev_id->id);
- if (!((tpm_inf.base >> 8) & 0xff))
- tpm_inf.base = 0;
- return 0;
+ if (pnp_port_valid(dev, 0)) {
+ TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff);
+ TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff);
+ tpm_inf.base = pnp_port_start(dev, 1);
+ dev_info(&dev->dev, "Found %s with ID %s\n",
+ dev->name, dev_id->id);
+ return 0;
+ }
+ return -ENODEV;
}
static struct pnp_driver tpm_inf_pnp = {
.name = "tpm_inf_pnp",
.id_table = tpm_pnp_tbl,
- .probe = tpm_inf_acpi_probe,
+ .probe = tpm_inf_pnp_probe,
};
static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
@@ -386,19 +388,30 @@
int productid[2];
char chipname[20];
- if (pci_enable_device(pci_dev))
- return -EIO;
+ rc = pci_enable_device(pci_dev);
+ if (rc)
+ return rc;
dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device);
- /* read IO-ports from ACPI */
- pnp_register_driver(&tpm_inf_pnp);
- pnp_unregister_driver(&tpm_inf_pnp);
+ /* read IO-ports from PnP */
+ rc = pnp_register_driver(&tpm_inf_pnp);
+ if (rc < 0) {
+ dev_err(&pci_dev->dev,
+ "Error %x from pnp_register_driver!\n",rc);
+ goto error2;
+ }
+ if (!rc) {
+ dev_info(&pci_dev->dev, "No Infineon TPM found!\n");
+ goto error;
+ } else {
+ pnp_registered = 1;
+ }
/* Make sure, we have received valid config ports */
if (!TPM_INF_ADDR) {
- pci_disable_device(pci_dev);
- return -EIO;
+ dev_err(&pci_dev->dev, "No valid IO-ports received!\n");
+ goto error;
}
/* query chip for its vendor, its version number a.s.o. */
@@ -418,23 +431,21 @@
switch ((productid[0] << 8) | productid[1]) {
case 6:
- sprintf(chipname, " (SLD 9630 TT 1.1)");
+ snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
break;
case 11:
- sprintf(chipname, " (SLB 9635 TT 1.2)");
+ snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
break;
default:
- sprintf(chipname, " (unknown chip)");
+ snprintf(chipname, sizeof(chipname), " (unknown chip)");
break;
}
- chipname[19] = 0;
if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
if (tpm_inf.base == 0) {
dev_err(&pci_dev->dev, "No IO-ports found!\n");
- pci_disable_device(pci_dev);
- return -EIO;
+ goto error;
}
/* configure TPM with IO-ports */
outb(IOLIMH, TPM_INF_ADDR);
@@ -452,8 +463,7 @@
dev_err(&pci_dev->dev,
"Could not set IO-ports to %04x\n",
tpm_inf.base);
- pci_disable_device(pci_dev);
- return -EIO;
+ goto error;
}
/* activate register */
@@ -479,14 +489,16 @@
productid[0], productid[1], chipname);
rc = tpm_register_hardware(pci_dev, &tpm_inf);
- if (rc < 0) {
- pci_disable_device(pci_dev);
- return -ENODEV;
- }
+ if (rc < 0)
+ goto error;
return 0;
} else {
dev_info(&pci_dev->dev, "No Infineon TPM found!\n");
+error:
+ pnp_unregister_driver(&tpm_inf_pnp);
+error2:
pci_disable_device(pci_dev);
+ pnp_registered = 0;
return -ENODEV;
}
}
@@ -521,6 +533,8 @@
static void __exit cleanup_inf(void)
{
+ if (pnp_registered)
+ pnp_unregister_driver(&tpm_inf_pnp);
pci_unregister_driver(&inf_pci_driver);
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 6e4be3b..9d65712 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -153,7 +153,6 @@
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
-extern void rs_360_init(void);
static void release_mem(struct tty_struct *tty, int idx);
@@ -2911,11 +2910,6 @@
#ifdef CONFIG_EARLY_PRINTK
disable_early_printk();
#endif
-#ifdef CONFIG_SERIAL_68360
- /* This is not a console initcall. I know not what it's doing here.
- So I haven't moved it. dwmw2 */
- rs_360_init();
-#endif
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 665103c..b8d0c29 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -434,21 +434,25 @@
/* used by selection: complement pointer position */
void complement_pos(struct vc_data *vc, int offset)
{
- static unsigned short *p;
+ static int old_offset = -1;
static unsigned short old;
static unsigned short oldx, oldy;
WARN_CONSOLE_UNLOCKED();
- if (p) {
- scr_writew(old, p);
+ if (old_offset != -1 && old_offset >= 0 &&
+ old_offset < vc->vc_screenbuf_size) {
+ scr_writew(old, screenpos(vc, old_offset, 1));
if (DO_UPDATE(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx);
}
- if (offset == -1)
- p = NULL;
- else {
+
+ old_offset = offset;
+
+ if (offset != -1 && offset >= 0 &&
+ offset < vc->vc_screenbuf_size) {
unsigned short new;
+ unsigned short *p;
p = screenpos(vc, offset, 1);
old = scr_readw(p);
new = old ^ vc->vc_complement_mask;
@@ -459,6 +463,7 @@
vc->vc_sw->con_putc(vc, new, oldy, oldx);
}
}
+
}
static void insert_char(struct vc_data *vc, unsigned int nr)
@@ -2272,7 +2277,9 @@
ret = paste_selection(tty);
break;
case TIOCL_UNBLANKSCREEN:
+ acquire_console_sem();
unblank_screen();
+ release_console_sem();
break;
case TIOCL_SELLOADLUT:
ret = sel_loadlut(p);
@@ -2317,8 +2324,10 @@
}
break;
case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+ acquire_console_sem();
ignore_poke = 1;
do_blank_screen(0);
+ release_console_sem();
break;
case TIOCL_BLANKEDSCREEN:
ret = console_blanked;
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index b53e2e2..c3898af 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -346,6 +346,13 @@
tristate "MPC8xx Watchdog Timer"
depends on WATCHDOG && 8xx
+config BOOKE_WDT
+ tristate "PowerPC Book-E Watchdog Timer"
+ depends on WATCHDOG && (BOOKE || 4xx)
+ ---help---
+ Please see Documentation/watchdog/watchdog-api.txt for
+ more information.
+
# MIPS Architecture
config INDYDOG
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index c183883..cfeac6f 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -2,42 +2,68 @@
# Makefile for the WatchDog device drivers.
#
+# Only one watchdog can succeed. We probe the ISA/PCI/USB based
+# watchdog-cards first, then the architecture specific watchdog
+# drivers and then the architecture independant "softdog" driver.
+# This means that if your ISA/PCI/USB card isn't detected that
+# you can fall back to an architecture specific driver and if
+# that also fails then you can fall back to the software watchdog
+# to give you some cover.
+
+# ISA-based Watchdog Cards
obj-$(CONFIG_PCWATCHDOG) += pcwd.o
-obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
-obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
-obj-$(CONFIG_IB700_WDT) += ib700wdt.o
obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
-obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
-obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_WDT) += wdt.o
+
+# PCI-based Watchdog Cards
+obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
obj-$(CONFIG_WDTPCI) += wdt_pci.o
+
+# USB-based Watchdog Cards
+obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+
+# ARM Architecture
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
-obj-$(CONFIG_MACHZ_WDT) += machzwd.o
-obj-$(CONFIG_SH_WDT) += shwdt.o
+obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
-obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
-obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
-obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
-obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
-obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+
+# X86 (i386 + ia64 + x86_64) Architecture
+obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
-obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
+obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
+obj-$(CONFIG_IB700_WDT) += ib700wdt.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
+obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
+obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
-obj-$(CONFIG_INDYDOG) += indydog.o
-obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
-obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
-obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
-obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
+obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+
+# PowerPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+
+# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
+obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
-# Only one watchdog can succeed. We probe the hardware watchdog
-# drivers first, then the softdog driver. This means if your hardware
-# watchdog dies or is 'borrowed' for some reason the software watchdog
-# still gives you some cover.
+# MIPS Architecture
+obj-$(CONFIG_INDYDOG) += indydog.o
+# S390 Architecture
+
+# SUPERH Architecture
+obj-$(CONFIG_SH_WDT) += shwdt.o
+
+# SPARC64 Architecture
+
+# Architecture Independant
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
new file mode 100644
index 0000000..abc30cc
--- /dev/null
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -0,0 +1,192 @@
+/*
+ * drivers/char/watchdog/booke_wdt.c
+ *
+ * Watchdog timer for PowerPC Book-E systems
+ *
+ * Author: Matthew McClintock
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/notifier.h>
+#include <linux/watchdog.h>
+
+#include <asm/reg_booke.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot.
+ * Also, the wdt_period sets the watchdog timer period timeout.
+ * For E500 cpus the wdt_period sets which bit changing from 0->1 will
+ * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
+ * first time nothing will happen, the second time a watchdog exception will
+ * occur, and the final time the board will reset.
+ */
+
+#ifdef CONFIG_FSL_BOOKE
+#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
+#else
+#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
+#endif /* for timing information */
+
+u32 booke_wdt_enabled = 0;
+u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
+
+#ifdef CONFIG_FSL_BOOKE
+#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
+#else
+#define WDTP(x) (TCR_WP(x))
+#endif
+
+/*
+ * booke_wdt_enable:
+ */
+static __inline__ void booke_wdt_enable(void)
+{
+ u32 val;
+
+ val = mfspr(SPRN_TCR);
+ val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
+
+ mtspr(SPRN_TCR, val);
+}
+
+/*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+ mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
+ * booke_wdt_write:
+ */
+static ssize_t booke_wdt_write (struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ booke_wdt_ping();
+ return count;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "PowerPC Book-E Watchdog",
+};
+
+/*
+ * booke_wdt_ioctl:
+ */
+static int booke_wdt_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ u32 tmp = 0;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user ((struct watchdog_info *) arg, &ident,
+ sizeof(struct watchdog_info)))
+ return -EFAULT;
+ case WDIOC_GETSTATUS:
+ return put_user(ident.options, (u32 *) arg);
+ case WDIOC_GETBOOTSTATUS:
+ /* XXX: something is clearing TSR */
+ tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
+ /* returns 1 if last reset was caused by the WDT */
+ return (tmp ? 1 : 0);
+ case WDIOC_KEEPALIVE:
+ booke_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(booke_wdt_period, (u32 *) arg))
+ return -EFAULT;
+ mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
+ return 0;
+ case WDIOC_GETTIMEOUT:
+ return put_user(booke_wdt_period, (u32 *) arg);
+ case WDIOC_SETOPTIONS:
+ if (get_user(tmp, (u32 *) arg))
+ return -EINVAL;
+ if (tmp == WDIOS_ENABLECARD) {
+ booke_wdt_ping();
+ break;
+ } else
+ return -EINVAL;
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+/*
+ * booke_wdt_open:
+ */
+static int booke_wdt_open (struct inode *inode, struct file *file)
+{
+ if (booke_wdt_enabled == 0) {
+ booke_wdt_enabled = 1;
+ booke_wdt_enable();
+ printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
+ booke_wdt_period);
+ }
+
+ return 0;
+}
+
+static struct file_operations booke_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = booke_wdt_write,
+ .ioctl = booke_wdt_ioctl,
+ .open = booke_wdt_open,
+};
+
+static struct miscdevice booke_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &booke_wdt_fops,
+};
+
+static void __exit booke_wdt_exit(void)
+{
+ misc_deregister(&booke_wdt_miscdev);
+}
+
+/*
+ * booke_wdt_init:
+ */
+static int __init booke_wdt_init(void)
+{
+ int ret = 0;
+
+ printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
+ ident.firmware_version = cpu_specs[0].pvr_value;
+
+ ret = misc_register(&booke_wdt_miscdev);
+ if (ret) {
+ printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ return ret;
+ }
+
+ if (booke_wdt_enabled == 1) {
+ printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
+ booke_wdt_period);
+ booke_wdt_enable();
+ }
+
+ return ret;
+}
+device_initcall(booke_wdt_init);
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index e7640bc..0cfb9b9 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -182,7 +182,7 @@
static struct miscdevice ixp2000_wdt_miscdev =
{
.minor = WATCHDOG_MINOR,
- .name = "IXP2000 Watchdog",
+ .name = "watchdog",
.fops = &ixp2000_wdt_fops,
};
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
index 8d916af..b5be8b1 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -176,7 +176,7 @@
static struct miscdevice ixp4xx_wdt_miscdev =
{
.minor = WATCHDOG_MINOR,
- .name = "IXP4xx Watchdog",
+ .name = "watchdog",
.fops = &ixp4xx_wdt_fops,
};
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index f85ac89..8b292bf 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -27,7 +27,10 @@
* Fixed tmr_count / wdt_count confusion
* Added configurable debug
*
- * 11-Jan-2004 BJD Fixed divide-by-2 in timeout code
+ * 11-Jan-2005 BJD Fixed divide-by-2 in timeout code
+ *
+ * 25-Jan-2005 DA Added suspend/resume support
+ * Replaced reboot notifier with .shutdown method
*
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
*/
@@ -40,8 +43,6 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
@@ -317,20 +318,6 @@
}
}
-/*
- * Notifier for system down
- */
-
-static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if(code==SYS_DOWN || code==SYS_HALT) {
- /* Turn the WDT off */
- s3c2410wdt_stop();
- }
- return NOTIFY_DONE;
-}
-
/* kernel interface */
static struct file_operations s3c2410wdt_fops = {
@@ -348,10 +335,6 @@
.fops = &s3c2410wdt_fops,
};
-static struct notifier_block s3c2410wdt_notifier = {
- .notifier_call = s3c2410wdt_notify_sys,
-};
-
/* interrupt handler code */
static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
@@ -432,18 +415,10 @@
}
}
- ret = register_reboot_notifier(&s3c2410wdt_notifier);
- if (ret) {
- printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n",
- ret);
- return ret;
- }
-
ret = misc_register(&s3c2410wdt_miscdev);
if (ret) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
- unregister_reboot_notifier(&s3c2410wdt_notifier);
return ret;
}
@@ -479,15 +454,63 @@
return 0;
}
+static void s3c2410wdt_shutdown(struct device *dev)
+{
+ s3c2410wdt_stop();
+}
+
+#ifdef CONFIG_PM
+
+static unsigned long wtcon_save;
+static unsigned long wtdat_save;
+
+static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level)
+{
+ if (level == SUSPEND_POWER_DOWN) {
+ /* Save watchdog state, and turn it off. */
+ wtcon_save = readl(wdt_base + S3C2410_WTCON);
+ wtdat_save = readl(wdt_base + S3C2410_WTDAT);
+
+ /* Note that WTCNT doesn't need to be saved. */
+ s3c2410wdt_stop();
+ }
+
+ return 0;
+}
+
+static int s3c2410wdt_resume(struct device *dev, u32 level)
+{
+ if (level == RESUME_POWER_ON) {
+ /* Restore watchdog state. */
+
+ writel(wtdat_save, wdt_base + S3C2410_WTDAT);
+ writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
+ writel(wtcon_save, wdt_base + S3C2410_WTCON);
+
+ printk(KERN_INFO PFX "watchdog %sabled\n",
+ (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+ }
+
+ return 0;
+}
+
+#else
+#define s3c2410wdt_suspend NULL
+#define s3c2410wdt_resume NULL
+#endif /* CONFIG_PM */
+
+
static struct device_driver s3c2410wdt_driver = {
.name = "s3c2410-wdt",
.bus = &platform_bus_type,
.probe = s3c2410wdt_probe,
.remove = s3c2410wdt_remove,
+ .shutdown = s3c2410wdt_shutdown,
+ .suspend = s3c2410wdt_suspend,
+ .resume = s3c2410wdt_resume,
};
-
static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
static int __init watchdog_init(void)
@@ -499,13 +522,13 @@
static void __exit watchdog_exit(void)
{
driver_unregister(&s3c2410wdt_driver);
- unregister_reboot_notifier(&s3c2410wdt_notifier);
}
module_init(watchdog_init);
module_exit(watchdog_exit);
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, "
+ "Dimitry Andric <dimitry.andric@tomtom.com>");
MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index c456856..b4a102a 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -206,7 +206,7 @@
static struct miscdevice scx200_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
- .name = NAME,
+ .name = "watchdog",
.fops = &scx200_wdt_fops,
};
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index 4d7ed93..20e5eb8 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -77,7 +77,7 @@
static struct timer_list watchdog_ticktock =
TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long timer_alive;
+static unsigned long driver_open, orphan_timer;
static char expect_close;
@@ -87,6 +87,9 @@
static void watchdog_fire(unsigned long data)
{
+ if (test_and_clear_bit(0, &orphan_timer))
+ module_put(THIS_MODULE);
+
if (soft_noboot)
printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
else
@@ -128,9 +131,9 @@
static int softdog_open(struct inode *inode, struct file *file)
{
- if(test_and_set_bit(0, &timer_alive))
+ if (test_and_set_bit(0, &driver_open))
return -EBUSY;
- if (nowayout)
+ if (!test_and_clear_bit(0, &orphan_timer))
__module_get(THIS_MODULE);
/*
* Activate timer
@@ -147,11 +150,13 @@
*/
if (expect_close == 42) {
softdog_stop();
+ module_put(THIS_MODULE);
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ set_bit(0, &orphan_timer);
softdog_keepalive();
}
- clear_bit(0, &timer_alive);
+ clear_bit(0, &driver_open);
expect_close = 0;
return 0;
}
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index 465e0fd..b5d8210 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -93,6 +93,12 @@
w83627hf_select_wd_register();
+ outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+ t=inb_p(WDT_EFDR); /* read CRF6 */
+ if (t != 0) {
+ printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
+ outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
+ }
outb_p(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 5b29c3b..327b58e 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -58,4 +58,31 @@
See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
+config DELL_RBU
+ tristate "BIOS update support for DELL systems via sysfs"
+ select FW_LOADER
+ help
+ Say m if you want to have the option of updating the BIOS for your
+ DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
+ supporting application to comunicate with the BIOS regarding the new
+ image for the image update to take effect.
+ See <file:Documentation/dell_rbu.txt> for more details on the driver.
+
+config DCDBAS
+ tristate "Dell Systems Management Base Driver"
+ depends on X86 || X86_64
+ default m
+ help
+ The Dell Systems Management Base Driver provides a sysfs interface
+ for systems management software to perform System Management
+ Interrupts (SMIs) and Host Control Actions (system power cycle or
+ power off after OS shutdown) on certain Dell systems.
+
+ See <file:Documentation/dcdbas.txt> for more details on the driver
+ and the Dell systems on which Dell systems management software makes
+ use of this driver.
+
+ Say Y or M here to enable the driver for use by Dell systems
+ management software such as Dell OpenManage.
+
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 90fd0b2..8542997 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -4,3 +4,5 @@
obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
+obj-$(CONFIG_DELL_RBU) += dell_rbu.o
+obj-$(CONFIG_DCDBAS) += dcdbas.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
new file mode 100644
index 0000000..955537f
--- /dev/null
+++ b/drivers/firmware/dcdbas.c
@@ -0,0 +1,596 @@
+/*
+ * dcdbas.c: Dell Systems Management Base Driver
+ *
+ * The Dell Systems Management Base Driver provides a sysfs interface for
+ * systems management software to perform System Management Interrupts (SMIs)
+ * and Host Control Actions (power cycle or power off after OS shutdown) on
+ * Dell systems.
+ *
+ * See Documentation/dcdbas.txt for more information.
+ *
+ * Copyright (C) 1995-2005 Dell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+
+#include "dcdbas.h"
+
+#define DRIVER_NAME "dcdbas"
+#define DRIVER_VERSION "5.6.0-1"
+#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
+
+static struct platform_device *dcdbas_pdev;
+
+static u8 *smi_data_buf;
+static dma_addr_t smi_data_buf_handle;
+static unsigned long smi_data_buf_size;
+static u32 smi_data_buf_phys_addr;
+static DECLARE_MUTEX(smi_data_lock);
+
+static unsigned int host_control_action;
+static unsigned int host_control_smi_type;
+static unsigned int host_control_on_shutdown;
+
+/**
+ * smi_data_buf_free: free SMI data buffer
+ */
+static void smi_data_buf_free(void)
+{
+ if (!smi_data_buf)
+ return;
+
+ dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+ __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+
+ dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
+ smi_data_buf_handle);
+ smi_data_buf = NULL;
+ smi_data_buf_handle = 0;
+ smi_data_buf_phys_addr = 0;
+ smi_data_buf_size = 0;
+}
+
+/**
+ * smi_data_buf_realloc: grow SMI data buffer if needed
+ */
+static int smi_data_buf_realloc(unsigned long size)
+{
+ void *buf;
+ dma_addr_t handle;
+
+ if (smi_data_buf_size >= size)
+ return 0;
+
+ if (size > MAX_SMI_DATA_BUF_SIZE)
+ return -EINVAL;
+
+ /* new buffer is needed */
+ buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL);
+ if (!buf) {
+ dev_dbg(&dcdbas_pdev->dev,
+ "%s: failed to allocate memory size %lu\n",
+ __FUNCTION__, size);
+ return -ENOMEM;
+ }
+ /* memory zeroed by dma_alloc_coherent */
+
+ if (smi_data_buf)
+ memcpy(buf, smi_data_buf, smi_data_buf_size);
+
+ /* free any existing buffer */
+ smi_data_buf_free();
+
+ /* set up new buffer for use */
+ smi_data_buf = buf;
+ smi_data_buf_handle = handle;
+ smi_data_buf_phys_addr = (u32) virt_to_phys(buf);
+ smi_data_buf_size = size;
+
+ dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+ __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+
+ return 0;
+}
+
+static ssize_t smi_data_buf_phys_addr_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%x\n", smi_data_buf_phys_addr);
+}
+
+static ssize_t smi_data_buf_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%lu\n", smi_data_buf_size);
+}
+
+static ssize_t smi_data_buf_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long buf_size;
+ ssize_t ret;
+
+ buf_size = simple_strtoul(buf, NULL, 10);
+
+ /* make sure SMI data buffer is at least buf_size */
+ down(&smi_data_lock);
+ ret = smi_data_buf_realloc(buf_size);
+ up(&smi_data_lock);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
+ size_t count)
+{
+ size_t max_read;
+ ssize_t ret;
+
+ down(&smi_data_lock);
+
+ if (pos >= smi_data_buf_size) {
+ ret = 0;
+ goto out;
+ }
+
+ max_read = smi_data_buf_size - pos;
+ ret = min(max_read, count);
+ memcpy(buf, smi_data_buf + pos, ret);
+out:
+ up(&smi_data_lock);
+ return ret;
+}
+
+static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
+ size_t count)
+{
+ ssize_t ret;
+
+ down(&smi_data_lock);
+
+ ret = smi_data_buf_realloc(pos + count);
+ if (ret)
+ goto out;
+
+ memcpy(smi_data_buf + pos, buf, count);
+ ret = count;
+out:
+ up(&smi_data_lock);
+ return ret;
+}
+
+static ssize_t host_control_action_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", host_control_action);
+}
+
+static ssize_t host_control_action_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t ret;
+
+ /* make sure buffer is available for host control command */
+ down(&smi_data_lock);
+ ret = smi_data_buf_realloc(sizeof(struct apm_cmd));
+ up(&smi_data_lock);
+ if (ret)
+ return ret;
+
+ host_control_action = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+static ssize_t host_control_smi_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", host_control_smi_type);
+}
+
+static ssize_t host_control_smi_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ host_control_smi_type = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+static ssize_t host_control_on_shutdown_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", host_control_on_shutdown);
+}
+
+static ssize_t host_control_on_shutdown_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ host_control_on_shutdown = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+/**
+ * smi_request: generate SMI request
+ *
+ * Called with smi_data_lock.
+ */
+static int smi_request(struct smi_cmd *smi_cmd)
+{
+ cpumask_t old_mask;
+ int ret = 0;
+
+ if (smi_cmd->magic != SMI_CMD_MAGIC) {
+ dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
+ __FUNCTION__);
+ return -EBADR;
+ }
+
+ /* SMI requires CPU 0 */
+ old_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(0));
+ if (smp_processor_id() != 0) {
+ dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
+ __FUNCTION__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* generate SMI */
+ asm volatile (
+ "outb %b0,%w1"
+ : /* no output args */
+ : "a" (smi_cmd->command_code),
+ "d" (smi_cmd->command_address),
+ "b" (smi_cmd->ebx),
+ "c" (smi_cmd->ecx)
+ : "memory"
+ );
+
+out:
+ set_cpus_allowed(current, old_mask);
+ return ret;
+}
+
+/**
+ * smi_request_store:
+ *
+ * The valid values are:
+ * 0: zero SMI data buffer
+ * 1: generate calling interface SMI
+ * 2: generate raw SMI
+ *
+ * User application writes smi_cmd to smi_data before telling driver
+ * to generate SMI.
+ */
+static ssize_t smi_request_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct smi_cmd *smi_cmd;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ ssize_t ret;
+
+ down(&smi_data_lock);
+
+ if (smi_data_buf_size < sizeof(struct smi_cmd)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ smi_cmd = (struct smi_cmd *)smi_data_buf;
+
+ switch (val) {
+ case 2:
+ /* Raw SMI */
+ ret = smi_request(smi_cmd);
+ if (!ret)
+ ret = count;
+ break;
+ case 1:
+ /* Calling Interface SMI */
+ smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer);
+ ret = smi_request(smi_cmd);
+ if (!ret)
+ ret = count;
+ break;
+ case 0:
+ memset(smi_data_buf, 0, smi_data_buf_size);
+ ret = count;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ up(&smi_data_lock);
+ return ret;
+}
+
+/**
+ * host_control_smi: generate host control SMI
+ *
+ * Caller must set up the host control command in smi_data_buf.
+ */
+static int host_control_smi(void)
+{
+ struct apm_cmd *apm_cmd;
+ u8 *data;
+ unsigned long flags;
+ u32 num_ticks;
+ s8 cmd_status;
+ u8 index;
+
+ apm_cmd = (struct apm_cmd *)smi_data_buf;
+ apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL;
+
+ switch (host_control_smi_type) {
+ case HC_SMITYPE_TYPE1:
+ spin_lock_irqsave(&rtc_lock, flags);
+ /* write SMI data buffer physical address */
+ data = (u8 *)&smi_data_buf_phys_addr;
+ for (index = PE1300_CMOS_CMD_STRUCT_PTR;
+ index < (PE1300_CMOS_CMD_STRUCT_PTR + 4);
+ index++, data++) {
+ outb(index,
+ (CMOS_BASE_PORT + CMOS_PAGE2_INDEX_PORT_PIIX4));
+ outb(*data,
+ (CMOS_BASE_PORT + CMOS_PAGE2_DATA_PORT_PIIX4));
+ }
+
+ /* first set status to -1 as called by spec */
+ cmd_status = ESM_STATUS_CMD_UNSUCCESSFUL;
+ outb((u8) cmd_status, PCAT_APM_STATUS_PORT);
+
+ /* generate SMM call */
+ outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ /* wait a few to see if it executed */
+ num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
+ while ((cmd_status = inb(PCAT_APM_STATUS_PORT))
+ == ESM_STATUS_CMD_UNSUCCESSFUL) {
+ num_ticks--;
+ if (num_ticks == EXPIRED_TIMER)
+ return -ETIME;
+ }
+ break;
+
+ case HC_SMITYPE_TYPE2:
+ case HC_SMITYPE_TYPE3:
+ spin_lock_irqsave(&rtc_lock, flags);
+ /* write SMI data buffer physical address */
+ data = (u8 *)&smi_data_buf_phys_addr;
+ for (index = PE1400_CMOS_CMD_STRUCT_PTR;
+ index < (PE1400_CMOS_CMD_STRUCT_PTR + 4);
+ index++, data++) {
+ outb(index, (CMOS_BASE_PORT + CMOS_PAGE1_INDEX_PORT));
+ outb(*data, (CMOS_BASE_PORT + CMOS_PAGE1_DATA_PORT));
+ }
+
+ /* generate SMM call */
+ if (host_control_smi_type == HC_SMITYPE_TYPE3)
+ outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
+ else
+ outb(ESM_APM_CMD, PE1400_APM_CONTROL_PORT);
+
+ /* restore RTC index pointer since it was written to above */
+ CMOS_READ(RTC_REG_C);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ /* read control port back to serialize write */
+ cmd_status = inb(PE1400_APM_CONTROL_PORT);
+
+ /* wait a few to see if it executed */
+ num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
+ while (apm_cmd->status == ESM_STATUS_CMD_UNSUCCESSFUL) {
+ num_ticks--;
+ if (num_ticks == EXPIRED_TIMER)
+ return -ETIME;
+ }
+ break;
+
+ default:
+ dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
+ __FUNCTION__, host_control_smi_type);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+/**
+ * dcdbas_host_control: initiate host control
+ *
+ * This function is called by the driver after the system has
+ * finished shutting down if the user application specified a
+ * host control action to perform on shutdown. It is safe to
+ * use smi_data_buf at this point because the system has finished
+ * shutting down and no userspace apps are running.
+ */
+static void dcdbas_host_control(void)
+{
+ struct apm_cmd *apm_cmd;
+ u8 action;
+
+ if (host_control_action == HC_ACTION_NONE)
+ return;
+
+ action = host_control_action;
+ host_control_action = HC_ACTION_NONE;
+
+ if (!smi_data_buf) {
+ dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__);
+ return;
+ }
+
+ if (smi_data_buf_size < sizeof(struct apm_cmd)) {
+ dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
+ __FUNCTION__);
+ return;
+ }
+
+ apm_cmd = (struct apm_cmd *)smi_data_buf;
+
+ /* power off takes precedence */
+ if (action & HC_ACTION_HOST_CONTROL_POWEROFF) {
+ apm_cmd->command = ESM_APM_POWER_CYCLE;
+ apm_cmd->reserved = 0;
+ *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 0;
+ host_control_smi();
+ } else if (action & HC_ACTION_HOST_CONTROL_POWERCYCLE) {
+ apm_cmd->command = ESM_APM_POWER_CYCLE;
+ apm_cmd->reserved = 0;
+ *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 20;
+ host_control_smi();
+ }
+}
+
+/**
+ * dcdbas_reboot_notify: handle reboot notification for host control
+ */
+static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
+ void *unused)
+{
+ static unsigned int notify_cnt = 0;
+
+ switch (code) {
+ case SYS_DOWN:
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ if (host_control_on_shutdown) {
+ /* firmware is going to perform host control action */
+ if (++notify_cnt == 2) {
+ printk(KERN_WARNING
+ "Please wait for shutdown "
+ "action to complete...\n");
+ dcdbas_host_control();
+ }
+ /*
+ * register again and initiate the host control
+ * action on the second notification to allow
+ * everyone that registered to be notified
+ */
+ register_reboot_notifier(nb);
+ }
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block dcdbas_reboot_nb = {
+ .notifier_call = dcdbas_reboot_notify,
+ .next = NULL,
+ .priority = 0
+};
+
+static DCDBAS_BIN_ATTR_RW(smi_data);
+
+static struct bin_attribute *dcdbas_bin_attrs[] = {
+ &bin_attr_smi_data,
+ NULL
+};
+
+static DCDBAS_DEV_ATTR_RW(smi_data_buf_size);
+static DCDBAS_DEV_ATTR_RO(smi_data_buf_phys_addr);
+static DCDBAS_DEV_ATTR_WO(smi_request);
+static DCDBAS_DEV_ATTR_RW(host_control_action);
+static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
+static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
+
+static struct device_attribute *dcdbas_dev_attrs[] = {
+ &dev_attr_smi_data_buf_size,
+ &dev_attr_smi_data_buf_phys_addr,
+ &dev_attr_smi_request,
+ &dev_attr_host_control_action,
+ &dev_attr_host_control_smi_type,
+ &dev_attr_host_control_on_shutdown,
+ NULL
+};
+
+/**
+ * dcdbas_init: initialize driver
+ */
+static int __init dcdbas_init(void)
+{
+ int i;
+
+ host_control_action = HC_ACTION_NONE;
+ host_control_smi_type = HC_SMITYPE_NONE;
+
+ dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+ if (IS_ERR(dcdbas_pdev))
+ return PTR_ERR(dcdbas_pdev);
+
+ /*
+ * BIOS SMI calls require buffer addresses be in 32-bit address space.
+ * This is done by setting the DMA mask below.
+ */
+ dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
+ dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask;
+
+ register_reboot_notifier(&dcdbas_reboot_nb);
+
+ for (i = 0; dcdbas_bin_attrs[i]; i++)
+ sysfs_create_bin_file(&dcdbas_pdev->dev.kobj,
+ dcdbas_bin_attrs[i]);
+
+ for (i = 0; dcdbas_dev_attrs[i]; i++)
+ device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]);
+
+ dev_info(&dcdbas_pdev->dev, "%s (version %s)\n",
+ DRIVER_DESCRIPTION, DRIVER_VERSION);
+
+ return 0;
+}
+
+/**
+ * dcdbas_exit: perform driver cleanup
+ */
+static void __exit dcdbas_exit(void)
+{
+ platform_device_unregister(dcdbas_pdev);
+ unregister_reboot_notifier(&dcdbas_reboot_nb);
+ smi_data_buf_free();
+}
+
+module_init(dcdbas_init);
+module_exit(dcdbas_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR("Dell Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
new file mode 100644
index 0000000..58a8518
--- /dev/null
+++ b/drivers/firmware/dcdbas.h
@@ -0,0 +1,107 @@
+/*
+ * dcdbas.h: Definitions for Dell Systems Management Base driver
+ *
+ * Copyright (C) 1995-2005 Dell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DCDBAS_H_
+#define _DCDBAS_H_
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define MAX_SMI_DATA_BUF_SIZE (256 * 1024)
+
+#define HC_ACTION_NONE (0)
+#define HC_ACTION_HOST_CONTROL_POWEROFF BIT(1)
+#define HC_ACTION_HOST_CONTROL_POWERCYCLE BIT(2)
+
+#define HC_SMITYPE_NONE (0)
+#define HC_SMITYPE_TYPE1 (1)
+#define HC_SMITYPE_TYPE2 (2)
+#define HC_SMITYPE_TYPE3 (3)
+
+#define ESM_APM_CMD (0x0A0)
+#define ESM_APM_POWER_CYCLE (0x10)
+#define ESM_STATUS_CMD_UNSUCCESSFUL (-1)
+
+#define CMOS_BASE_PORT (0x070)
+#define CMOS_PAGE1_INDEX_PORT (0)
+#define CMOS_PAGE1_DATA_PORT (1)
+#define CMOS_PAGE2_INDEX_PORT_PIIX4 (2)
+#define CMOS_PAGE2_DATA_PORT_PIIX4 (3)
+#define PE1400_APM_CONTROL_PORT (0x0B0)
+#define PCAT_APM_CONTROL_PORT (0x0B2)
+#define PCAT_APM_STATUS_PORT (0x0B3)
+#define PE1300_CMOS_CMD_STRUCT_PTR (0x38)
+#define PE1400_CMOS_CMD_STRUCT_PTR (0x70)
+
+#define MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN (14)
+#define MAX_SYSMGMT_LONGCMD_SGENTRY_NUM (16)
+
+#define TIMEOUT_USEC_SHORT_SEMA_BLOCKING (10000)
+#define EXPIRED_TIMER (0)
+
+#define SMI_CMD_MAGIC (0x534D4931)
+
+#define DCDBAS_DEV_ATTR_RW(_name) \
+ DEVICE_ATTR(_name,0600,_name##_show,_name##_store);
+
+#define DCDBAS_DEV_ATTR_RO(_name) \
+ DEVICE_ATTR(_name,0400,_name##_show,NULL);
+
+#define DCDBAS_DEV_ATTR_WO(_name) \
+ DEVICE_ATTR(_name,0200,NULL,_name##_store);
+
+#define DCDBAS_BIN_ATTR_RW(_name) \
+struct bin_attribute bin_attr_##_name = { \
+ .attr = { .name = __stringify(_name), \
+ .mode = 0600, \
+ .owner = THIS_MODULE }, \
+ .read = _name##_read, \
+ .write = _name##_write, \
+}
+
+struct smi_cmd {
+ __u32 magic;
+ __u32 ebx;
+ __u32 ecx;
+ __u16 command_address;
+ __u8 command_code;
+ __u8 reserved;
+ __u8 command_buffer[1];
+} __attribute__ ((packed));
+
+struct apm_cmd {
+ __u8 command;
+ __s8 status;
+ __u16 reserved;
+ union {
+ struct {
+ __u8 parm[MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN];
+ } __attribute__ ((packed)) shortreq;
+
+ struct {
+ __u16 num_sg_entries;
+ struct {
+ __u32 size;
+ __u64 addr;
+ } __attribute__ ((packed))
+ sglist[MAX_SYSMGMT_LONGCMD_SGENTRY_NUM];
+ } __attribute__ ((packed)) longreq;
+ } __attribute__ ((packed)) parameters;
+} __attribute__ ((packed));
+
+#endif /* _DCDBAS_H_ */
+
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
new file mode 100644
index 0000000..3b865f3
--- /dev/null
+++ b/drivers/firmware/dell_rbu.c
@@ -0,0 +1,634 @@
+/*
+ * dell_rbu.c
+ * Bios Update driver for Dell systems
+ * Author: Dell Inc
+ * Abhay Salunke <abhay_salunke@dell.com>
+ *
+ * Copyright (C) 2005 Dell Inc.
+ *
+ * Remote BIOS Update (rbu) driver is used for updating DELL BIOS by
+ * creating entries in the /sys file systems on Linux 2.6 and higher
+ * kernels. The driver supports two mechanism to update the BIOS namely
+ * contiguous and packetized. Both these methods still require having some
+ * application to set the CMOS bit indicating the BIOS to update itself
+ * after a reboot.
+ *
+ * Contiguous method:
+ * This driver writes the incoming data in a monolithic image by allocating
+ * contiguous physical pages large enough to accommodate the incoming BIOS
+ * image size.
+ *
+ * Packetized method:
+ * The driver writes the incoming packet image by allocating a new packet
+ * on every time the packet data is written. This driver requires an
+ * application to break the BIOS image in to fixed sized packet chunks.
+ *
+ * See Documentation/dell_rbu.txt for more info.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+
+MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
+MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+#define BIOS_SCAN_LIMIT 0xffffffff
+#define MAX_IMAGE_LENGTH 16
+static struct _rbu_data {
+ void *image_update_buffer;
+ unsigned long image_update_buffer_size;
+ unsigned long bios_image_size;
+ int image_update_ordernum;
+ int dma_alloc;
+ spinlock_t lock;
+ unsigned long packet_read_count;
+ unsigned long packet_write_count;
+ unsigned long num_packets;
+ unsigned long packetsize;
+} rbu_data;
+
+static char image_type[MAX_IMAGE_LENGTH] = "mono";
+module_param_string(image_type, image_type, sizeof(image_type), 0);
+MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet");
+
+struct packet_data {
+ struct list_head list;
+ size_t length;
+ void *data;
+ int ordernum;
+};
+
+static struct packet_data packet_data_head;
+
+static struct platform_device *rbu_device;
+static int context;
+static dma_addr_t dell_rbu_dmaaddr;
+
+static void init_packet_head(void)
+{
+ INIT_LIST_HEAD(&packet_data_head.list);
+ rbu_data.packet_write_count = 0;
+ rbu_data.packet_read_count = 0;
+ rbu_data.num_packets = 0;
+ rbu_data.packetsize = 0;
+}
+
+static int fill_last_packet(void *data, size_t length)
+{
+ struct list_head *ptemp_list;
+ struct packet_data *packet = NULL;
+ int packet_count = 0;
+
+ pr_debug("fill_last_packet: entry \n");
+
+ if (!rbu_data.num_packets) {
+ pr_debug("fill_last_packet: num_packets=0\n");
+ return -ENOMEM;
+ }
+
+ packet_count = rbu_data.num_packets;
+
+ ptemp_list = (&packet_data_head.list)->prev;
+
+ packet = list_entry(ptemp_list, struct packet_data, list);
+
+ if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) {
+ pr_debug("dell_rbu:%s: packet size data "
+ "overrun\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ pr_debug("fill_last_packet : buffer = %p\n", packet->data);
+
+ memcpy((packet->data + rbu_data.packet_write_count), data, length);
+
+ if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) {
+ /*
+ * this was the last data chunk in the packet
+ * so reinitialize the packet data counter to zero
+ */
+ rbu_data.packet_write_count = 0;
+ } else
+ rbu_data.packet_write_count += length;
+
+ pr_debug("fill_last_packet: exit \n");
+ return 0;
+}
+
+static int create_packet(size_t length)
+{
+ struct packet_data *newpacket;
+ int ordernum = 0;
+
+ pr_debug("create_packet: entry \n");
+
+ if (!rbu_data.packetsize) {
+ pr_debug("create_packet: packetsize not specified\n");
+ return -EINVAL;
+ }
+
+ newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+ if (!newpacket) {
+ printk(KERN_WARNING
+ "dell_rbu:%s: failed to allocate new "
+ "packet\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ ordernum = get_order(length);
+ /*
+ * there is no upper limit on memory
+ * address for packetized mechanism
+ */
+ newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL,
+ ordernum);
+
+ pr_debug("create_packet: newpacket %p\n", newpacket->data);
+
+ if (!newpacket->data) {
+ printk(KERN_WARNING
+ "dell_rbu:%s: failed to allocate new "
+ "packet\n", __FUNCTION__);
+ kfree(newpacket);
+ return -ENOMEM;
+ }
+
+ newpacket->ordernum = ordernum;
+ ++rbu_data.num_packets;
+ /*
+ * initialize the newly created packet headers
+ */
+ INIT_LIST_HEAD(&newpacket->list);
+ list_add_tail(&newpacket->list, &packet_data_head.list);
+ /*
+ * packets have fixed size
+ */
+ newpacket->length = rbu_data.packetsize;
+
+ pr_debug("create_packet: exit \n");
+
+ return 0;
+}
+
+static int packetize_data(void *data, size_t length)
+{
+ int rc = 0;
+
+ if (!rbu_data.packet_write_count) {
+ if ((rc = create_packet(length)))
+ return rc;
+ }
+ if ((rc = fill_last_packet(data, length)))
+ return rc;
+
+ return rc;
+}
+
+static int
+do_packet_read(char *data, struct list_head *ptemp_list,
+ int length, int bytes_read, int *list_read_count)
+{
+ void *ptemp_buf;
+ struct packet_data *newpacket = NULL;
+ int bytes_copied = 0;
+ int j = 0;
+
+ newpacket = list_entry(ptemp_list, struct packet_data, list);
+ *list_read_count += newpacket->length;
+
+ if (*list_read_count > bytes_read) {
+ /* point to the start of unread data */
+ j = newpacket->length - (*list_read_count - bytes_read);
+ /* point to the offset in the packet buffer */
+ ptemp_buf = (u8 *) newpacket->data + j;
+ /*
+ * check if there is enough room in
+ * * the incoming buffer
+ */
+ if (length > (*list_read_count - bytes_read))
+ /*
+ * copy what ever is there in this
+ * packet and move on
+ */
+ bytes_copied = (*list_read_count - bytes_read);
+ else
+ /* copy the remaining */
+ bytes_copied = length;
+ memcpy(data, ptemp_buf, bytes_copied);
+ }
+ return bytes_copied;
+}
+
+static int packet_read_list(char *data, size_t * pread_length)
+{
+ struct list_head *ptemp_list;
+ int temp_count = 0;
+ int bytes_copied = 0;
+ int bytes_read = 0;
+ int remaining_bytes = 0;
+ char *pdest = data;
+
+ /* check if we have any packets */
+ if (0 == rbu_data.num_packets)
+ return -ENOMEM;
+
+ remaining_bytes = *pread_length;
+ bytes_read = rbu_data.packet_read_count;
+
+ ptemp_list = (&packet_data_head.list)->next;
+ while (!list_empty(ptemp_list)) {
+ bytes_copied = do_packet_read(pdest, ptemp_list,
+ remaining_bytes, bytes_read,
+ &temp_count);
+ remaining_bytes -= bytes_copied;
+ bytes_read += bytes_copied;
+ pdest += bytes_copied;
+ /*
+ * check if we reached end of buffer before reaching the
+ * last packet
+ */
+ if (remaining_bytes == 0)
+ break;
+
+ ptemp_list = ptemp_list->next;
+ }
+ /*finally set the bytes read */
+ *pread_length = bytes_read - rbu_data.packet_read_count;
+ rbu_data.packet_read_count = bytes_read;
+ return 0;
+}
+
+static void packet_empty_list(void)
+{
+ struct list_head *ptemp_list;
+ struct list_head *pnext_list;
+ struct packet_data *newpacket;
+
+ ptemp_list = (&packet_data_head.list)->next;
+ while (!list_empty(ptemp_list)) {
+ newpacket =
+ list_entry(ptemp_list, struct packet_data, list);
+ pnext_list = ptemp_list->next;
+ list_del(ptemp_list);
+ ptemp_list = pnext_list;
+ /*
+ * zero out the RBU packet memory before freeing
+ * to make sure there are no stale RBU packets left in memory
+ */
+ memset(newpacket->data, 0, rbu_data.packetsize);
+ free_pages((unsigned long)newpacket->data,
+ newpacket->ordernum);
+ kfree(newpacket);
+ }
+ rbu_data.packet_write_count = 0;
+ rbu_data.packet_read_count = 0;
+ rbu_data.num_packets = 0;
+ rbu_data.packetsize = 0;
+}
+
+/*
+ * img_update_free: Frees the buffer allocated for storing BIOS image
+ * Always called with lock held and returned with lock held
+ */
+static void img_update_free(void)
+{
+ if (!rbu_data.image_update_buffer)
+ return;
+ /*
+ * zero out this buffer before freeing it to get rid of any stale
+ * BIOS image copied in memory.
+ */
+ memset(rbu_data.image_update_buffer, 0,
+ rbu_data.image_update_buffer_size);
+ if (rbu_data.dma_alloc == 1)
+ dma_free_coherent(NULL, rbu_data.bios_image_size,
+ rbu_data.image_update_buffer,
+ dell_rbu_dmaaddr);
+ else
+ free_pages((unsigned long)rbu_data.image_update_buffer,
+ rbu_data.image_update_ordernum);
+
+ /*
+ * Re-initialize the rbu_data variables after a free
+ */
+ rbu_data.image_update_ordernum = -1;
+ rbu_data.image_update_buffer = NULL;
+ rbu_data.image_update_buffer_size = 0;
+ rbu_data.bios_image_size = 0;
+ rbu_data.dma_alloc = 0;
+}
+
+/*
+ * img_update_realloc: This function allocates the contiguous pages to
+ * accommodate the requested size of data. The memory address and size
+ * values are stored globally and on every call to this function the new
+ * size is checked to see if more data is required than the existing size.
+ * If true the previous memory is freed and new allocation is done to
+ * accommodate the new size. If the incoming size is less then than the
+ * already allocated size, then that memory is reused. This function is
+ * called with lock held and returns with lock held.
+ */
+static int img_update_realloc(unsigned long size)
+{
+ unsigned char *image_update_buffer = NULL;
+ unsigned long rc;
+ unsigned long img_buf_phys_addr;
+ int ordernum;
+ int dma_alloc = 0;
+
+ /*
+ * check if the buffer of sufficient size has been
+ * already allocated
+ */
+ if (rbu_data.image_update_buffer_size >= size) {
+ /*
+ * check for corruption
+ */
+ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
+ printk(KERN_ERR "dell_rbu:%s: corruption "
+ "check failed\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ /*
+ * we have a valid pre-allocated buffer with
+ * sufficient size
+ */
+ return 0;
+ }
+
+ /*
+ * free any previously allocated buffer
+ */
+ img_update_free();
+
+ spin_unlock(&rbu_data.lock);
+
+ ordernum = get_order(size);
+ image_update_buffer =
+ (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum);
+
+ img_buf_phys_addr =
+ (unsigned long)virt_to_phys(image_update_buffer);
+
+ if (img_buf_phys_addr > BIOS_SCAN_LIMIT) {
+ free_pages((unsigned long)image_update_buffer, ordernum);
+ ordernum = -1;
+ image_update_buffer = dma_alloc_coherent(NULL, size,
+ &dell_rbu_dmaaddr,
+ GFP_KERNEL);
+ dma_alloc = 1;
+ }
+
+ spin_lock(&rbu_data.lock);
+
+ if (image_update_buffer != NULL) {
+ rbu_data.image_update_buffer = image_update_buffer;
+ rbu_data.image_update_buffer_size = size;
+ rbu_data.bios_image_size =
+ rbu_data.image_update_buffer_size;
+ rbu_data.image_update_ordernum = ordernum;
+ rbu_data.dma_alloc = dma_alloc;
+ rc = 0;
+ } else {
+ pr_debug("Not enough memory for image update:"
+ "size = %ld\n", size);
+ rc = -ENOMEM;
+ }
+
+ return rc;
+}
+
+static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count)
+{
+ int retval;
+ size_t bytes_left;
+ size_t data_length;
+ char *ptempBuf = buffer;
+ unsigned long imagesize;
+
+ /* check to see if we have something to return */
+ if (rbu_data.num_packets == 0) {
+ pr_debug("read_packet_data: no packets written\n");
+ retval = -ENOMEM;
+ goto read_rbu_data_exit;
+ }
+
+ imagesize = rbu_data.num_packets * rbu_data.packetsize;
+
+ if (pos > imagesize) {
+ retval = 0;
+ printk(KERN_WARNING "dell_rbu:read_packet_data: "
+ "data underrun\n");
+ goto read_rbu_data_exit;
+ }
+
+ bytes_left = imagesize - pos;
+ data_length = min(bytes_left, count);
+
+ if ((retval = packet_read_list(ptempBuf, &data_length)) < 0)
+ goto read_rbu_data_exit;
+
+ if ((pos + count) > imagesize) {
+ rbu_data.packet_read_count = 0;
+ /* this was the last copy */
+ retval = bytes_left;
+ } else
+ retval = count;
+
+ read_rbu_data_exit:
+ return retval;
+}
+
+static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
+{
+ unsigned char *ptemp = NULL;
+ size_t bytes_left = 0;
+ size_t data_length = 0;
+ ssize_t ret_count = 0;
+
+ /* check to see if we have something to return */
+ if ((rbu_data.image_update_buffer == NULL) ||
+ (rbu_data.bios_image_size == 0)) {
+ pr_debug("read_rbu_data_mono: image_update_buffer %p ,"
+ "bios_image_size %lu\n",
+ rbu_data.image_update_buffer,
+ rbu_data.bios_image_size);
+ ret_count = -ENOMEM;
+ goto read_rbu_data_exit;
+ }
+
+ if (pos > rbu_data.bios_image_size) {
+ ret_count = 0;
+ goto read_rbu_data_exit;
+ }
+
+ bytes_left = rbu_data.bios_image_size - pos;
+ data_length = min(bytes_left, count);
+
+ ptemp = rbu_data.image_update_buffer;
+ memcpy(buffer, (ptemp + pos), data_length);
+
+ if ((pos + count) > rbu_data.bios_image_size)
+ /* this was the last copy */
+ ret_count = bytes_left;
+ else
+ ret_count = count;
+ read_rbu_data_exit:
+ return ret_count;
+}
+
+static ssize_t
+read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count)
+{
+ ssize_t ret_count = 0;
+
+ spin_lock(&rbu_data.lock);
+
+ if (!strcmp(image_type, "mono"))
+ ret_count = read_rbu_mono_data(buffer, pos, count);
+ else if (!strcmp(image_type, "packet"))
+ ret_count = read_packet_data(buffer, pos, count);
+ else
+ pr_debug("read_rbu_data: invalid image type specified\n");
+
+ spin_unlock(&rbu_data.lock);
+ return ret_count;
+}
+
+static ssize_t
+read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
+ size_t count)
+{
+ int size = 0;
+ if (!pos)
+ size = sprintf(buffer, "%s\n", image_type);
+ return size;
+}
+
+static ssize_t
+write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
+ size_t count)
+{
+ int rc = count;
+ spin_lock(&rbu_data.lock);
+
+ if (strlen(buffer) < MAX_IMAGE_LENGTH)
+ sscanf(buffer, "%s", image_type);
+ else
+ printk(KERN_WARNING "dell_rbu: image_type is invalid"
+ "max chars = %d, \n incoming str--%s-- \n",
+ MAX_IMAGE_LENGTH, buffer);
+
+ /* we must free all previous allocations */
+ packet_empty_list();
+ img_update_free();
+
+ spin_unlock(&rbu_data.lock);
+ return rc;
+
+}
+
+static struct bin_attribute rbu_data_attr = {
+ .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
+ .read = read_rbu_data,
+};
+
+static struct bin_attribute rbu_image_type_attr = {
+ .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
+ .read = read_rbu_image_type,
+ .write = write_rbu_image_type,
+};
+
+static void callbackfn_rbu(const struct firmware *fw, void *context)
+{
+ int rc = 0;
+
+ if (!fw || !fw->size)
+ return;
+
+ spin_lock(&rbu_data.lock);
+ if (!strcmp(image_type, "mono")) {
+ if (!img_update_realloc(fw->size))
+ memcpy(rbu_data.image_update_buffer,
+ fw->data, fw->size);
+ } else if (!strcmp(image_type, "packet")) {
+ if (!rbu_data.packetsize)
+ rbu_data.packetsize = fw->size;
+ else if (rbu_data.packetsize != fw->size) {
+ packet_empty_list();
+ rbu_data.packetsize = fw->size;
+ }
+ packetize_data(fw->data, fw->size);
+ } else
+ pr_debug("invalid image type specified.\n");
+ spin_unlock(&rbu_data.lock);
+
+ rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ "dell_rbu", &rbu_device->dev,
+ &context, callbackfn_rbu);
+ if (rc)
+ printk(KERN_ERR
+ "dell_rbu:%s request_firmware_nowait failed"
+ " %d\n", __FUNCTION__, rc);
+}
+
+static int __init dcdrbu_init(void)
+{
+ int rc = 0;
+ spin_lock_init(&rbu_data.lock);
+
+ init_packet_head();
+ rbu_device =
+ platform_device_register_simple("dell_rbu", -1, NULL, 0);
+ if (!rbu_device) {
+ printk(KERN_ERR
+ "dell_rbu:%s:platform_device_register_simple "
+ "failed\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
+ sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
+
+ rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ "dell_rbu", &rbu_device->dev,
+ &context, callbackfn_rbu);
+ if (rc)
+ printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait"
+ " failed %d\n", __FUNCTION__, rc);
+
+ return rc;
+
+}
+
+static __exit void dcdrbu_exit(void)
+{
+ spin_lock(&rbu_data.lock);
+ packet_empty_list();
+ img_update_free();
+ spin_unlock(&rbu_data.lock);
+ platform_device_unregister(rbu_device);
+}
+
+module_exit(dcdrbu_exit);
+module_init(dcdrbu_init);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 140d5f8..138dc50 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -12,12 +12,20 @@
of a system. Most modern motherboards include such a device. It
can include temperature sensors, voltage sensors, fan speed
sensors and various additional features such as the ability to
- control the speed of the fans.
+ control the speed of the fans. If you want this support you
+ should say Y here and also to the specific driver(s) for your
+ sensors chip(s) below.
+
+ This support can also be built as a module. If so, the module
+ will be called hwmon.
+
+config HWMON_VID
+ tristate
+ default n
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for Analog Devices ADM1021
and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
@@ -30,7 +38,7 @@
config SENSORS_ADM1025
tristate "Analog Devices ADM1025 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1025
and Philips NE1619 sensor chips.
@@ -41,7 +49,7 @@
config SENSORS_ADM1026
tristate "Analog Devices ADM1026 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1026
sensor chip.
@@ -52,7 +60,6 @@
config SENSORS_ADM1031
tristate "Analog Devices ADM1031 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Analog Devices ADM1031
and ADM1030 sensor chips.
@@ -63,7 +70,7 @@
config SENSORS_ADM9240
tristate "Analog Devices ADM9240 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM9240,
Dallas DS1780, National Semiconductor LM81 sensor chips.
@@ -74,7 +81,7 @@
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
chip found on some Asus mainboards.
@@ -85,7 +92,7 @@
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for the Attansic ATXP1 VID
controller.
@@ -99,7 +106,6 @@
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Dallas Semiconductor
DS1621 and DS1625 sensor chips.
@@ -110,7 +116,6 @@
config SENSORS_FSCHER
tristate "FSC Hermes"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -121,7 +126,6 @@
config SENSORS_FSCPOS
tristate "FSC Poseidon"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -132,7 +136,6 @@
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for Genesys Logic GL518SM
sensor chips.
@@ -143,7 +146,7 @@
config SENSORS_GL520SM
tristate "Genesys Logic GL520SM"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Genesys Logic GL520SM
sensor chips.
@@ -154,7 +157,8 @@
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
+ select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for ITE IT87xx sensor chips
and clones: SiS960.
@@ -165,7 +169,6 @@
config SENSORS_LM63
tristate "National Semiconductor LM63"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for the National Semiconductor
LM63 remote diode digital temperature sensor with integrated fan
@@ -178,7 +181,6 @@
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM75
sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
@@ -194,7 +196,6 @@
config SENSORS_LM77
tristate "National Semiconductor LM77"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM77
sensor chips.
@@ -205,7 +206,8 @@
config SENSORS_LM78
tristate "National Semiconductor LM78 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM78,
LM78-J and LM79.
@@ -216,7 +218,6 @@
config SENSORS_LM80
tristate "National Semiconductor LM80"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor
LM80 sensor chips.
@@ -227,7 +228,6 @@
config SENSORS_LM83
tristate "National Semiconductor LM83"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor
LM83 sensor chips.
@@ -238,7 +238,7 @@
config SENSORS_LM85
tristate "National Semiconductor LM85 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM85
sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
@@ -249,7 +249,7 @@
config SENSORS_LM87
tristate "National Semiconductor LM87"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
sensor chips.
@@ -260,7 +260,6 @@
config SENSORS_LM90
tristate "National Semiconductor LM90 and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM90,
LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
@@ -275,7 +274,6 @@
config SENSORS_LM92
tristate "National Semiconductor LM92 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM92
and Maxim MAX6635 sensor chips.
@@ -286,7 +284,6 @@
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for MAX1619 sensor chip.
@@ -296,8 +293,8 @@
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get access to the hardware monitoring
functions of the National Semiconductor PC8736x Super-I/O chips.
@@ -311,7 +308,6 @@
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
depends on HWMON && I2C && PCI && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the integrated sensors in
@@ -323,7 +319,6 @@
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the integrated fan
@@ -336,7 +331,6 @@
config SENSORS_SMSC47B397
tristate "SMSC LPC47B397-NC"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the SMSC LPC47B397-NC
@@ -348,7 +342,6 @@
config SENSORS_VIA686A
tristate "VIA686A"
depends on HWMON && I2C && PCI
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the integrated sensors in
@@ -360,7 +353,8 @@
config SENSORS_W83781D
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
depends on HWMON && I2C
- select I2C_SENSOR
+ select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for the Winbond W8378x series
of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
@@ -369,10 +363,18 @@
This driver can also be built as a module. If so, the module
will be called w83781d.
+config SENSORS_W83792D
+ tristate "Winbond W83792D"
+ depends on HWMON && I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Winbond W83792D chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83792d.
+
config SENSORS_W83L785TS
tristate "Winbond W83L785TS-S"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for the Winbond W83L785TS-S
sensor chip, which is used on the Asus A7N8X, among other
@@ -384,8 +386,8 @@
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for the Winbond W836X7 series
of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
@@ -396,7 +398,6 @@
config SENSORS_W83627EHF
tristate "Winbond W83627EHF"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get preliminary support for the hardware
@@ -404,6 +405,9 @@
Only fan and temperature inputs are supported at the moment, while
the chip does much more than that.
+ This driver also supports the W83627EHG, which is the lead-free
+ version of the W83627EHF.
+
This driver can also be built as a module. If so, the module
will be called w83627ehf.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2781403..381f1bf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -2,9 +2,13 @@
# Makefile for sensor chip drivers.
#
+obj-$(CONFIG_HWMON) += hwmon.o
+obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
+
# asb100, then w83781d go first, as they can override other drivers' addresses.
obj-$(CONFIG_SENSORS_ASB100) += asb100.o
obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
+obj-$(CONFIG_SENSORS_W83792D) += w83792d.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index d2c774c..e928cdb 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -24,7 +24,8 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
@@ -32,10 +33,9 @@
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
+I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
/* adm1021 constants specified below */
@@ -89,6 +89,7 @@
/* Each client has this additional data */
struct adm1021_data {
struct i2c_client client;
+ struct class_device *class_dev;
enum chips type;
struct semaphore update_lock;
@@ -185,7 +186,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm1021_detect);
+ return i2c_probe(adapter, &addr_data, adm1021_detect);
}
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -196,15 +197,6 @@
int err = 0;
const char *type_name = "";
- /* Make sure we aren't probing the ISA bus!! This is just a safety check
- at this moment; i2c_detect really won't call us. */
-#ifdef DEBUG
- if (i2c_is_isa_adapter(adapter)) {
- dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n");
- return 0;
- }
-#endif
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto error0;
@@ -295,6 +287,12 @@
adm1021_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error2;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_max);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
@@ -305,6 +303,8 @@
return 0;
+error2:
+ i2c_detach_client(new_client);
error1:
kfree(data);
error0:
@@ -322,14 +322,15 @@
static int adm1021_detach_client(struct i2c_client *client)
{
+ struct adm1021_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index e452d0d..526b7ff 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -50,8 +50,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -60,13 +61,12 @@
*/
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_2(adm1025, ne1619);
+I2C_CLIENT_INSMOD_2(adm1025, ne1619);
/*
* The ADM1025 registers
@@ -132,6 +132,7 @@
struct adm1025_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -312,7 +313,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm1025_detect);
+ return i2c_probe(adapter, &addr_data, adm1025_detect);
}
/*
@@ -416,6 +417,12 @@
adm1025_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -452,6 +459,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -464,7 +473,7 @@
struct adm1025_data *data = i2c_get_clientdata(client);
int i;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
/*
* Set high limits
@@ -502,15 +511,15 @@
static int adm1025_detach_client(struct i2c_client *client)
{
+ struct adm1025_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index c8a7f47..6251581 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -28,16 +28,16 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(adm1026);
+I2C_CLIENT_INSMOD_1(adm1026);
static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
@@ -259,6 +259,7 @@
struct adm1026_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -319,13 +320,15 @@
if (!(adapter->class & I2C_CLASS_HWMON)) {
return 0;
}
- return i2c_detect(adapter, &addr_data, adm1026_detect);
+ return i2c_probe(adapter, &addr_data, adm1026_detect);
}
int adm1026_detach_client(struct i2c_client *client)
{
+ struct adm1026_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -1549,12 +1552,18 @@
goto exitfree;
/* Set the VRM version */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
/* Initialize the ADM1026 chip */
adm1026_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exitdetach;
+ }
+
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
@@ -1690,6 +1699,8 @@
return 0;
/* Error out and cleanup code */
+exitdetach:
+ i2c_detach_client(new_client);
exitfree:
kfree(data);
exit:
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 9362509..58338ed 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -26,7 +26,8 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Following macros takes channel parameter starting from 0 to 2 */
#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr))
@@ -59,16 +60,16 @@
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_2(adm1030, adm1031);
+I2C_CLIENT_INSMOD_2(adm1030, adm1031);
typedef u8 auto_chan_table_t[8][2];
/* Each client has this additional data */
struct adm1031_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
int chip_type;
char valid; /* !=0 if following fields are valid */
@@ -725,10 +726,10 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm1031_detect);
+ return i2c_probe(adapter, &addr_data, adm1031_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -788,6 +789,12 @@
adm1031_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan1_div);
device_create_file(&new_client->dev, &dev_attr_fan1_min);
@@ -833,6 +840,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -841,11 +850,14 @@
static int adm1031_detach_client(struct i2c_client *client)
{
+ struct adm1031_data *data = i2c_get_clientdata(client);
int ret;
+
+ hwmon_device_unregister(data->class_dev);
if ((ret = i2c_detach_client(client)) != 0) {
return ret;
}
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index ce2a6eb..bc7faef 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -45,17 +45,16 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-
/* Insmod parameters */
-SENSORS_INSMOD_3(adm9240, ds1780, lm81);
+I2C_CLIENT_INSMOD_3(adm9240, ds1780, lm81);
/* ADM9240 registers */
#define ADM9240_REG_MAN_ID 0x3e
@@ -150,6 +149,7 @@
struct adm9240_data {
enum chips type;
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid;
unsigned long last_updated_measure;
@@ -582,6 +582,12 @@
adm9240_init_client(new_client);
/* populate sysfs filesystem */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -615,6 +621,9 @@
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
return 0;
+
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -625,20 +634,20 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm9240_detect);
+ return i2c_probe(adapter, &addr_data, adm9240_detect);
}
static int adm9240_detach_client(struct i2c_client *client)
{
+ struct adm9240_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
@@ -648,7 +657,7 @@
u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
- data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
+ data->vrm = vid_which_vrm(); /* need this to report vid as mV */
dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
data->vrm % 10);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 70d996d..8e34855 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -39,8 +39,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include "lm75.h"
@@ -54,11 +55,8 @@
/* I2C addresses to scan */
static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
-/* ISA addresses to scan (none) */
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-
/* Insmod parameters */
-SENSORS_INSMOD_1(asb100);
+I2C_CLIENT_INSMOD_1(asb100);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
@@ -183,6 +181,7 @@
dynamically allocated, at the same time the client itself is allocated. */
struct asb100_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -621,7 +620,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, asb100_detect);
+ return i2c_probe(adapter, &addr_data, asb100_detect);
}
static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
@@ -714,14 +713,6 @@
struct i2c_client *new_client;
struct asb100_data *data;
- /* asb100 is SMBus only */
- if (i2c_is_isa_adapter(adapter)) {
- pr_debug("asb100.o: detect failed, "
- "cannot attach to legacy adapter!\n");
- err = -ENODEV;
- goto ERROR0;
- }
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("asb100.o: detect failed, "
"smbus byte data not supported!\n");
@@ -821,6 +812,12 @@
data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file_in(new_client, 0);
device_create_file_in(new_client, 1);
device_create_file_in(new_client, 2);
@@ -847,6 +844,11 @@
return 0;
+ERROR3:
+ i2c_detach_client(data->lm75[1]);
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[1]);
+ kfree(data->lm75[0]);
ERROR2:
i2c_detach_client(new_client);
ERROR1:
@@ -857,21 +859,23 @@
static int asb100_detach_client(struct i2c_client *client)
{
+ struct asb100_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "client deregistration failed; "
- "client not detached.\n");
- return err;
- }
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
- if (i2c_get_clientdata(client)==NULL) {
- /* subclients */
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ /* main client */
+ if (data)
+ kfree(data);
+
+ /* subclient */
+ else
kfree(client);
- } else {
- /* main client */
- kfree(i2c_get_clientdata(client));
- }
return 0;
}
@@ -969,7 +973,7 @@
vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
vid = vid_from_reg(vid, data->vrm);
/* Start monitoring */
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index fca3fc1..deb4d34 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -23,8 +23,9 @@
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
@@ -40,9 +41,8 @@
#define ATXP1_GPIO1MASK 0x0f
static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-SENSORS_INSMOD_1(atxp1);
+I2C_CLIENT_INSMOD_1(atxp1);
static int atxp1_attach_adapter(struct i2c_adapter * adapter);
static int atxp1_detach_client(struct i2c_client * client);
@@ -59,6 +59,7 @@
struct atxp1_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
unsigned long last_updated;
u8 valid;
@@ -252,7 +253,7 @@
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, &atxp1_detect);
+ return i2c_probe(adapter, &addr_data, &atxp1_detect);
};
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -295,7 +296,7 @@
}
/* Get VRM */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if ((data->vrm != 90) && (data->vrm != 91)) {
dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
@@ -317,6 +318,12 @@
goto exit_free;
}
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_gpio1);
device_create_file(&new_client->dev, &dev_attr_gpio2);
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
@@ -326,6 +333,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -334,14 +343,17 @@
static int atxp1_detach_client(struct i2c_client * client)
{
+ struct atxp1_data * data = i2c_get_clientdata(client);
int err;
+ hwmon_device_unregister(data->class_dev);
+
err = i2c_detach_client(client);
if (err)
dev_err(&client->dev, "Failed to detach client.\n");
else
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return err;
};
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 5360d58..b0199e0 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -26,16 +26,16 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include "lm75.h"
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(ds1621);
+I2C_CLIENT_INSMOD_1(ds1621);
static int polarity = -1;
module_param(polarity, int, 0);
MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
@@ -71,6 +71,7 @@
/* Each client has this additional data */
struct ds1621_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -179,10 +180,10 @@
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, ds1621_detect);
+ return i2c_probe(adapter, &addr_data, ds1621_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int ds1621_detect(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -250,6 +251,12 @@
ds1621_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_alarms);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -259,6 +266,8 @@
/* OK, this is not exactly good programming practice, usually. But it is
very code-efficient in this case. */
+ exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -267,15 +276,15 @@
static int ds1621_detach_client(struct i2c_client *client)
{
+ struct ds1621_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index da41174..eef6061 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -31,20 +31,20 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
*/
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(fscher);
+I2C_CLIENT_INSMOD_1(fscher);
/*
* The FSCHER registers
@@ -132,6 +132,7 @@
struct fscher_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -287,7 +288,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, fscher_detect);
+ return i2c_probe(adapter, &addr_data, fscher_detect);
}
static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -341,6 +342,12 @@
fscher_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file_revision(new_client);
device_create_file_alarms(new_client);
device_create_file_control(new_client);
@@ -360,6 +367,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -368,15 +377,15 @@
static int fscher_detach_client(struct i2c_client *client)
{
+ struct fscher_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 301ae98..5fc77a5f 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -34,19 +34,19 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
*/
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(fscpos);
+I2C_CLIENT_INSMOD_1(fscpos);
/*
* The FSCPOS registers
@@ -113,6 +113,7 @@
*/
struct fscpos_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* 0 until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -434,7 +435,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, fscpos_detect);
+ return i2c_probe(adapter, &addr_data, fscpos_detect);
}
int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -496,6 +497,12 @@
dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_event);
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
@@ -526,6 +533,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -534,14 +543,14 @@
static int fscpos_detach_client(struct i2c_client *client)
{
+ struct fscpos_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, client"
- " not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 6bedf72..256b932 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -41,14 +41,14 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80);
+I2C_CLIENT_INSMOD_2(gl518sm_r00, gl518sm_r80);
/* Many GL518 constants specified below */
@@ -117,6 +117,7 @@
/* Each client has this additional data */
struct gl518_data {
struct i2c_client client;
+ struct class_device *class_dev;
enum chips type;
struct semaphore update_lock;
@@ -346,7 +347,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, gl518_detect);
+ return i2c_probe(adapter, &addr_data, gl518_detect);
}
static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -419,6 +420,12 @@
gl518_init_client((struct i2c_client *) new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -450,6 +457,8 @@
/* OK, this is not exactly good programming practice, usually. But it is
very code-efficient in this case. */
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -477,16 +486,15 @@
static int gl518_detach_client(struct i2c_client *client)
{
+ struct gl518_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
-
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 80ae8d3..12fd757 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -26,8 +26,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Type of the extra sensor */
static unsigned short extra_sensor_type;
@@ -36,10 +37,9 @@
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(gl520sm);
+I2C_CLIENT_INSMOD_1(gl520sm);
/* Many GL520 constants specified below
One of the inputs can be configured as either temp or voltage.
@@ -120,6 +120,7 @@
/* Client data */
struct gl520_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until the following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -518,7 +519,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, gl520_detect);
+ return i2c_probe(adapter, &addr_data, gl520_detect);
}
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -571,6 +572,12 @@
gl520_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file_vid(new_client, 0);
device_create_file_in(new_client, 0);
@@ -592,6 +599,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -608,7 +617,7 @@
conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
data->alarm_mask = 0xff;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if (extra_sensor_type == 1)
conf &= ~0x10;
@@ -639,15 +648,15 @@
static int gl520_detach_client(struct i2c_client *client)
{
+ struct gl520_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
new file mode 100644
index 0000000..312769a
--- /dev/null
+++ b/drivers/hwmon/hwmon-vid.c
@@ -0,0 +1,189 @@
+/*
+ hwmon-vid.c - VID/VRM/VRD voltage conversions
+
+ Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
+
+ Partly imported from i2c-vid.h of the lm_sensors project
+ Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ With assistance from Trent Piepho <xyzzy@speakeasy.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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon-vid.h>
+
+/*
+ Common code for decoding VID pins.
+
+ References:
+
+ For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
+ available at http://developer.intel.com/.
+
+ For VRD 10.0 and up, "VRD x.y Design Guide",
+ available at http://developer.intel.com/.
+
+ AMD Opteron processors don't follow the Intel specifications.
+ I'm going to "make up" 2.4 as the spec number for the Opterons.
+ No good reason just a mnemonic for the 24x Opteron processor
+ series.
+
+ Opteron VID encoding is:
+ 00000 = 1.550 V
+ 00001 = 1.525 V
+ . . . .
+ 11110 = 0.800 V
+ 11111 = 0.000 V (off)
+*/
+
+/* vrm is the VRM/VRD document version multiplied by 10.
+ val is the 4-, 5- or 6-bit VID code.
+ Returned value is in mV to avoid floating point in the kernel. */
+int vid_from_reg(int val, int vrm)
+{
+ int vid;
+
+ switch(vrm) {
+
+ case 0:
+ return 0;
+
+ case 100: /* VRD 10.0 */
+ if((val & 0x1f) == 0x1f)
+ return 0;
+ if((val & 0x1f) <= 0x09 || val == 0x0a)
+ vid = 10875 - (val & 0x1f) * 250;
+ else
+ vid = 18625 - (val & 0x1f) * 250;
+ if(val & 0x20)
+ vid -= 125;
+ vid /= 10; /* only return 3 dec. places for now */
+ return vid;
+
+ case 24: /* Opteron processor */
+ return(val == 0x1f ? 0 : 1550 - val * 25);
+
+ case 91: /* VRM 9.1 */
+ case 90: /* VRM 9.0 */
+ return(val == 0x1f ? 0 :
+ 1850 - val * 25);
+
+ case 85: /* VRM 8.5 */
+ return((val & 0x10 ? 25 : 0) +
+ ((val & 0x0f) > 0x04 ? 2050 : 1250) -
+ ((val & 0x0f) * 50));
+
+ case 84: /* VRM 8.4 */
+ val &= 0x0f;
+ /* fall through */
+ default: /* VRM 8.2 */
+ return(val == 0x1f ? 0 :
+ val & 0x10 ? 5100 - (val) * 100 :
+ 2050 - (val) * 50);
+ }
+}
+
+
+/*
+ After this point is the code to automatically determine which
+ VRM/VRD specification should be used depending on the CPU.
+*/
+
+struct vrm_model {
+ u8 vendor;
+ u8 eff_family;
+ u8 eff_model;
+ int vrm_type;
+};
+
+#define ANY 0xFF
+
+#ifdef CONFIG_X86
+
+static struct vrm_model vrm_models[] = {
+ {X86_VENDOR_AMD, 0x6, ANY, 90}, /* Athlon Duron etc */
+ {X86_VENDOR_AMD, 0xF, ANY, 24}, /* Athlon 64, Opteron */
+ {X86_VENDOR_INTEL, 0x6, 0x9, 85}, /* 0.13um too */
+ {X86_VENDOR_INTEL, 0x6, 0xB, 85}, /* Tualatin */
+ {X86_VENDOR_INTEL, 0x6, ANY, 82}, /* any P6 */
+ {X86_VENDOR_INTEL, 0x7, ANY, 0}, /* Itanium */
+ {X86_VENDOR_INTEL, 0xF, 0x0, 90}, /* P4 */
+ {X86_VENDOR_INTEL, 0xF, 0x1, 90}, /* P4 Willamette */
+ {X86_VENDOR_INTEL, 0xF, 0x2, 90}, /* P4 Northwood */
+ {X86_VENDOR_INTEL, 0xF, 0x3, 100}, /* P4 Prescott */
+ {X86_VENDOR_INTEL, 0xF, 0x4, 100}, /* P4 Prescott */
+ {X86_VENDOR_INTEL, 0x10,ANY, 0}, /* Itanium 2 */
+ {X86_VENDOR_UNKNOWN, ANY, ANY, 0} /* stop here */
+};
+
+static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor)
+{
+ int i = 0;
+
+ while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
+ if (vrm_models[i].vendor==vendor)
+ if ((vrm_models[i].eff_family==eff_family)
+ && ((vrm_models[i].eff_model==eff_model) ||
+ (vrm_models[i].eff_model==ANY)))
+ return vrm_models[i].vrm_type;
+ i++;
+ }
+
+ return 0;
+}
+
+int vid_which_vrm(void)
+{
+ struct cpuinfo_x86 *c = cpu_data;
+ u32 eax;
+ u8 eff_family, eff_model;
+ int vrm_ret;
+
+ if (c->x86 < 6) /* Any CPU with family lower than 6 */
+ return 0; /* doesn't have VID and/or CPUID */
+
+ eax = cpuid_eax(1);
+ eff_family = ((eax & 0x00000F00)>>8);
+ eff_model = ((eax & 0x000000F0)>>4);
+ if (eff_family == 0xF) { /* use extended model & family */
+ eff_family += ((eax & 0x00F00000)>>20);
+ eff_model += ((eax & 0x000F0000)>>16)<<4;
+ }
+ vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor);
+ if (vrm_ret == 0)
+ printk(KERN_INFO "hwmon-vid: Unknown VRM version of your "
+ "x86 CPU\n");
+ return vrm_ret;
+}
+
+/* and now something completely different for the non-x86 world */
+#else
+int vid_which_vrm(void)
+{
+ printk(KERN_INFO "hwmon-vid: Unknown VRM version of your CPU\n");
+ return 0;
+}
+#endif
+
+EXPORT_SYMBOL(vid_from_reg);
+EXPORT_SYMBOL(vid_which_vrm);
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+
+MODULE_DESCRIPTION("hwmon-vid driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
new file mode 100644
index 0000000..9b41c9b
--- /dev/null
+++ b/drivers/hwmon/hwmon.c
@@ -0,0 +1,98 @@
+/*
+ hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
+
+ This file defines the sysfs class "hwmon", for use by sensors drivers.
+
+ Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.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/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/hwmon.h>
+
+#define HWMON_ID_PREFIX "hwmon"
+#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
+
+static struct class *hwmon_class;
+
+static DEFINE_IDR(hwmon_idr);
+
+/**
+ * hwmon_device_register - register w/ hwmon sysfs class
+ * @dev: the device to register
+ *
+ * hwmon_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct class_device *hwmon_device_register(struct device *dev)
+{
+ struct class_device *cdev;
+ int id;
+
+ if (idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)
+ return ERR_PTR(-ENOMEM);
+
+ if (idr_get_new(&hwmon_idr, NULL, &id) < 0)
+ return ERR_PTR(-ENOMEM);
+
+ id = id & MAX_ID_MASK;
+ cdev = class_device_create(hwmon_class, MKDEV(0,0), dev,
+ HWMON_ID_FORMAT, id);
+
+ if (IS_ERR(cdev))
+ idr_remove(&hwmon_idr, id);
+
+ return cdev;
+}
+
+/**
+ * hwmon_device_unregister - removes the previously registered class device
+ *
+ * @cdev: the class device to destroy
+ */
+void hwmon_device_unregister(struct class_device *cdev)
+{
+ int id;
+
+ if (sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1) {
+ class_device_unregister(cdev);
+ idr_remove(&hwmon_idr, id);
+ } else
+ dev_dbg(cdev->dev,
+ "hwmon_device_unregister() failed: bad class ID!\n");
+}
+
+static int __init hwmon_init(void)
+{
+ hwmon_class = class_create(THIS_MODULE, "hwmon");
+ if (IS_ERR(hwmon_class)) {
+ printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
+ return PTR_ERR(hwmon_class);
+ }
+ return 0;
+}
+
+static void __exit hwmon_exit(void)
+{
+ class_destroy(hwmon_class);
+}
+
+module_init(hwmon_init);
+module_exit(hwmon_exit);
+
+EXPORT_SYMBOL_GPL(hwmon_device_register);
+EXPORT_SYMBOL_GPL(hwmon_device_unregister);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index db20c9e..53cc2b6 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -36,19 +36,21 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
/* Insmod parameters */
-SENSORS_INSMOD_2(it87, it8712);
+I2C_CLIENT_INSMOD_2(it87, it8712);
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
@@ -192,6 +194,7 @@
allocated. */
struct it87_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -218,7 +221,7 @@
static int it87_attach_adapter(struct i2c_adapter *adapter);
-static int it87_find(int *address);
+static int it87_isa_attach_adapter(struct i2c_adapter *adapter);
static int it87_detect(struct i2c_adapter *adapter, int address, int kind);
static int it87_detach_client(struct i2c_client *client);
@@ -239,6 +242,14 @@
.detach_client = it87_detach_client,
};
+static struct i2c_driver it87_isa_driver = {
+ .owner = THIS_MODULE,
+ .name = "it87-isa",
+ .attach_adapter = it87_isa_attach_adapter,
+ .detach_client = it87_detach_client,
+};
+
+
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -686,11 +697,16 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, it87_detect);
+ return i2c_probe(adapter, &addr_data, it87_detect);
}
-/* SuperIO detection - will change normal_isa[0] if a chip is found */
-static int it87_find(int *address)
+static int it87_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+ return it87_detect(adapter, isa_address, -1);
+}
+
+/* SuperIO detection - will change isa_address if a chip is found */
+static int __init it87_find(int *address)
{
int err = -ENODEV;
@@ -721,7 +737,7 @@
return err;
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int it87_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
@@ -738,7 +754,7 @@
/* Reserve the ISA region */
if (is_isa)
- if (!request_region(address, IT87_EXTENT, it87_driver.name))
+ if (!request_region(address, IT87_EXTENT, it87_isa_driver.name))
goto ERROR0;
/* Probe whether there is anything available on this address. Already
@@ -784,7 +800,7 @@
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = &it87_driver;
+ new_client->driver = is_isa ? &it87_isa_driver : &it87_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
@@ -840,6 +856,12 @@
it87_init_client(new_client, data);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
@@ -897,13 +919,15 @@
}
if (data->type == it8712) {
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
device_create_file_vrm(new_client);
device_create_file_vid(new_client);
}
return 0;
+ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
kfree(data);
ERROR1:
@@ -915,17 +939,17 @@
static int it87_detach_client(struct i2c_client *client)
{
+ struct it87_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
if(i2c_is_isa_client(client))
release_region(client->addr, IT87_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -1158,16 +1182,28 @@
static int __init sm_it87_init(void)
{
- int addr;
+ int addr, res;
if (!it87_find(&addr)) {
- normal_isa[0] = addr;
+ isa_address = addr;
}
- return i2c_add_driver(&it87_driver);
+
+ res = i2c_add_driver(&it87_driver);
+ if (res)
+ return res;
+
+ res = i2c_isa_add_driver(&it87_isa_driver);
+ if (res) {
+ i2c_del_driver(&it87_driver);
+ return res;
+ }
+
+ return 0;
}
static void __exit sm_it87_exit(void)
{
+ i2c_isa_del_driver(&it87_isa_driver);
i2c_del_driver(&it87_driver);
}
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 7c6f9ea..be5c709 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -42,8 +42,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -51,13 +52,12 @@
*/
static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(lm63);
+I2C_CLIENT_INSMOD_1(lm63);
/*
* The LM63 registers
@@ -152,6 +152,7 @@
struct lm63_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -358,7 +359,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm63_detect);
+ return i2c_probe(adapter, &addr_data, lm63_detect);
}
/*
@@ -437,6 +438,12 @@
lm63_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
if (data->config & 0x04) { /* tachometer enabled */
device_create_file(&new_client->dev,
&sensor_dev_attr_fan1_input.dev_attr);
@@ -462,6 +469,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -505,15 +514,15 @@
static int lm63_detach_client(struct i2c_client *client)
{
+ struct lm63_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 5be164e..9a3ebdf 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -23,17 +23,17 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include "lm75.h"
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm75);
+I2C_CLIENT_INSMOD_1(lm75);
/* Many LM75 constants specified below */
@@ -46,6 +46,7 @@
/* Each client has this additional data */
struct lm75_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -107,10 +108,10 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm75_detect);
+ return i2c_probe(adapter, &addr_data, lm75_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
@@ -119,16 +120,6 @@
int err = 0;
const char *name = "";
- /* Make sure we aren't probing the ISA bus!! This is just a safety check
- at this moment; i2c_detect really won't call us. */
-#ifdef DEBUG
- if (i2c_is_isa_adapter(adapter)) {
- dev_dbg(&adapter->dev,
- "lm75_detect called for an ISA bus adapter?!?\n");
- goto exit;
- }
-#endif
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
goto exit;
@@ -208,12 +199,20 @@
lm75_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_max);
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -222,8 +221,10 @@
static int lm75_detach_client(struct i2c_client *client)
{
+ struct lm75_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -251,8 +252,12 @@
static void lm75_init_client(struct i2c_client *client)
{
- /* Initialize the LM75 chip */
- lm75_write_value(client, LM75_REG_CONF, 0);
+ int reg;
+
+ /* Enable if in shutdown mode */
+ reg = lm75_read_value(client, LM75_REG_CONF);
+ if (reg >= 0 && (reg & 0x01))
+ lm75_write_value(client, LM75_REG_CONF, reg & 0xfe);
}
static struct lm75_data *lm75_update_device(struct device *dev)
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index 63e3f2f..af7dc65 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -25,7 +25,7 @@
which contains this code, we don't worry about the wasted space.
*/
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
/* straight from the datasheet */
#define LM75_TEMP_MIN (-55000)
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index b98f449..866eab9 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -30,15 +30,14 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm77);
+I2C_CLIENT_INSMOD_1(lm77);
/* The LM77 registers */
#define LM77_REG_TEMP 0x00
@@ -51,6 +50,7 @@
/* Each client has this additional data */
struct lm77_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
@@ -208,10 +208,10 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm77_detect);
+ return i2c_probe(adapter, &addr_data, lm77_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -317,6 +317,12 @@
lm77_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -327,6 +333,8 @@
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -335,8 +343,10 @@
static int lm77_detach_client(struct i2c_client *client)
{
+ struct lm77_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 2924146..f6730dc 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -23,7 +23,10 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
/* Addresses to scan */
@@ -31,10 +34,10 @@
0x25, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
/* Insmod parameters */
-SENSORS_INSMOD_3(lm78, lm78j, lm79);
+I2C_CLIENT_INSMOD_2(lm78, lm79);
/* Many LM78 constants specified below */
@@ -104,13 +107,6 @@
return val * 1000;
}
-/* VID: mV
- REG: (see doc/vid) */
-static inline int VID_FROM_REG(u8 val)
-{
- return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50;
-}
-
#define DIV_FROM_REG(val) (1 << (val))
/* There are some complications in a module like this. First off, LM78 chips
@@ -134,6 +130,7 @@
allocated. */
struct lm78_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -156,6 +153,7 @@
static int lm78_attach_adapter(struct i2c_adapter *adapter);
+static int lm78_isa_attach_adapter(struct i2c_adapter *adapter);
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind);
static int lm78_detach_client(struct i2c_client *client);
@@ -174,6 +172,14 @@
.detach_client = lm78_detach_client,
};
+static struct i2c_driver lm78_isa_driver = {
+ .owner = THIS_MODULE,
+ .name = "lm78-isa",
+ .attach_adapter = lm78_isa_attach_adapter,
+ .detach_client = lm78_detach_client,
+};
+
+
/* 7 Voltages */
static ssize_t show_in(struct device *dev, char *buf, int nr)
{
@@ -445,7 +451,7 @@
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
- return sprintf(buf, "%d\n", VID_FROM_REG(data->vid));
+ return sprintf(buf, "%d\n", vid_from_reg(82, data->vid));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
@@ -465,10 +471,15 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm78_detect);
+ return i2c_probe(adapter, &addr_data, lm78_detect);
}
-/* This function is called by i2c_detect */
+static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+ return lm78_detect(adapter, isa_address, -1);
+}
+
+/* This function is called by i2c_probe */
int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i, err;
@@ -485,7 +496,8 @@
/* Reserve the ISA region */
if (is_isa)
- if (!request_region(address, LM78_EXTENT, lm78_driver.name)) {
+ if (!request_region(address, LM78_EXTENT,
+ lm78_isa_driver.name)) {
err = -EBUSY;
goto ERROR0;
}
@@ -540,7 +552,7 @@
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = &lm78_driver;
+ new_client->driver = is_isa ? &lm78_isa_driver : &lm78_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
@@ -559,10 +571,9 @@
/* Determine the chip type. */
if (kind <= 0) {
i = lm78_read_value(new_client, LM78_REG_CHIPID);
- if (i == 0x00 || i == 0x20)
+ if (i == 0x00 || i == 0x20 /* LM78 */
+ || i == 0x40) /* LM78-J */
kind = lm78;
- else if (i == 0x40)
- kind = lm78j;
else if ((i & 0xfe) == 0xc0)
kind = lm79;
else {
@@ -578,8 +589,6 @@
if (kind == lm78) {
client_name = "lm78";
- } else if (kind == lm78j) {
- client_name = "lm78-j";
} else if (kind == lm79) {
client_name = "lm79";
}
@@ -605,6 +614,12 @@
}
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -643,6 +658,8 @@
return 0;
+ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
kfree(data);
ERROR1:
@@ -654,18 +671,18 @@
static int lm78_detach_client(struct i2c_client *client)
{
+ struct lm78_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
if(i2c_is_isa_client(client))
release_region(client->addr, LM78_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -777,18 +794,31 @@
static int __init sm_lm78_init(void)
{
- return i2c_add_driver(&lm78_driver);
+ int res;
+
+ res = i2c_add_driver(&lm78_driver);
+ if (res)
+ return res;
+
+ res = i2c_isa_add_driver(&lm78_isa_driver);
+ if (res) {
+ i2c_del_driver(&lm78_driver);
+ return res;
+ }
+
+ return 0;
}
static void __exit sm_lm78_exit(void)
{
+ i2c_isa_del_driver(&lm78_isa_driver);
i2c_del_driver(&lm78_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
+MODULE_DESCRIPTION("LM78/LM79 driver");
MODULE_LICENSE("GPL");
module_init(sm_lm78_init);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 8100595..83af8b3 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -26,15 +26,15 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c,
0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm80);
+I2C_CLIENT_INSMOD_1(lm80);
/* Many LM80 constants specified below */
@@ -107,6 +107,7 @@
struct lm80_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -389,7 +390,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm80_detect);
+ return i2c_probe(adapter, &addr_data, lm80_detect);
}
int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -451,6 +452,12 @@
data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in1_min);
device_create_file(&new_client->dev, &dev_attr_in2_min);
@@ -487,6 +494,8 @@
return 0;
+error_detach:
+ i2c_detach_client(new_client);
error_free:
kfree(data);
exit:
@@ -495,15 +504,15 @@
static int lm80_detach_client(struct i2c_client *client)
{
+ struct lm80_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index a49008b..d74b2c2 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -32,8 +32,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -45,13 +46,12 @@
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(lm83);
+I2C_CLIENT_INSMOD_1(lm83);
/*
* The LM83 registers
@@ -138,6 +138,7 @@
struct lm83_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -212,7 +213,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm83_detect);
+ return i2c_probe(adapter, &addr_data, lm83_detect);
}
/*
@@ -312,6 +313,12 @@
*/
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_create_file(&new_client->dev,
@@ -340,6 +347,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -348,15 +357,15 @@
static int lm83_detach_client(struct i2c_client *client)
{
+ struct lm83_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index b4d7fd4..ab214df 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -28,15 +28,15 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
+I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
/* The LM85 registers */
@@ -281,15 +281,6 @@
#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))
#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1)
-/* i2c-vid.h defines vid_from_reg() */
-#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))
-
-/* Unlike some other drivers we DO NOT set initial limits. Use
- * the config file to set limits. Some users have reported
- * motherboards shutting down when we set limits in a previous
- * version of the driver.
- */
-
/* Chip sampling rates
*
* Some sensors are not updated more frequently than once per second
@@ -339,6 +330,7 @@
struct lm85_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -1019,7 +1011,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm85_detect);
+ return i2c_probe(adapter, &addr_data, lm85_detect);
}
int lm85_detect(struct i2c_adapter *adapter, int address,
@@ -1031,11 +1023,6 @@
int err = 0;
const char *type_name = "";
- if (i2c_is_isa_adapter(adapter)) {
- /* This chip has no ISA interface */
- goto ERROR0 ;
- };
-
if (!i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
/* We need to be able to do byte I/O */
@@ -1160,12 +1147,18 @@
goto ERROR1;
/* Set the VRM version */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
/* Initialize the LM85 chip */
lm85_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR2;
+ }
+
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan2_input);
device_create_file(&new_client->dev, &dev_attr_fan3_input);
@@ -1235,6 +1228,8 @@
return 0;
/* Error out and cleanup code */
+ ERROR2:
+ i2c_detach_client(new_client);
ERROR1:
kfree(data);
ERROR0:
@@ -1243,8 +1238,10 @@
int lm85_detach_client(struct i2c_client *client)
{
+ struct lm85_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 1921ed1..dca996d 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -57,8 +57,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -66,13 +67,12 @@
*/
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(lm87);
+I2C_CLIENT_INSMOD_1(lm87);
/*
* The LM87 registers
@@ -175,6 +175,7 @@
struct lm87_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -537,7 +538,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm87_detect);
+ return i2c_probe(adapter, &addr_data, lm87_detect);
}
/*
@@ -608,6 +609,12 @@
data->in_scale[7] = 1875;
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in1_min);
device_create_file(&new_client->dev, &dev_attr_in1_max);
@@ -673,6 +680,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -685,7 +694,7 @@
u8 config;
data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
config = lm87_read_value(client, LM87_REG_CONFIG);
if (!(config & 0x01)) {
@@ -719,15 +728,15 @@
static int lm87_detach_client(struct i2c_client *client)
{
+ struct lm87_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index a67dcad..14de05f 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -75,8 +75,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -89,13 +90,12 @@
*/
static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
/*
* The LM90 registers
@@ -200,6 +200,7 @@
struct lm90_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -352,7 +353,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm90_detect);
+ return i2c_probe(adapter, &addr_data, lm90_detect);
}
/*
@@ -500,6 +501,12 @@
lm90_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_create_file(&new_client->dev,
@@ -524,6 +531,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -547,15 +556,15 @@
static int lm90_detach_client(struct i2c_client *client)
{
+ struct lm90_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 215c8e4..647b7c7 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -44,17 +44,16 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* The LM92 and MAX6635 have 2 two-state pins for address selection,
resulting in 4 possible addresses. */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm92);
+I2C_CLIENT_INSMOD_1(lm92);
/* The LM92 registers */
#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */
@@ -96,6 +95,7 @@
/* Client data (each client gets its own) */
struct lm92_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -359,6 +359,12 @@
lm92_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
@@ -370,6 +376,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -380,20 +388,20 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm92_detect);
+ return i2c_probe(adapter, &addr_data, lm92_detect);
}
static int lm92_detach_client(struct i2c_client *client)
{
+ struct lm92_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 3c159f1..16bf71f 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -31,20 +31,19 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(max1619);
+I2C_CLIENT_INSMOD_1(max1619);
/*
* The MAX1619 registers
@@ -104,6 +103,7 @@
struct max1619_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -179,7 +179,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, max1619_detect);
+ return i2c_probe(adapter, &addr_data, max1619_detect);
}
/*
@@ -275,6 +275,12 @@
max1619_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp2_input);
device_create_file(&new_client->dev, &dev_attr_temp2_min);
@@ -285,6 +291,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -308,15 +316,15 @@
static int max1619_detach_client(struct i2c_client *client)
{
+ struct max1619_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index fa4032d..cf2a357 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -38,23 +38,19 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{ NULL }};
static u8 devid;
-static unsigned int extra_isa[3];
+static unsigned short address;
+static unsigned short extra_isa[3];
static u8 confreg[4];
enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-static struct i2c_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .normal_isa = normal_isa,
- .forces = forces,
-};
static int init = 1;
module_param(init, int, 0);
@@ -186,6 +182,7 @@
struct pc87360_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
@@ -224,8 +221,7 @@
* Functions declaration
*/
-static int pc87360_attach_adapter(struct i2c_adapter *adapter);
-static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pc87360_detect(struct i2c_adapter *adapter);
static int pc87360_detach_client(struct i2c_client *client);
static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
@@ -242,8 +238,7 @@
static struct i2c_driver pc87360_driver = {
.owner = THIS_MODULE,
.name = "pc87360",
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = pc87360_attach_adapter,
+ .attach_adapter = pc87360_detect,
.detach_client = pc87360_detach_client,
};
@@ -251,168 +246,178 @@
* Sysfs stuff
*/
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index],
+ FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index],
+ FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n",
+ FAN_DIV_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t show_fan_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n",
+ FAN_STATUS_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
long fan_min = simple_strtol(buf, NULL, 10);
down(&data->update_lock);
- fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr]));
+ fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index]));
/* If it wouldn't fit, change clock divisor */
while (fan_min > 255
- && (data->fan_status[nr] & 0x60) != 0x60) {
+ && (data->fan_status[attr->index] & 0x60) != 0x60) {
fan_min >>= 1;
- data->fan[nr] >>= 1;
- data->fan_status[nr] += 0x20;
+ data->fan[attr->index] >>= 1;
+ data->fan_status[attr->index] += 0x20;
}
- data->fan_min[nr] = fan_min > 255 ? 255 : fan_min;
- pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr),
- data->fan_min[nr]);
+ data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min;
+ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(attr->index),
+ data->fan_min[attr->index]);
/* Write new divider, preserve alarm bits */
- pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr),
- data->fan_status[nr] & 0xF9);
+ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index),
+ data->fan_status[attr->index] & 0xF9);
up(&data->update_lock);
return count;
}
#define show_and_set_fan(offset) \
-static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \
- FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
-} \
-static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \
- FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
-} \
-static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", \
- FAN_DIV_FROM_REG(data->fan_status[offset-1])); \
-} \
-static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", \
- FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \
-} \
-static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset-1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
- show_fan##offset##_input, NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
- show_fan##offset##_min, set_fan##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
- show_fan##offset##_div, NULL); \
-static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
- show_fan##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan_input, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
+ show_fan_min, set_fan_min, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
+ show_fan_div, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
+ show_fan_status, NULL, offset-1);
show_and_set_fan(1)
show_and_set_fan(2)
show_and_set_fan(3)
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n",
+ PWM_FROM_REG(data->pwm[attr->index],
+ FAN_CONFIG_INVERT(data->fan_conf,
+ attr->index)));
+}
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->pwm[attr->index] = PWM_TO_REG(val,
+ FAN_CONFIG_INVERT(data->fan_conf, attr->index));
+ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index),
+ data->pwm[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_pwm(offset) \
-static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", \
- PWM_FROM_REG(data->pwm[offset-1], \
- FAN_CONFIG_INVERT(data->fan_conf, \
- offset-1))); \
-} \
-static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->pwm[offset-1] = PWM_TO_REG(val, \
- FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \
- pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \
- data->pwm[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
- show_pwm##offset, set_pwm##offset);
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
+ show_pwm, set_pwm, offset-1);
show_and_set_pwm(1)
show_and_set_pwm(2)
show_and_set_pwm(3)
+static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+ data->in_vref));
+}
+static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+ data->in_vref));
+}
+static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+ data->in_vref));
+}
+static ssize_t show_in_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN,
+ data->in_min[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_max[attr->index] = IN_TO_REG(val,
+ data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX,
+ data->in_max[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_in(offset) \
-static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
- data->in_vref)); \
-} \
-static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
- data->in_vref)); \
-} \
-static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
- data->in_vref)); \
-} \
-static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", data->in_status[offset]); \
-} \
-static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_min[offset] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \
- data->in_min[offset]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_max[offset] = IN_TO_REG(val, \
- data->in_vref); \
- pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \
- data->in_max[offset]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
- show_in##offset##_input, NULL); \
-static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
- show_in##offset##_max, set_in##offset##_max); \
-static DEVICE_ATTR(in##offset##_status, S_IRUGO, \
- show_in##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in_input, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+ show_in_max, set_in_max, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_status, S_IRUGO, \
+ show_in_status, NULL, offset);
show_and_set_in(0)
show_and_set_in(1)
show_and_set_in(2)
@@ -425,88 +430,97 @@
show_and_set_in(9)
show_and_set_in(10)
+static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+ data->in_vref));
+}
+static ssize_t show_therm_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+ data->in_vref));
+}
+static ssize_t show_therm_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+ data->in_vref));
+}
+static ssize_t show_therm_crit(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11],
+ data->in_vref));
+}
+static ssize_t show_therm_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_therm_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN,
+ data->in_min[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX,
+ data->in_max[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT,
+ data->in_crit[attr->index-11]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_therm(offset) \
-static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", data->in_status[offset+7]); \
-} \
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \
- data->in_min[offset+7]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \
- data->in_max[offset+7]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \
- data->in_crit[offset-4]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
- show_temp##offset##_input, NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
- show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
- show_temp##offset##_max, set_temp##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
- show_temp##offset##_crit, set_temp##offset##_crit); \
-static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
- show_temp##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_therm_input, NULL, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+ show_therm_min, set_therm_min, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+ show_therm_max, set_therm_max, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+ show_therm_crit, set_therm_crit, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+ show_therm_status, NULL, 11+offset-4);
show_and_set_therm(4)
show_and_set_therm(5)
show_and_set_therm(6)
@@ -539,84 +553,93 @@
}
static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index]));
+}
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index]));
+}
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[attr->index]));
+}
+static ssize_t show_temp_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", data->temp_status[attr->index]);
+}
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_min[attr->index] = TEMP_TO_REG(val);
+ pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN,
+ data->temp_min[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_max[attr->index] = TEMP_TO_REG(val);
+ pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX,
+ data->temp_max[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_crit[attr->index] = TEMP_TO_REG(val);
+ pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT,
+ data->temp_crit[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_temp(offset) \
-static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \
-}\
-static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \
-}\
-static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", data->temp_status[offset-1]); \
-}\
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->temp_min[offset-1] = TEMP_TO_REG(val); \
- pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \
- data->temp_min[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->temp_max[offset-1] = TEMP_TO_REG(val); \
- pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \
- data->temp_max[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->temp_crit[offset-1] = TEMP_TO_REG(val); \
- pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \
- data->temp_crit[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
- show_temp##offset##_input, NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
- show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
- show_temp##offset##_max, set_temp##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
- show_temp##offset##_crit, set_temp##offset##_crit); \
-static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
- show_temp##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp_input, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+ show_temp_min, set_temp_min, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+ show_temp_max, set_temp_max, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+ show_temp_crit, set_temp_crit, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+ show_temp_status, NULL, offset-1);
show_and_set_temp(1)
show_and_set_temp(2)
show_and_set_temp(3)
@@ -632,12 +655,7 @@
* Device detection, registration and update
*/
-static int pc87360_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_detect(adapter, &addr_data, pc87360_detect);
-}
-
-static int pc87360_find(int sioaddr, u8 *devid, int *address)
+static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses)
{
u16 val;
int i;
@@ -683,7 +701,7 @@
continue;
}
- address[i] = val;
+ addresses[i] = val;
if (i==0) { /* Fans */
confreg[0] = superio_inb(sioaddr, 0xF0);
@@ -727,9 +745,7 @@
return 0;
}
-/* We don't really care about the address.
- Read from extra_isa instead. */
-int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
+static int pc87360_detect(struct i2c_adapter *adapter)
{
int i;
struct i2c_client *new_client;
@@ -738,9 +754,6 @@
const char *name = "pc87360";
int use_thermistors = 0;
- if (!i2c_is_isa_adapter(adapter))
- return -ENODEV;
-
if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
return -ENOMEM;
memset(data, 0x00, sizeof(struct pc87360_data));
@@ -838,51 +851,57 @@
}
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
if (data->innr) {
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in7_input);
- device_create_file(&new_client->dev, &dev_attr_in8_input);
- device_create_file(&new_client->dev, &dev_attr_in9_input);
- device_create_file(&new_client->dev, &dev_attr_in10_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in7_min);
- device_create_file(&new_client->dev, &dev_attr_in8_min);
- device_create_file(&new_client->dev, &dev_attr_in9_min);
- device_create_file(&new_client->dev, &dev_attr_in10_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_in7_max);
- device_create_file(&new_client->dev, &dev_attr_in8_max);
- device_create_file(&new_client->dev, &dev_attr_in9_max);
- device_create_file(&new_client->dev, &dev_attr_in10_max);
- device_create_file(&new_client->dev, &dev_attr_in0_status);
- device_create_file(&new_client->dev, &dev_attr_in1_status);
- device_create_file(&new_client->dev, &dev_attr_in2_status);
- device_create_file(&new_client->dev, &dev_attr_in3_status);
- device_create_file(&new_client->dev, &dev_attr_in4_status);
- device_create_file(&new_client->dev, &dev_attr_in5_status);
- device_create_file(&new_client->dev, &dev_attr_in6_status);
- device_create_file(&new_client->dev, &dev_attr_in7_status);
- device_create_file(&new_client->dev, &dev_attr_in8_status);
- device_create_file(&new_client->dev, &dev_attr_in9_status);
- device_create_file(&new_client->dev, &dev_attr_in10_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_status.dev_attr);
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
device_create_file(&new_client->dev, &dev_attr_vrm);
@@ -890,90 +909,92 @@
}
if (data->tempnr) {
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_status);
- device_create_file(&new_client->dev, &dev_attr_temp2_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_status.dev_attr);
device_create_file(&new_client->dev, &dev_attr_alarms_temp);
}
if (data->tempnr == 3) {
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
- device_create_file(&new_client->dev, &dev_attr_temp3_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_status.dev_attr);
}
if (data->innr == 14) {
- device_create_file(&new_client->dev, &dev_attr_temp4_input);
- device_create_file(&new_client->dev, &dev_attr_temp5_input);
- device_create_file(&new_client->dev, &dev_attr_temp6_input);
- device_create_file(&new_client->dev, &dev_attr_temp4_min);
- device_create_file(&new_client->dev, &dev_attr_temp5_min);
- device_create_file(&new_client->dev, &dev_attr_temp6_min);
- device_create_file(&new_client->dev, &dev_attr_temp4_max);
- device_create_file(&new_client->dev, &dev_attr_temp5_max);
- device_create_file(&new_client->dev, &dev_attr_temp6_max);
- device_create_file(&new_client->dev, &dev_attr_temp4_crit);
- device_create_file(&new_client->dev, &dev_attr_temp5_crit);
- device_create_file(&new_client->dev, &dev_attr_temp6_crit);
- device_create_file(&new_client->dev, &dev_attr_temp4_status);
- device_create_file(&new_client->dev, &dev_attr_temp5_status);
- device_create_file(&new_client->dev, &dev_attr_temp6_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_status.dev_attr);
}
if (data->fannr) {
if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) {
device_create_file(&new_client->dev,
- &dev_attr_fan1_input);
+ &sensor_dev_attr_fan1_input.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan1_min);
+ &sensor_dev_attr_fan1_min.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan1_div);
+ &sensor_dev_attr_fan1_div.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan1_status);
+ &sensor_dev_attr_fan1_status.dev_attr);
}
if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) {
device_create_file(&new_client->dev,
- &dev_attr_fan2_input);
+ &sensor_dev_attr_fan2_input.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan2_min);
+ &sensor_dev_attr_fan2_min.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan2_div);
+ &sensor_dev_attr_fan2_div.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan2_status);
+ &sensor_dev_attr_fan2_status.dev_attr);
}
if (FAN_CONFIG_CONTROL(data->fan_conf, 0))
- device_create_file(&new_client->dev, &dev_attr_pwm1);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
if (FAN_CONFIG_CONTROL(data->fan_conf, 1))
- device_create_file(&new_client->dev, &dev_attr_pwm2);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
}
if (data->fannr == 3) {
if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) {
device_create_file(&new_client->dev,
- &dev_attr_fan3_input);
+ &sensor_dev_attr_fan3_input.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan3_min);
+ &sensor_dev_attr_fan3_min.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan3_div);
+ &sensor_dev_attr_fan3_div.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan3_status);
+ &sensor_dev_attr_fan3_status.dev_attr);
}
if (FAN_CONFIG_CONTROL(data->fan_conf, 2))
- device_create_file(&new_client->dev, &dev_attr_pwm3);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
}
return 0;
+ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@@ -990,11 +1011,10 @@
struct pc87360_data *data = i2c_get_clientdata(client);
int i;
- if ((i = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((i = i2c_detach_client(client)))
return i;
- }
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@@ -1320,23 +1340,23 @@
/* Arbitrarily pick one of the addresses */
for (i = 0; i < 3; i++) {
if (extra_isa[i] != 0x0000) {
- normal_isa[0] = extra_isa[i];
+ address = extra_isa[i];
break;
}
}
- if (normal_isa[0] == 0x0000) {
+ if (address == 0x0000) {
printk(KERN_WARNING "pc87360: No active logical device, "
"module not inserted.\n");
return -ENODEV;
}
- return i2c_add_driver(&pc87360_driver);
+ return i2c_isa_add_driver(&pc87360_driver);
}
static void __exit pc87360_exit(void)
{
- i2c_del_driver(&pc87360_driver);
+ i2c_isa_del_driver(&pc87360_driver);
}
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 6bbfc8f..8610bce 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -55,7 +55,9 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <asm/io.h>
@@ -68,14 +70,10 @@
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Addresses to scan.
+/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(sis5595);
+static unsigned short address;
/* Many SIS5595 constants specified below */
@@ -168,6 +166,7 @@
allocated. */
struct sis5595_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -190,8 +189,7 @@
static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
-static int sis5595_attach_adapter(struct i2c_adapter *adapter);
-static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind);
+static int sis5595_detect(struct i2c_adapter *adapter);
static int sis5595_detach_client(struct i2c_client *client);
static int sis5595_read_value(struct i2c_client *client, u8 register);
@@ -202,9 +200,7 @@
static struct i2c_driver sis5595_driver = {
.owner = THIS_MODULE,
.name = "sis5595",
- .id = I2C_DRIVERID_SIS5595,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = sis5595_attach_adapter,
+ .attach_adapter = sis5595_detect,
.detach_client = sis5595_detach_client,
};
@@ -476,14 +472,7 @@
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
/* This is called when the module is loaded */
-static int sis5595_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, sis5595_detect);
-}
-
-int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
+static int sis5595_detect(struct i2c_adapter *adapter)
{
int err = 0;
int i;
@@ -492,10 +481,6 @@
char val;
u16 a;
- /* Make sure we are probing the ISA bus!! */
- if (!i2c_is_isa_adapter(adapter))
- goto exit;
-
if (force_addr)
address = force_addr & ~(SIS5595_EXTENT - 1);
/* Reserve the ISA region */
@@ -578,6 +563,12 @@
}
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -608,7 +599,9 @@
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
}
return 0;
-
+
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit_release:
@@ -619,18 +612,17 @@
static int sis5595_detach_client(struct i2c_client *client)
{
+ struct sis5595_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- if (i2c_is_isa_client(client))
- release_region(client->addr, SIS5595_EXTENT);
+ release_region(client->addr, SIS5595_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -745,7 +737,6 @@
{
u16 val;
int *i;
- int addr = 0;
for (i = blacklist; *i != 0; i++) {
struct pci_dev *dev;
@@ -761,22 +752,19 @@
pci_read_config_word(dev, SIS5595_BASE_REG, &val))
return -ENODEV;
- addr = val & ~(SIS5595_EXTENT - 1);
- if (addr == 0 && force_addr == 0) {
+ address = val & ~(SIS5595_EXTENT - 1);
+ if (address == 0 && force_addr == 0) {
dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
- if (force_addr)
- addr = force_addr; /* so detect will get called */
- if (!addr) {
+ if (!address) {
dev_err(&dev->dev,"No SiS 5595 sensors found.\n");
return -ENODEV;
}
- normal_isa[0] = addr;
s_bridge = pci_dev_get(dev);
- if (i2c_add_driver(&sis5595_driver)) {
+ if (i2c_isa_add_driver(&sis5595_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
}
@@ -803,7 +791,7 @@
{
pci_unregister_driver(&sis5595_pci_driver);
if (s_bridge != NULL) {
- i2c_del_driver(&sis5595_driver);
+ i2c_isa_del_driver(&sis5595_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index fdeeb3a..7fe7157 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -31,23 +31,14 @@
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <asm/io.h>
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47b397 };
-static struct i2c_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .normal_isa = normal_isa,
- .probe = normal_i2c, /* cheat */
- .ignore = normal_i2c, /* cheat */
- .forces = forces,
-};
+static unsigned short address;
/* Super-I/0 registers and commands */
@@ -100,6 +91,7 @@
struct smsc47b397_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -215,52 +207,40 @@
#define device_create_file_fan(client, num) \
device_create_file(&client->dev, &dev_attr_fan##num##_input)
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind);
-
-static int smsc47b397_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, smsc47b397_detect);
-}
-
static int smsc47b397_detach_client(struct i2c_client *client)
{
+ struct smsc47b397_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, SMSC_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
+static int smsc47b397_detect(struct i2c_adapter *adapter);
+
static struct i2c_driver smsc47b397_driver = {
.owner = THIS_MODULE,
.name = "smsc47b397",
- .id = I2C_DRIVERID_SMSC47B397,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = smsc47b397_attach_adapter,
+ .attach_adapter = smsc47b397_detect,
.detach_client = smsc47b397_detach_client,
};
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
+static int smsc47b397_detect(struct i2c_adapter *adapter)
{
struct i2c_client *new_client;
struct smsc47b397_data *data;
int err = 0;
- if (!i2c_is_isa_adapter(adapter)) {
- return 0;
- }
-
- if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) {
- dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr);
+ if (!request_region(address, SMSC_EXTENT, smsc47b397_driver.name)) {
+ dev_err(&adapter->dev, "Region 0x%x already in use!\n",
+ address);
return -EBUSY;
}
@@ -272,7 +252,7 @@
new_client = &data->client;
i2c_set_clientdata(new_client, data);
- new_client->addr = addr;
+ new_client->addr = address;
init_MUTEX(&data->lock);
new_client->adapter = adapter;
new_client->driver = &smsc47b397_driver;
@@ -285,6 +265,12 @@
if ((err = i2c_attach_client(new_client)))
goto error_free;
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_detach;
+ }
+
device_create_file_temp(new_client, 1);
device_create_file_temp(new_client, 2);
device_create_file_temp(new_client, 3);
@@ -297,14 +283,16 @@
return 0;
+error_detach:
+ i2c_detach_client(new_client);
error_free:
kfree(data);
error_release:
- release_region(addr, SMSC_EXTENT);
+ release_region(address, SMSC_EXTENT);
return err;
}
-static int __init smsc47b397_find(unsigned int *addr)
+static int __init smsc47b397_find(unsigned short *addr)
{
u8 id, rev;
@@ -333,15 +321,15 @@
{
int ret;
- if ((ret = smsc47b397_find(normal_isa)))
+ if ((ret = smsc47b397_find(&address)))
return ret;
- return i2c_add_driver(&smsc47b397_driver);
+ return i2c_isa_add_driver(&smsc47b397_driver);
}
static void __exit smsc47b397_exit(void)
{
- i2c_del_driver(&smsc47b397_driver);
+ i2c_isa_del_driver(&smsc47b397_driver);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 7166ad0..7e699a8 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -30,21 +30,14 @@
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <asm/io.h>
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47m1 };
-static struct i2c_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .normal_isa = normal_isa,
- .forces = forces,
-};
+static unsigned short address;
/* Super-I/0 registers and commands */
@@ -108,6 +101,7 @@
struct smsc47m1_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -121,9 +115,7 @@
};
-static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
-static int smsc47m1_find(int *address);
-static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind);
+static int smsc47m1_detect(struct i2c_adapter *adapter);
static int smsc47m1_detach_client(struct i2c_client *client);
static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
@@ -136,9 +128,7 @@
static struct i2c_driver smsc47m1_driver = {
.owner = THIS_MODULE,
.name = "smsc47m1",
- .id = I2C_DRIVERID_SMSC47M1,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = smsc47m1_attach_adapter,
+ .attach_adapter = smsc47m1_detect,
.detach_client = smsc47m1_detach_client,
};
@@ -354,14 +344,7 @@
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
-static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, smsc47m1_detect);
-}
-
-static int smsc47m1_find(int *address)
+static int __init smsc47m1_find(unsigned short *addr)
{
u8 val;
@@ -388,10 +371,10 @@
}
superio_select();
- *address = (superio_inb(SUPERIO_REG_BASE) << 8)
- | superio_inb(SUPERIO_REG_BASE + 1);
+ *addr = (superio_inb(SUPERIO_REG_BASE) << 8)
+ | superio_inb(SUPERIO_REG_BASE + 1);
val = superio_inb(SUPERIO_REG_ACT);
- if (*address == 0 || (val & 0x01) == 0) {
+ if (*addr == 0 || (val & 0x01) == 0) {
printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
superio_exit();
return -ENODEV;
@@ -401,17 +384,13 @@
return 0;
}
-static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
+static int smsc47m1_detect(struct i2c_adapter *adapter)
{
struct i2c_client *new_client;
struct smsc47m1_data *data;
int err = 0;
int fan1, fan2, pwm1, pwm2;
- if (!i2c_is_isa_adapter(adapter)) {
- return 0;
- }
-
if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) {
dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
return -EBUSY;
@@ -461,6 +440,13 @@
function. */
smsc47m1_update_device(&new_client->dev, 1);
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_detach;
+ }
+
if (fan1) {
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan1_min);
@@ -494,6 +480,8 @@
return 0;
+error_detach:
+ i2c_detach_client(new_client);
error_free:
kfree(data);
error_release:
@@ -503,16 +491,16 @@
static int smsc47m1_detach_client(struct i2c_client *client)
{
+ struct smsc47m1_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, SMSC_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -573,16 +561,16 @@
static int __init sm_smsc47m1_init(void)
{
- if (smsc47m1_find(normal_isa)) {
+ if (smsc47m1_find(&address)) {
return -ENODEV;
}
- return i2c_add_driver(&smsc47m1_driver);
+ return i2c_isa_add_driver(&smsc47m1_driver);
}
static void __exit sm_smsc47m1_exit(void)
{
- i2c_del_driver(&smsc47m1_driver);
+ i2c_isa_del_driver(&smsc47m1_driver);
}
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 164d479..eb84997 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -35,7 +35,9 @@
#include <linux/pci.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -47,14 +49,10 @@
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Addresses to scan.
+/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(via686a);
+static unsigned short address;
/*
The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -297,6 +295,7 @@
via686a client is allocated. */
struct via686a_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -315,8 +314,7 @@
static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
-static int via686a_attach_adapter(struct i2c_adapter *adapter);
-static int via686a_detect(struct i2c_adapter *adapter, int address, int kind);
+static int via686a_detect(struct i2c_adapter *adapter);
static int via686a_detach_client(struct i2c_client *client);
static inline int via686a_read_value(struct i2c_client *client, u8 reg)
@@ -576,22 +574,13 @@
static struct i2c_driver via686a_driver = {
.owner = THIS_MODULE,
.name = "via686a",
- .id = I2C_DRIVERID_VIA686A,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = via686a_attach_adapter,
+ .attach_adapter = via686a_detect,
.detach_client = via686a_detach_client,
};
/* This is called when the module is loaded */
-static int via686a_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, via686a_detect);
-}
-
-static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
+static int via686a_detect(struct i2c_adapter *adapter)
{
struct i2c_client *new_client;
struct via686a_data *data;
@@ -599,13 +588,6 @@
const char client_name[] = "via686a";
u16 val;
- /* Make sure we are probing the ISA bus!! */
- if (!i2c_is_isa_adapter(adapter)) {
- dev_err(&adapter->dev,
- "via686a_detect called for an I2C bus adapter?!?\n");
- return 0;
- }
-
/* 8231 requires multiple of 256, we enforce that on 686 as well */
if (force_addr)
address = force_addr & 0xFF00;
@@ -637,7 +619,7 @@
if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
err = -ENOMEM;
- goto ERROR0;
+ goto exit_release;
}
memset(data, 0, sizeof(struct via686a_data));
@@ -655,12 +637,18 @@
init_MUTEX(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
- goto ERROR3;
+ goto exit_free;
/* Initialize the VIA686A chip */
via686a_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -695,25 +683,27 @@
return 0;
-ERROR3:
+exit_detach:
+ i2c_detach_client(new_client);
+exit_free:
kfree(data);
-ERROR0:
+exit_release:
release_region(address, VIA686A_EXTENT);
return err;
}
static int via686a_detach_client(struct i2c_client *client)
{
+ struct via686a_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, VIA686A_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -810,29 +800,25 @@
const struct pci_device_id *id)
{
u16 val;
- int addr = 0;
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
return -ENODEV;
- addr = val & ~(VIA686A_EXTENT - 1);
- if (addr == 0 && force_addr == 0) {
+ address = val & ~(VIA686A_EXTENT - 1);
+ if (address == 0 && force_addr == 0) {
dev_err(&dev->dev, "base address not set - upgrade BIOS "
"or use force_addr=0xaddr\n");
return -ENODEV;
}
- if (force_addr)
- addr = force_addr; /* so detect will get called */
- if (!addr) {
+ if (!address) {
dev_err(&dev->dev, "No Via 686A sensors found.\n");
return -ENODEV;
}
- normal_isa[0] = addr;
s_bridge = pci_dev_get(dev);
- if (i2c_add_driver(&via686a_driver)) {
+ if (i2c_isa_add_driver(&via686a_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
}
@@ -859,7 +845,7 @@
{
pci_unregister_driver(&via686a_pci_driver);
if (s_bridge != NULL) {
- i2c_del_driver(&via686a_driver);
+ i2c_isa_del_driver(&via686a_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 8a40b69..b60efe8 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -9,6 +9,9 @@
Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
in testing and debugging this driver.
+ This driver also supports the W83627EHG, which is the lead-free
+ version of the W83627EHF.
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -37,17 +40,14 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <asm/io.h>
#include "lm75.h"
-/* Addresses to scan
- The actual ISA address is read from Super-I/O configuration space */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(w83627ehf);
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
/*
* Super-I/O constants and functions
@@ -174,6 +174,7 @@
struct w83627ehf_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -666,15 +667,12 @@
}
}
-static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
+static int w83627ehf_detect(struct i2c_adapter *adapter)
{
struct i2c_client *client;
struct w83627ehf_data *data;
int i, err = 0;
- if (!i2c_is_isa_adapter(adapter))
- return 0;
-
if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) {
err = -EBUSY;
goto exit;
@@ -720,6 +718,12 @@
data->has_fan |= (1 << 4);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&client->dev, &dev_attr_fan1_input);
device_create_file(&client->dev, &dev_attr_fan1_min);
device_create_file(&client->dev, &dev_attr_fan1_div);
@@ -753,6 +757,8 @@
return 0;
+exit_detach:
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit_release:
@@ -761,24 +767,17 @@
return err;
}
-static int w83627ehf_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, w83627ehf_detect);
-}
-
static int w83627ehf_detach_client(struct i2c_client *client)
{
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, REGION_LENGTH);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -786,12 +785,11 @@
static struct i2c_driver w83627ehf_driver = {
.owner = THIS_MODULE,
.name = "w83627ehf",
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = w83627ehf_attach_adapter,
+ .attach_adapter = w83627ehf_detect,
.detach_client = w83627ehf_detach_client,
};
-static int __init w83627ehf_find(int sioaddr, int *address)
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
{
u16 val;
@@ -809,8 +807,8 @@
superio_select(W83627EHF_LD_HWM);
val = (superio_inb(SIO_REG_ADDR) << 8)
| superio_inb(SIO_REG_ADDR + 1);
- *address = val & ~(REGION_LENGTH - 1);
- if (*address == 0) {
+ *addr = val & ~(REGION_LENGTH - 1);
+ if (*addr == 0) {
superio_exit();
return -ENODEV;
}
@@ -826,16 +824,16 @@
static int __init sensors_w83627ehf_init(void)
{
- if (w83627ehf_find(0x2e, &normal_isa[0])
- && w83627ehf_find(0x4e, &normal_isa[0]))
+ if (w83627ehf_find(0x2e, &address)
+ && w83627ehf_find(0x4e, &address))
return -ENODEV;
- return i2c_add_driver(&w83627ehf_driver);
+ return i2c_isa_add_driver(&w83627ehf_driver);
}
static void __exit sensors_w83627ehf_exit(void)
{
- i2c_del_driver(&w83627ehf_driver);
+ i2c_isa_del_driver(&w83627ehf_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index bd87a42..02bd5c0 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -42,8 +42,10 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
#include "lm75.h"
@@ -56,12 +58,11 @@
MODULE_PARM_DESC(force_i2c,
"Initialize the i2c address of the sensors");
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
/* Insmod parameters */
-SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);
+enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };
static int init = 1;
module_param(init, bool, 0);
@@ -277,6 +278,7 @@
dynamically allocated, at the same time when a new client is allocated. */
struct w83627hf_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -314,9 +316,7 @@
};
-static int w83627hf_attach_adapter(struct i2c_adapter *adapter);
-static int w83627hf_detect(struct i2c_adapter *adapter, int address,
- int kind);
+static int w83627hf_detect(struct i2c_adapter *adapter);
static int w83627hf_detach_client(struct i2c_client *client);
static int w83627hf_read_value(struct i2c_client *client, u16 register);
@@ -328,9 +328,7 @@
static struct i2c_driver w83627hf_driver = {
.owner = THIS_MODULE,
.name = "w83627hf",
- .id = I2C_DRIVERID_W83627HF,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = w83627hf_attach_adapter,
+ .attach_adapter = w83627hf_detect,
.detach_client = w83627hf_detach_client,
};
@@ -959,16 +957,7 @@
} while (0)
-/* This function is called when:
- * w83627hf_driver is inserted (when this module is loaded), for each
- available adapter
- * when a new adapter is inserted (and w83627hf_driver is still present) */
-static int w83627hf_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_detect(adapter, &addr_data, w83627hf_detect);
-}
-
-static int w83627hf_find(int sioaddr, int *address)
+static int __init w83627hf_find(int sioaddr, unsigned short *addr)
{
u16 val;
@@ -988,32 +977,24 @@
superio_select(W83627HF_LD_HWM);
val = (superio_inb(WINB_BASE_REG) << 8) |
superio_inb(WINB_BASE_REG + 1);
- *address = val & ~(WINB_EXTENT - 1);
- if (*address == 0 && force_addr == 0) {
+ *addr = val & ~(WINB_EXTENT - 1);
+ if (*addr == 0 && force_addr == 0) {
superio_exit();
return -ENODEV;
}
- if (force_addr)
- *address = force_addr; /* so detect will get called */
superio_exit();
return 0;
}
-int w83627hf_detect(struct i2c_adapter *adapter, int address,
- int kind)
+static int w83627hf_detect(struct i2c_adapter *adapter)
{
- int val;
+ int val, kind;
struct i2c_client *new_client;
struct w83627hf_data *data;
int err = 0;
const char *client_name = "";
- if (!i2c_is_isa_adapter(adapter)) {
- err = -ENODEV;
- goto ERROR0;
- }
-
if(force_addr)
address = force_addr & ~(WINB_EXTENT - 1);
@@ -1102,6 +1083,12 @@
data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file_in(new_client, 0);
if (kind != w83697hf)
device_create_file_in(new_client, 1);
@@ -1152,6 +1139,8 @@
return 0;
+ ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
kfree(data);
ERROR1:
@@ -1162,16 +1151,16 @@
static int w83627hf_detach_client(struct i2c_client *client)
{
+ struct w83627hf_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, WINB_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -1327,7 +1316,7 @@
data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82;
} else {
/* Convert VID to voltage based on default VRM */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
}
tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
@@ -1485,20 +1474,17 @@
static int __init sensors_w83627hf_init(void)
{
- int addr;
-
- if (w83627hf_find(0x2e, &addr)
- && w83627hf_find(0x4e, &addr)) {
+ if (w83627hf_find(0x2e, &address)
+ && w83627hf_find(0x4e, &address)) {
return -ENODEV;
}
- normal_isa[0] = addr;
- return i2c_add_driver(&w83627hf_driver);
+ return i2c_isa_add_driver(&w83627hf_driver);
}
static void __exit sensors_w83627hf_exit(void)
{
- i2c_del_driver(&w83627hf_driver);
+ i2c_isa_del_driver(&w83627hf_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 0bb131c..4c43337 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -38,8 +38,10 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
#include "lm75.h"
@@ -47,10 +49,10 @@
static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
/* Insmod parameters */
-SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
+I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
@@ -218,6 +220,7 @@
allocated. */
struct w83781d_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -255,6 +258,7 @@
};
static int w83781d_attach_adapter(struct i2c_adapter *adapter);
+static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter);
static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
static int w83781d_detach_client(struct i2c_client *client);
@@ -273,6 +277,14 @@
.detach_client = w83781d_detach_client,
};
+static struct i2c_driver w83781d_isa_driver = {
+ .owner = THIS_MODULE,
+ .name = "w83781d-isa",
+ .attach_adapter = w83781d_isa_attach_adapter,
+ .detach_client = w83781d_detach_client,
+};
+
+
/* following are the sysfs callback functions */
#define show_in_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
@@ -856,7 +868,13 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, w83781d_detect);
+ return i2c_probe(adapter, &addr_data, w83781d_detect);
+}
+
+static int
+w83781d_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+ return w83781d_detect(adapter, isa_address, -1);
}
/* Assumes that adapter is of I2C, not ISA variety.
@@ -961,10 +979,10 @@
ERROR_SC_3:
i2c_detach_client(data->lm75[0]);
ERROR_SC_2:
- if (NULL != data->lm75[1])
+ if (data->lm75[1])
kfree(data->lm75[1]);
ERROR_SC_1:
- if (NULL != data->lm75[0])
+ if (data->lm75[0])
kfree(data->lm75[0]);
ERROR_SC_0:
return err;
@@ -999,7 +1017,7 @@
if (is_isa)
if (!request_region(address, W83781D_EXTENT,
- w83781d_driver.name)) {
+ w83781d_isa_driver.name)) {
dev_dbg(&adapter->dev, "Request of region "
"0x%x-0x%x for w83781d failed\n", address,
address + W83781D_EXTENT - 1);
@@ -1057,7 +1075,7 @@
new_client->addr = address;
init_MUTEX(&data->lock);
new_client->adapter = adapter;
- new_client->driver = &w83781d_driver;
+ new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
@@ -1189,6 +1207,12 @@
data->pwmenable[i] = 1;
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
+ }
+
device_create_file_in(new_client, 0);
if (kind != w83783s)
device_create_file_in(new_client, 1);
@@ -1241,6 +1265,15 @@
return 0;
+ERROR4:
+ if (data->lm75[1]) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+ }
+ if (data->lm75[0]) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -1255,24 +1288,26 @@
static int
w83781d_detach_client(struct i2c_client *client)
{
+ struct w83781d_data *data = i2c_get_clientdata(client);
int err;
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
+
if (i2c_is_isa_client(client))
release_region(client->addr, W83781D_EXTENT);
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
- if (i2c_get_clientdata(client)==NULL) {
- /* subclients */
+ /* main client */
+ if (data)
+ kfree(data);
+
+ /* subclient */
+ else
kfree(client);
- } else {
- /* main client */
- kfree(i2c_get_clientdata(client));
- }
return 0;
}
@@ -1443,7 +1478,7 @@
w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
}
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if ((type != w83781d) && (type != as99127f)) {
tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -1613,12 +1648,25 @@
static int __init
sensors_w83781d_init(void)
{
- return i2c_add_driver(&w83781d_driver);
+ int res;
+
+ res = i2c_add_driver(&w83781d_driver);
+ if (res)
+ return res;
+
+ res = i2c_isa_add_driver(&w83781d_isa_driver);
+ if (res) {
+ i2c_del_driver(&w83781d_driver);
+ return res;
+ }
+
+ return 0;
}
static void __exit
sensors_w83781d_exit(void)
{
+ i2c_isa_del_driver(&w83781d_isa_driver);
i2c_del_driver(&w83781d_driver);
}
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
new file mode 100644
index 0000000..ba0c280
--- /dev/null
+++ b/drivers/hwmon/w83792d.c
@@ -0,0 +1,1649 @@
+/*
+ w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+ Copyright (C) 2004, 2005 Winbond Electronics Corp.
+ Chunhao Huang <DZShen@Winbond.com.tw>,
+ Rudolf Marek <r.marek@sh.cvut.cz>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Note:
+ 1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver.
+ 2. This driver is only for Winbond W83792D C version device, there
+ are also some motherboards with B version W83792D device. The
+ calculation method to in6-in7(measured value, limits) is a little
+ different between C and B version. C or B version can be identified
+ by CR[0x49h].
+*/
+
+/*
+ Supports following chips:
+
+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
+ w83792d 9 7 7 3 0x7a 0x5ca3 yes no
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(w83792d);
+I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+ "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to one to force chip initialization");
+
+/* The W83792D registers */
+static const u8 W83792D_REG_IN[9] = {
+ 0x20, /* Vcore A in DataSheet */
+ 0x21, /* Vcore B in DataSheet */
+ 0x22, /* VIN0 in DataSheet */
+ 0x23, /* VIN1 in DataSheet */
+ 0x24, /* VIN2 in DataSheet */
+ 0x25, /* VIN3 in DataSheet */
+ 0x26, /* 5VCC in DataSheet */
+ 0xB0, /* 5VSB in DataSheet */
+ 0xB1 /* VBAT in DataSheet */
+};
+#define W83792D_REG_LOW_BITS1 0x3E /* Low Bits I in DataSheet */
+#define W83792D_REG_LOW_BITS2 0x3F /* Low Bits II in DataSheet */
+static const u8 W83792D_REG_IN_MAX[9] = {
+ 0x2B, /* Vcore A High Limit in DataSheet */
+ 0x2D, /* Vcore B High Limit in DataSheet */
+ 0x2F, /* VIN0 High Limit in DataSheet */
+ 0x31, /* VIN1 High Limit in DataSheet */
+ 0x33, /* VIN2 High Limit in DataSheet */
+ 0x35, /* VIN3 High Limit in DataSheet */
+ 0x37, /* 5VCC High Limit in DataSheet */
+ 0xB4, /* 5VSB High Limit in DataSheet */
+ 0xB6 /* VBAT High Limit in DataSheet */
+};
+static const u8 W83792D_REG_IN_MIN[9] = {
+ 0x2C, /* Vcore A Low Limit in DataSheet */
+ 0x2E, /* Vcore B Low Limit in DataSheet */
+ 0x30, /* VIN0 Low Limit in DataSheet */
+ 0x32, /* VIN1 Low Limit in DataSheet */
+ 0x34, /* VIN2 Low Limit in DataSheet */
+ 0x36, /* VIN3 Low Limit in DataSheet */
+ 0x38, /* 5VCC Low Limit in DataSheet */
+ 0xB5, /* 5VSB Low Limit in DataSheet */
+ 0xB7 /* VBAT Low Limit in DataSheet */
+};
+static const u8 W83792D_REG_FAN[7] = {
+ 0x28, /* FAN 1 Count in DataSheet */
+ 0x29, /* FAN 2 Count in DataSheet */
+ 0x2A, /* FAN 3 Count in DataSheet */
+ 0xB8, /* FAN 4 Count in DataSheet */
+ 0xB9, /* FAN 5 Count in DataSheet */
+ 0xBA, /* FAN 6 Count in DataSheet */
+ 0xBE /* FAN 7 Count in DataSheet */
+};
+static const u8 W83792D_REG_FAN_MIN[7] = {
+ 0x3B, /* FAN 1 Count Low Limit in DataSheet */
+ 0x3C, /* FAN 2 Count Low Limit in DataSheet */
+ 0x3D, /* FAN 3 Count Low Limit in DataSheet */
+ 0xBB, /* FAN 4 Count Low Limit in DataSheet */
+ 0xBC, /* FAN 5 Count Low Limit in DataSheet */
+ 0xBD, /* FAN 6 Count Low Limit in DataSheet */
+ 0xBF /* FAN 7 Count Low Limit in DataSheet */
+};
+#define W83792D_REG_FAN_CFG 0x84 /* FAN Configuration in DataSheet */
+static const u8 W83792D_REG_FAN_DIV[4] = {
+ 0x47, /* contains FAN2 and FAN1 Divisor */
+ 0x5B, /* contains FAN4 and FAN3 Divisor */
+ 0x5C, /* contains FAN6 and FAN5 Divisor */
+ 0x9E /* contains FAN7 Divisor. */
+};
+static const u8 W83792D_REG_PWM[7] = {
+ 0x81, /* FAN 1 Duty Cycle, be used to control */
+ 0x83, /* FAN 2 Duty Cycle, be used to control */
+ 0x94, /* FAN 3 Duty Cycle, be used to control */
+ 0xA3, /* FAN 4 Duty Cycle, be used to control */
+ 0xA4, /* FAN 5 Duty Cycle, be used to control */
+ 0xA5, /* FAN 6 Duty Cycle, be used to control */
+ 0xA6 /* FAN 7 Duty Cycle, be used to control */
+};
+#define W83792D_REG_BANK 0x4E
+#define W83792D_REG_TEMP2_CONFIG 0xC2
+#define W83792D_REG_TEMP3_CONFIG 0xCA
+
+static const u8 W83792D_REG_TEMP1[3] = {
+ 0x27, /* TEMP 1 in DataSheet */
+ 0x39, /* TEMP 1 Over in DataSheet */
+ 0x3A, /* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83792D_REG_TEMP_ADD[2][6] = {
+ { 0xC0, /* TEMP 2 in DataSheet */
+ 0xC1, /* TEMP 2(0.5 deg) in DataSheet */
+ 0xC5, /* TEMP 2 Over High part in DataSheet */
+ 0xC6, /* TEMP 2 Over Low part in DataSheet */
+ 0xC3, /* TEMP 2 Thyst High part in DataSheet */
+ 0xC4 }, /* TEMP 2 Thyst Low part in DataSheet */
+ { 0xC8, /* TEMP 3 in DataSheet */
+ 0xC9, /* TEMP 3(0.5 deg) in DataSheet */
+ 0xCD, /* TEMP 3 Over High part in DataSheet */
+ 0xCE, /* TEMP 3 Over Low part in DataSheet */
+ 0xCB, /* TEMP 3 Thyst High part in DataSheet */
+ 0xCC } /* TEMP 3 Thyst Low part in DataSheet */
+};
+
+static const u8 W83792D_REG_THERMAL[3] = {
+ 0x85, /* SmartFanI: Fan1 target value */
+ 0x86, /* SmartFanI: Fan2 target value */
+ 0x96 /* SmartFanI: Fan3 target value */
+};
+
+static const u8 W83792D_REG_TOLERANCE[3] = {
+ 0x87, /* (bit3-0)SmartFan Fan1 tolerance */
+ 0x87, /* (bit7-4)SmartFan Fan2 tolerance */
+ 0x97 /* (bit3-0)SmartFan Fan3 tolerance */
+};
+
+static const u8 W83792D_REG_POINTS[3][4] = {
+ { 0x85, /* SmartFanII: Fan1 temp point 1 */
+ 0xE3, /* SmartFanII: Fan1 temp point 2 */
+ 0xE4, /* SmartFanII: Fan1 temp point 3 */
+ 0xE5 }, /* SmartFanII: Fan1 temp point 4 */
+ { 0x86, /* SmartFanII: Fan2 temp point 1 */
+ 0xE6, /* SmartFanII: Fan2 temp point 2 */
+ 0xE7, /* SmartFanII: Fan2 temp point 3 */
+ 0xE8 }, /* SmartFanII: Fan2 temp point 4 */
+ { 0x96, /* SmartFanII: Fan3 temp point 1 */
+ 0xE9, /* SmartFanII: Fan3 temp point 2 */
+ 0xEA, /* SmartFanII: Fan3 temp point 3 */
+ 0xEB } /* SmartFanII: Fan3 temp point 4 */
+};
+
+static const u8 W83792D_REG_LEVELS[3][4] = {
+ { 0x88, /* (bit3-0) SmartFanII: Fan1 Non-Stop */
+ 0x88, /* (bit7-4) SmartFanII: Fan1 Level 1 */
+ 0xE0, /* (bit7-4) SmartFanII: Fan1 Level 2 */
+ 0xE0 }, /* (bit3-0) SmartFanII: Fan1 Level 3 */
+ { 0x89, /* (bit3-0) SmartFanII: Fan2 Non-Stop */
+ 0x89, /* (bit7-4) SmartFanII: Fan2 Level 1 */
+ 0xE1, /* (bit7-4) SmartFanII: Fan2 Level 2 */
+ 0xE1 }, /* (bit3-0) SmartFanII: Fan2 Level 3 */
+ { 0x98, /* (bit3-0) SmartFanII: Fan3 Non-Stop */
+ 0x98, /* (bit7-4) SmartFanII: Fan3 Level 1 */
+ 0xE2, /* (bit7-4) SmartFanII: Fan3 Level 2 */
+ 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */
+};
+
+#define W83792D_REG_CONFIG 0x40
+#define W83792D_REG_VID_FANDIV 0x47
+#define W83792D_REG_CHIPID 0x49
+#define W83792D_REG_WCHIPID 0x58
+#define W83792D_REG_CHIPMAN 0x4F
+#define W83792D_REG_PIN 0x4B
+#define W83792D_REG_I2C_SUBADDR 0x4A
+
+#define W83792D_REG_ALARM1 0xA9 /* realtime status register1 */
+#define W83792D_REG_ALARM2 0xAA /* realtime status register2 */
+#define W83792D_REG_ALARM3 0xAB /* realtime status register3 */
+#define W83792D_REG_CHASSIS 0x42 /* Bit 5: Case Open status bit */
+#define W83792D_REG_CHASSIS_CLR 0x44 /* Bit 7: Case Open CLR_CHS/Reset bit */
+
+/* control in0/in1 's limit modifiability */
+#define W83792D_REG_VID_IN_B 0x17
+
+#define W83792D_REG_VBAT 0x5D
+#define W83792D_REG_I2C_ADDR 0x48
+
+/* Conversions. Rounding and limit checking is only done on the TO_REG
+ variants. Note that you should be a bit careful with which arguments
+ these macros are called: arguments may be evaluated more than once.
+ Fixing this is just not worth it. */
+#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \
+ ((((nr)==6)||((nr)==7))?(val*6):(val*4)))
+#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \
+ ((((nr)==6)||((nr)==7))?(val/6):(val/4)))
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+ if (rpm == 0)
+ return 255;
+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
+ ((val) == 255 ? 0 : \
+ 1350000 / ((val) * (div))))
+
+/* for temp1 */
+#define TEMP1_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+ : (val)) / 1000, 0, 0xff))
+#define TEMP1_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+/* for temp2 and temp3, because they need addtional resolution */
+#define TEMP_ADD_FROM_REG(val1, val2) \
+ ((((val1) & 0x80 ? (val1)-0x100 \
+ : (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
+#define TEMP_ADD_TO_REG_HIGH(val) \
+ (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+ : (val)) / 1000, 0, 0xff))
+#define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00)
+
+#define PWM_FROM_REG(val) (val)
+#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+#define DIV_FROM_REG(val) (1 << (val))
+
+static inline u8
+DIV_TO_REG(long val)
+{
+ int i;
+ val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ for (i = 0; i < 6; i++) {
+ if (val == 0)
+ break;
+ val >>= 1;
+ }
+ return ((u8) i);
+}
+
+struct w83792d_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct semaphore lock;
+ enum chips type;
+
+ struct semaphore update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* array of 2 pointers to subclients */
+ struct i2c_client *lm75[2];
+
+ u8 in[9]; /* Register value */
+ u8 in_max[9]; /* Register value */
+ u8 in_min[9]; /* Register value */
+ u8 low_bits[2]; /* Additional resolution to voltage in0-6 */
+ u8 fan[7]; /* Register value */
+ u8 fan_min[7]; /* Register value */
+ u8 temp1[3]; /* current, over, thyst */
+ u8 temp_add[2][6]; /* Register value */
+ u8 fan_div[7]; /* Register encoding, shifted right */
+ u8 pwm[7]; /* We only consider the first 3 set of pwm,
+ although 792 chip has 7 set of pwm. */
+ u8 pwmenable[3];
+ u8 pwm_mode[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */
+ u32 alarms; /* realtime status register encoding,combined */
+ u8 chassis; /* Chassis status */
+ u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */
+ u8 thermal_cruise[3]; /* Smart FanI: Fan1,2,3 target value */
+ u8 tolerance[3]; /* Fan1,2,3 tolerance(Smart Fan I/II) */
+ u8 sf2_points[3][4]; /* Smart FanII: Fan1,2,3 temperature points */
+ u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */
+};
+
+static int w83792d_attach_adapter(struct i2c_adapter *adapter);
+static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind);
+static int w83792d_detach_client(struct i2c_client *client);
+
+static int w83792d_read_value(struct i2c_client *client, u8 register);
+static int w83792d_write_value(struct i2c_client *client, u8 register,
+ u8 value);
+static struct w83792d_data *w83792d_update_device(struct device *dev);
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
+#endif
+
+static void w83792d_init_client(struct i2c_client *client);
+
+static struct i2c_driver w83792d_driver = {
+ .owner = THIS_MODULE,
+ .name = "w83792d",
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = w83792d_attach_adapter,
+ .detach_client = w83792d_detach_client,
+};
+
+static long in_count_from_reg(int nr, struct w83792d_data *data)
+{
+ u16 vol_count = data->in[nr];
+ u16 low_bits = 0;
+ vol_count = (vol_count << 2);
+ switch (nr)
+ {
+ case 0: /* vin0 */
+ low_bits = (data->low_bits[0]) & 0x03;
+ break;
+ case 1: /* vin1 */
+ low_bits = ((data->low_bits[0]) & 0x0c) >> 2;
+ break;
+ case 2: /* vin2 */
+ low_bits = ((data->low_bits[0]) & 0x30) >> 4;
+ break;
+ case 3: /* vin3 */
+ low_bits = ((data->low_bits[0]) & 0xc0) >> 6;
+ break;
+ case 4: /* vin4 */
+ low_bits = (data->low_bits[1]) & 0x03;
+ break;
+ case 5: /* vin5 */
+ low_bits = ((data->low_bits[1]) & 0x0c) >> 2;
+ break;
+ case 6: /* vin6 */
+ low_bits = ((data->low_bits[1]) & 0x30) >> 4;
+ default:
+ break;
+ }
+ vol_count = vol_count | low_bits;
+ return vol_count;
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf,"%ld\n", IN_FROM_REG(nr,(in_count_from_reg(nr, data))));
+}
+
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ struct w83792d_data *data = w83792d_update_device(dev); \
+ return sprintf(buf,"%ld\n", (long)(IN_FROM_REG(nr, (data->reg[nr])*4))); \
+}
+
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg (struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83792d_data *data = i2c_get_clientdata(client); \
+ u32 val; \
+ \
+ val = simple_strtoul(buf, NULL, 10); \
+ data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \
+ w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \
+ \
+ return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+#define sysfs_in_reg(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \
+ NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, store_in_max, offset);
+
+sysfs_in_reg(0);
+sysfs_in_reg(1);
+sysfs_in_reg(2);
+sysfs_in_reg(3);
+sysfs_in_reg(4);
+sysfs_in_reg(5);
+sysfs_in_reg(6);
+sysfs_in_reg(7);
+sysfs_in_reg(8);
+
+#define device_create_file_in(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_max.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_min.dev_attr); \
+} while (0)
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index - 1; \
+ struct w83792d_data *data = w83792d_update_device(dev); \
+ return sprintf(buf,"%d\n", \
+ FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83792d_write_value(client, W83792D_REG_FAN_MIN[nr],
+ data->fan_min[nr]);
+
+ return count;
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr - 1]));
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+ determined in part by the fan divisor. This follows the principle of
+ least suprise; the user doesn't expect the fan minimum to change just
+ because the divisor changed. */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ unsigned long min;
+ /*u8 reg;*/
+ u8 fan_div_reg = 0;
+ u8 tmp_fan_div;
+
+ /* Save fan_min */
+ min = FAN_FROM_REG(data->fan_min[nr],
+ DIV_FROM_REG(data->fan_div[nr]));
+
+ data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
+
+ fan_div_reg = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]);
+ fan_div_reg &= (nr & 0x01) ? 0x8f : 0xf8;
+ tmp_fan_div = (nr & 0x01) ? (((data->fan_div[nr]) << 4) & 0x70)
+ : ((data->fan_div[nr]) & 0x07);
+ w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1],
+ fan_div_reg | tmp_fan_div);
+
+ /* Restore fan_min */
+ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+ w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]);
+
+ return count;
+}
+
+#define sysfs_fan(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
+ offset); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, store_fan_div, offset); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, store_fan_min, offset);
+
+sysfs_fan(1);
+sysfs_fan(2);
+sysfs_fan(3);
+sysfs_fan(4);
+sysfs_fan(5);
+sysfs_fan(6);
+sysfs_fan(7);
+
+#define device_create_file_fan(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_div.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_min.dev_attr); \
+} while (0)
+
+
+/* read/write the temperature1, includes measured value and limits */
+
+static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[nr]));
+}
+
+static ssize_t store_temp1(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+
+ data->temp1[nr] = TEMP1_TO_REG(val);
+ w83792d_write_value(client, W83792D_REG_TEMP1[nr],
+ data->temp1[nr]);
+
+ return count;
+}
+
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1,
+ store_temp1, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1,
+ store_temp1, 2);
+
+#define device_create_file_temp1(client) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_max_hyst.dev_attr); \
+} while (0)
+
+
+/* read/write the temperature2-3, includes measured value and limits */
+
+static ssize_t show_temp23(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf,"%ld\n",
+ (long)TEMP_ADD_FROM_REG(data->temp_add[nr][index],
+ data->temp_add[nr][index+1]));
+}
+
+static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+
+ data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val);
+ data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val);
+ w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index],
+ data->temp_add[nr][index]);
+ w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1],
+ data->temp_add[nr][index+1]);
+
+ return count;
+}
+
+#define sysfs_temp23(name,idx) \
+static SENSOR_DEVICE_ATTR_2(name##_input, S_IRUGO, show_temp23, NULL, \
+ idx, 0); \
+static SENSOR_DEVICE_ATTR_2(name##_max, S_IRUGO | S_IWUSR, \
+ show_temp23, store_temp23, idx, 2); \
+static SENSOR_DEVICE_ATTR_2(name##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp23, store_temp23, idx, 4);
+
+sysfs_temp23(temp2,0)
+sysfs_temp23(temp3,1)
+
+#define device_create_file_temp_add(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_max.dev_attr); \
+device_create_file(&client->dev, \
+&sensor_dev_attr_temp##offset##_max_hyst.dev_attr); \
+} while (0)
+
+
+/* get reatime status of all sensors items: voltage, temp, fan */
+static ssize_t
+show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->alarms);
+}
+
+static
+DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+#define device_create_file_alarms(client) \
+device_create_file(&client->dev, &dev_attr_alarms);
+
+
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr-1]));
+}
+
+static ssize_t
+show_pwmenable(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ long pwm_enable_tmp = 1;
+
+ switch (data->pwmenable[nr]) {
+ case 0:
+ pwm_enable_tmp = 1; /* manual mode */
+ break;
+ case 1:
+ pwm_enable_tmp = 3; /*thermal cruise/Smart Fan I */
+ break;
+ case 2:
+ pwm_enable_tmp = 2; /* Smart Fan II */
+ break;
+ }
+
+ return sprintf(buf, "%ld\n", pwm_enable_tmp);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->pwm[nr] = PWM_TO_REG(val);
+ w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+
+ return count;
+}
+
+static ssize_t
+store_pwmenable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
+
+ val = simple_strtoul(buf, NULL, 10);
+ switch (val) {
+ case 1:
+ data->pwmenable[nr] = 0; /* manual mode */
+ break;
+ case 2:
+ data->pwmenable[nr] = 2; /* Smart Fan II */
+ break;
+ case 3:
+ data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */
+ break;
+ default:
+ return -EINVAL;
+ }
+ cfg1_tmp = data->pwmenable[0];
+ cfg2_tmp = (data->pwmenable[1]) << 2;
+ cfg3_tmp = (data->pwmenable[2]) << 4;
+ cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0;
+ fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp;
+ w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp);
+
+ return count;
+}
+
+#define sysfs_pwm(offset) \
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+ show_pwm, store_pwm, offset); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+ show_pwmenable, store_pwmenable, offset); \
+
+sysfs_pwm(1);
+sysfs_pwm(2);
+sysfs_pwm(3);
+
+
+#define device_create_file_pwm(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset.dev_attr); \
+} while (0)
+
+#define device_create_file_pwmenable(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_enable.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_mode[nr-1]);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 pwm_mode_mask = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->pwm_mode[nr] = SENSORS_LIMIT(val, 0, 1);
+ pwm_mode_mask = w83792d_read_value(client,
+ W83792D_REG_PWM[nr]) & 0x7f;
+ w83792d_write_value(client, W83792D_REG_PWM[nr],
+ ((data->pwm_mode[nr]) << 7) | pwm_mode_mask);
+
+ return count;
+}
+
+#define sysfs_pwm_mode(offset) \
+static SENSOR_DEVICE_ATTR(pwm##offset##_mode, S_IRUGO | S_IWUSR, \
+ show_pwm_mode, store_pwm_mode, offset);
+
+sysfs_pwm_mode(1);
+sysfs_pwm_mode(2);
+sysfs_pwm_mode(3);
+
+#define device_create_file_pwm_mode(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_mode.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_regs_chassis(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->chassis);
+}
+
+static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
+
+#define device_create_file_chassis(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_chassis); \
+} while (0)
+
+
+static ssize_t
+show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->chassis_clear);
+}
+
+static ssize_t
+store_chassis_clear(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 temp1 = 0, temp2 = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+
+ data->chassis_clear = SENSORS_LIMIT(val, 0 ,1);
+ temp1 = ((data->chassis_clear) << 7) & 0x80;
+ temp2 = w83792d_read_value(client,
+ W83792D_REG_CHASSIS_CLR) & 0x7f;
+ w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
+
+ return count;
+}
+
+static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
+ show_chassis_clear, store_chassis_clear);
+
+#define device_create_file_chassis_clear(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_chassis_clear); \
+} while (0)
+
+
+
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t
+show_thermal_cruise(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->thermal_cruise[nr-1]);
+}
+
+static ssize_t
+store_thermal_cruise(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 target_tmp=0, target_mask=0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ target_tmp = val;
+ target_tmp = target_tmp & 0x7f;
+ target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80;
+ data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
+ w83792d_write_value(client, W83792D_REG_THERMAL[nr],
+ (data->thermal_cruise[nr]) | target_mask);
+
+ return count;
+}
+
+#define sysfs_thermal_cruise(offset) \
+static SENSOR_DEVICE_ATTR(thermal_cruise##offset, S_IRUGO | S_IWUSR, \
+ show_thermal_cruise, store_thermal_cruise, offset);
+
+sysfs_thermal_cruise(1);
+sysfs_thermal_cruise(2);
+sysfs_thermal_cruise(3);
+
+#define device_create_file_thermal_cruise(client, offset) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_thermal_cruise##offset.dev_attr); \
+} while (0)
+
+
+/* For Smart Fan I/Thermal Cruise and Smart Fan II */
+static ssize_t
+show_tolerance(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->tolerance[nr-1]);
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 tol_tmp, tol_mask;
+
+ val = simple_strtoul(buf, NULL, 10);
+ tol_mask = w83792d_read_value(client,
+ W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
+ tol_tmp = SENSORS_LIMIT(val, 0, 15);
+ tol_tmp &= 0x0f;
+ data->tolerance[nr] = tol_tmp;
+ if (nr == 1) {
+ tol_tmp <<= 4;
+ }
+ w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
+ tol_mask | tol_tmp);
+
+ return count;
+}
+
+#define sysfs_tolerance(offset) \
+static SENSOR_DEVICE_ATTR(tolerance##offset, S_IRUGO | S_IWUSR, \
+ show_tolerance, store_tolerance, offset);
+
+sysfs_tolerance(1);
+sysfs_tolerance(2);
+sysfs_tolerance(3);
+
+#define device_create_file_tolerance(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_tolerance##offset.dev_attr); \
+} while (0)
+
+
+/* For Smart Fan II */
+static ssize_t
+show_sf2_point(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->sf2_points[index-1][nr-1]);
+}
+
+static ssize_t
+store_sf2_point(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr - 1;
+ int index = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 mask_tmp = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
+ mask_tmp = w83792d_read_value(client,
+ W83792D_REG_POINTS[index][nr]) & 0x80;
+ w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
+ mask_tmp|data->sf2_points[index][nr]);
+
+ return count;
+}
+
+#define sysfs_sf2_point(offset, index) \
+static SENSOR_DEVICE_ATTR_2(sf2_point##offset##_fan##index, S_IRUGO | S_IWUSR, \
+ show_sf2_point, store_sf2_point, offset, index);
+
+sysfs_sf2_point(1, 1); /* Fan1 */
+sysfs_sf2_point(2, 1); /* Fan1 */
+sysfs_sf2_point(3, 1); /* Fan1 */
+sysfs_sf2_point(4, 1); /* Fan1 */
+sysfs_sf2_point(1, 2); /* Fan2 */
+sysfs_sf2_point(2, 2); /* Fan2 */
+sysfs_sf2_point(3, 2); /* Fan2 */
+sysfs_sf2_point(4, 2); /* Fan2 */
+sysfs_sf2_point(1, 3); /* Fan3 */
+sysfs_sf2_point(2, 3); /* Fan3 */
+sysfs_sf2_point(3, 3); /* Fan3 */
+sysfs_sf2_point(4, 3); /* Fan3 */
+
+#define device_create_file_sf2_point(client, offset, index) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_sf2_point##offset##_fan##index.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_sf2_level(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n",
+ (((data->sf2_levels[index-1][nr]) * 100) / 15));
+}
+
+static ssize_t
+store_sf2_level(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 mask_tmp=0, level_tmp=0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
+ mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
+ & ((nr==3) ? 0xf0 : 0x0f);
+ if (nr==3) {
+ level_tmp = data->sf2_levels[index][nr];
+ } else {
+ level_tmp = data->sf2_levels[index][nr] << 4;
+ }
+ w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp);
+
+ return count;
+}
+
+#define sysfs_sf2_level(offset, index) \
+static SENSOR_DEVICE_ATTR_2(sf2_level##offset##_fan##index, S_IRUGO | S_IWUSR, \
+ show_sf2_level, store_sf2_level, offset, index);
+
+sysfs_sf2_level(1, 1); /* Fan1 */
+sysfs_sf2_level(2, 1); /* Fan1 */
+sysfs_sf2_level(3, 1); /* Fan1 */
+sysfs_sf2_level(1, 2); /* Fan2 */
+sysfs_sf2_level(2, 2); /* Fan2 */
+sysfs_sf2_level(3, 2); /* Fan2 */
+sysfs_sf2_level(1, 3); /* Fan3 */
+sysfs_sf2_level(2, 3); /* Fan3 */
+sysfs_sf2_level(3, 3); /* Fan3 */
+
+#define device_create_file_sf2_level(client, offset, index) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_sf2_level##offset##_fan##index.dev_attr); \
+} while (0)
+
+
+/* This function is called when:
+ * w83792d_driver is inserted (when this module is loaded), for each
+ available adapter
+ * when a new adapter is inserted (and w83792d_driver is still present) */
+static int
+w83792d_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, w83792d_detect);
+}
+
+
+static int
+w83792d_create_subclient(struct i2c_adapter *adapter,
+ struct i2c_client *new_client, int addr,
+ struct i2c_client **sub_cli)
+{
+ int err;
+ struct i2c_client *sub_client;
+
+ (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!(sub_client)) {
+ return -ENOMEM;
+ }
+ memset(sub_client, 0x00, sizeof(struct i2c_client));
+ sub_client->addr = 0x48 + addr;
+ i2c_set_clientdata(sub_client, NULL);
+ sub_client->adapter = adapter;
+ sub_client->driver = &w83792d_driver;
+ sub_client->flags = 0;
+ strlcpy(sub_client->name, "w83792d subclient", I2C_NAME_SIZE);
+ if ((err = i2c_attach_client(sub_client))) {
+ dev_err(&new_client->dev, "subclient registration "
+ "at address 0x%x failed\n", sub_client->addr);
+ kfree(sub_client);
+ return err;
+ }
+ return 0;
+}
+
+
+static int
+w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
+ struct i2c_client *new_client)
+{
+ int i, id, err;
+ u8 val;
+ struct w83792d_data *data = i2c_get_clientdata(new_client);
+
+ id = i2c_adapter_id(adapter);
+ if (force_subclients[0] == id && force_subclients[1] == address) {
+ for (i = 2; i <= 3; i++) {
+ if (force_subclients[i] < 0x48 ||
+ force_subclients[i] > 0x4f) {
+ dev_err(&new_client->dev, "invalid subclient "
+ "address %d; must be 0x48-0x4f\n",
+ force_subclients[i]);
+ err = -ENODEV;
+ goto ERROR_SC_0;
+ }
+ }
+ w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
+ (force_subclients[2] & 0x07) |
+ ((force_subclients[3] & 0x07) << 4));
+ }
+
+ val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
+ if (!(val & 0x08)) {
+ err = w83792d_create_subclient(adapter, new_client, val & 0x7,
+ &data->lm75[0]);
+ if (err < 0)
+ goto ERROR_SC_0;
+ }
+ if (!(val & 0x80)) {
+ if ((data->lm75[0] != NULL) &&
+ ((val & 0x7) == ((val >> 4) & 0x7))) {
+ dev_err(&new_client->dev, "duplicate addresses 0x%x, "
+ "use force_subclient\n", data->lm75[0]->addr);
+ err = -ENODEV;
+ goto ERROR_SC_1;
+ }
+ err = w83792d_create_subclient(adapter, new_client,
+ (val >> 4) & 0x7, &data->lm75[1]);
+ if (err < 0)
+ goto ERROR_SC_1;
+ }
+
+ return 0;
+
+/* Undo inits in case of errors */
+
+ERROR_SC_1:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ERROR_SC_0:
+ return err;
+}
+
+
+static int
+w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ int i = 0, val1 = 0, val2;
+ struct i2c_client *new_client;
+ struct w83792d_data *data;
+ int err = 0;
+ const char *client_name = "";
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto ERROR0;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access w83792d_{read,write}_value. */
+
+ if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto ERROR0;
+ }
+ memset(data, 0, sizeof(struct w83792d_data));
+
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+ new_client->addr = address;
+ init_MUTEX(&data->lock);
+ new_client->adapter = adapter;
+ new_client->driver = &w83792d_driver;
+ new_client->flags = 0;
+
+ /* Now, we do the remaining detection. */
+
+ /* The w83792d may be stuck in some other bank than bank 0. This may
+ make reading other information impossible. Specify a force=... or
+ force_*=... parameter, and the Winbond will be reset to the right
+ bank. */
+ if (kind < 0) {
+ if (w83792d_read_value(new_client, W83792D_REG_CONFIG) & 0x80) {
+ dev_warn(&new_client->dev, "Detection failed at step "
+ "3\n");
+ goto ERROR1;
+ }
+ val1 = w83792d_read_value(new_client, W83792D_REG_BANK);
+ val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+ /* Check for Winbond ID if in bank 0 */
+ if (!(val1 & 0x07)) { /* is Bank0 */
+ if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
+ ((val1 & 0x80) && (val2 != 0x5c))) {
+ goto ERROR1;
+ }
+ }
+ /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
+ should match */
+ if (w83792d_read_value(new_client,
+ W83792D_REG_I2C_ADDR) != address) {
+ dev_warn(&new_client->dev, "Detection failed "
+ "at step 5\n");
+ goto ERROR1;
+ }
+ }
+
+ /* We have either had a force parameter, or we have already detected the
+ Winbond. Put it now into bank 0 and Vendor ID High Byte */
+ w83792d_write_value(new_client,
+ W83792D_REG_BANK,
+ (w83792d_read_value(new_client,
+ W83792D_REG_BANK) & 0x78) | 0x80);
+
+ /* Determine the chip type. */
+ if (kind <= 0) {
+ /* get vendor ID */
+ val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+ if (val2 != 0x5c) { /* the vendor is NOT Winbond */
+ goto ERROR1;
+ }
+ val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID);
+ if (val1 == 0x7a && address >= 0x2c) {
+ kind = w83792d;
+ } else {
+ if (kind == 0)
+ dev_warn(&new_client->dev,
+ "w83792d: Ignoring 'force' parameter for"
+ " unknown chip at adapter %d, address"
+ " 0x%02x\n", i2c_adapter_id(adapter),
+ address);
+ goto ERROR1;
+ }
+ }
+
+ if (kind == w83792d) {
+ client_name = "w83792d";
+ } else {
+ dev_err(&new_client->dev, "w83792d: Internal error: unknown"
+ " kind (%d)?!?", kind);
+ goto ERROR1;
+ }
+
+ /* Fill in the remaining client fields and put into the global list */
+ strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+ data->type = kind;
+
+ data->valid = 0;
+ init_MUTEX(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(new_client)))
+ goto ERROR1;
+
+ if ((err = w83792d_detect_subclients(adapter, address,
+ kind, new_client)))
+ goto ERROR2;
+
+ /* Initialize the chip */
+ w83792d_init_client(new_client);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 1; i <= 7; i++) {
+ data->fan_min[i - 1] = w83792d_read_value(new_client,
+ W83792D_REG_FAN_MIN[i]);
+ }
+
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+ device_create_file_in(new_client, 0);
+ device_create_file_in(new_client, 1);
+ device_create_file_in(new_client, 2);
+ device_create_file_in(new_client, 3);
+ device_create_file_in(new_client, 4);
+ device_create_file_in(new_client, 5);
+ device_create_file_in(new_client, 6);
+ device_create_file_in(new_client, 7);
+ device_create_file_in(new_client, 8);
+
+ device_create_file_fan(new_client, 1);
+ device_create_file_fan(new_client, 2);
+ device_create_file_fan(new_client, 3);
+ device_create_file_fan(new_client, 4);
+ device_create_file_fan(new_client, 5);
+ device_create_file_fan(new_client, 6);
+ device_create_file_fan(new_client, 7);
+
+ device_create_file_temp1(new_client); /* Temp1 */
+ device_create_file_temp_add(new_client, 2); /* Temp2 */
+ device_create_file_temp_add(new_client, 3); /* Temp3 */
+
+ device_create_file_alarms(new_client);
+
+ device_create_file_pwm(new_client, 1);
+ device_create_file_pwm(new_client, 2);
+ device_create_file_pwm(new_client, 3);
+
+ device_create_file_pwmenable(new_client, 1);
+ device_create_file_pwmenable(new_client, 2);
+ device_create_file_pwmenable(new_client, 3);
+
+ device_create_file_pwm_mode(new_client, 1);
+ device_create_file_pwm_mode(new_client, 2);
+ device_create_file_pwm_mode(new_client, 3);
+
+ device_create_file_chassis(new_client);
+ device_create_file_chassis_clear(new_client);
+
+ device_create_file_thermal_cruise(new_client, 1);
+ device_create_file_thermal_cruise(new_client, 2);
+ device_create_file_thermal_cruise(new_client, 3);
+
+ device_create_file_tolerance(new_client, 1);
+ device_create_file_tolerance(new_client, 2);
+ device_create_file_tolerance(new_client, 3);
+
+ device_create_file_sf2_point(new_client, 1, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 2, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 3, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 4, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 1, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 2, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 3, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 4, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 1, 3); /* Fan3 */
+ device_create_file_sf2_point(new_client, 2, 3); /* Fan3 */
+ device_create_file_sf2_point(new_client, 3, 3); /* Fan3 */
+ device_create_file_sf2_point(new_client, 4, 3); /* Fan3 */
+
+ device_create_file_sf2_level(new_client, 1, 1); /* Fan1 */
+ device_create_file_sf2_level(new_client, 2, 1); /* Fan1 */
+ device_create_file_sf2_level(new_client, 3, 1); /* Fan1 */
+ device_create_file_sf2_level(new_client, 1, 2); /* Fan2 */
+ device_create_file_sf2_level(new_client, 2, 2); /* Fan2 */
+ device_create_file_sf2_level(new_client, 3, 2); /* Fan2 */
+ device_create_file_sf2_level(new_client, 1, 3); /* Fan3 */
+ device_create_file_sf2_level(new_client, 2, 3); /* Fan3 */
+ device_create_file_sf2_level(new_client, 3, 3); /* Fan3 */
+
+ return 0;
+
+ERROR3:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ if (data->lm75[1] != NULL) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+ }
+ERROR2:
+ i2c_detach_client(new_client);
+ERROR1:
+ kfree(data);
+ERROR0:
+ return err;
+}
+
+static int
+w83792d_detach_client(struct i2c_client *client)
+{
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ int err;
+
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ /* main client */
+ if (data)
+ kfree(data);
+ /* subclient */
+ else
+ kfree(client);
+
+ return 0;
+}
+
+/* The SMBus locks itself, usually, but nothing may access the Winbond between
+ bank switches. ISA access must always be locked explicitly!
+ We ignore the W83792D BUSY flag at this moment - it could lead to deadlocks,
+ would slow down the W83792D access and should not be necessary.
+ There are some ugly typecasts here, but the good news is - they should
+ nowhere else be necessary! */
+static int
+w83792d_read_value(struct i2c_client *client, u8 reg)
+{
+ int res=0;
+ res = i2c_smbus_read_byte_data(client, reg);
+
+ return res;
+}
+
+static int
+w83792d_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+ i2c_smbus_write_byte_data(client, reg, value);
+ return 0;
+}
+
+/* Called when we have found a new W83792D. It should set limits, etc. */
+static void
+w83792d_init_client(struct i2c_client *client)
+{
+ u8 temp2_cfg, temp3_cfg, vid_in_b;
+
+ if (init) {
+ w83792d_write_value(client, W83792D_REG_CONFIG, 0x80);
+ }
+ /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0):
+ W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of
+ vin0/vin1 can be modified by user;
+ W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of
+ vin0/vin1 auto-updated, can NOT be modified by user. */
+ vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B);
+ w83792d_write_value(client, W83792D_REG_VID_IN_B,
+ vid_in_b & 0xbf);
+
+ temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP2_CONFIG);
+ temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP3_CONFIG);
+ w83792d_write_value(client, W83792D_REG_TEMP2_CONFIG,
+ temp2_cfg & 0xe6);
+ w83792d_write_value(client, W83792D_REG_TEMP3_CONFIG,
+ temp3_cfg & 0xe6);
+
+ /* Start monitoring */
+ w83792d_write_value(client, W83792D_REG_CONFIG,
+ (w83792d_read_value(client,
+ W83792D_REG_CONFIG) & 0xf7)
+ | 0x01);
+}
+
+static struct w83792d_data *w83792d_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ int i, j;
+ u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp;
+
+ down(&data->update_lock);
+
+ if (time_after
+ (jiffies - data->last_updated, (unsigned long) (HZ * 3))
+ || time_before(jiffies, data->last_updated) || !data->valid) {
+ dev_dbg(dev, "Starting device update\n");
+
+ /* Update the voltages measured value and limits */
+ for (i = 0; i < 9; i++) {
+ data->in[i] = w83792d_read_value(client,
+ W83792D_REG_IN[i]);
+ data->in_max[i] = w83792d_read_value(client,
+ W83792D_REG_IN_MAX[i]);
+ data->in_min[i] = w83792d_read_value(client,
+ W83792D_REG_IN_MIN[i]);
+ }
+ data->low_bits[0] = w83792d_read_value(client,
+ W83792D_REG_LOW_BITS1);
+ data->low_bits[1] = w83792d_read_value(client,
+ W83792D_REG_LOW_BITS2);
+ for (i = 0; i < 7; i++) {
+ /* Update the Fan measured value and limits */
+ data->fan[i] = w83792d_read_value(client,
+ W83792D_REG_FAN[i]);
+ data->fan_min[i] = w83792d_read_value(client,
+ W83792D_REG_FAN_MIN[i]);
+ /* Update the PWM/DC Value and PWM/DC flag */
+ pwm_array_tmp[i] = w83792d_read_value(client,
+ W83792D_REG_PWM[i]);
+ data->pwm[i] = pwm_array_tmp[i] & 0x0f;
+ data->pwm_mode[i] = (pwm_array_tmp[i] >> 7) & 0x01;
+ }
+
+ reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
+ data->pwmenable[0] = reg_tmp & 0x03;
+ data->pwmenable[1] = (reg_tmp>>2) & 0x03;
+ data->pwmenable[2] = (reg_tmp>>4) & 0x03;
+
+ for (i = 0; i < 3; i++) {
+ data->temp1[i] = w83792d_read_value(client,
+ W83792D_REG_TEMP1[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 6; j++) {
+ data->temp_add[i][j] = w83792d_read_value(
+ client,W83792D_REG_TEMP_ADD[i][j]);
+ }
+ }
+
+ /* Update the Fan Divisor */
+ for (i = 0; i < 4; i++) {
+ reg_array_tmp[i] = w83792d_read_value(client,
+ W83792D_REG_FAN_DIV[i]);
+ }
+ data->fan_div[0] = reg_array_tmp[0] & 0x07;
+ data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07;
+ data->fan_div[2] = reg_array_tmp[1] & 0x07;
+ data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07;
+ data->fan_div[4] = reg_array_tmp[2] & 0x07;
+ data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07;
+ data->fan_div[6] = reg_array_tmp[3] & 0x07;
+
+ /* Update the realtime status */
+ data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) +
+ (w83792d_read_value(client, W83792D_REG_ALARM2) << 8) +
+ (w83792d_read_value(client, W83792D_REG_ALARM3) << 16);
+
+ /* Update CaseOpen status and it's CLR_CHS. */
+ data->chassis = (w83792d_read_value(client,
+ W83792D_REG_CHASSIS) >> 5) & 0x01;
+ data->chassis_clear = (w83792d_read_value(client,
+ W83792D_REG_CHASSIS_CLR) >> 7) & 0x01;
+
+ /* Update Thermal Cruise/Smart Fan I target value */
+ for (i = 0; i < 3; i++) {
+ data->thermal_cruise[i] =
+ w83792d_read_value(client,
+ W83792D_REG_THERMAL[i]) & 0x7f;
+ }
+
+ /* Update Smart Fan I/II tolerance */
+ reg_tmp = w83792d_read_value(client, W83792D_REG_TOLERANCE[0]);
+ data->tolerance[0] = reg_tmp & 0x0f;
+ data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
+ data->tolerance[2] = w83792d_read_value(client,
+ W83792D_REG_TOLERANCE[2]) & 0x0f;
+
+ /* Update Smart Fan II temperature points */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 4; j++) {
+ data->sf2_points[i][j] = w83792d_read_value(
+ client,W83792D_REG_POINTS[i][j]) & 0x7f;
+ }
+ }
+
+ /* Update Smart Fan II duty cycle levels */
+ for (i = 0; i < 3; i++) {
+ reg_tmp = w83792d_read_value(client,
+ W83792D_REG_LEVELS[i][0]);
+ data->sf2_levels[i][0] = reg_tmp & 0x0f;
+ data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f;
+ reg_tmp = w83792d_read_value(client,
+ W83792D_REG_LEVELS[i][2]);
+ data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f;
+ data->sf2_levels[i][3] = reg_tmp & 0x0f;
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ up(&data->update_lock);
+
+#ifdef DEBUG
+ w83792d_print_debug(data, dev);
+#endif
+
+ return data;
+}
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
+{
+ int i=0, j=0;
+ dev_dbg(dev, "==========The following is the debug message...========\n");
+ dev_dbg(dev, "9 set of Voltages: =====>\n");
+ for (i=0; i<9; i++) {
+ dev_dbg(dev, "vin[%d] is: 0x%x\n", i, data->in[i]);
+ dev_dbg(dev, "vin[%d] max is: 0x%x\n", i, data->in_max[i]);
+ dev_dbg(dev, "vin[%d] min is: 0x%x\n", i, data->in_min[i]);
+ }
+ dev_dbg(dev, "Low Bit1 is: 0x%x\n", data->low_bits[0]);
+ dev_dbg(dev, "Low Bit2 is: 0x%x\n", data->low_bits[1]);
+ dev_dbg(dev, "7 set of Fan Counts and Duty Cycles: =====>\n");
+ for (i=0; i<7; i++) {
+ dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]);
+ dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]);
+ dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]);
+ dev_dbg(dev, "pwm_mode[%d] is: 0x%x\n", i, data->pwm_mode[i]);
+ }
+ dev_dbg(dev, "3 set of Temperatures: =====>\n");
+ for (i=0; i<3; i++) {
+ dev_dbg(dev, "temp1[%d] is: 0x%x\n", i, data->temp1[i]);
+ }
+
+ for (i=0; i<2; i++) {
+ for (j=0; j<6; j++) {
+ dev_dbg(dev, "temp_add[%d][%d] is: 0x%x\n", i, j,
+ data->temp_add[i][j]);
+ }
+ }
+
+ for (i=0; i<7; i++) {
+ dev_dbg(dev, "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]);
+ }
+ dev_dbg(dev, "==========End of the debug message...==================\n");
+ dev_dbg(dev, "\n");
+}
+#endif
+
+static int __init
+sensors_w83792d_init(void)
+{
+ return i2c_add_driver(&w83792d_driver);
+}
+
+static void __exit
+sensors_w83792d_exit(void)
+{
+ i2c_del_driver(&w83792d_driver);
+}
+
+MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>");
+MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83792d_init);
+module_exit(sensors_w83792d_exit);
+
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 4469d52..133e34a 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -36,7 +36,8 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* How many retries on register read error */
#define MAX_RETRIES 5
@@ -47,13 +48,12 @@
*/
static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(w83l785ts);
+I2C_CLIENT_INSMOD_1(w83l785ts);
/*
* The W83L785TS-S registers
@@ -105,6 +105,7 @@
struct w83l785ts_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -140,7 +141,7 @@
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, w83l785ts_detect);
+ return i2c_probe(adapter, &addr_data, w83l785ts_detect);
}
/*
@@ -239,11 +240,19 @@
*/
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_max);
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -252,15 +261,15 @@
static int w83l785ts_detach_client(struct i2c_client *client)
{
+ struct w83l785ts_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
return 0;
}
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index cd17039..71c5a85 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,12 +4,8 @@
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
-obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o
obj-y += busses/ chips/ algos/
-i2c-sensor-objs := i2c-sensor-detect.o i2c-sensor-vid.o
-
-
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index fb5b732..df05df1 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -519,8 +519,6 @@
/* -----exported algorithm data: ------------------------------------- */
static struct i2c_algorithm i2c_bit_algo = {
- .name = "Bit-shift algorithm",
- .id = I2C_ALGO_BIT,
.master_xfer = bit_xfer,
.functionality = bit_func,
};
@@ -541,8 +539,6 @@
DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
/* register new adapter to i2c module... */
-
- adap->id |= i2c_bit_algo.id;
adap->algo = &i2c_bit_algo;
adap->timeout = 100; /* default values, should */
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
index e6cae39..2db7bfc 100644
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -713,8 +713,6 @@
/* -----exported algorithm data: ------------------------------------- */
static struct i2c_algorithm iic_algo = {
- .name = "ITE IIC algorithm",
- .id = I2C_ALGO_IIC,
.master_xfer = iic_xfer,
.algo_control = algo_control, /* ioctl */
.functionality = iic_func,
@@ -738,8 +736,6 @@
adap->name));
/* register new adapter to i2c module... */
-
- adap->id |= iic_algo.id;
adap->algo = &iic_algo;
adap->timeout = 100; /* default values, should */
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index cc3a952..beb10ed 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -187,12 +187,14 @@
int numbytes = 0;
int state;
int ret;
+ int timeout = 100;
- state = pca_status(adap);
- if ( state != 0xF8 ) {
- dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state );
- /* FIXME: what to do. Force stop ? */
- return -EREMOTEIO;
+ while ((state = pca_status(adap)) != 0xf8 && timeout--) {
+ msleep(10);
+ }
+ if (state != 0xf8) {
+ dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state);
+ return -EIO;
}
DEB1("{{{ XFER %d messages\n", num);
@@ -354,8 +356,6 @@
}
static struct i2c_algorithm pca_algo = {
- .name = "PCA9564 algorithm",
- .id = I2C_ALGO_PCA,
.master_xfer = pca_xfer,
.functionality = pca_func,
};
@@ -369,8 +369,6 @@
int rval;
/* register new adapter to i2c module... */
-
- adap->id |= pca_algo.id;
adap->algo = &pca_algo;
adap->timeout = 100; /* default values, should */
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 8d087da..6e498df 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -459,8 +459,6 @@
/* -----exported algorithm data: ------------------------------------- */
static struct i2c_algorithm pcf_algo = {
- .name = "PCF8584 algorithm",
- .id = I2C_ALGO_PCF,
.master_xfer = pcf_xfer,
.functionality = pcf_func,
};
@@ -476,8 +474,6 @@
DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
/* register new adapter to i2c module... */
-
- adap->id |= pcf_algo.id;
adap->algo = &pcf_algo;
adap->timeout = 100; /* default values, should */
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
index 422721b..932c4fa 100644
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -149,7 +149,7 @@
err = i2c_write(adap, p->buf, p->len);
}
- return err;
+ return (err < 0) ? err : i;
}
static u32 sgi_func(struct i2c_adapter *adap)
@@ -158,8 +158,6 @@
}
static struct i2c_algorithm sgi_algo = {
- .name = "SGI algorithm",
- .id = I2C_ALGO_SGI,
.master_xfer = sgi_xfer,
.functionality = sgi_func,
};
@@ -169,7 +167,6 @@
*/
int i2c_sgi_add_bus(struct i2c_adapter *adap)
{
- adap->id |= sgi_algo.id;
adap->algo = &sgi_algo;
return i2c_add_adapter(adap);
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
index f278549..8ed5ad1 100644
--- a/drivers/i2c/algos/i2c-algo-sibyte.c
+++ b/drivers/i2c/algos/i2c-algo-sibyte.c
@@ -135,8 +135,6 @@
/* -----exported algorithm data: ------------------------------------- */
static struct i2c_algorithm i2c_sibyte_algo = {
- .name = "SiByte algorithm",
- .id = I2C_ALGO_SIBYTE,
.smbus_xfer = smbus_xfer,
.algo_control = algo_control, /* ioctl */
.functionality = bit_func,
@@ -151,8 +149,6 @@
struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
/* register new adapter to i2c module... */
-
- i2c_adap->id |= i2c_sibyte_algo.id;
i2c_adap->algo = &i2c_sibyte_algo;
/* Set the frequency to 100 kHz */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 916ba5e..6e9da13 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -182,14 +182,8 @@
will be called i2c-iop3xx.
config I2C_ISA
- tristate "ISA Bus support"
+ tristate
depends on I2C
- help
- If you say yes to this option, support will be included for i2c
- interfaces that are on the ISA bus.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-isa.
config I2C_ITE
tristate "ITE I2C Adapter"
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index f634a07..f021acd 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -472,8 +472,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-i2c SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = ali1535_access,
.functionality = ali1535_func,
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index fdd881a..8694750 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -366,8 +366,6 @@
}
static struct i2c_algorithm ali1563_algorithm = {
- .name = "Non-i2c SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = ali1563_access,
.functionality = ali1563_func,
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 0f781a1..b3f50bf 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -462,8 +462,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = ali15x3_access,
.functionality = ali15x3_func,
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 6347ebc..6ad0603 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -295,8 +295,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = amd756_access,
.functionality = amd756_func,
};
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index d664448..45ea24b 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -323,8 +323,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus 2.0 adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = amd8111_access,
.functionality = amd8111_func,
};
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index a7ff112..d06edce 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -283,8 +283,6 @@
}
static struct i2c_algorithm au1550_algo = {
- .name = "Au1550 algorithm",
- .id = I2C_ALGO_AU1550,
.master_xfer = au1550_xfer,
.functionality = au1550_func,
};
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 1ab4131..709beab 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -535,8 +535,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = i801_access,
.functionality = i801_func,
};
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 93ca36d..a3ed959 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -627,8 +627,6 @@
}
static struct i2c_algorithm iic_algo = {
- .name = "IBM IIC algorithm",
- .id = I2C_ALGO_OCP,
.master_xfer = iic_xfer,
.functionality = iic_func
};
@@ -727,7 +725,7 @@
adap = &dev->adap;
strcpy(adap->name, "IBM IIC");
i2c_set_adapdata(adap, dev);
- adap->id = I2C_HW_OCP | iic_algo.id;
+ adap->id = I2C_HW_OCP;
adap->algo = &iic_algo;
adap->client_register = NULL;
adap->client_unregister = NULL;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 6b682e9..7bd9102 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -399,8 +399,6 @@
}
static struct i2c_algorithm iop3xx_i2c_algo = {
- .name = "IOP3xx I2C algorithm",
- .id = I2C_ALGO_IOP3XX,
.master_xfer = iop3xx_i2c_master_xfer,
.algo_control = iop3xx_i2c_algo_control,
.functionality = iop3xx_i2c_func,
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index 00e7f71..bdc6806 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -1,6 +1,8 @@
/*
- i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware
- monitoring
+ i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
+ Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+
+ Based on the i2c-isa pseudo-adapter from the lm_sensors project
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
This program is free software; you can redistribute it and/or modify
@@ -18,30 +20,36 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* This implements an i2c algorithm/adapter for ISA bus. Not that this is
- on first sight very useful; almost no functionality is preserved.
- Except that it makes writing drivers for chips which can be on both
- the SMBus and the ISA bus very much easier. See lm78.c for an example
- of this. */
+/* This implements an i2c-core-like thing for ISA hardware monitoring
+ chips. Such chips are linked to the i2c subsystem for historical
+ reasons (because the early ISA hardware monitoring chips such as the
+ LM78 had both an I2C and an ISA interface). They used to be
+ registered with the main i2c-core, but as a first step in the
+ direction of a clean separation between I2C and ISA chip drivers,
+ we now have this separate core for ISA ones. It is significantly
+ more simple than the real one, of course, because we don't have to
+ handle multiple busses: there is only one (fake) ISA adapter.
+ It is worth noting that we still rely on i2c-core for some things
+ at the moment - but hopefully this won't last. */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/i2c.h>
+#include <linux/i2c-isa.h>
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
static struct i2c_algorithm isa_algorithm = {
- .name = "ISA bus algorithm",
- .id = I2C_ALGO_ISA,
.functionality = isa_func,
};
/* There can only be one... */
static struct i2c_adapter isa_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_ISA,
.class = I2C_CLASS_HWMON,
.algo = &isa_algorithm,
.name = "ISA main adapter",
@@ -53,17 +61,146 @@
return 0;
}
+
+/* Copied from i2c-core */
+static ssize_t show_adapter_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
+ return sprintf(buf, "%s\n", adap->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+
+static int i2c_isa_device_probe(struct device *dev)
+{
+ return -ENODEV;
+}
+
+static int i2c_isa_device_remove(struct device *dev)
+{
+ return 0;
+}
+
+
+/* We implement an interface which resembles i2c_{add,del}_driver,
+ but for i2c-isa drivers. We don't have to remember and handle lists
+ of drivers and adapters so this is much more simple, of course. */
+
+int i2c_isa_add_driver(struct i2c_driver *driver)
+{
+ int res;
+
+ /* Add the driver to the list of i2c drivers in the driver core */
+ driver->driver.name = driver->name;
+ driver->driver.bus = &i2c_bus_type;
+ driver->driver.probe = i2c_isa_device_probe;
+ driver->driver.remove = i2c_isa_device_remove;
+ res = driver_register(&driver->driver);
+ if (res)
+ return res;
+ dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->name);
+
+ /* Now look for clients */
+ driver->attach_adapter(&isa_adapter);
+
+ return 0;
+}
+
+int i2c_isa_del_driver(struct i2c_driver *driver)
+{
+ struct list_head *item, *_n;
+ struct i2c_client *client;
+ int res;
+
+ /* Detach all clients belonging to this one driver */
+ list_for_each_safe(item, _n, &isa_adapter.clients) {
+ client = list_entry(item, struct i2c_client, list);
+ if (client->driver != driver)
+ continue;
+ dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
+ client->name, client->addr);
+ if ((res = driver->detach_client(client))) {
+ dev_err(&isa_adapter.dev, "Failed, driver "
+ "%s not unregistered!\n",
+ driver->name);
+ return res;
+ }
+ }
+
+ /* Get the driver off the core list */
+ driver_unregister(&driver->driver);
+ dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->name);
+
+ return 0;
+}
+
+
static int __init i2c_isa_init(void)
{
- return i2c_add_adapter(&isa_adapter);
+ init_MUTEX(&isa_adapter.clist_lock);
+ INIT_LIST_HEAD(&isa_adapter.clients);
+
+ isa_adapter.nr = ANY_I2C_ISA_BUS;
+ isa_adapter.dev.parent = &platform_bus;
+ sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
+ isa_adapter.dev.driver = &i2c_adapter_driver;
+ isa_adapter.dev.release = &i2c_adapter_dev_release;
+ device_register(&isa_adapter.dev);
+ device_create_file(&isa_adapter.dev, &dev_attr_name);
+
+ /* Add this adapter to the i2c_adapter class */
+ memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
+ isa_adapter.class_dev.dev = &isa_adapter.dev;
+ isa_adapter.class_dev.class = &i2c_adapter_class;
+ strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
+ BUS_ID_SIZE);
+ class_device_register(&isa_adapter.class_dev);
+
+ dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
+
+ return 0;
}
static void __exit i2c_isa_exit(void)
{
- i2c_del_adapter(&isa_adapter);
+#ifdef DEBUG
+ struct list_head *item, *_n;
+ struct i2c_client *client = NULL;
+#endif
+
+ /* There should be no more active client */
+#ifdef DEBUG
+ dev_dbg(&isa_adapter.dev, "Looking for clients\n");
+ list_for_each_safe(item, _n, &isa_adapter.clients) {
+ client = list_entry(item, struct i2c_client, list);
+ dev_err(&isa_adapter.dev, "Driver %s still has an active "
+ "ISA client at 0x%x\n", client->driver->name,
+ client->addr);
+ }
+ if (client != NULL)
+ return;
+#endif
+
+ /* Clean up the sysfs representation */
+ dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
+ init_completion(&isa_adapter.dev_released);
+ init_completion(&isa_adapter.class_dev_released);
+ class_device_unregister(&isa_adapter.class_dev);
+ device_remove_file(&isa_adapter.dev, &dev_attr_name);
+ device_unregister(&isa_adapter.dev);
+
+ /* Wait for sysfs to drop all references */
+ dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
+ wait_for_completion(&isa_adapter.dev_released);
+ wait_for_completion(&isa_adapter.class_dev_released);
+
+ dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
}
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+EXPORT_SYMBOL(i2c_isa_add_driver);
+EXPORT_SYMBOL(i2c_isa_del_driver);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("ISA bus access through i2c");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
index 94ae808..37b49c2 100644
--- a/drivers/i2c/busses/i2c-keywest.c
+++ b/drivers/i2c/busses/i2c-keywest.c
@@ -87,12 +87,9 @@
};
#endif /* DEBUG */
-static int probe;
-
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
MODULE_LICENSE("GPL");
-module_param(probe, bool, 0);
#ifdef POLLED_MODE
/* Don't schedule, the g5 fan controller is too
@@ -498,8 +495,6 @@
/* For now, we only handle combined mode (smbus) */
static struct i2c_algorithm keywest_algorithm = {
- .name = "Keywest i2c",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = keywest_smbus_xfer,
.master_xfer = keywest_xfer,
.functionality = keywest_func,
@@ -621,7 +616,6 @@
sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
chan->iface = iface;
chan->chan_no = i;
- chan->adapter.id = I2C_ALGO_SMBUS;
chan->adapter.algo = &keywest_algorithm;
chan->adapter.algo_data = NULL;
chan->adapter.client_register = NULL;
@@ -635,15 +629,6 @@
chan->adapter.name);
i2c_set_adapdata(&chan->adapter, NULL);
}
- if (probe) {
- printk("Probe: ");
- for (addr = 0x00; addr <= 0x7f; addr++) {
- if (i2c_smbus_xfer(&chan->adapter,addr,
- 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
- printk("%02x ", addr);
- }
- printk("\n");
- }
}
printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 9ad3e92..f065583 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -272,8 +272,6 @@
}
static struct i2c_algorithm mpc_algo = {
- .name = "MPC algorithm",
- .id = I2C_ALGO_MPC107,
.master_xfer = mpc_xfer,
.functionality = mpc_functionality,
};
@@ -281,7 +279,7 @@
static struct i2c_adapter mpc_ops = {
.owner = THIS_MODULE,
.name = "MPC adapter",
- .id = I2C_ALGO_MPC107 | I2C_HW_MPC107,
+ .id = I2C_HW_MPC107,
.algo = &mpc_algo,
.class = I2C_CLASS_HWMON,
.timeout = 1,
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 5b85278..99abca4 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -423,18 +423,16 @@
mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
- int i, rc = 0;
+ int i, rc;
for (i=0; i<num; i++)
- if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) != 0)
- break;
+ if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) < 0)
+ return rc;
- return rc;
+ return num;
}
static struct i2c_algorithm mv64xxx_i2c_algo = {
- .name = MV64XXX_I2C_CTLR_NAME " algorithm",
- .id = I2C_ALGO_MV64XXX,
.master_xfer = mv64xxx_i2c_xfer,
.functionality = mv64xxx_i2c_functionality,
};
@@ -523,7 +521,7 @@
drv_data->freq_m = pdata->freq_m;
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
- drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX;
+ drv_data->adapter.id = I2C_HW_MV64XXX;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
drv_data->adapter.class = I2C_CLASS_HWMON;
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 74eb89a..e0b7a91 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -110,8 +110,6 @@
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = nforce2_access,
.functionality = nforce2_func,
};
@@ -131,7 +129,6 @@
struct nforce2_smbus *smbus = adap->algo_data;
unsigned char protocol, pec, temp;
unsigned char len = 0; /* to keep the compiler quiet */
- int timeout = 0;
int i;
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
@@ -191,29 +188,10 @@
case I2C_SMBUS_PROC_CALL:
dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
return -1;
- /*
- outb_p(command, NVIDIA_SMB_CMD);
- outb_p(data->word, NVIDIA_SMB_DATA);
- outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
- protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec;
- read_write = I2C_SMBUS_READ;
- break;
- */
case I2C_SMBUS_BLOCK_PROC_CALL:
dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
return -1;
- /*
- protocol |= pec;
- len = min_t(u8, data->block[0], 31);
- outb_p(command, NVIDIA_SMB_CMD);
- outb_p(len, NVIDIA_SMB_BCNT);
- for (i = 0; i < len; i++)
- outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i);
- protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec;
- read_write = I2C_SMBUS_READ;
- break;
- */
case I2C_SMBUS_WORD_DATA_PEC:
case I2C_SMBUS_BLOCK_DATA_PEC:
@@ -232,12 +210,6 @@
temp = inb_p(NVIDIA_SMB_STS);
-#if 0
- do {
- i2c_do_pause(1);
- temp = inb_p(NVIDIA_SMB_STS);
- } while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT));
-#endif
if (~temp & NVIDIA_SMB_STS_DONE) {
udelay(500);
temp = inb_p(NVIDIA_SMB_STS);
@@ -247,9 +219,10 @@
temp = inb_p(NVIDIA_SMB_STS);
}
- if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE)
- || (temp & NVIDIA_SMB_STS_STATUS))
+ if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+ dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
return -1;
+ }
if (read_write == I2C_SMBUS_WRITE)
return 0;
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 6d34ee3..6d48a4d 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -399,8 +399,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = piix4_access,
.functionality = piix4_func,
};
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index a3b3825..73a092f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -568,7 +568,6 @@
/* i2c bus registration info */
static struct i2c_algorithm s3c24xx_i2c_algorithm = {
- .name = "S3C2410-I2C-Algorithm",
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index bbd5e4e..080318d 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -357,8 +357,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = sis5595_access,
.functionality = sis5595_func,
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index f58455e..86f0f44 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -448,8 +448,6 @@
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = sis630_access,
.functionality = sis630_func,
};
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 6484792..ead2ff3 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -249,8 +249,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = sis96x_access,
.functionality = sis96x_func,
};
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 00d94e8..73f481e 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -109,8 +109,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.functionality = stub_func,
.smbus_xfer = stub_xfer,
};
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 6b50080..99d209e 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -286,8 +286,6 @@
}
static struct i2c_algorithm smbus_algorithm = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = vt596_access,
.functionality = vt596_func,
};
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index a18bdd9..a1d580e 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -395,8 +395,6 @@
/* For now, we only handle combined mode (smbus) */
static struct i2c_algorithm scx200_acb_algorithm = {
- .name = "NatSemi SCx200 ACCESS.bus",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = scx200_acb_smbus_xfer,
.functionality = scx200_acb_func,
};
@@ -456,7 +454,7 @@
i2c_set_adapdata(adapter, iface);
snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
adapter->owner = THIS_MODULE;
- adapter->id = I2C_ALGO_SMBUS;
+ adapter->id = I2C_HW_SMBUS_SCX200;
adapter->algo = &scx200_acb_algorithm;
adapter->class = I2C_CLASS_HWMON;
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 43f70db..6bd44a4 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -2,17 +2,12 @@
# Miscellaneous I2C chip drivers configuration
#
-config I2C_SENSOR
- tristate
- default n
-
menu "Miscellaneous I2C Chip support"
depends on I2C
config SENSORS_DS1337
tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Dallas Semiconductor
DS1337 and DS1339 real-time clock chips.
@@ -23,7 +18,6 @@
config SENSORS_DS1374
tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Dallas Semiconductor
DS1374 real-time clock chips.
@@ -34,7 +28,6 @@
config SENSORS_EEPROM
tristate "EEPROM reader"
depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get read-only access to the EEPROM data
available on modern memory DIMMs and Sony Vaio laptops. Such
@@ -46,7 +39,6 @@
config SENSORS_PCF8574
tristate "Philips PCF8574 and PCF8574A"
depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Philips PCF8574 and
PCF8574A chips.
@@ -67,7 +59,6 @@
config SENSORS_PCF8591
tristate "Philips PCF8591"
depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Philips PCF8591 chips.
@@ -77,7 +68,6 @@
config SENSORS_RTC8564
tristate "Epson 8564 RTC chip"
depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for the Epson 8564 RTC chip.
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
index 82cf959..9d3175c 100644
--- a/drivers/i2c/chips/ds1337.c
+++ b/drivers/i2c/chips/ds1337.c
@@ -17,7 +17,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/bcd.h>
@@ -39,9 +38,8 @@
* Functions declaration
*/
static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-SENSORS_INSMOD_1(ds1337);
+I2C_CLIENT_INSMOD_1(ds1337);
static int ds1337_attach_adapter(struct i2c_adapter *adapter);
static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
@@ -227,7 +225,7 @@
static int ds1337_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, ds1337_detect);
+ return i2c_probe(adapter, &addr_data, ds1337_detect);
}
/*
@@ -354,11 +352,8 @@
int err;
struct ds1337_data *data = i2c_get_clientdata(client);
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
list_del(&data->list);
kfree(data);
diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c
index a445736..0936327 100644
--- a/drivers/i2c/chips/ds1374.c
+++ b/drivers/i2c/chips/ds1374.c
@@ -53,7 +53,6 @@
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
- .force = ignore,
};
static ulong ds1374_read_rtc(void)
@@ -166,7 +165,7 @@
"can't confirm time set from rtc chip\n");
}
-ulong new_time;
+static ulong new_time;
DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time);
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index a2da31b..d58403a 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -33,15 +33,13 @@
#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(eeprom);
+I2C_CLIENT_INSMOD_1(eeprom);
/* Size of EEPROM in bytes */
@@ -153,21 +151,16 @@
static int eeprom_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, eeprom_detect);
+ return i2c_probe(adapter, &addr_data, eeprom_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct eeprom_data *data;
int err = 0;
- /* prevent 24RF08 corruption */
- if (kind < 0)
- i2c_smbus_xfer(adapter, address, 0, 0, 0,
- I2C_SMBUS_QUICK, NULL);
-
/* There are three ways we can read the EEPROM data:
(1) I2C block reads (faster, but unsupported by most adapters)
(2) Consecutive byte reads (100% overhead)
@@ -231,10 +224,8 @@
int err;
err = i2c_detach_client(client);
- if (err) {
- dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+ if (err)
return err;
- }
kfree(i2c_get_clientdata(client));
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 354a262..8ee56d4 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -1489,7 +1489,7 @@
if (the_transceiver)
return 0;
- isp = kcalloc(1, sizeof *isp, GFP_KERNEL);
+ isp = kzalloc(sizeof *isp, GFP_KERNEL);
if (!isp)
return 0;
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
index 778d7e1..3f14528 100644
--- a/drivers/i2c/chips/m41t00.c
+++ b/drivers/i2c/chips/m41t00.c
@@ -42,7 +42,6 @@
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
- .force = ignore,
};
ulong
@@ -145,7 +144,7 @@
return;
}
-ulong new_time;
+static ulong new_time;
DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time);
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 0230375..9e1aeb6 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -5,97 +5,60 @@
Based on i2c/chips/eeprom.c
- The MAX6875 has two EEPROM sections: config and user.
- At reset, the config EEPROM is read into the registers.
+ The MAX6875 has a bank of registers and two banks of EEPROM.
+ Address ranges are defined as follows:
+ * 0x0000 - 0x0046 = configuration registers
+ * 0x8000 - 0x8046 = configuration EEPROM
+ * 0x8100 - 0x82FF = user EEPROM
- This driver make 3 binary files available in sysfs:
- reg_config - direct access to the registers
- eeprom_config - acesses configuration eeprom space
- eeprom_user - free for application use
+ This driver makes the user EEPROM available for read.
- In our application, we put device serial & model numbers in user eeprom.
+ The registers & config EEPROM should be accessed via i2c-dev.
- Notes:
- 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT
- be overwritten, so the driver explicitly prevents that.
- 2) It's a good idea to keep the config (0x45) locked in config EEPROM.
- You can temporarily enable config writes by changing register 0x45.
+ The MAX6875 ignores the lowest address bit, so each chip responds to
+ two addresses - 0x50/0x51 and 0x52/0x53.
+
+ Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read
+ address, so this driver is destructive if loaded for the wrong EEPROM chip.
This program is free software; 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/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <asm/semaphore.h>
-/* Addresses to scan */
-/* No address scanned by default, as this could corrupt standard EEPROMS. */
+/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
/* Insmod parameters */
-SENSORS_INSMOD_1(max6875);
-
-/* this param will prevent 'accidental' writes to the eeprom */
-static int allow_write = 0;
-module_param(allow_write, int, 0);
-MODULE_PARM_DESC(allow_write,
- "Enable write access:\n"
- "*0: Read only\n"
- " 1: Read/Write access");
+I2C_CLIENT_INSMOD_1(max6875);
/* The MAX6875 can only read/write 16 bytes at a time */
#define SLICE_SIZE 16
#define SLICE_BITS 4
-/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */
-#define CONFIG_EEPROM_BASE 0x8000
-#define CONFIG_EEPROM_SIZE 0x0046
-#define CONFIG_EEPROM_SLICES 5
-
/* USER EEPROM is at addresses 0x8100 - 0x82FF */
#define USER_EEPROM_BASE 0x8100
#define USER_EEPROM_SIZE 0x0200
#define USER_EEPROM_SLICES 32
/* MAX6875 commands */
-#define MAX6875_CMD_BLOCK_WRITE 0x83
-#define MAX6875_CMD_BLOCK_READ 0x84
-#define MAX6875_CMD_REBOOT 0x88
-
-enum max6875_area_type {
- max6875_register_config=0,
- max6875_eeprom_config,
- max6875_eeprom_user,
- max6857_max
-};
-
-struct eeprom_block {
- enum max6875_area_type type;
- u8 slices;
- u32 size;
- u32 valid;
- u32 base;
- unsigned long *updated;
- u8 *data;
-};
+#define MAX6875_CMD_BLK_READ 0x84
/* Each client has this additional data */
struct max6875_data {
struct i2c_client client;
struct semaphore update_lock;
- struct eeprom_block blocks[max6857_max];
- /* the above structs point into the arrays below */
- u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)];
- unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)];
+
+ u32 valid;
+ u8 data[USER_EEPROM_SIZE];
+ unsigned long last_updated[USER_EEPROM_SLICES];
};
static int max6875_attach_adapter(struct i2c_adapter *adapter);
@@ -111,337 +74,160 @@
.detach_client = max6875_detach_client,
};
-static int max6875_update_slice(struct i2c_client *client,
- struct eeprom_block *blk,
- int slice)
+static void max6875_update_slice(struct i2c_client *client, int slice)
{
struct max6875_data *data = i2c_get_clientdata(client);
- int i, j, addr, count;
- u8 rdbuf[SLICE_SIZE];
- int retval = 0;
+ int i, j, addr;
+ u8 *buf;
- if (slice >= blk->slices)
- return -1;
+ if (slice >= USER_EEPROM_SLICES)
+ return;
down(&data->update_lock);
- if (!(blk->valid & (1 << slice)) ||
- (jiffies - blk->updated[slice] > 300 * HZ) ||
- (jiffies < blk->updated[slice])) {
- dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n",
- slice, blk->base);
+ buf = &data->data[slice << SLICE_BITS];
- addr = blk->base + (slice << SLICE_BITS);
- count = blk->size - (slice << SLICE_BITS);
- if (count > SLICE_SIZE) {
- count = SLICE_SIZE;
+ if (!(data->valid & (1 << slice)) ||
+ time_after(jiffies, data->last_updated[slice])) {
+
+ dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
+
+ data->valid &= ~(1 << slice);
+
+ addr = USER_EEPROM_BASE + (slice << SLICE_BITS);
+
+ /* select the eeprom address */
+ if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
+ dev_err(&client->dev, "address set failed\n");
+ goto exit_up;
}
- /* Preset the read address */
- if (addr < 0x100) {
- /* select the register */
- if (i2c_smbus_write_byte(client, addr & 0xFF)) {
- dev_dbg(&client->dev, "max6875 register select has failed!\n");
- retval = -1;
- goto exit;
+ if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ if (i2c_smbus_read_i2c_block_data(client,
+ MAX6875_CMD_BLK_READ,
+ buf) != SLICE_SIZE) {
+ goto exit_up;
}
} else {
- /* select the eeprom */
- if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
- dev_dbg(&client->dev, "max6875 address set has failed!\n");
- retval = -1;
- goto exit;
- }
- }
-
- if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ,
- rdbuf) != SLICE_SIZE)
- {
- retval = -1;
- goto exit;
- }
-
- memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count);
- } else {
- for (i = 0; i < count; i++) {
+ for (i = 0; i < SLICE_SIZE; i++) {
j = i2c_smbus_read_byte(client);
- if (j < 0)
- {
- retval = -1;
- goto exit;
+ if (j < 0) {
+ goto exit_up;
}
- blk->data[(slice << SLICE_BITS) + i] = (u8) j;
+ buf[i] = j;
}
}
- blk->updated[slice] = jiffies;
- blk->valid |= (1 << slice);
+ data->last_updated[slice] = jiffies;
+ data->valid |= (1 << slice);
}
- exit:
+exit_up:
up(&data->update_lock);
- return retval;
}
-static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count,
- enum max6875_area_type area_type)
+static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
{
- struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
struct max6875_data *data = i2c_get_clientdata(client);
- struct eeprom_block *blk;
- int slice;
+ int slice, max_slice;
- blk = &data->blocks[area_type];
-
- if (off > blk->size)
+ if (off > USER_EEPROM_SIZE)
return 0;
- if (off + count > blk->size)
- count = blk->size - off;
- /* Only refresh slices which contain requested bytes */
- for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
- max6875_update_slice(client, blk, slice);
+ if (off + count > USER_EEPROM_SIZE)
+ count = USER_EEPROM_SIZE - off;
- memcpy(buf, &blk->data[off], count);
+ /* refresh slices which contain requested bytes */
+ max_slice = (off + count - 1) >> SLICE_BITS;
+ for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
+ max6875_update_slice(client, slice);
+
+ memcpy(buf, &data->data[off], count);
return count;
}
-static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- return max6875_read(kobj, buf, off, count, max6875_eeprom_user);
-}
-
-static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- return max6875_read(kobj, buf, off, count, max6875_eeprom_config);
-}
-
-static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- return max6875_read(kobj, buf, off, count, max6875_register_config);
-}
-
-
-static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count,
- enum max6875_area_type area_type)
-{
- struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
- struct max6875_data *data = i2c_get_clientdata(client);
- struct eeprom_block *blk;
- int slice, addr, retval;
- ssize_t sent = 0;
-
- blk = &data->blocks[area_type];
-
- if (off > blk->size)
- return 0;
- if ((off + count) > blk->size)
- count = blk->size - off;
-
- if (down_interruptible(&data->update_lock))
- return -EAGAIN;
-
- /* writing to a register is done with i2c_smbus_write_byte_data() */
- if (blk->type == max6875_register_config) {
- for (sent = 0; sent < count; sent++) {
- addr = off + sent;
- if (addr == 0x44)
- continue;
-
- retval = i2c_smbus_write_byte_data(client, addr, buf[sent]);
- }
- } else {
- int cmd, val;
-
- /* We are writing to EEPROM */
- for (sent = 0; sent < count; sent++) {
- addr = blk->base + off + sent;
- cmd = addr >> 8;
- val = (addr & 0xff) | (buf[sent] << 8); // reversed
-
- if (addr == 0x8044)
- continue;
-
- retval = i2c_smbus_write_word_data(client, cmd, val);
-
- if (retval) {
- goto error_exit;
- }
-
- /* A write takes up to 11 ms */
- msleep(11);
- }
- }
-
- /* Invalidate the scratch buffer */
- for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
- blk->valid &= ~(1 << slice);
-
- error_exit:
- up(&data->update_lock);
-
- return sent;
-}
-
-static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- return max6875_write(kobj, buf, off, count, max6875_eeprom_user);
-}
-
-static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- return max6875_write(kobj, buf, off, count, max6875_eeprom_config);
-}
-
-static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- return max6875_write(kobj, buf, off, count, max6875_register_config);
-}
-
static struct bin_attribute user_eeprom_attr = {
.attr = {
- .name = "eeprom_user",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP,
+ .name = "eeprom",
+ .mode = S_IRUGO,
.owner = THIS_MODULE,
},
- .size = USER_EEPROM_SIZE,
- .read = max6875_user_read,
- .write = max6875_user_write,
-};
-
-static struct bin_attribute config_eeprom_attr = {
- .attr = {
- .name = "eeprom_config",
- .mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
- },
- .size = CONFIG_EEPROM_SIZE,
- .read = max6875_config_read,
- .write = max6875_config_write,
-};
-
-static struct bin_attribute config_register_attr = {
- .attr = {
- .name = "reg_config",
- .mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
- },
- .size = CONFIG_EEPROM_SIZE,
- .read = max6875_cfgreg_read,
- .write = max6875_cfgreg_write,
+ .size = USER_EEPROM_SIZE,
+ .read = max6875_read,
};
static int max6875_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, max6875_detect);
+ return i2c_probe(adapter, &addr_data, max6875_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
{
- struct i2c_client *new_client;
+ struct i2c_client *real_client;
+ struct i2c_client *fake_client;
struct max6875_data *data;
int err = 0;
- /* Prevent 24RF08 corruption (in case of user error) */
- if (kind < 0)
- i2c_smbus_xfer(adapter, address, 0, 0, 0,
- I2C_SMBUS_QUICK, NULL);
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+ | I2C_FUNC_SMBUS_READ_BYTE))
+ return 0;
- /* There are three ways we can read the EEPROM data:
- (1) I2C block reads (faster, but unsupported by most adapters)
- (2) Consecutive byte reads (100% overhead)
- (3) Regular byte data reads (200% overhead)
- The third method is not implemented by this driver because all
- known adapters support at least the second. */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA |
- I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
- goto exit;
+ /* Only check even addresses */
+ if (address & 1)
+ return 0;
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access eeprom_{read,write}_value. */
- if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
+ if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL)))
+ return -ENOMEM;
memset(data, 0, sizeof(struct max6875_data));
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &max6875_driver;
- new_client->flags = 0;
+ /* A fake client is created on the odd address */
+ if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit_kfree1;
+ }
+ memset(fake_client, 0, sizeof(struct i2c_client));
- /* Setup the user section */
- data->blocks[max6875_eeprom_user].type = max6875_eeprom_user;
- data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES;
- data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE;
- data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE;
- data->blocks[max6875_eeprom_user].data = data->data;
- data->blocks[max6875_eeprom_user].updated = data->last_updated;
-
- /* Setup the config section */
- data->blocks[max6875_eeprom_config].type = max6875_eeprom_config;
- data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES;
- data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE;
- data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE;
- data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE];
- data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES];
-
- /* Setup the register section */
- data->blocks[max6875_register_config].type = max6875_register_config;
- data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES;
- data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE;
- data->blocks[max6875_register_config].base = 0;
- data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE];
- data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES];
-
- /* Init the data */
- memset(data->data, 0xff, sizeof(data->data));
-
- /* Fill in the remaining client fields */
- strlcpy(new_client->name, "max6875", I2C_NAME_SIZE);
+ /* Init real i2c_client */
+ real_client = &data->client;
+ i2c_set_clientdata(real_client, data);
+ real_client->addr = address;
+ real_client->adapter = adapter;
+ real_client->driver = &max6875_driver;
+ real_client->flags = 0;
+ strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
init_MUTEX(&data->update_lock);
- /* Verify that the chip is really what we think it is */
- if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) ||
- (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0))
- goto exit_kfree;
+ /* Init fake client data */
+ /* set the client data to the i2c_client so that it will get freed */
+ i2c_set_clientdata(fake_client, fake_client);
+ fake_client->addr = address | 1;
+ fake_client->adapter = adapter;
+ fake_client->driver = &max6875_driver;
+ fake_client->flags = 0;
+ strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
- /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */
- if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) ||
- (data->blocks[max6875_eeprom_config].data[0x42] != 0) ||
- (data->blocks[max6875_register_config].data[0x41] != 0) ||
- (data->blocks[max6875_register_config].data[0x42] != 0) ||
- (data->blocks[max6875_eeprom_config].data[0x40] !=
- data->blocks[max6875_register_config].data[0x40]))
- goto exit_kfree;
+ /* Prevent 24RF08 corruption (in case of user error) */
+ i2c_smbus_write_quick(real_client, 0);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_kfree;
+ if ((err = i2c_attach_client(real_client)) != 0)
+ goto exit_kfree2;
- /* create the sysfs eeprom files with the correct permissions */
- if (allow_write == 0) {
- user_eeprom_attr.attr.mode &= ~S_IWUGO;
- user_eeprom_attr.write = NULL;
- config_eeprom_attr.attr.mode &= ~S_IWUGO;
- config_eeprom_attr.write = NULL;
- config_register_attr.attr.mode &= ~S_IWUGO;
- config_register_attr.write = NULL;
- }
- sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr);
- sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr);
- sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr);
+ if ((err = i2c_attach_client(fake_client)) != 0)
+ goto exit_detach;
+
+ sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
return 0;
-exit_kfree:
+exit_detach:
+ i2c_detach_client(real_client);
+exit_kfree2:
+ kfree(fake_client);
+exit_kfree1:
kfree(data);
-exit:
return err;
}
@@ -450,13 +236,9 @@
int err;
err = i2c_detach_client(client);
- if (err) {
- dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+ if (err)
return err;
- }
-
kfree(i2c_get_clientdata(client));
-
return 0;
}
diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c
index 9f3ad45..225577fd 100644
--- a/drivers/i2c/chips/pca9539.c
+++ b/drivers/i2c/chips/pca9539.c
@@ -13,14 +13,12 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>
-#include <linux/i2c-sensor.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
-static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
/* Insmod parameters */
-SENSORS_INSMOD_1(pca9539);
+I2C_CLIENT_INSMOD_1(pca9539);
enum pca9539_cmd
{
@@ -109,10 +107,10 @@
static int pca9539_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, pca9539_detect);
+ return i2c_probe(adapter, &addr_data, pca9539_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -164,10 +162,8 @@
{
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
kfree(i2c_get_clientdata(client));
return 0;
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index cfcf646..6525743 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -39,16 +39,14 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_2(pcf8574, pcf8574a);
+I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
/* Initial values */
#define PCF8574_INIT 255 /* All outputs on (input mode) */
@@ -113,10 +111,10 @@
static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, pcf8574_detect);
+ return i2c_probe(adapter, &addr_data, pcf8574_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -186,11 +184,8 @@
{
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
kfree(i2c_get_clientdata(client));
return 0;
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index db812ad..80f1df9 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -24,15 +24,13 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(pcf8591);
+I2C_CLIENT_INSMOD_1(pcf8591);
static int input_mode;
module_param(input_mode, int, 0);
@@ -164,10 +162,10 @@
*/
static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, pcf8591_detect);
+ return i2c_probe(adapter, &addr_data, pcf8591_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -241,11 +239,8 @@
{
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
kfree(i2c_get_clientdata(client));
return 0;
diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c
index 588fc22..0b5385c 100644
--- a/drivers/i2c/chips/rtc8564.c
+++ b/drivers/i2c/chips/rtc8564.c
@@ -67,7 +67,6 @@
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
- .force = ignore,
};
static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 4a9ead2..dda472e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -61,7 +61,7 @@
return rc;
}
-static struct bus_type i2c_bus_type = {
+struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.suspend = i2c_bus_suspend,
@@ -78,13 +78,13 @@
return 0;
}
-static void i2c_adapter_dev_release(struct device *dev)
+void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
complete(&adap->dev_released);
}
-static struct device_driver i2c_adapter_driver = {
+struct device_driver i2c_adapter_driver = {
.name = "i2c_adapter",
.bus = &i2c_bus_type,
.probe = i2c_device_probe,
@@ -97,7 +97,7 @@
complete(&adap->class_dev_released);
}
-static struct class i2c_adapter_class = {
+struct class i2c_adapter_class = {
.name = "i2c-adapter",
.release = &i2c_adapter_class_dev_release,
};
@@ -188,6 +188,8 @@
strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
class_device_register(&adap->class_dev);
+ dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
/* inform drivers of new adapters */
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
@@ -196,8 +198,6 @@
driver->attach_adapter(adap);
}
- dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
-
out_unlock:
up(&core_lists);
return res;
@@ -220,8 +220,8 @@
break;
}
if (adap_from_list != adap) {
- pr_debug("I2C: Attempting to delete an unregistered "
- "adapter\n");
+ pr_debug("i2c-core: attempting to delete unregistered "
+ "adapter [%s]\n", adap->name);
res = -EINVAL;
goto out_unlock;
}
@@ -230,9 +230,8 @@
driver = list_entry(item, struct i2c_driver, list);
if (driver->detach_adapter)
if ((res = driver->detach_adapter(adap))) {
- dev_warn(&adap->dev, "can't detach adapter "
- "while detaching driver %s: driver "
- "not detached!\n", driver->name);
+ dev_err(&adap->dev, "detach_adapter failed "
+ "for driver [%s]\n", driver->name);
goto out_unlock;
}
}
@@ -247,9 +246,8 @@
* must be deleted, as this would cause invalid states.
*/
if ((res=client->driver->detach_client(client))) {
- dev_err(&adap->dev, "adapter not "
- "unregistered, because client at "
- "address %02x can't be detached. ",
+ dev_err(&adap->dev, "detach_client failed for client "
+ "[%s] at address 0x%02x\n", client->name,
client->addr);
goto out_unlock;
}
@@ -270,7 +268,7 @@
/* free dynamically allocated bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
- dev_dbg(&adap->dev, "adapter unregistered\n");
+ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
out_unlock:
up(&core_lists);
@@ -303,7 +301,7 @@
goto out_unlock;
list_add_tail(&driver->list,&drivers);
- pr_debug("i2c-core: driver %s registered.\n", driver->name);
+ pr_debug("i2c-core: driver [%s] registered\n", driver->name);
/* now look for instances of driver on our adapters */
if (driver->flags & I2C_DF_NOTIFY) {
@@ -331,21 +329,17 @@
/* Have a look at each adapter, if clients of this driver are still
* attached. If so, detach them to be able to kill the driver
* afterwards.
- */
- pr_debug("i2c-core: unregister_driver - looking for clients.\n");
- /* removing clients does not depend on the notify flag, else
+ *
+ * Removing clients does not depend on the notify flag, else
* invalid operation might (will!) result, when using stale client
* pointers.
*/
list_for_each(item1,&adapters) {
adap = list_entry(item1, struct i2c_adapter, list);
- dev_dbg(&adap->dev, "examining adapter\n");
if (driver->detach_adapter) {
if ((res = driver->detach_adapter(adap))) {
- dev_warn(&adap->dev, "while unregistering "
- "dummy driver %s, adapter could "
- "not be detached properly; driver "
- "not unloaded!",driver->name);
+ dev_err(&adap->dev, "detach_adapter failed "
+ "for driver [%s]\n", driver->name);
goto out_unlock;
}
} else {
@@ -353,16 +347,13 @@
client = list_entry(item2, struct i2c_client, list);
if (client->driver != driver)
continue;
- pr_debug("i2c-core.o: detaching client %s:\n", client->name);
+ dev_dbg(&adap->dev, "detaching client [%s] "
+ "at 0x%02x\n", client->name,
+ client->addr);
if ((res = driver->detach_client(client))) {
- dev_err(&adap->dev, "while "
- "unregistering driver "
- "`%s', the client at "
- "address %02x of "
- "adapter could not "
- "be detached; driver "
- "not unloaded!",
- driver->name,
+ dev_err(&adap->dev, "detach_client "
+ "failed for client [%s] at "
+ "0x%02x\n", client->name,
client->addr);
goto out_unlock;
}
@@ -372,7 +363,7 @@
driver_unregister(&driver->driver);
list_del(&driver->list);
- pr_debug("i2c-core: driver unregistered: %s\n", driver->name);
+ pr_debug("i2c-core: driver [%s] unregistered\n", driver->name);
out_unlock:
up(&core_lists);
@@ -417,15 +408,12 @@
if (adapter->client_register) {
if (adapter->client_register(client)) {
- dev_warn(&adapter->dev, "warning: client_register "
- "seems to have failed for client %02x\n",
- client->addr);
+ dev_dbg(&adapter->dev, "client_register "
+ "failed for client [%s] at 0x%02x\n",
+ client->name, client->addr);
}
}
- dev_dbg(&adapter->dev, "client [%s] registered to adapter\n",
- client->name);
-
if (client->flags & I2C_CLIENT_ALLOW_USE)
client->usage_count = 0;
@@ -436,7 +424,8 @@
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
- pr_debug("registering %s\n", client->dev.bus_id);
+ dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+ client->name, client->dev.bus_id);
device_register(&client->dev);
device_create_file(&client->dev, &dev_attr_client_name);
@@ -449,8 +438,12 @@
struct i2c_adapter *adapter = client->adapter;
int res = 0;
- if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0))
+ if ((client->flags & I2C_CLIENT_ALLOW_USE)
+ && (client->usage_count > 0)) {
+ dev_warn(&client->dev, "Client [%s] still busy, "
+ "can't detach\n", client->name);
return -EBUSY;
+ }
if (adapter->client_unregister) {
res = adapter->client_unregister(client);
@@ -669,98 +662,128 @@
* Will not work for 10-bit addresses!
* ----------------------------------------------------
*/
+static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
+ int (*found_proc) (struct i2c_adapter *, int, int))
+{
+ int err;
+
+ /* Make sure the address is valid */
+ if (addr < 0x03 || addr > 0x77) {
+ dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
+ addr);
+ return -EINVAL;
+ }
+
+ /* Skip if already in use */
+ if (i2c_check_addr(adapter, addr))
+ return 0;
+
+ /* Make sure there is something at this address, unless forced */
+ if (kind < 0) {
+ if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+ I2C_SMBUS_QUICK, NULL) < 0)
+ return 0;
+
+ /* prevent 24RF08 corruption */
+ if ((addr & ~0x0f) == 0x50)
+ i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+ I2C_SMBUS_QUICK, NULL);
+ }
+
+ /* Finally call the custom detection function */
+ err = found_proc(adapter, addr, kind);
+
+ /* -ENODEV can be returned if there is a chip at the given address
+ but it isn't supported by this chip driver. We catch it here as
+ this isn't an error. */
+ return (err == -ENODEV) ? 0 : err;
+}
+
int i2c_probe(struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int))
{
- int addr,i,found,err;
+ int i, err;
int adap_id = i2c_adapter_id(adapter);
/* Forget it if we can't probe using SMBUS_QUICK */
if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
return -1;
- for (addr = 0x00; addr <= 0x7f; addr++) {
+ /* Force entries are done first, and are not affected by ignore
+ entries */
+ if (address_data->forces) {
+ unsigned short **forces = address_data->forces;
+ int kind;
- /* Skip if already in use */
- if (i2c_check_addr(adapter,addr))
- continue;
-
- /* If it is in one of the force entries, we don't do any detection
- at all */
- found = 0;
-
- for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) {
- if (((adap_id == address_data->force[i]) ||
- (address_data->force[i] == ANY_I2C_BUS)) &&
- (addr == address_data->force[i+1])) {
- dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n",
- adap_id, addr);
- if ((err = found_proc(adapter,addr,0)))
- return err;
- found = 1;
+ for (kind = 0; forces[kind]; kind++) {
+ for (i = 0; forces[kind][i] != I2C_CLIENT_END;
+ i += 2) {
+ if (forces[kind][i] == adap_id
+ || forces[kind][i] == ANY_I2C_BUS) {
+ dev_dbg(&adapter->dev, "found force "
+ "parameter for adapter %d, "
+ "addr 0x%02x, kind %d\n",
+ adap_id, forces[kind][i + 1],
+ kind);
+ err = i2c_probe_address(adapter,
+ forces[kind][i + 1],
+ kind, found_proc);
+ if (err)
+ return err;
+ }
}
}
- if (found)
- continue;
-
- /* If this address is in one of the ignores, we can forget about
- it right now */
- for (i = 0;
- !found && (address_data->ignore[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adap_id == address_data->ignore[i]) ||
- ((address_data->ignore[i] == ANY_I2C_BUS))) &&
- (addr == address_data->ignore[i+1])) {
- dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, "
- "addr %04x\n", adap_id ,addr);
- found = 1;
- }
- }
- if (found)
- continue;
-
- /* Now, we will do a detection, but only if it is in the normal or
- probe entries */
- for (i = 0;
- !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
- i += 1) {
- if (addr == address_data->normal_i2c[i]) {
- found = 1;
- dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, "
- "addr %02x\n", adap_id, addr);
- }
- }
-
- for (i = 0;
- !found && (address_data->probe[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adap_id == address_data->probe[i]) ||
- ((address_data->probe[i] == ANY_I2C_BUS))) &&
- (addr == address_data->probe[i+1])) {
- found = 1;
- dev_dbg(&adapter->dev, "found probe parameter for adapter %d, "
- "addr %04x\n", adap_id,addr);
- }
- }
- if (!found)
- continue;
-
- /* OK, so we really should examine this address. First check
- whether there is some client here at all! */
- if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
- if ((err = found_proc(adapter,addr,-1)))
- return err;
}
- return 0;
-}
-/*
- * return id number for a specific adapter
- */
-int i2c_adapter_id(struct i2c_adapter *adap)
-{
- return adap->nr;
+ /* Probe entries are done second, and are not affected by ignore
+ entries either */
+ for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
+ if (address_data->probe[i] == adap_id
+ || address_data->probe[i] == ANY_I2C_BUS) {
+ dev_dbg(&adapter->dev, "found probe parameter for "
+ "adapter %d, addr 0x%02x\n", adap_id,
+ address_data->probe[i + 1]);
+ err = i2c_probe_address(adapter,
+ address_data->probe[i + 1],
+ -1, found_proc);
+ if (err)
+ return err;
+ }
+ }
+
+ /* Normal entries are done last, unless shadowed by an ignore entry */
+ for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
+ int j, ignore;
+
+ ignore = 0;
+ for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
+ j += 2) {
+ if ((address_data->ignore[j] == adap_id ||
+ address_data->ignore[j] == ANY_I2C_BUS)
+ && address_data->ignore[j + 1]
+ == address_data->normal_i2c[i]) {
+ dev_dbg(&adapter->dev, "found ignore "
+ "parameter for adapter %d, "
+ "addr 0x%02x\n", adap_id,
+ address_data->ignore[j + 1]);
+ }
+ ignore = 1;
+ break;
+ }
+ if (ignore)
+ continue;
+
+ dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
+ "addr 0x%02x\n", adap_id,
+ address_data->normal_i2c[i]);
+ err = i2c_probe_address(adapter, address_data->normal_i2c[i],
+ -1, found_proc);
+ if (err)
+ return err;
+ }
+
+ return 0;
}
struct i2c_adapter* i2c_get_adapter(int id)
@@ -1171,6 +1194,12 @@
}
+/* Next four are needed by i2c-isa */
+EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
+EXPORT_SYMBOL_GPL(i2c_adapter_driver);
+EXPORT_SYMBOL_GPL(i2c_adapter_class);
+EXPORT_SYMBOL_GPL(i2c_bus_type);
+
EXPORT_SYMBOL(i2c_add_adapter);
EXPORT_SYMBOL(i2c_del_adapter);
EXPORT_SYMBOL(i2c_add_driver);
@@ -1186,7 +1215,6 @@
EXPORT_SYMBOL(i2c_master_recv);
EXPORT_SYMBOL(i2c_control);
EXPORT_SYMBOL(i2c_transfer);
-EXPORT_SYMBOL(i2c_adapter_id);
EXPORT_SYMBOL(i2c_get_adapter);
EXPORT_SYMBOL(i2c_put_adapter);
EXPORT_SYMBOL(i2c_probe);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index bc5d557..aa7a4fa 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -434,7 +434,8 @@
devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor),
S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor);
- dev_dbg(&adap->dev, "Registered as minor %d\n", i2c_dev->minor);
+ pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+ adap->name, i2c_dev->minor);
/* register this i2c device with the driver core */
i2c_dev->adap = adap;
@@ -471,7 +472,7 @@
wait_for_completion(&i2c_dev->released);
kfree(i2c_dev);
- dev_dbg(&adap->dev, "Adapter unregistered\n");
+ pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
return 0;
}
diff --git a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c
deleted file mode 100644
index f99a816..0000000
--- a/drivers/i2c/i2c-sensor-detect.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- i2c-sensor-detect.c - Part of lm_sensors, Linux kernel modules for hardware
- monitoring
- Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl> and
- Mark D. Studebaker <mdsxyz123@yahoo.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
-static unsigned short empty[] = {I2C_CLIENT_END};
-static unsigned int empty_isa[] = {I2C_CLIENT_ISA_END};
-
-/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */
-int i2c_detect(struct i2c_adapter *adapter,
- struct i2c_address_data *address_data,
- int (*found_proc) (struct i2c_adapter *, int, int))
-{
- int addr, i, found, j, err;
- struct i2c_force_data *this_force;
- int is_isa = i2c_is_isa_adapter(adapter);
- int adapter_id =
- is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter);
- unsigned short *normal_i2c;
- unsigned int *normal_isa;
- unsigned short *probe;
- unsigned short *ignore;
-
- /* Forget it if we can't probe using SMBUS_QUICK */
- if ((!is_isa) &&
- !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK))
- return -1;
-
- /* Use default "empty" list if the adapter doesn't specify any */
- normal_i2c = probe = ignore = empty;
- normal_isa = empty_isa;
- if (address_data->normal_i2c)
- normal_i2c = address_data->normal_i2c;
- if (address_data->normal_isa)
- normal_isa = address_data->normal_isa;
- if (address_data->probe)
- probe = address_data->probe;
- if (address_data->ignore)
- ignore = address_data->ignore;
-
- for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) {
- if (!is_isa && i2c_check_addr(adapter, addr))
- continue;
-
- /* If it is in one of the force entries, we don't do any
- detection at all */
- found = 0;
- for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) {
- for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) {
- if ( ((adapter_id == this_force->force[j]) ||
- ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) &&
- (addr == this_force->force[j + 1]) ) {
- dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr);
- if ((err = found_proc(adapter, addr, this_force->kind)))
- return err;
- found = 1;
- }
- }
- }
- if (found)
- continue;
-
- /* If this address is in one of the ignores, we can forget about it
- right now */
- for (i = 0; !found && (ignore[i] != I2C_CLIENT_END); i += 2) {
- if ( ((adapter_id == ignore[i]) ||
- ((ignore[i] == ANY_I2C_BUS) &&
- !is_isa)) &&
- (addr == ignore[i + 1])) {
- dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr);
- found = 1;
- }
- }
- if (found)
- continue;
-
- /* Now, we will do a detection, but only if it is in the normal or
- probe entries */
- if (is_isa) {
- for (i = 0; !found && (normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) {
- if (addr == normal_isa[i]) {
- dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr);
- found = 1;
- }
- }
- } else {
- for (i = 0; !found && (normal_i2c[i] != I2C_CLIENT_END); i += 1) {
- if (addr == normal_i2c[i]) {
- found = 1;
- dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x\n", adapter_id, addr);
- }
- }
- }
-
- for (i = 0;
- !found && (probe[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adapter_id == probe[i]) ||
- ((probe[i] == ANY_I2C_BUS) && !is_isa))
- && (addr == probe[i + 1])) {
- dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr);
- found = 1;
- }
- }
- if (!found)
- continue;
-
- /* OK, so we really should examine this address. First check
- whether there is some client here at all! */
- if (is_isa ||
- (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0))
- if ((err = found_proc(adapter, addr, -1)))
- return err;
- }
- return 0;
-}
-
-EXPORT_SYMBOL(i2c_detect);
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
- "Rudolf Marek <r.marek@sh.cvut.cz>");
-
-MODULE_DESCRIPTION("i2c-sensor driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-sensor-vid.c b/drivers/i2c/i2c-sensor-vid.c
deleted file mode 100644
index 922e22f..0000000
--- a/drivers/i2c/i2c-sensor-vid.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- i2c-sensor-vid.c - Part of lm_sensors, Linux kernel modules for hardware
- monitoring
-
- Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-struct vrm_model {
- u8 vendor;
- u8 eff_family;
- u8 eff_model;
- int vrm_type;
-};
-
-#define ANY 0xFF
-
-#ifdef CONFIG_X86
-
-static struct vrm_model vrm_models[] = {
- {X86_VENDOR_AMD, 0x6, ANY, 90}, /* Athlon Duron etc */
- {X86_VENDOR_AMD, 0xF, ANY, 24}, /* Athlon 64, Opteron */
- {X86_VENDOR_INTEL, 0x6, 0x9, 85}, /* 0.13um too */
- {X86_VENDOR_INTEL, 0x6, 0xB, 85}, /* 0xB Tualatin */
- {X86_VENDOR_INTEL, 0x6, ANY, 82}, /* any P6 */
- {X86_VENDOR_INTEL, 0x7, ANY, 0}, /* Itanium */
- {X86_VENDOR_INTEL, 0xF, 0x3, 100}, /* P4 Prescott */
- {X86_VENDOR_INTEL, 0xF, ANY, 90}, /* P4 before Prescott */
- {X86_VENDOR_INTEL, 0x10,ANY, 0}, /* Itanium 2 */
- {X86_VENDOR_UNKNOWN, ANY, ANY, 0} /* stop here */
- };
-
-static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor)
-{
- int i = 0;
-
- while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
- if (vrm_models[i].vendor==vendor)
- if ((vrm_models[i].eff_family==eff_family)&& \
- ((vrm_models[i].eff_model==eff_model)|| \
- (vrm_models[i].eff_model==ANY)))
- return vrm_models[i].vrm_type;
- i++;
- }
-
- return 0;
-}
-
-int i2c_which_vrm(void)
-{
- struct cpuinfo_x86 *c = cpu_data;
- u32 eax;
- u8 eff_family, eff_model;
- int vrm_ret;
-
- if (c->x86 < 6) return 0; /* any CPU with familly lower than 6
- dont have VID and/or CPUID */
- eax = cpuid_eax(1);
- eff_family = ((eax & 0x00000F00)>>8);
- eff_model = ((eax & 0x000000F0)>>4);
- if (eff_family == 0xF) { /* use extended model & family */
- eff_family += ((eax & 0x00F00000)>>20);
- eff_model += ((eax & 0x000F0000)>>16)<<4;
- }
- vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor);
- if (vrm_ret == 0)
- printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your"
- " x86 CPU\n");
- return vrm_ret;
-}
-
-/* and now for something completely different for Non-x86 world*/
-#else
-int i2c_which_vrm(void)
-{
- printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your CPU\n");
- return 0;
-}
-#endif
-
-EXPORT_SYMBOL(i2c_which_vrm);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index c9d3a00..234f5de 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -754,7 +754,7 @@
idedisk_prepare_flush(q, rq);
- ret = blk_execute_rq(q, disk, rq);
+ ret = blk_execute_rq(q, disk, rq, 0);
/*
* if we failed and caller wants error offset, get it
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 248e3cc..f174aee 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -150,7 +150,7 @@
switch (rq->pm->pm_step) {
case ide_pm_flush_cache: /* Suspend step 1 (flush cache) complete */
- if (rq->pm->pm_state == 4)
+ if (rq->pm->pm_state == PM_EVENT_FREEZE)
rq->pm->pm_step = ide_pm_state_completed;
else
rq->pm->pm_step = idedisk_pm_standby;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index dae1bd5..73ca8f7 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1229,7 +1229,7 @@
rq.special = &args;
rq.pm = &rqpm;
rqpm.pm_step = ide_pm_state_start_suspend;
- rqpm.pm_state = state;
+ rqpm.pm_state = state.event;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
@@ -1248,7 +1248,7 @@
rq.special = &args;
rq.pm = &rqpm;
rqpm.pm_step = ide_pm_state_start_resume;
- rqpm.pm_state = 0;
+ rqpm.pm_state = PM_EVENT_ON;
return ide_do_drive_cmd(drive, &rq, ide_head_wait);
}
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 10592ce..24e21b2 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -350,9 +350,9 @@
{
ide_hwif_t *hwif = NULL;
- printk("SC1200: suspend(%u)\n", state);
+ printk("SC1200: suspend(%u)\n", state.event);
- if (state == 0) {
+ if (state.event == PM_EVENT_ON) {
// we only save state when going from full power to less
//
@@ -386,8 +386,8 @@
/* You don't need to iterate over disks -- sysfs should have done that for you already */
pci_disable_device(dev);
- pci_set_power_state(dev,state);
- dev->current_state = state;
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+ dev->current_state = state.event;
return 0;
}
@@ -396,8 +396,8 @@
ide_hwif_t *hwif = NULL;
printk("SC1200: resume\n");
- pci_set_power_state(dev,0); // bring chip back from sleep state
- dev->current_state = 0;
+ pci_set_power_state(dev, PCI_D0); // bring chip back from sleep state
+ dev->current_state = PM_EVENT_ON;
pci_enable_device(dev);
//
// loop over all interfaces that are part of this pci device:
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index ea65b07..87d1f8a 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1504,12 +1504,12 @@
}
static int
-pmac_ide_macio_suspend(struct macio_dev *mdev, u32 state)
+pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t state)
{
ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
int rc = 0;
- if (state != mdev->ofdev.dev.power.power_state && state >= 2) {
+ if (state.event != mdev->ofdev.dev.power.power_state.event && state.event >= PM_EVENT_SUSPEND) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
mdev->ofdev.dev.power.power_state = state;
@@ -1524,10 +1524,10 @@
ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
int rc = 0;
- if (mdev->ofdev.dev.power.power_state != 0) {
+ if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
rc = pmac_ide_do_resume(hwif);
if (rc == 0)
- mdev->ofdev.dev.power.power_state = 0;
+ mdev->ofdev.dev.power.power_state = PMSG_ON;
}
return rc;
@@ -1608,12 +1608,12 @@
}
static int
-pmac_ide_pci_suspend(struct pci_dev *pdev, u32 state)
+pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
int rc = 0;
- if (state != pdev->dev.power.power_state && state >= 2) {
+ if (state.event != pdev->dev.power.power_state.event && state.event >= 2) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
pdev->dev.power.power_state = state;
@@ -1628,10 +1628,10 @@
ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
int rc = 0;
- if (pdev->dev.power.power_state != 0) {
+ if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
rc = pmac_ide_do_resume(hwif);
if (rc == 0)
- pdev->dev.power.power_state = 0;
+ pdev->dev.power.power_state = PMSG_ON;
}
return rc;
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index bebcc47..b233225 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -1068,6 +1068,8 @@
struct unit_directory *ud;
int i = 0;
int length = 0;
+ /* ieee1394:venNmoNspNverN */
+ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
if (!cdev)
return -ENODEV;
@@ -1094,6 +1096,12 @@
PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
PUT_ENVP("VERSION=%06x", ud->version);
+ snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
+ ud->vendor_id,
+ ud->model_id,
+ ud->specifier_id,
+ ud->version);
+ PUT_ENVP("MODALIAS=%s", buf);
#undef PUT_ENVP
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 36074e6..6b1ab87 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -1464,26 +1464,6 @@
{ 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
};
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- union i2c_smbus_data data;
-
- if (i2c_smbus_xfer(i2c_ad, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))
- PRINT(KERN_ERR, lynx->id,"eeprom read start has failed");
- else
- {
- u16 addr;
- for (addr=0x00; addr < 0x100; addr++) {
- if (i2c_smbus_xfer(i2c_ad, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {
- PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr);
- break;
- }
- else
- PRINT(KERN_DEBUG, lynx->id,"got serial eeprom data at %x: %x",addr, data.byte);
- }
- }
-#endif
-
/* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we
do it more efficiently in one transaction rather then using several reads */
if (i2c_transfer(i2c_ad, msg, 2) < 0) {
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index fae1c2d..211ba32 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -463,7 +463,7 @@
return NULL;
for (i = 0; i < len; i++) {
- element = kcalloc(1, sizeof(struct port_table_attribute),
+ element = kzalloc(sizeof(struct port_table_attribute),
GFP_KERNEL);
if (!element)
goto err;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 20e3a16..19c14c4 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -160,6 +160,8 @@
# define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
#elif defined(CONFIG_ARCH_S390)
# define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#elif defined(CONFIG_MIPS)
+# define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR)
#else
# define COMPAT_TEST test_thread_flag(TIF_32BIT)
#endif
@@ -391,6 +393,7 @@
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+ case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
len = NBITS(len) * sizeof(long);
@@ -419,6 +422,13 @@
return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
}
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) {
+ int len;
+ len = NBITS(SW_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->sw, len) ? -EFAULT : len;
+ }
+
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
int len;
if (!dev->name) return -ENOENT;
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index a011803..462f8d3 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -75,7 +75,7 @@
if (!request_region(ioport, iolen, "emu10k1-gp"))
return -EBUSY;
- emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL);
+ emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
port = gameport_allocate_port();
if (!emu || !port) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 57615bc..47e93da 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -83,7 +83,7 @@
struct fm801_gp *gp;
struct gameport *port;
- gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL);
+ gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
port = gameport_allocate_port();
if (!gp || !port) {
printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 70f0518..d2e55dc 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -142,7 +142,7 @@
return -EBUSY;
}
- ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+ ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
port = gameport_allocate_port();
if (!ns558 || !port) {
printk(KERN_ERR "ns558: Memory allocation failed.\n");
@@ -215,7 +215,7 @@
if (!request_region(ioport, iolen, "ns558-pnp"))
return -EBUSY;
- ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+ ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
port = gameport_allocate_port();
if (!ns558 || !port) {
printk(KERN_ERR "ns558: Memory allocation failed\n");
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a275211..88636a2 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -89,6 +89,15 @@
break;
+ case EV_SW:
+
+ if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
+ return;
+
+ change_bit(code, dev->sw);
+
+ break;
+
case EV_ABS:
if (code > ABS_MAX || !test_bit(code, dev->absbit))
@@ -402,6 +411,7 @@
SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF);
+ SPRINTF_BIT_A2(swbit, "SW=", SW_MAX, EV_SW);
envp[i++] = NULL;
@@ -490,6 +500,7 @@
SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF);
+ SPRINTF_BIT_B2(swbit, "SW=", SW_MAX, EV_SW);
len += sprintf(buf + len, "\n");
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index bf34f75..bf654301 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -269,7 +269,7 @@
int i;
int err;
- if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL)))
+ if (!(a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL)))
return -ENOMEM;
a3d->gameport = gameport;
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 2659629..cf35ae6 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -469,7 +469,7 @@
int i;
int err;
- if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL)))
+ if (!(port = kzalloc(sizeof(struct adi_port), GFP_KERNEL)))
return -ENOMEM;
port->gameport = gameport;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index c3a5739..64b1313 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -655,7 +655,7 @@
int i;
int err;
- if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL)))
+ if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL)))
return - ENOMEM;
err = analog_init_port(gameport, drv, port);
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index a600220..0b2e9fa 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -163,7 +163,7 @@
int i, j;
int err;
- if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL)))
+ if (!(cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL)))
return -ENOMEM;
cobra->gameport = gameport;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index fbd3eed..2a3e4bb2 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -572,7 +572,7 @@
}
}
- if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
+ if (!(db9 = kzalloc(sizeof(struct db9), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 95bbdd3..5427bf9 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -554,7 +554,7 @@
return NULL;
}
- if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
+ if (!(gc = kzalloc(sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 7d96942..8e4f92b 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -242,7 +242,7 @@
unsigned char data[GF2K_LENGTH];
int i, err;
- if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL)))
+ if (!(gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL)))
return -ENOMEM;
gf2k->gameport = gameport;
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index d1500d2..9d3f910 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -301,7 +301,7 @@
int i, j, t;
int err;
- if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL)))
+ if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL)))
return -ENOMEM;
grip->gameport = gameport;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 0da7bd1..da17eee 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -607,7 +607,7 @@
struct grip_mp *grip;
int err;
- if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL)))
+ if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
return -ENOMEM;
grip->gameport = gameport;
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index f93da7b..6a70ec4 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -183,7 +183,7 @@
int i, t;
int err;
- if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL)))
+ if (!(guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL)))
return -ENOMEM;
guillemot->gameport = gameport;
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 9d3f8c3..d7b3472 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -212,7 +212,7 @@
int i, t;
int err;
- if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL)))
+ if (!(interact = kzalloc(sizeof(struct interact), GFP_KERNEL)))
return -ENOMEM;
interact->gameport = gameport;
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 47144a7..9e03537 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -590,7 +590,7 @@
comment[0] = 0;
- sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL);
+ sw = kzalloc(sizeof(struct sw), GFP_KERNEL);
buf = kmalloc(SW_LENGTH, GFP_KERNEL);
idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
if (!sw || !buf || !idbuf) {
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index 9eb9954..7431efc 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -262,7 +262,7 @@
int i, j, k, l, m;
int err;
- if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL)))
+ if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL)))
return -ENOMEM;
tmdc->gameport = gameport;
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 28100d4..0c5b9c8 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -178,7 +178,7 @@
return NULL;
}
- if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
+ if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index a855171..cd4b6e7 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/irq.h>
@@ -32,7 +33,6 @@
/* zero code, 124 scancodes + 3 hinge combinations */
#define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 )
#define SCAN_INTERVAL (HZ/10)
-#define CORGIKBD_PRESSED 1
#define HINGE_SCAN_INTERVAL (HZ/4)
@@ -73,25 +73,13 @@
struct input_dev input;
char phys[32];
- unsigned char state[ARRAY_SIZE(corgikbd_keycode)];
spinlock_t lock;
-
struct timer_list timer;
struct timer_list htimer;
-};
-static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data)
-{
- if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) {
- corgikbd_data->state[scancode] |= CORGIKBD_PRESSED;
- input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1);
- if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
- input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
- } else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) {
- corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED;
- input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0);
- }
-}
+ unsigned int suspended;
+ unsigned long suspend_jiffies;
+};
#define KB_DISCHARGE_DELAY 10
#define KB_ACTIVATE_DELAY 10
@@ -105,36 +93,36 @@
*/
static inline void corgikbd_discharge_all(void)
{
- // STROBE All HiZ
+ /* STROBE All HiZ */
GPCR2 = CORGI_GPIO_ALL_STROBE_BIT;
GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT;
}
static inline void corgikbd_activate_all(void)
{
- // STROBE ALL -> High
+ /* STROBE ALL -> High */
GPSR2 = CORGI_GPIO_ALL_STROBE_BIT;
GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT;
udelay(KB_DISCHARGE_DELAY);
- // Clear any interrupts we may have triggered when altering the GPIO lines
+ /* Clear any interrupts we may have triggered when altering the GPIO lines */
GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT;
GEDR2 = CORGI_GPIO_LOW_SENSE_BIT;
}
static inline void corgikbd_activate_col(int col)
{
- // STROBE col -> High, not col -> HiZ
+ /* STROBE col -> High, not col -> HiZ */
GPSR2 = CORGI_GPIO_STROBE_BIT(col);
GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
}
static inline void corgikbd_reset_col(int col)
{
- // STROBE col -> Low
+ /* STROBE col -> Low */
GPCR2 = CORGI_GPIO_STROBE_BIT(col);
- // STROBE col -> out, not col -> HiZ
+ /* STROBE col -> out, not col -> HiZ */
GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
}
@@ -149,10 +137,13 @@
/* Scan the hardware keyboard and push any changes up through the input layer */
static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
{
- unsigned int row, col, rowd, scancode;
+ unsigned int row, col, rowd;
unsigned long flags;
unsigned int num_pressed;
+ if (corgikbd_data->suspended)
+ return;
+
spin_lock_irqsave(&corgikbd_data->lock, flags);
if (regs)
@@ -173,10 +164,21 @@
rowd = GET_ROWS_STATUS(col);
for (row = 0; row < KB_ROWS; row++) {
+ unsigned int scancode, pressed;
+
scancode = SCANCODE(row, col);
- handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data);
- if (rowd & KB_ROWMASK(row))
+ pressed = rowd & KB_ROWMASK(row);
+
+ input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], pressed);
+
+ if (pressed)
num_pressed++;
+
+ if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
+ && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) {
+ input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
+ corgikbd_data->suspend_jiffies=jiffies;
+ }
}
corgikbd_reset_col(col);
}
@@ -221,8 +223,11 @@
* The hinge switches generate no interrupt so they need to be
* monitored by a timer.
*
- * When we detect changes, we debounce it and then pass the three
- * positions the system can take as keypresses to the input system.
+ * We debounce the switches and pass them to the input system.
+ *
+ * gprr == 0x00 - Keyboard with Landscape Screen
+ * 0x08 - No Keyboard with Portrait Screen
+ * 0x0c - Keyboard and Screen Closed
*/
#define HINGE_STABLE_COUNT 2
@@ -235,7 +240,7 @@
unsigned long gprr;
unsigned long flags;
- gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
+ gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
if (gprr != sharpsl_hinge_state) {
hinge_count = 0;
sharpsl_hinge_state = gprr;
@@ -244,9 +249,8 @@
if (hinge_count >= HINGE_STABLE_COUNT) {
spin_lock_irqsave(&corgikbd_data->lock, flags);
- handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */
- handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */
- handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed */
+ input_report_switch(&corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
+ input_report_switch(&corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
input_sync(&corgikbd_data->input);
spin_unlock_irqrestore(&corgikbd_data->lock, flags);
@@ -255,19 +259,45 @@
mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL);
}
+#ifdef CONFIG_PM
+static int corgikbd_suspend(struct device *dev, pm_message_t state, uint32_t level)
+{
+ if (level == SUSPEND_POWER_DOWN) {
+ struct corgikbd *corgikbd = dev_get_drvdata(dev);
+ corgikbd->suspended = 1;
+ }
+ return 0;
+}
+
+static int corgikbd_resume(struct device *dev, uint32_t level)
+{
+ if (level == RESUME_POWER_ON) {
+ struct corgikbd *corgikbd = dev_get_drvdata(dev);
+
+ /* Upon resume, ignore the suspend key for a short while */
+ corgikbd->suspend_jiffies=jiffies;
+ corgikbd->suspended = 0;
+ }
+ return 0;
+}
+#else
+#define corgikbd_suspend NULL
+#define corgikbd_resume NULL
+#endif
+
static int __init corgikbd_probe(struct device *dev)
{
int i;
struct corgikbd *corgikbd;
- corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL);
+ corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL);
if (!corgikbd)
return -ENOMEM;
dev_set_drvdata(dev,corgikbd);
strcpy(corgikbd->phys, "corgikbd/input0");
- spin_lock_init(corgikbd->lock);
+ spin_lock_init(&corgikbd->lock);
/* Init Keyboard rescan timer */
init_timer(&corgikbd->timer);
@@ -279,6 +309,8 @@
corgikbd->htimer.function = corgikbd_hinge_timer;
corgikbd->htimer.data = (unsigned long) corgikbd;
+ corgikbd->suspend_jiffies=jiffies;
+
init_input_dev(&corgikbd->input);
corgikbd->input.private = corgikbd;
corgikbd->input.name = "Corgi Keyboard";
@@ -288,7 +320,7 @@
corgikbd->input.id.vendor = 0x0001;
corgikbd->input.id.product = 0x0001;
corgikbd->input.id.version = 0x0100;
- corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR);
+ corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
corgikbd->input.keycode = corgikbd->keycode;
corgikbd->input.keycodesize = sizeof(unsigned char);
corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode);
@@ -297,6 +329,8 @@
for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
set_bit(corgikbd->keycode[i], corgikbd->input.keybit);
clear_bit(0, corgikbd->input.keybit);
+ set_bit(SW_0, corgikbd->input.swbit);
+ set_bit(SW_1, corgikbd->input.swbit);
input_register_device(&corgikbd->input);
mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL);
@@ -343,6 +377,8 @@
.bus = &platform_bus_type,
.probe = corgikbd_probe,
.remove = corgikbd_remove,
+ .suspend = corgikbd_suspend,
+ .resume = corgikbd_resume,
};
static int __devinit corgikbd_init(void)
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 2bb2fe7..12bdd3e 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -883,7 +883,7 @@
psmouse_deactivate(parent);
}
- if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
+ if (!(psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 79ca384..1bd88fc 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -87,7 +87,7 @@
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL);
+ serport = kzalloc(sizeof(struct serport), GFP_KERNEL);
if (!serport)
return -ENOMEM;
@@ -165,7 +165,7 @@
if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY;
- serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL);
+ serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 3f8b61c..5d19261 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -53,11 +53,8 @@
#define SyncHS() while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
-#define CCNT_ON() {int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
-#define CCNT_OFF() {int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
-
-#define WAIT_HS_400_VGA 7013U // 17.615us
-#define WAIT_HS_400_QVGA 16622U // 41.750us
+#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
+#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
/* ADS7846 Touch Screen Controller bit definitions */
@@ -69,41 +66,29 @@
#define ADSCTRL_STS (1u << 7) /* Start Bit */
/* External Functions */
-extern int w100fb_get_xres(void);
-extern int w100fb_get_blanking(void);
-extern int w100fb_get_fastsysclk(void);
+extern unsigned long w100fb_get_hsynclen(struct device *dev);
extern unsigned int get_clk_frequency_khz(int info);
static unsigned long calc_waittime(void)
{
- int w100fb_xres = w100fb_get_xres();
- unsigned int waittime = 0;
+ unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev);
- if (w100fb_xres == 480 || w100fb_xres == 640) {
- waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U;
-
- if (w100fb_get_fastsysclk() == 100)
- waittime = waittime * 75 / 100;
-
- if (w100fb_xres == 640)
- waittime *= 3;
-
- return waittime;
- }
-
- return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U;
+ if (hsync_len)
+ return get_clk_frequency_khz(0)*1000/hsync_len;
+ else
+ return 0;
}
static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
{
+ unsigned long timer1 = 0, timer2, pmnc = 0;
int pos = 0;
- unsigned long timer1 = 0, timer2;
- int dosleep;
- dosleep = !w100fb_get_blanking();
+ if (wait_time && doSend) {
+ PMNC_GET(pmnc);
+ if (!(pmnc & 0x01))
+ PMNC_SET(0x01);
- if (dosleep && doSend) {
- CCNT_ON();
/* polling HSync */
SyncHS();
/* get CCNT */
@@ -119,11 +104,11 @@
corgi_ssp_ads7846_put(cmd);
corgi_ssp_ads7846_get();
- if (dosleep) {
+ if (wait_time) {
/* Wait after HSync */
CCNT(timer2);
if (timer2-timer1 > wait_time) {
- /* timeout */
+ /* too slow - timeout, try again */
SyncHS();
/* get OSCR */
CCNT(timer1);
@@ -134,8 +119,8 @@
CCNT(timer2);
}
corgi_ssp_ads7846_put(cmd);
- if (dosleep)
- CCNT_OFF();
+ if (wait_time && !(pmnc & 0x01))
+ PMNC_SET(pmnc);
}
return pos;
}
@@ -244,7 +229,7 @@
}
#ifdef CONFIG_PM
-static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level)
+static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level)
{
if (level == SUSPEND_POWER_DOWN) {
struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 17cf766..26c545f 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -10,7 +10,6 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/kernel.h>
@@ -1242,6 +1241,8 @@
#ifdef CONFIG_HISAX_ENTERNOW_PCI
#define CARD_FN_ENTERNOW_PCI 1
+#else
+#define CARD_FN_ENTERNOW_PCI 0
#endif
#define TEI_PER_CARD 1
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
index f47f2b9..38619e8 100644
--- a/drivers/isdn/i4l/isdn_v110.c
+++ b/drivers/isdn/i4l/isdn_v110.c
@@ -516,11 +516,11 @@
}
int
-isdn_v110_stat_callback(int idx, isdn_ctrl * c)
+isdn_v110_stat_callback(int idx, isdn_ctrl *c)
{
isdn_v110_stream *v = NULL;
int i;
- int ret;
+ int ret = 0;
if (idx < 0)
return 0;
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 7c16c25..c0712a1 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -708,7 +708,7 @@
{
struct media_bay_info *bay = macio_get_drvdata(mdev);
- if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) {
+ if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == PM_EVENT_SUSPEND) {
down(&bay->lock);
bay->sleeping = 1;
set_mb_power(bay, 0);
@@ -723,8 +723,8 @@
{
struct media_bay_info *bay = macio_get_drvdata(mdev);
- if (mdev->ofdev.dev.power.power_state != 0) {
- mdev->ofdev.dev.power.power_state = 0;
+ if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
+ mdev->ofdev.dev.power.power_state = PMSG_ON;
/* We re-enable the bay using it's previous content
only if it did not change. Note those bozo timings,
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 4a0a0ad..645a2e5 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -3065,7 +3065,7 @@
static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
{
- if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+ if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended)
return 0;
/* Suspend PMU event interrupts */
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index d0a4bab..b82bc31 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -144,7 +144,7 @@
}
/* Hash the cipher key with the given hash algorithm */
- hash_tfm = crypto_alloc_tfm(opts, 0);
+ hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
if (hash_tfm == NULL) {
ti->error = PFX "Error initializing ESSIV hash";
return -EINVAL;
@@ -172,7 +172,8 @@
/* Setup the essiv_tfm with the given salt */
essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
- CRYPTO_TFM_MODE_ECB);
+ CRYPTO_TFM_MODE_ECB |
+ CRYPTO_TFM_REQ_MAY_SLEEP);
if (essiv_tfm == NULL) {
ti->error = PFX "Error allocating crypto tfm for ESSIV";
kfree(salt);
@@ -587,7 +588,7 @@
goto bad1;
}
- tfm = crypto_alloc_tfm(cipher, crypto_flags);
+ tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
if (!tfm) {
ti->error = PFX "Error allocating crypto tfm";
goto bad1;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 45754bb..9de0001 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -239,6 +239,11 @@
dp->context_ptr = data;
}
+static void dm_bio_destructor(struct bio *bio)
+{
+ bio_free(bio, _bios);
+}
+
/*-----------------------------------------------------------------
* IO routines that accept a list of pages.
*---------------------------------------------------------------*/
@@ -263,6 +268,7 @@
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
bio->bi_private = io;
+ bio->bi_destructor = dm_bio_destructor;
bio_set_region(bio, region);
/*
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index d487d9d..930b9fc 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -399,6 +399,11 @@
unsigned short idx;
};
+static void dm_bio_destructor(struct bio *bio)
+{
+ bio_free(bio, dm_set);
+}
+
/*
* Creates a little bio that is just does part of a bvec.
*/
@@ -410,6 +415,7 @@
struct bio_vec *bv = bio->bi_io_vec + idx;
clone = bio_alloc_bioset(GFP_NOIO, 1, dm_set);
+ clone->bi_destructor = dm_bio_destructor;
*clone->bi_io_vec = *bv;
clone->bi_sector = sector;
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 781f23f..6284894 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -387,8 +387,6 @@
/* exported algorithm data */
static struct i2c_algorithm saa7146_algo = {
- .name = "saa7146 i2c algorithm",
- .id = I2C_ALGO_SAA7146,
.master_xfer = saa7146_i2c_xfer,
.functionality = saa7146_i2c_func,
};
@@ -412,7 +410,7 @@
#endif
i2c_adapter->algo = &saa7146_algo;
i2c_adapter->algo_data = NULL;
- i2c_adapter->id = I2C_ALGO_SAA7146;
+ i2c_adapter->id = I2C_HW_SAA7146;
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
i2c_adapter->retries = SAA7146_I2C_RETRIES;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index be4266d..56495cb 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -172,8 +172,6 @@
}
static struct i2c_algorithm flexcop_algo = {
- .name = "FlexCop I2C algorithm",
- .id = I2C_ALGO_BIT,
.master_xfer = flexcop_master_xfer,
.functionality = flexcop_i2c_func,
};
@@ -192,7 +190,6 @@
fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
fc->i2c_adap.algo = &flexcop_algo;
fc->i2c_adap.algo_data = NULL;
- fc->i2c_adap.id = I2C_ALGO_BIT;
if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
return ret;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index b12545f..1e85d16 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,5 +1,5 @@
config DVB_BT8XX
- tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards"
+ tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && VIDEO_BT848
select DVB_MT352
select DVB_SP887X
@@ -8,8 +8,8 @@
select DVB_OR51211
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
- the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and
- pcHDTV HD2000 cards.
+ the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
+ the pcHDTV HD2000 cards, and certain AVerMedia cards.
Since these cards have no MPEG decoder onboard, they transmit
only compressed MPEG data over the PCI bus, so you need
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 7d8b3ca..9ea5747 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -888,7 +888,7 @@
if (down_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
- if (state > 0) { /* state 0 seems to mean DEVICE_PM_ON */
+ if (state.event > PM_EVENT_ON) {
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
#ifdef ENABLE_RC
cancel_delayed_work(&cinergyt2->rc_query_work);
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index c3e1b66..9e96a18 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -141,8 +141,6 @@
}
static struct i2c_algorithm cxusb_i2c_algo = {
- .name = "Conexant USB I2C algorithm",
- .id = I2C_ALGO_BIT,
.master_xfer = cxusb_i2c_xfer,
.functionality = cxusb_i2c_func,
};
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 9b9d6f8..00b9464 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -156,8 +156,6 @@
}
struct i2c_algorithm dibusb_i2c_algo = {
- .name = "DiBcom USB I2C algorithm",
- .id = I2C_ALGO_BIT,
.master_xfer = dibusb_i2c_xfer,
.functionality = dibusb_i2c_func,
};
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 9a676afc..f70e0be 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -77,8 +77,6 @@
}
static struct i2c_algorithm digitv_i2c_algo = {
- .name = "Nebula DigiTV USB I2C algorithm",
- .id = I2C_ALGO_BIT,
.master_xfer = digitv_i2c_xfer,
.functionality = digitv_i2c_func,
};
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 9f0a8d9..da97094 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -27,7 +27,6 @@
#endif
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
- d->i2c_adap.id = I2C_ALGO_BIT;
i2c_set_adapdata(&d->i2c_adap, d);
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 1f1cd7a..7142b9c 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -69,8 +69,8 @@
};
static int i2c_write_demod_bytes (struct lgdt330x_state* state,
- u8 *buf, /* data bytes to send */
- int len /* number of bytes to send */ )
+ u8 *buf, /* data bytes to send */
+ int len /* number of bytes to send */ )
{
struct i2c_msg msg =
{ .addr = state->config->demod_address,
@@ -129,13 +129,13 @@
};
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
if (ret == 0) {
/* force reset high (inactive) and unmask interrupts */
reset[1] = 0x7f;
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
}
return ret;
}
@@ -149,13 +149,13 @@
};
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
if (ret == 0) {
/* force reset high (inactive) */
reset[1] = 0x01;
ret = i2c_write_demod_bytes(state,
- reset, sizeof(reset));
+ reset, sizeof(reset));
}
return ret;
}
@@ -172,7 +172,6 @@
}
}
-
static int lgdt330x_init(struct dvb_frontend* fe)
{
/* Hardware reset is done using gpio[0] of cx23880x chip.
@@ -229,13 +228,13 @@
case LGDT3302:
chip_name = "LGDT3302";
err = i2c_write_demod_bytes(state, lgdt3302_init_data,
- sizeof(lgdt3302_init_data));
- break;
+ sizeof(lgdt3302_init_data));
+ break;
case LGDT3303:
chip_name = "LGDT3303";
err = i2c_write_demod_bytes(state, lgdt3303_init_data,
- sizeof(lgdt3303_init_data));
- break;
+ sizeof(lgdt3303_init_data));
+ break;
default:
chip_name = "undefined";
printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
@@ -262,15 +261,15 @@
switch (state->config->demod_chip) {
case LGDT3302:
err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
- buf, sizeof(buf));
- break;
+ buf, sizeof(buf));
+ break;
case LGDT3303:
err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
- buf, sizeof(buf));
- break;
+ buf, sizeof(buf));
+ break;
default:
printk(KERN_WARNING
- "Only LGDT3302 and LGDT3303 are supported chips.\n");
+ "Only LGDT3302 and LGDT3303 are supported chips.\n");
err = -ENODEV;
}
@@ -330,7 +329,7 @@
if (state->config->demod_chip == LGDT3303) {
err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data,
- sizeof(lgdt3303_8vsb_44_data));
+ sizeof(lgdt3303_8vsb_44_data));
}
break;
@@ -378,18 +377,19 @@
/* Select the requested mode */
i2c_write_demod_bytes(state, top_ctrl_cfg,
- sizeof(top_ctrl_cfg));
- state->config->set_ts_params(fe, 0);
+ sizeof(top_ctrl_cfg));
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 0);
state->current_modulation = param->u.vsb.modulation;
}
- /* Change only if we are actually changing the channel */
- if (state->current_frequency != param->frequency) {
- /* Tune to the new frequency */
+ /* Tune to the specified frequency */
+ if (state->config->pll_set)
state->config->pll_set(fe, param);
- /* Keep track of the new frequency */
- state->current_frequency = param->frequency;
- }
+
+ /* Keep track of the new frequency */
+ state->current_frequency = param->frequency;
+
lgdt330x_SwReset(state);
return 0;
}
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 706e0bc..85b437b 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -633,7 +633,6 @@
i2c_set_adapdata(&pluto->i2c_adap, pluto);
strcpy(pluto->i2c_adap.name, DRIVER_NAME);
pluto->i2c_adap.owner = THIS_MODULE;
- pluto->i2c_adap.id = I2C_ALGO_BIT;
pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
pluto->i2c_adap.dev.parent = &pdev->dev;
pluto->i2c_adap.algo_data = &pluto->i2c_bit;
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index bf3c011..d8bf658 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -102,6 +102,9 @@
select VIDEO_DEV
select VIDEO_SAA7146_VV
select DVB_STV0299
+ select DVB_TDA1004X
+ select DVB_TDA10021
+ select FW_LOADER
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index aa43b5f..7daf7b1 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1472,8 +1472,6 @@
static struct i2c_algorithm ttusb_dec_algo = {
- .name = "ttusb dec i2c algorithm",
- .id = I2C_ALGO_BIT,
.master_xfer = master_xfer,
.functionality = functionality,
};
@@ -1525,7 +1523,6 @@
#endif
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
- ttusb->i2c_adap.id = I2C_ALGO_BIT;
result = i2c_add_adapter(&ttusb->i2c_adap);
if (result) {
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 3f57423..16c85c0 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -254,6 +254,7 @@
select VIDEO_BUF_DVB
select DVB_MT352
select DVB_CX22702
+ select DVB_TDA1004X
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 810e7aa..3e6f534 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -29,7 +29,7 @@
obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 48989ed..1ca2b67 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -391,7 +390,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_adv7170;
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index f898b65..173bca1 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -39,7 +39,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -441,7 +440,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_adv7175;
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 8733588..3ee0afc 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -507,7 +506,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_bt819;
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index a070417..76c1b63 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -188,7 +188,7 @@
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, bt832_attach);
#else
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ if (adap->id == I2C_HW_B_BT848)
return i2c_probe(adap, &addr_data, bt832_attach);
#endif
return 0;
@@ -241,7 +241,7 @@
};
static struct i2c_client client_template =
{
- I2C_DEVNAME("bt832"),
+ .name = "bt832",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index a5d529c..8eb871d 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -295,7 +294,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_bt856;
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index eee9322..087efb4 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -4047,7 +4047,6 @@
struct bttv_buffer_set idle;
unsigned long flags;
- dprintk("bttv%d: suspend %d\n", btv->c.nr, state);
/* stop dma + irqs */
spin_lock_irqsave(&btv->s_lock,flags);
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index 234a855..706dc48 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -109,7 +109,7 @@
#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
#endif
- I2C_DEVNAME("bt848"),
+ .name = "bt848",
.id = I2C_HW_B_BT848,
.client_register = attach_inform,
};
@@ -270,8 +270,6 @@
}
static struct i2c_algorithm bttv_algo = {
- .name = "bt878",
- .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
.master_xfer = bttv_i2c_xfer,
.algo_control = algo_control,
.functionality = functionality,
@@ -282,8 +280,8 @@
#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
#endif
- I2C_DEVNAME("bt878"),
- .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */,
+ .name = "bt878",
+ .id = I2C_HW_B_BT848 /* FIXME */,
.algo = &bttv_algo,
.client_register = attach_inform,
};
@@ -298,7 +296,7 @@
if (bttv_debug)
printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
btv->c.nr,client->driver->name,client->addr,
- i2c_clientname(client));
+ client->name);
if (!client->driver->command)
return 0;
@@ -326,7 +324,7 @@
}
static struct i2c_client bttv_i2c_client_template = {
- I2C_DEVNAME("bttv internal"),
+ .name = "bttv internal",
};
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index a628a55..7f59803 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -95,7 +95,7 @@
struct cx88_core *core = i2c_get_adapdata(client->adapter);
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
- client->driver->name,client->addr,i2c_clientname(client));
+ client->driver->name, client->addr, client->name);
if (!client->driver->command)
return 0;
@@ -128,7 +128,7 @@
{
struct cx88_core *core = i2c_get_adapdata(client->adapter);
- dprintk(1, "i2c detach [client=%s]\n", i2c_clientname(client));
+ dprintk(1, "i2c detach [client=%s]\n", client->name);
return 0;
}
@@ -152,7 +152,7 @@
/* ----------------------------------------------------------------------- */
static struct i2c_adapter cx8800_i2c_adap_template = {
- I2C_DEVNAME("cx2388x"),
+ .name = "cx2388x",
.owner = THIS_MODULE,
.id = I2C_HW_B_CX2388x,
.client_register = attach_inform,
@@ -160,7 +160,7 @@
};
static struct i2c_client cx8800_i2c_client_template = {
- I2C_DEVNAME("cx88xx internal"),
+ .name = "cx88xx internal",
};
static char *i2c_devs[128] = {
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
new file mode 100644
index 0000000..b2b0384
--- /dev/null
+++ b/drivers/media/video/indycam.c
@@ -0,0 +1,412 @@
+/*
+ * indycam.c - Silicon Graphics IndyCam digital camera driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+/* IndyCam decodes stream of photons into digital image representation ;-) */
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "indycam.h"
+
+//#define INDYCAM_DEBUG
+
+#define INDYCAM_MODULE_VERSION "0.0.3"
+
+MODULE_DESCRIPTION("SGI IndyCam driver");
+MODULE_VERSION(INDYCAM_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#ifdef INDYCAM_DEBUG
+#define dprintk(x...) printk("IndyCam: " x);
+#define indycam_regdump(client) indycam_regdump_debug(client)
+#else
+#define dprintk(x...)
+#define indycam_regdump(client)
+#endif
+
+#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct indycam {
+ struct i2c_client *client;
+ int version;
+};
+
+static struct i2c_driver i2c_driver_indycam;
+
+static const unsigned char initseq[] = {
+ INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
+ INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */
+ INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
+ 0x00, /* INDYCAM_BRIGHTNESS (read-only) */
+ INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
+ INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */
+ INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
+ INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
+};
+
+/* IndyCam register handling */
+
+static int indycam_read_reg(struct i2c_client *client, unsigned char reg,
+ unsigned char *value)
+{
+ int ret;
+
+ if (reg == INDYCAM_RESET) {
+ dprintk("indycam_read_reg(): "
+ "skipping write-only register %d\n", reg);
+ *value = 0;
+ return 0;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
+ "register = 0x%02x\n", reg);
+ return ret;
+ }
+
+ *value = (unsigned char)ret;
+
+ return 0;
+}
+
+static int indycam_write_reg(struct i2c_client *client, unsigned char reg,
+ unsigned char value)
+{
+ int err;
+
+ if ((reg == INDYCAM_BRIGHTNESS)
+ || (reg == INDYCAM_VERSION)) {
+ dprintk("indycam_write_reg(): "
+ "skipping read-only register %d\n", reg);
+ return 0;
+ }
+
+ dprintk("Writing Reg %d = 0x%02x\n", reg, value);
+ err = i2c_smbus_write_byte_data(client, reg, value);
+ if (err) {
+ printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
+ "register = 0x%02x, value = 0x%02x\n", reg, value);
+ }
+ return err;
+}
+
+static int indycam_write_block(struct i2c_client *client, unsigned char reg,
+ unsigned char length, unsigned char *data)
+{
+ unsigned char i;
+ int err;
+
+ for (i = reg; i < length; i++) {
+ err = indycam_write_reg(client, reg + i, data[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Helper functions */
+
+#ifdef INDYCAM_DEBUG
+static void indycam_regdump_debug(struct i2c_client *client)
+{
+ int i;
+ unsigned char val;
+
+ for (i = 0; i < 9; i++) {
+ indycam_read_reg(client, i, &val);
+ dprintk("Reg %d = 0x%02x\n", i, val);
+ }
+}
+#endif
+
+static int indycam_get_controls(struct i2c_client *client,
+ struct indycam_control *ctrl)
+{
+ unsigned char ctrl_reg;
+
+ indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
+ ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA)
+ ? INDYCAM_VALUE_ENABLED
+ : INDYCAM_VALUE_DISABLED;
+ ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL)
+ ? INDYCAM_VALUE_ENABLED
+ : INDYCAM_VALUE_DISABLED;
+ indycam_read_reg(client, INDYCAM_SHUTTER,
+ (unsigned char *)&ctrl->shutter);
+ indycam_read_reg(client, INDYCAM_GAIN,
+ (unsigned char *)&ctrl->gain);
+ indycam_read_reg(client, INDYCAM_RED_BALANCE,
+ (unsigned char *)&ctrl->red_balance);
+ indycam_read_reg(client, INDYCAM_BLUE_BALANCE,
+ (unsigned char *)&ctrl->blue_balance);
+ indycam_read_reg(client, INDYCAM_RED_SATURATION,
+ (unsigned char *)&ctrl->red_saturation);
+ indycam_read_reg(client, INDYCAM_BLUE_SATURATION,
+ (unsigned char *)&ctrl->blue_saturation);
+ indycam_read_reg(client, INDYCAM_GAMMA,
+ (unsigned char *)&ctrl->gamma);
+
+ return 0;
+}
+
+static int indycam_set_controls(struct i2c_client *client,
+ struct indycam_control *ctrl)
+{
+ unsigned char ctrl_reg;
+
+ indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg);
+ if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) {
+ if (ctrl->agc)
+ ctrl_reg |= INDYCAM_CONTROL_AGCENA;
+ else
+ ctrl_reg &= ~INDYCAM_CONTROL_AGCENA;
+ }
+ if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) {
+ if (ctrl->awb)
+ ctrl_reg |= INDYCAM_CONTROL_AWBCTL;
+ else
+ ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL;
+ }
+ indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg);
+
+ if (ctrl->shutter >= 0)
+ indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter);
+ if (ctrl->gain >= 0)
+ indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain);
+ if (ctrl->red_balance >= 0)
+ indycam_write_reg(client, INDYCAM_RED_BALANCE,
+ ctrl->red_balance);
+ if (ctrl->blue_balance >= 0)
+ indycam_write_reg(client, INDYCAM_BLUE_BALANCE,
+ ctrl->blue_balance);
+ if (ctrl->red_saturation >= 0)
+ indycam_write_reg(client, INDYCAM_RED_SATURATION,
+ ctrl->red_saturation);
+ if (ctrl->blue_saturation >= 0)
+ indycam_write_reg(client, INDYCAM_BLUE_SATURATION,
+ ctrl->blue_saturation);
+ if (ctrl->gamma >= 0)
+ indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma);
+
+ return 0;
+}
+
+/* I2C-interface */
+
+static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ int err = 0;
+ struct indycam *camera;
+ struct i2c_client *client;
+
+ printk(KERN_INFO "SGI IndyCam driver version %s\n",
+ INDYCAM_MODULE_VERSION);
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ camera = kmalloc(sizeof(struct indycam), GFP_KERNEL);
+ if (!camera) {
+ err = -ENOMEM;
+ goto out_free_client;
+ }
+
+ memset(client, 0, sizeof(struct i2c_client));
+ memset(camera, 0, sizeof(struct indycam));
+
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &i2c_driver_indycam;
+ client->flags = 0;
+ strcpy(client->name, "IndyCam client");
+ i2c_set_clientdata(client, camera);
+
+ camera->client = client;
+
+ err = i2c_attach_client(client);
+ if (err)
+ goto out_free_camera;
+
+ camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION);
+ if (camera->version != CAMERA_VERSION_INDY &&
+ camera->version != CAMERA_VERSION_MOOSE) {
+ err = -ENODEV;
+ goto out_detach_client;
+ }
+ printk(KERN_INFO "IndyCam v%d.%d detected\n",
+ INDYCAM_VERSION_MAJOR(camera->version),
+ INDYCAM_VERSION_MINOR(camera->version));
+
+ indycam_regdump(client);
+
+ // initialize
+ err = indycam_write_block(client, 0, sizeof(initseq),
+ (unsigned char *)&initseq);
+ if (err) {
+ printk(KERN_ERR "IndyCam initalization failed\n");
+ err = -EIO;
+ goto out_detach_client;
+ }
+
+ indycam_regdump(client);
+
+ // white balance
+ err = indycam_write_reg(client, INDYCAM_CONTROL,
+ INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
+ if (err) {
+ printk(KERN_ERR "IndyCam white balance "
+ "initialization failed\n");
+ err = -EIO;
+ goto out_detach_client;
+ }
+
+ indycam_regdump(client);
+
+ printk(KERN_INFO "IndyCam initialized\n");
+
+ return 0;
+
+out_detach_client:
+ i2c_detach_client(client);
+out_free_camera:
+ kfree(camera);
+out_free_client:
+ kfree(client);
+ return err;
+}
+
+static int indycam_probe(struct i2c_adapter *adap)
+{
+ /* Indy specific crap */
+ if (adap->id == VINO_ADAPTER)
+ return indycam_attach(adap, INDYCAM_ADDR, 0);
+ /* Feel free to add probe here :-) */
+ return -ENODEV;
+}
+
+static int indycam_detach(struct i2c_client *client)
+{
+ struct indycam *camera = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(camera);
+ kfree(client);
+ return 0;
+}
+
+static int indycam_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ // struct indycam *camera = i2c_get_clientdata(client);
+
+ /* The old video_decoder interface just isn't enough,
+ * so we'll use some custom commands. */
+ switch (cmd) {
+ case DECODER_GET_CAPABILITIES: {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_NTSC;
+ cap->inputs = 1;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS: {
+ int *iarg = arg;
+
+ *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
+ DECODER_STATUS_COLOR;
+ break;
+ }
+ case DECODER_SET_NORM: {
+ int *iarg = arg;
+
+ switch (*iarg) {
+ case VIDEO_MODE_NTSC:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_INPUT: {
+ int *iarg = arg;
+
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_SET_OUTPUT: {
+ int *iarg = arg;
+
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT: {
+ /* Always enabled */
+ break;
+ }
+ case DECODER_SET_PICTURE: {
+ // struct video_picture *pic = arg;
+ /* TODO: convert values for indycam_set_controls() */
+ break;
+ }
+ case DECODER_INDYCAM_GET_CONTROLS: {
+ struct indycam_control *ctrl = arg;
+ indycam_get_controls(client, ctrl);
+ }
+ case DECODER_INDYCAM_SET_CONTROLS: {
+ struct indycam_control *ctrl = arg;
+ indycam_set_controls(client, ctrl);
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver i2c_driver_indycam = {
+ .owner = THIS_MODULE,
+ .name = "indycam",
+ .id = I2C_DRIVERID_INDYCAM,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = indycam_probe,
+ .detach_client = indycam_detach,
+ .command = indycam_command,
+};
+
+static int __init indycam_init(void)
+{
+ return i2c_add_driver(&i2c_driver_indycam);
+}
+
+static void __exit indycam_exit(void)
+{
+ i2c_del_driver(&i2c_driver_indycam);
+}
+
+module_init(indycam_init);
+module_exit(indycam_exit);
diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h
new file mode 100644
index 0000000..d9ddb6b
--- /dev/null
+++ b/drivers/media/video/indycam.h
@@ -0,0 +1,112 @@
+/*
+ * indycam.h - Silicon Graphics IndyCam digital camera driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * 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 _INDYCAM_H_
+#define _INDYCAM_H_
+
+/* I2C address for the Guinness Camera */
+#define INDYCAM_ADDR 0x56
+
+/* Camera version */
+#define CAMERA_VERSION_INDY 0x10 /* v1.0 */
+#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */
+#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4)
+#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f)
+
+/* Register bus addresses */
+#define INDYCAM_CONTROL 0x00
+#define INDYCAM_SHUTTER 0x01
+#define INDYCAM_GAIN 0x02
+#define INDYCAM_BRIGHTNESS 0x03 /* read-only */
+#define INDYCAM_RED_BALANCE 0x04
+#define INDYCAM_BLUE_BALANCE 0x05
+#define INDYCAM_RED_SATURATION 0x06
+#define INDYCAM_BLUE_SATURATION 0x07
+#define INDYCAM_GAMMA 0x08
+#define INDYCAM_VERSION 0x0e /* read-only */
+#define INDYCAM_RESET 0x0f /* write-only */
+
+#define INDYCAM_LED 0x46
+#define INDYCAM_ORIENTATION 0x47
+#define INDYCAM_BUTTON 0x48
+
+/* Field definitions of registers */
+#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */
+#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */
+ /* 2-3 are reserved */
+#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */
+
+#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */
+#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */
+#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */
+#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */
+#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */
+#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */
+#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */
+#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */
+#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */
+
+#define INDYCAM_LED_ACTIVE 0x10
+#define INDYCAM_LED_INACTIVE 0x30
+#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40
+#define INDYCAM_BUTTON_RELEASED 0x10
+
+#define INDYCAM_SHUTTER_MIN 0x00
+#define INDYCAM_SHUTTER_MAX 0xff
+#define INDYCAM_GAIN_MIN 0x00
+#define INDYCAM_GAIN_MAX 0xff
+#define INDYCAM_RED_BALANCE_MIN 0x00 /* the effect is the opposite? */
+#define INDYCAM_RED_BALANCE_MAX 0xff
+#define INDYCAM_BLUE_BALANCE_MIN 0x00 /* the effect is the opposite? */
+#define INDYCAM_BLUE_BALANCE_MAX 0xff
+#define INDYCAM_RED_SATURATION_MIN 0x00
+#define INDYCAM_RED_SATURATION_MAX 0xff
+#define INDYCAM_BLUE_SATURATION_MIN 0x00
+#define INDYCAM_BLUE_SATURATION_MAX 0xff
+#define INDYCAM_GAMMA_MIN 0x00
+#define INDYCAM_GAMMA_MAX 0xff
+
+/* Driver interface definitions */
+
+#define INDYCAM_VALUE_ENABLED 1
+#define INDYCAM_VALUE_DISABLED 0
+#define INDYCAM_VALUE_UNCHANGED -1
+
+/* When setting controls, a value of -1 leaves the control unchanged. */
+struct indycam_control {
+ int agc; /* boolean */
+ int awb; /* boolean */
+ int shutter;
+ int gain;
+ int red_balance;
+ int blue_balance;
+ int red_saturation;
+ int blue_saturation;
+ int gamma;
+};
+
+#define DECODER_INDYCAM_GET_CONTROLS _IOR('d', 193, struct indycam_control)
+#define DECODER_INDYCAM_SET_CONTROLS _IOW('d', 194, struct indycam_control)
+
+/* Default values for controls */
+
+#define INDYCAM_AGC_DEFAULT INDYCAM_VALUE_ENABLED
+#define INDYCAM_AWB_DEFAULT INDYCAM_VALUE_ENABLED
+
+#define INDYCAM_SHUTTER_DEFAULT INDYCAM_SHUTTER_60
+#define INDYCAM_GAIN_DEFAULT 0x80
+#define INDYCAM_RED_BALANCE_DEFAULT 0x18
+#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4
+#define INDYCAM_RED_SATURATION_DEFAULT 0x80
+#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0
+#define INDYCAM_GAMMA_DEFAULT 0x80
+
+#endif
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 9fc5055..1e273ff 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -308,7 +308,7 @@
static struct i2c_client client_template =
{
- I2C_DEVNAME("unset"),
+ .name = "unset",
.driver = &driver
};
@@ -429,10 +429,10 @@
struct i2c_client c; char buf; int i,rc;
switch (adap->id) {
- case I2C_ALGO_BIT | I2C_HW_B_BT848:
+ case I2C_HW_B_BT848:
probe = probe_bttv;
break;
- case I2C_ALGO_SAA7134:
+ case I2C_HW_SAA7134:
probe = probe_saa7134;
break;
}
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index fe19401..3f2a882 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
#include "meye.h"
#include <linux/meye.h>
@@ -121,7 +122,7 @@
memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
/* give only 32 bit DMA addresses */
- if (dma_set_mask(&meye.mchip_dev->dev, 0xffffffff))
+ if (dma_set_mask(&meye.mchip_dev->dev, DMA_32BIT_MASK))
return -1;
meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev,
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index 62f1b8d..ca02f6f 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -1416,7 +1416,7 @@
static int msp_probe(struct i2c_adapter *adap);
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
-static int msp_suspend(struct device * dev, u32 state, u32 level);
+static int msp_suspend(struct device * dev, pm_message_t state, u32 level);
static int msp_resume(struct device * dev, u32 level);
static void msp_wake_thread(struct i2c_client *client);
@@ -1437,7 +1437,7 @@
static struct i2c_client client_template =
{
- I2C_DEVNAME("(unset)"),
+ .name = "(unset)",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
@@ -1509,7 +1509,7 @@
}
/* hello world :-) */
- printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c));
+ printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
if (HAVE_NICAM(msp))
printk(" +nicam");
if (HAVE_SIMPLE(msp))
@@ -1817,7 +1817,7 @@
return 0;
}
-static int msp_suspend(struct device * dev, u32 state, u32 level)
+static int msp_suspend(struct device * dev, pm_message_t state, u32 level)
{
struct i2c_client *c = container_of(dev, struct i2c_client, dev);
diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c
index 3433619..b3f4d26 100644
--- a/drivers/media/video/ovcamchip/ov6x20.c
+++ b/drivers/media/video/ovcamchip/ov6x20.c
@@ -164,10 +164,10 @@
DDEBUG(4, &c->dev, "entered");
switch (c->adapter->id) {
- case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511:
+ case I2C_HW_SMBUS_OV511:
rc = ov_write_regvals(c, regvals_init_6x20_511);
break;
- case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518:
+ case I2C_HW_SMBUS_OV518:
rc = ov_write_regvals(c, regvals_init_6x20_518);
break;
default:
@@ -338,7 +338,7 @@
/******** Palette-specific regs ********/
/* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
- if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
+ if (c->adapter->id == I2C_HW_SMBUS_OV518) {
if (win->format == VIDEO_PALETTE_GREY)
ov_write_mask(c, 0x13, 0x00, 0x20);
else
diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c
index 44a8423..6eab458 100644
--- a/drivers/media/video/ovcamchip/ov6x30.c
+++ b/drivers/media/video/ovcamchip/ov6x30.c
@@ -301,7 +301,7 @@
/******** Palette-specific regs ********/
if (win->format == VIDEO_PALETTE_GREY) {
- if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
+ if (c->adapter->id == I2C_HW_SMBUS_OV518) {
/* Do nothing - we're already in 8-bit mode */
} else {
ov_write_mask(c, 0x13, 0x20, 0x20);
@@ -313,7 +313,7 @@
* Therefore, the OV6630 needs to be in 8-bit multiplexed
* output mode */
- if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
+ if (c->adapter->id == I2C_HW_SMBUS_OV518) {
/* Do nothing - we want to stay in 8-bit mode */
/* Warning: Messing with reg 0x13 breaks OV518 color */
} else {
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 54dd561..2de34eb 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -296,10 +296,10 @@
* attach to adapters that are known to contain OV camera chips. */
switch (adap->id) {
- case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511):
- case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518):
- case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OVFX2):
- case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF):
+ case I2C_HW_SMBUS_OV511:
+ case I2C_HW_SMBUS_OV518:
+ case I2C_HW_SMBUS_OVFX2:
+ case I2C_HW_SMBUS_W9968CF:
PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
break;
default:
@@ -314,7 +314,7 @@
}
memcpy(c, &client_template, sizeof *c);
c->adapter = adap;
- strcpy(i2c_clientname(c), "OV????");
+ strcpy(c->name, "OV????");
ov = kmalloc(sizeof *ov, GFP_KERNEL);
if (!ov) {
@@ -328,7 +328,7 @@
if (rc < 0)
goto error;
- strcpy(i2c_clientname(c), chip_names[ov->subtype]);
+ strcpy(c->name, chip_names[ov->subtype]);
PDEBUG(1, "Camera chip detection complete");
@@ -421,7 +421,7 @@
};
static struct i2c_client client_template = {
- I2C_DEVNAME("(unset)"),
+ .name = "(unset)",
.driver = &driver,
};
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 22d055d..e116bdb 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -470,7 +470,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7110;
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index fcd8973..fe8a5e4 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -42,7 +42,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -489,7 +488,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7111;
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 2ba997f..d9f50e2 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -45,7 +45,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -827,7 +826,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7114;
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 79d05ea..382911c 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -598,7 +598,7 @@
static struct i2c_client client_template =
{
- I2C_DEVNAME("saa6752hs"),
+ .name = "saa6752hs",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 1203b93..eae6b52 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -334,7 +334,7 @@
struct tuner_setup tun_setup;
d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
- client->driver->name,client->addr,i2c_clientname(client));
+ client->driver->name, client->addr, client->name);
if (!client->driver->command)
return 0;
@@ -370,8 +370,6 @@
}
static struct i2c_algorithm saa7134_algo = {
- .name = "saa7134",
- .id = I2C_ALGO_SAA7134,
.master_xfer = saa7134_i2c_xfer,
.algo_control = algo_control,
.functionality = functionality,
@@ -382,14 +380,14 @@
#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
#endif
- I2C_DEVNAME("saa7134"),
- .id = I2C_ALGO_SAA7134,
+ .name = "saa7134",
+ .id = I2C_HW_SAA7134,
.algo = &saa7134_algo,
.client_register = attach_inform,
};
static struct i2c_client saa7134_client_template = {
- I2C_DEVNAME("saa7134 internal"),
+ .name = "saa7134 internal",
};
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 108e7a4..132aa79 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -39,7 +39,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/videodev.h>
@@ -387,7 +386,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7185;
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
new file mode 100644
index 0000000..454f5c1
--- /dev/null
+++ b/drivers/media/video/saa7191.c
@@ -0,0 +1,512 @@
+/*
+ * saa7191.c - Philips SAA7191 video decoder driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include "saa7191.h"
+
+#define SAA7191_MODULE_VERSION "0.0.3"
+
+MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
+MODULE_VERSION(SAA7191_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO)
+
+struct saa7191 {
+ struct i2c_client *client;
+
+ /* the register values are stored here as the actual
+ * I2C-registers are write-only */
+ unsigned char reg[25];
+
+ unsigned char norm;
+ unsigned char input;
+};
+
+static struct i2c_driver i2c_driver_saa7191;
+
+static const unsigned char initseq[] = {
+ 0, /* Subaddress */
+ 0x50, /* SAA7191_REG_IDEL */
+ 0x30, /* SAA7191_REG_HSYB */
+ 0x00, /* SAA7191_REG_HSYS */
+ 0xe8, /* SAA7191_REG_HCLB */
+ 0xb6, /* SAA7191_REG_HCLS */
+ 0xf4, /* SAA7191_REG_HPHI */
+ 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */
+ 0x00, /* SAA7191_REG_HUEC */
+ 0xf8, /* SAA7191_REG_CKTQ */
+ 0xf8, /* SAA7191_REG_CKTS */
+ 0x90, /* SAA7191_REG_PLSE */
+ 0x90, /* SAA7191_REG_SESE */
+ 0x00, /* SAA7191_REG_GAIN */
+ 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */
+ 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */
+ 0x99, /* SAA7191_REG_CTL3 - automatic field detection */
+ 0x00, /* SAA7191_REG_CTL4 */
+ 0x2c, /* SAA7191_REG_CHCV */
+ 0x00, /* unused */
+ 0x00, /* unused */
+ 0x34, /* SAA7191_REG_HS6B */
+ 0x0a, /* SAA7191_REG_HS6S */
+ 0xf4, /* SAA7191_REG_HC6B */
+ 0xce, /* SAA7191_REG_HC6S */
+ 0xf4, /* SAA7191_REG_HP6I */
+};
+
+/* SAA7191 register handling */
+
+static unsigned char saa7191_read_reg(struct i2c_client *client,
+ unsigned char reg)
+{
+ return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
+}
+
+static int saa7191_read_status(struct i2c_client *client,
+ unsigned char *value)
+{
+ int ret;
+
+ ret = i2c_master_recv(client, value, 1);
+ if (ret < 0) {
+ printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int saa7191_write_reg(struct i2c_client *client, unsigned char reg,
+ unsigned char value)
+{
+
+ ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* the first byte of data must be the first subaddress number (register) */
+static int saa7191_write_block(struct i2c_client *client,
+ unsigned char length, unsigned char *data)
+{
+ int i;
+ int ret;
+
+ struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
+ for (i = 0; i < (length - 1); i++) {
+ decoder->reg[data[0] + i] = data[i + 1];
+ }
+
+ ret = i2c_master_send(client, data, length);
+ if (ret < 0) {
+ printk(KERN_ERR "SAA7191: saa7191_write_block(): "
+ "write failed");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Helper functions */
+
+static int saa7191_set_input(struct i2c_client *client, int input)
+{
+ unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
+ unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
+ int err;
+
+ switch (input) {
+ case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
+ iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
+ | SAA7191_IOCK_GPSW2);
+ /* Chrominance trap active */
+ luma &= ~SAA7191_LUMA_BYPS;
+ break;
+ case SAA7191_INPUT_SVIDEO: /* Set S-Video input */
+ iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2;
+ /* Chrominance trap bypassed */
+ luma |= SAA7191_LUMA_BYPS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
+ if (err)
+ return -EIO;
+ err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
+ if (err)
+ return -EIO;
+
+ return 0;
+}
+
+static int saa7191_set_norm(struct i2c_client *client, int norm)
+{
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+ unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+ unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+ unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
+ int err;
+
+ switch(norm) {
+ case SAA7191_NORM_AUTO: {
+ unsigned char status;
+
+ // does status depend on current norm ?
+ if (saa7191_read_status(client, &status))
+ return -EIO;
+
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~SAA7191_CTL3_FSEL;
+ ctl3 |= SAA7191_CTL3_AUFD;
+ chcv = (status & SAA7191_STATUS_FIDT)
+ ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL;
+ break;
+ }
+ case SAA7191_NORM_PAL:
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+ chcv = SAA7191_CHCV_PAL;
+ break;
+ case SAA7191_NORM_NTSC:
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~SAA7191_CTL3_AUFD;
+ ctl3 |= SAA7191_CTL3_FSEL;
+ chcv = SAA7191_CHCV_NTSC;
+ break;
+ case SAA7191_NORM_SECAM:
+ stdc |= SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+ chcv = SAA7191_CHCV_PAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+ if (err)
+ return -EIO;
+ err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ if (err)
+ return -EIO;
+ err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
+ if (err)
+ return -EIO;
+
+ decoder->norm = norm;
+
+ return 0;
+}
+
+static int saa7191_get_controls(struct i2c_client *client,
+ struct saa7191_control *ctrl)
+{
+ unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC);
+ unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+
+ if (hue < 0x80) {
+ hue += 0x80;
+ } else {
+ hue -= 0x80;
+ }
+ ctrl->hue = hue;
+
+ ctrl->vtrc = (stdc & SAA7191_STDC_VTRC)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+
+ return 0;
+}
+
+static int saa7191_set_controls(struct i2c_client *client,
+ struct saa7191_control *ctrl)
+{
+ int err;
+
+ if (ctrl->hue >= 0) {
+ unsigned char hue = ctrl->hue & 0xff;
+ if (hue < 0x80) {
+ hue += 0x80;
+ } else {
+ hue -= 0x80;
+ }
+ err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue);
+ if (err)
+ return -EIO;
+ }
+ if (ctrl->vtrc >= 0) {
+ unsigned char stdc =
+ saa7191_read_reg(client, SAA7191_REG_STDC);
+
+ if (ctrl->vtrc) {
+ stdc |= SAA7191_STDC_VTRC;
+ } else {
+ stdc &= ~SAA7191_STDC_VTRC;
+ }
+
+ err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
+ if (err)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* I2C-interface */
+
+static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ int err = 0;
+ struct saa7191 *decoder;
+ struct i2c_client *client;
+
+ printk(KERN_INFO "Philips SAA7191 driver version %s\n",
+ SAA7191_MODULE_VERSION);
+
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder) {
+ err = -ENOMEM;
+ goto out_free_client;
+ }
+
+ memset(client, 0, sizeof(struct i2c_client));
+ memset(decoder, 0, sizeof(struct saa7191));
+
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &i2c_driver_saa7191;
+ client->flags = 0;
+ strcpy(client->name, "saa7191 client");
+ i2c_set_clientdata(client, decoder);
+
+ decoder->client = client;
+
+ err = i2c_attach_client(client);
+ if (err)
+ goto out_free_decoder;
+
+ decoder->input = SAA7191_INPUT_COMPOSITE;
+ decoder->norm = SAA7191_NORM_AUTO;
+
+ err = saa7191_write_block(client, sizeof(initseq),
+ (unsigned char *)initseq);
+ if (err) {
+ printk(KERN_ERR "SAA7191 initialization failed\n");
+ goto out_detach_client;
+ }
+
+ printk(KERN_INFO "SAA7191 initialized\n");
+
+ return 0;
+
+out_detach_client:
+ i2c_detach_client(client);
+out_free_decoder:
+ kfree(decoder);
+out_free_client:
+ kfree(client);
+ return err;
+}
+
+static int saa7191_probe(struct i2c_adapter *adap)
+{
+ /* Always connected to VINO */
+ if (adap->id == VINO_ADAPTER)
+ return saa7191_attach(adap, SAA7191_ADDR, 0);
+ /* Feel free to add probe here :-) */
+ return -ENODEV;
+}
+
+static int saa7191_detach(struct i2c_client *client)
+{
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(decoder);
+ kfree(client);
+ return 0;
+}
+
+static int saa7191_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct saa7191 *decoder = i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case DECODER_GET_CAPABILITIES: {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
+ cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS: {
+ int *iarg = arg;
+ unsigned char status;
+ int res = 0;
+
+ if (saa7191_read_status(client, &status)) {
+ return -EIO;
+ }
+ if ((status & SAA7191_STATUS_HLCK) == 0)
+ res |= DECODER_STATUS_GOOD;
+ if (status & SAA7191_STATUS_CODE)
+ res |= DECODER_STATUS_COLOR;
+ switch (decoder->norm) {
+ case SAA7191_NORM_NTSC:
+ res |= DECODER_STATUS_NTSC;
+ break;
+ case SAA7191_NORM_PAL:
+ res |= DECODER_STATUS_PAL;
+ break;
+ case SAA7191_NORM_SECAM:
+ res |= DECODER_STATUS_SECAM;
+ break;
+ case SAA7191_NORM_AUTO:
+ default:
+ if (status & SAA7191_STATUS_FIDT)
+ res |= DECODER_STATUS_NTSC;
+ else
+ res |= DECODER_STATUS_PAL;
+ break;
+ }
+ *iarg = res;
+ break;
+ }
+ case DECODER_SET_NORM: {
+ int *iarg = arg;
+
+ switch (*iarg) {
+ case VIDEO_MODE_AUTO:
+ return saa7191_set_norm(client, SAA7191_NORM_AUTO);
+ case VIDEO_MODE_PAL:
+ return saa7191_set_norm(client, SAA7191_NORM_PAL);
+ case VIDEO_MODE_NTSC:
+ return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+ case VIDEO_MODE_SECAM:
+ return saa7191_set_norm(client, SAA7191_NORM_SECAM);
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_INPUT: {
+ int *iarg = arg;
+
+ switch (client->adapter->id) {
+ case VINO_ADAPTER:
+ return saa7191_set_input(client, *iarg);
+ default:
+ if (*iarg != 0)
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_SET_OUTPUT: {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0)
+ return -EINVAL;
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT: {
+ /* Always enabled */
+ break;
+ }
+ case DECODER_SET_PICTURE: {
+ struct video_picture *pic = arg;
+ unsigned val;
+ int err;
+
+ val = (pic->hue >> 8) - 0x80;
+ err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
+ if (err)
+ return -EIO;
+ break;
+ }
+ case DECODER_SAA7191_GET_STATUS: {
+ struct saa7191_status *status = arg;
+ unsigned char status_reg;
+
+ if (saa7191_read_status(client, &status_reg))
+ return -EIO;
+ status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+ status->ntsc = (status_reg & SAA7191_STATUS_FIDT)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+ status->color = (status_reg & SAA7191_STATUS_CODE)
+ ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED;
+
+ status->input = decoder->input;
+ status->norm = decoder->norm;
+ }
+ case DECODER_SAA7191_SET_NORM: {
+ int *norm = arg;
+ return saa7191_set_norm(client, *norm);
+ }
+ case DECODER_SAA7191_GET_CONTROLS: {
+ struct saa7191_control *ctrl = arg;
+ return saa7191_get_controls(client, ctrl);
+ }
+ case DECODER_SAA7191_SET_CONTROLS: {
+ struct saa7191_control *ctrl = arg;
+ return saa7191_set_controls(client, ctrl);
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver i2c_driver_saa7191 = {
+ .owner = THIS_MODULE,
+ .name = "saa7191",
+ .id = I2C_DRIVERID_SAA7191,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7191_probe,
+ .detach_client = saa7191_detach,
+ .command = saa7191_command
+};
+
+static int saa7191_init(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7191);
+}
+
+static void saa7191_exit(void)
+{
+ i2c_del_driver(&i2c_driver_saa7191);
+}
+
+module_init(saa7191_init);
+module_exit(saa7191_exit);
diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h
new file mode 100644
index 0000000..2720450
--- /dev/null
+++ b/drivers/media/video/saa7191.h
@@ -0,0 +1,139 @@
+/*
+ * saa7191.h - Philips SAA7191 video decoder driver
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * 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 _SAA7191_H_
+#define _SAA7191_H_
+
+/* Philips SAA7191 DMSD I2C bus address */
+#define SAA7191_ADDR 0x8a
+
+/* Register subaddresses. */
+#define SAA7191_REG_IDEL 0x00
+#define SAA7191_REG_HSYB 0x01
+#define SAA7191_REG_HSYS 0x02
+#define SAA7191_REG_HCLB 0x03
+#define SAA7191_REG_HCLS 0x04
+#define SAA7191_REG_HPHI 0x05
+#define SAA7191_REG_LUMA 0x06
+#define SAA7191_REG_HUEC 0x07
+#define SAA7191_REG_CKTQ 0x08
+#define SAA7191_REG_CKTS 0x09
+#define SAA7191_REG_PLSE 0x0a
+#define SAA7191_REG_SESE 0x0b
+#define SAA7191_REG_GAIN 0x0c
+#define SAA7191_REG_STDC 0x0d
+#define SAA7191_REG_IOCK 0x0e
+#define SAA7191_REG_CTL3 0x0f
+#define SAA7191_REG_CTL4 0x10
+#define SAA7191_REG_CHCV 0x11
+#define SAA7191_REG_HS6B 0x14
+#define SAA7191_REG_HS6S 0x15
+#define SAA7191_REG_HC6B 0x16
+#define SAA7191_REG_HC6S 0x17
+#define SAA7191_REG_HP6I 0x18
+#define SAA7191_REG_STATUS 0xff /* not really a subaddress */
+
+/* Status Register definitions */
+#define SAA7191_STATUS_CODE 0x01 /* color detected flag */
+#define SAA7191_STATUS_FIDT 0x20 /* format type NTSC/PAL */
+#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked/locked */
+#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */
+
+/* Luminance Control Register definitions */
+#define SAA7191_LUMA_BYPS 0x80
+
+/* Chroma Gain Control Settings Register definitions */
+/* 0=automatic colour-killer enabled, 1=forced colour on */
+#define SAA7191_GAIN_COLO 0x80
+
+/* Standard/Mode Control Register definitions */
+/* tv/vtr mode bit: 0=TV mode (slow time constant),
+ * 1=VTR mode (fast time constant) */
+#define SAA7191_STDC_VTRC 0x80
+/* SECAM mode bit: 0=other standards, 1=SECAM */
+#define SAA7191_STDC_SECS 0x01
+/* the bit fields above must be or'd with this value */
+#define SAA7191_STDC_VALUE 0x0c
+
+/* I/O and Clock Control Register definitions */
+/* horizontal clock PLL: 0=PLL closed,
+ * 1=PLL circuit open and horizontal freq fixed */
+#define SAA7191_IOCK_HPLL 0x80
+/* S-VHS bit (chrominance from CVBS or from chrominance input):
+ * 0=controlled by BYPS-bit, 1=from chrominance input */
+#define SAA7191_IOCK_CHRS 0x04
+/* general purpose switch 2
+ * VINO-specific: 0=used with CVBS, 1=used with S-Video */
+#define SAA7191_IOCK_GPSW2 0x02
+/* general purpose switch 1 */
+/* VINO-specific: 0=always, 1=not used!*/
+#define SAA7191_IOCK_GPSW1 0x01
+
+/* Miscellaneous Control #1 Register definitions */
+/* automatic field detection (50/60Hz standard) */
+#define SAA7191_CTL3_AUFD 0x80
+/* field select: (if AUFD=0)
+ * 0=50Hz (625 lines), 1=60Hz (525 lines) */
+#define SAA7191_CTL3_FSEL 0x40
+/* the bit fields above must be or'd with this value */
+#define SAA7191_CTL3_VALUE 0x19
+
+/* Chrominance Gain Control Register definitions
+ * (nominal value for UV CCIR level) */
+#define SAA7191_CHCV_NTSC 0x2c
+#define SAA7191_CHCV_PAL 0x59
+
+/* Driver interface definitions */
+#define SAA7191_INPUT_COMPOSITE 0
+#define SAA7191_INPUT_SVIDEO 1
+
+#define SAA7191_NORM_AUTO 0
+#define SAA7191_NORM_PAL 1
+#define SAA7191_NORM_NTSC 2
+#define SAA7191_NORM_SECAM 3
+
+#define SAA7191_VALUE_ENABLED 1
+#define SAA7191_VALUE_DISABLED 0
+#define SAA7191_VALUE_UNCHANGED -1
+
+struct saa7191_status {
+ /* 0=no signal, 1=signal active*/
+ int signal;
+ /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */
+ int ntsc;
+ /* 0=no color detected, 1=color detected */
+ int color;
+
+ /* current SAA7191_INPUT_ */
+ int input;
+ /* current SAA7191_NORM_ */
+ int norm;
+};
+
+#define SAA7191_HUE_MIN 0x00
+#define SAA7191_HUE_MAX 0xff
+#define SAA7191_HUE_DEFAULT 0x80
+
+#define SAA7191_VTRC_MIN 0x00
+#define SAA7191_VTRC_MAX 0x01
+#define SAA7191_VTRC_DEFAULT 0x00
+
+struct saa7191_control {
+ int hue;
+ int vtrc;
+};
+
+#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
+#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
+#define DECODER_SAA7191_GET_CONTROLS _IOR('d', 197, struct saa7191_control)
+#define DECODER_SAA7191_SET_CONTROLS _IOW('d', 198, struct saa7191_control)
+
+#endif
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 7cb1fb3..255b608 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -328,7 +328,7 @@
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda7432_attach);
#else
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ if (adap->id == I2C_HW_B_BT848)
return i2c_probe(adap, &addr_data, tda7432_attach);
#endif
return 0;
@@ -513,7 +513,7 @@
static struct i2c_client client_template =
{
- I2C_DEVNAME("tda7432"),
+ .name = "tda7432",
.driver = &driver,
};
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index c29bdfc..1794686 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -205,7 +205,7 @@
static int attach(struct i2c_adapter *adapter)
{
/* let's see whether this is a know adapter we can attach to */
- if (adapter->id != I2C_ALGO_SAA7146) {
+ if (adapter->id != I2C_HW_SAA7146) {
dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
return -ENODEV;
}
@@ -231,7 +231,7 @@
};
static struct i2c_client client_template = {
- I2C_DEVNAME("tda9840"),
+ .name = "tda9840",
.driver = &driver,
};
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 566e1a5..7e3dcdb 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -262,7 +262,7 @@
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda9875_attach);
#else
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ if (adap->id == I2C_HW_B_BT848)
return i2c_probe(adap, &addr_data, tda9875_attach);
#endif
return 0;
@@ -384,7 +384,7 @@
static struct i2c_client client_template =
{
- I2C_DEVNAME("tda9875"),
+ .name = "tda9875",
.driver = &driver,
};
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 108c3ad..d60fc56 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -618,9 +618,9 @@
return i2c_probe(adap, &addr_data, tda9887_attach);
#else
switch (adap->id) {
- case I2C_ALGO_BIT | I2C_HW_B_BT848:
- case I2C_ALGO_BIT | I2C_HW_B_RIVA:
- case I2C_ALGO_SAA7134:
+ case I2C_HW_B_BT848:
+ case I2C_HW_B_RIVA:
+ case I2C_HW_SAA7134:
return i2c_probe(adap, &addr_data, tda9887_attach);
break;
}
@@ -760,7 +760,7 @@
return 0;
}
-static int tda9887_suspend(struct device * dev, u32 state, u32 level)
+static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level)
{
dprintk("tda9887: suspend\n");
return 0;
@@ -793,7 +793,7 @@
};
static struct i2c_client client_template =
{
- I2C_DEVNAME("tda9887"),
+ .name = "tda9887",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index b44db8a..ee36883 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -86,7 +86,7 @@
static int attach(struct i2c_adapter *adapter)
{
/* let's see whether this is a know adapter we can attach to */
- if (adapter->id != I2C_ALGO_SAA7146) {
+ if (adapter->id != I2C_HW_SAA7146) {
dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
return -ENODEV;
}
@@ -200,7 +200,7 @@
};
static struct i2c_client client_template = {
- I2C_DEVNAME("tea6415c"),
+ .name = "tea6415c",
.driver = &driver,
};
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 48d4db7..17975c1 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -135,7 +135,7 @@
static int attach(struct i2c_adapter *adapter)
{
/* let's see whether this is a know adapter we can attach to */
- if (adapter->id != I2C_ALGO_SAA7146) {
+ if (adapter->id != I2C_HW_SAA7146) {
dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
return -ENODEV;
}
@@ -177,7 +177,7 @@
};
static struct i2c_client client_template = {
- I2C_DEVNAME("tea6420"),
+ .name = "tea6420",
.driver = &driver,
};
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
index 7d825e5..7920359 100644
--- a/drivers/media/video/tuner-3036.c
+++ b/drivers/media/video/tuner-3036.c
@@ -41,7 +41,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
/* ---------------------------------------------------------------------- */
@@ -166,7 +165,7 @@
tuner_probe(struct i2c_adapter *adap)
{
this_adap = 0;
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_LP))
+ if (adap->id == I2C_HW_B_LP)
return i2c_probe(adap, &addr_data, tuner_attach);
return 0;
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index f0a5798..3b1893c 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -672,7 +672,7 @@
return 0;
}
-static int tuner_suspend(struct device *dev, u32 state, u32 level)
+static int tuner_suspend(struct device *dev, pm_message_t state, u32 level)
{
struct i2c_client *c = container_of (dev, struct i2c_client, dev);
struct tuner *t = i2c_get_clientdata (c);
@@ -709,7 +709,7 @@
},
};
static struct i2c_client client_template = {
- I2C_DEVNAME("(tuner unset)"),
+ .name = "(tuner unset)",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index f42a1ef..258724b 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -162,24 +162,23 @@
unsigned char buffer[2];
if (-1 == subaddr) {
- dprintk("%s: chip_write: 0x%x\n",
- i2c_clientname(&chip->c), val);
+ dprintk("%s: chip_write: 0x%x\n", chip->c.name, val);
chip->shadow.bytes[1] = val;
buffer[0] = val;
if (1 != i2c_master_send(&chip->c,buffer,1)) {
printk(KERN_WARNING "%s: I/O error (write 0x%x)\n",
- i2c_clientname(&chip->c), val);
+ chip->c.name, val);
return -1;
}
} else {
dprintk("%s: chip_write: reg%d=0x%x\n",
- i2c_clientname(&chip->c), subaddr, val);
+ chip->c.name, subaddr, val);
chip->shadow.bytes[subaddr+1] = val;
buffer[0] = subaddr;
buffer[1] = val;
if (2 != i2c_master_send(&chip->c,buffer,2)) {
printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n",
- i2c_clientname(&chip->c), subaddr, val);
+ chip->c.name, subaddr, val);
return -1;
}
}
@@ -203,11 +202,10 @@
unsigned char buffer;
if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
- printk(KERN_WARNING "%s: I/O error (read)\n",
- i2c_clientname(&chip->c));
+ printk(KERN_WARNING "%s: I/O error (read)\n", chip->c.name);
return -1;
}
- dprintk("%s: chip_read: 0x%x\n",i2c_clientname(&chip->c),buffer);
+ dprintk("%s: chip_read: 0x%x\n", chip->c.name, buffer);
return buffer;
}
@@ -222,12 +220,11 @@
write[0] = subaddr;
if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
- printk(KERN_WARNING "%s: I/O error (read2)\n",
- i2c_clientname(&chip->c));
+ printk(KERN_WARNING "%s: I/O error (read2)\n", chip->c.name);
return -1;
}
dprintk("%s: chip_read2: reg%d=0x%x\n",
- i2c_clientname(&chip->c),subaddr,read[0]);
+ chip->c.name, subaddr, read[0]);
return read[0];
}
@@ -240,7 +237,7 @@
/* update our shadow register set; print bytes if (debug > 0) */
dprintk("%s: chip_cmd(%s): reg=%d, data:",
- i2c_clientname(&chip->c),name,cmd->bytes[0]);
+ chip->c.name, name, cmd->bytes[0]);
for (i = 1; i < cmd->count; i++) {
dprintk(" 0x%x",cmd->bytes[i]);
chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
@@ -249,7 +246,7 @@
/* send data to the chip */
if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
- printk(KERN_WARNING "%s: I/O error (%s)\n", i2c_clientname(&chip->c), name);
+ printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.name, name);
return -1;
}
return 0;
@@ -274,9 +271,9 @@
struct CHIPSTATE *chip = data;
struct CHIPDESC *desc = chiplist + chip->type;
- daemonize("%s",i2c_clientname(&chip->c));
+ daemonize("%s", chip->c.name);
allow_signal(SIGTERM);
- dprintk("%s: thread started\n", i2c_clientname(&chip->c));
+ dprintk("%s: thread started\n", chip->c.name);
for (;;) {
add_wait_queue(&chip->wq, &wait);
@@ -288,7 +285,7 @@
try_to_freeze();
if (chip->done || signal_pending(current))
break;
- dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
+ dprintk("%s: thread wakeup\n", chip->c.name);
/* don't do anything for radio or if mode != auto */
if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0)
@@ -301,7 +298,7 @@
mod_timer(&chip->wt, jiffies+2*HZ);
}
- dprintk("%s: thread exiting\n", i2c_clientname(&chip->c));
+ dprintk("%s: thread exiting\n", chip->c.name);
complete_and_exit(&chip->texit, 0);
return 0;
}
@@ -314,7 +311,7 @@
if (mode == chip->prevmode)
return;
- dprintk("%s: thread checkmode\n", i2c_clientname(&chip->c));
+ dprintk("%s: thread checkmode\n", chip->c.name);
chip->prevmode = mode;
if (mode & VIDEO_SOUND_STEREO)
@@ -1098,7 +1095,7 @@
/* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF,
/* off */ TDA8425_S1_OFF, /* on */ TDA8425_S1_CH2};
- if (chip->c.adapter->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) {
+ if (chip->c.adapter->id == I2C_HW_B_RIVA) {
memcpy (desc->inputmap, inputmap, sizeof (inputmap));
}
return 0;
@@ -1501,7 +1498,7 @@
(desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : "");
/* fill required data structures */
- strcpy(i2c_clientname(&chip->c),desc->name);
+ strcpy(chip->c.name, desc->name);
chip->type = desc-chiplist;
chip->shadow.count = desc->registers+1;
chip->prevmode = -1;
@@ -1538,7 +1535,7 @@
chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
if (chip->tpid < 0)
printk(KERN_WARNING "%s: kernel_thread() failed\n",
- i2c_clientname(&chip->c));
+ chip->c.name);
wake_up_interruptible(&chip->wq);
}
return 0;
@@ -1548,16 +1545,16 @@
{
/* don't attach on saa7146 based cards,
because dedicated drivers are used */
- if ((adap->id & I2C_ALGO_SAA7146))
+ if (adap->id == I2C_HW_SAA7146)
return 0;
#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, chip_attach);
#else
switch (adap->id) {
- case I2C_ALGO_BIT | I2C_HW_B_BT848:
- case I2C_ALGO_BIT | I2C_HW_B_RIVA:
- case I2C_ALGO_SAA7134:
+ case I2C_HW_B_BT848:
+ case I2C_HW_B_RIVA:
+ case I2C_HW_SAA7134:
return i2c_probe(adap, &addr_data, chip_attach);
}
#endif
@@ -1591,7 +1588,7 @@
struct CHIPSTATE *chip = i2c_get_clientdata(client);
struct CHIPDESC *desc = chiplist + chip->type;
- dprintk("%s: chip_command 0x%x\n",i2c_clientname(&chip->c),cmd);
+ dprintk("%s: chip_command 0x%x\n", chip->c.name, cmd);
switch (cmd) {
case AUDC_SET_INPUT:
@@ -1702,7 +1699,7 @@
static struct i2c_client client_template =
{
- I2C_DEVNAME("(unset)"),
+ .name = "(unset)",
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 127ec38..3c3356a 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -534,7 +534,7 @@
tveeprom_attach_adapter (struct i2c_adapter *adapter)
{
dprintk(1,"%s: id 0x%x\n",__FUNCTION__,adapter->id);
- if (adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ if (adapter->id != I2C_HW_B_BT848)
return 0;
return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
}
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 51b99cd..a43301a 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -91,7 +91,7 @@
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, i2c_clientname(client), sizeof(info.name));
+ strlcpy(info.name, client->name, sizeof(info.name));
info.modify_counter = 42 /* FIXME */;
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
@@ -100,7 +100,7 @@
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, i2c_clientname(client), sizeof(info.name));
+ strlcpy(info.name, client->name, sizeof(info.name));
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
return 0;
@@ -276,9 +276,9 @@
#else
/* TV card ??? */
switch (client->adapter->id) {
- case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3:
- case I2C_ALGO_BIT | I2C_HW_B_BT848:
- case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+ case I2C_HW_SMBUS_VOODOO3:
+ case I2C_HW_B_BT848:
+ case I2C_HW_B_RIVA:
/* ok, have a look ... */
break;
default:
@@ -295,7 +295,7 @@
devices[i].dev = NULL;
devices[i].minor = -1;
printk("tvmixer: %s unregistered (#1)\n",
- i2c_clientname(client));
+ client->name);
return 0;
}
}
@@ -354,7 +354,7 @@
if (devices[i].minor != -1) {
unregister_sound_mixer(devices[i].minor);
printk("tvmixer: %s unregistered (#2)\n",
- i2c_clientname(devices[i].dev));
+ devices[i].dev->name);
}
}
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 76e8681..d8a0f76 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -1,80 +1,606 @@
/*
- * (incomplete) Driver for the VINO (Video In No Out) system found in SGI Indys.
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
*
* This file is subject to the terms and conditions of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
+ * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
+ *
+ * Based on the previous version of the driver for 2.4 kernels by:
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
*/
-#include <linux/module.h>
+/*
+ * TODO:
+ * - remove "hacks" from memory allocation code and implement nopage()
+ * - check decimation, calculating and reporting image size when
+ * using decimation
+ * - check vino_acquire_input(), vino_set_input() and channel
+ * ownership handling
+ * - report VINO error-interrupts via ioctls ?
+ * - implement picture controls (all implemented?)
+ * - use macros for boolean values (?)
+ * - implement user mode buffers and overlay (?)
+ */
+
#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/wrapper.h>
-#include <linux/errno.h>
-#include <linux/irq.h>
+#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/time.h>
+#include <linux/moduleparam.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
#include <linux/i2c.h>
#include <linux/i2c-algo-sgi.h>
-#include <asm/addrspace.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-#include <asm/pgtable.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/video_decoder.h>
+
#include <asm/paccess.h>
#include <asm/io.h>
#include <asm/sgi/ip22.h>
-#include <asm/sgi/hpc3.h>
#include <asm/sgi/mc.h>
#include "vino.h"
+#include "saa7191.h"
+#include "indycam.h"
-/* debugging? */
-#if 1
-#define DEBUG(x...) printk(x);
+/* Uncomment the following line to get lots and lots of (mostly useless)
+ * debug info.
+ * Note that the debug output also slows down the driver significantly */
+// #define VINO_DEBUG
+
+#define VINO_MODULE_VERSION "0.0.3"
+#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 3)
+
+MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
+MODULE_VERSION(VINO_MODULE_VERSION);
+MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+MODULE_LICENSE("GPL");
+
+#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
+#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))
+
+#ifdef VINO_DEBUG
+#define dprintk(x...) printk("VINO: " x);
#else
-#define DEBUG(x...)
+#define dprintk(x...)
#endif
+#define VINO_NO_CHANNEL 0
+#define VINO_CHANNEL_A 1
+#define VINO_CHANNEL_B 2
-/* VINO ASIC registers */
-struct sgi_vino *vino;
+#define VINO_PAL_WIDTH 768
+#define VINO_PAL_HEIGHT 576
+#define VINO_NTSC_WIDTH 640
+#define VINO_NTSC_HEIGHT 480
-static const char *vinostr = "VINO IndyCam/TV";
-static int threshold_a = 512;
-static int threshold_b = 512;
+#define VINO_MIN_WIDTH 32
+#define VINO_MIN_HEIGHT 32
-struct vino_device {
- struct video_device vdev;
-#define VINO_CHAN_A 1
-#define VINO_CHAN_B 2
- int chan;
+#define VINO_CLIPPING_START_ODD_D1 1
+#define VINO_CLIPPING_START_ODD_PAL 1
+#define VINO_CLIPPING_START_ODD_NTSC 1
+
+#define VINO_CLIPPING_START_EVEN_D1 2
+#define VINO_CLIPPING_START_EVEN_PAL 2
+#define VINO_CLIPPING_START_EVEN_NTSC 2
+
+#define VINO_INPUT_CHANNEL_COUNT 3
+
+#define VINO_INPUT_NONE -1
+#define VINO_INPUT_COMPOSITE 0
+#define VINO_INPUT_SVIDEO 1
+#define VINO_INPUT_D1 2
+
+#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE)
+
+#define VINO_FIFO_THRESHOLD_DEFAULT 512
+
+/*#define VINO_FRAMEBUFFER_SIZE (VINO_PAL_WIDTH * VINO_PAL_HEIGHT * 4 \
+ + 2 * PAGE_SIZE)*/
+#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \
+ * VINO_PAL_HEIGHT * 4 \
+ + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))
+
+#define VINO_FRAMEBUFFER_MAX_COUNT 8
+
+#define VINO_FRAMEBUFFER_UNUSED 0
+#define VINO_FRAMEBUFFER_IN_USE 1
+#define VINO_FRAMEBUFFER_READY 2
+
+#define VINO_QUEUE_ERROR -1
+#define VINO_QUEUE_MAGIC 0x20050125
+
+#define VINO_MEMORY_NONE 0
+#define VINO_MEMORY_MMAP 1
+#define VINO_MEMORY_USERPTR 2
+
+#define VINO_DUMMY_DESC_COUNT 4
+#define VINO_DESC_FETCH_DELAY 5 /* microseconds */
+
+/* the number is the index for vino_data_formats */
+#define VINO_DATA_FMT_NONE -1
+#define VINO_DATA_FMT_GREY 0
+#define VINO_DATA_FMT_RGB332 1
+#define VINO_DATA_FMT_RGB32 2
+#define VINO_DATA_FMT_YUV 3
+//#define VINO_DATA_FMT_RGB24 4
+
+#define VINO_DATA_FMT_COUNT 4
+
+#define VINO_DATA_NORM_NONE -1
+#define VINO_DATA_NORM_NTSC 0
+#define VINO_DATA_NORM_PAL 1
+#define VINO_DATA_NORM_SECAM 2
+#define VINO_DATA_NORM_D1 3
+/* The following is a special entry that can be used to
+ * autodetect the norm. */
+#define VINO_DATA_NORM_AUTO 0xff
+
+#define VINO_DATA_NORM_COUNT 4
+
+/* Internal data structure definitions */
+
+struct vino_input {
+ char *name;
+ v4l2_std_id std;
+};
+
+struct vino_clipping {
+ unsigned int left, right, top, bottom;
+};
+
+struct vino_data_format {
+ /* the description */
+ char *description;
+ /* bytes per pixel */
+ unsigned int bpp;
+ /* V4L2 fourcc code */
+ __u32 pixelformat;
+ /* V4L2 colorspace (duh!) */
+ enum v4l2_colorspace colorspace;
+};
+
+struct vino_data_norm {
+ char *description;
+ unsigned int width, height;
+ struct vino_clipping odd;
+ struct vino_clipping even;
+
+ v4l2_std_id std;
+ unsigned int fps_min, fps_max;
+ __u32 framelines;
+};
+
+struct vino_descriptor_table {
+ /* the number of PAGE_SIZE sized pages in the buffer */
+ unsigned int page_count;
+ /* virtual (kmalloc'd) pointers to the actual data
+ * (in PAGE_SIZE chunks, used with mmap streaming) */
+ unsigned long *virtual;
+
+ /* cpu address for the VINO descriptor table
+ * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+ unsigned long *dma_cpu;
+ /* dma address for the VINO descriptor table
+ * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
+ dma_addr_t dma;
+};
+
+struct vino_framebuffer {
+ /* identifier nubmer */
+ unsigned int id;
+ /* the length of the whole buffer */
+ unsigned int size;
+ /* the length of actual data in buffer */
+ unsigned int data_size;
+ /* the data format */
+ unsigned int data_format;
+ /* the state of buffer data */
+ unsigned int state;
+ /* is the buffer mapped in user space? */
+ unsigned int map_count;
+ /* memory offset for mmap() */
+ unsigned int offset;
+ /* frame counter */
+ unsigned int frame_counter;
+ /* timestamp (written when image capture finishes) */
+ struct timeval timestamp;
+
+ struct vino_descriptor_table desc_table;
+
+ spinlock_t state_lock;
+};
+
+struct vino_framebuffer_fifo {
+ unsigned int length;
+
+ unsigned int used;
+ unsigned int head;
+ unsigned int tail;
+
+ unsigned int data[VINO_FRAMEBUFFER_MAX_COUNT];
+};
+
+struct vino_framebuffer_queue {
+ unsigned int magic;
+
+ /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */
+ unsigned int type;
+ unsigned int length;
+
+ /* data field of in and out contain index numbers for buffer */
+ struct vino_framebuffer_fifo in;
+ struct vino_framebuffer_fifo out;
+
+ struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_MAX_COUNT];
+
+ spinlock_t queue_lock;
+ struct semaphore queue_sem;
+ wait_queue_head_t frame_wait_queue;
+};
+
+struct vino_channel_settings {
+ unsigned int channel;
+
+ int input;
+ unsigned int data_format;
+ unsigned int data_norm;
+ struct vino_clipping clipping;
+ unsigned int decimation;
+ unsigned int line_size;
+ unsigned int alpha;
+ unsigned int fps;
+ unsigned int framert_reg;
+
+ unsigned int fifo_threshold;
+
+ struct vino_framebuffer_queue fb_queue;
+
+ /* number of the current field */
+ unsigned int field;
+
+ /* read in progress */
+ int reading;
+ /* streaming is active */
+ int streaming;
+ /* the driver is currently processing the queue */
+ int capturing;
+
+ struct semaphore sem;
+ spinlock_t capture_lock;
+
+ unsigned int users;
+
+ /* V4L support */
+ struct video_device *v4l_device;
};
struct vino_client {
+ /* the channel which owns this client:
+ * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+ unsigned int owner;
struct i2c_client *driver;
- int owner;
};
-struct vino_video {
- struct vino_device chA;
- struct vino_device chB;
+struct vino_settings {
+ struct vino_channel_settings a;
+ struct vino_channel_settings b;
struct vino_client decoder;
struct vino_client camera;
- struct semaphore input_lock;
+ /* a lock for vino register access */
+ spinlock_t vino_lock;
+ /* a lock for channel input changes */
+ spinlock_t input_lock;
- /* Loaded into VINO descriptors to clear End Of Descriptors table
- * interupt condition */
unsigned long dummy_page;
- unsigned int dummy_buf[4] __attribute__((aligned(8)));
+ struct vino_descriptor_table dummy_desc_table;
};
-static struct vino_video *Vino;
+/* Module parameters */
+
+/*
+ * Using vino_pixel_conversion the ARGB32-format pixels supplied
+ * by the VINO chip can be converted to more common formats
+ * like RGBA32 (or probably RGB24 in the future). This way we
+ * can give out data that can be specified correctly with
+ * the V4L2-definitions.
+ *
+ * The pixel format is specified as RGBA32 when no conversion
+ * is used.
+ *
+ * Note that this only affects the 32-bit bit depth.
+ *
+ * Use non-zero value to enable conversion.
+ */
+static int vino_pixel_conversion = 0;
+module_param_named(pixelconv, vino_pixel_conversion, int, 0);
+MODULE_PARM_DESC(pixelconv,
+ "enable pixel conversion (non-zero value enables)");
+
+/* Internal data structures */
+
+static struct sgi_vino *vino;
+
+static struct vino_settings *vino_drvdata;
+
+static const char *vino_driver_name = "vino";
+static const char *vino_driver_description = "SGI VINO";
+static const char *vino_bus_name = "GIO64 bus";
+static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
+static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
+
+static const struct vino_input vino_inputs[] = {
+ {
+ .name = "Composite",
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ },{
+ .name = "S-Video",
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ },{
+ .name = "D1 (IndyCam)",
+ .std = V4L2_STD_NTSC,
+ }
+};
+
+static const struct vino_data_format vino_data_formats[] = {
+ {
+ .description = "8-bit greyscale",
+ .bpp = 1,
+ .pixelformat = V4L2_PIX_FMT_GREY,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ },{
+ .description = "8-bit dithered RGB 3-3-2",
+ .bpp = 1,
+ .pixelformat = V4L2_PIX_FMT_RGB332,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },{
+ .description = "32-bit RGB",
+ .bpp = 4,
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },{
+ .description = "YUV 4:2:2",
+ .bpp = 4,
+ .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ }/*,{
+ .description = "24-bit RGB",
+ .bpp = 3,
+ .pixelformat = V4L2_PIX_FMT_RGB24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }*/
+};
+
+static const struct vino_data_norm vino_data_norms[] = {
+ {
+ .description = "NTSC",
+ .std = V4L2_STD_NTSC,
+ .fps_min = 6,
+ .fps_max = 30,
+ .framelines = 525,
+ .width = VINO_NTSC_WIDTH,
+ .height = VINO_NTSC_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_NTSC,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_NTSC
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_NTSC,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_NTSC
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ },{
+ .description = "PAL",
+ .std = V4L2_STD_PAL,
+ .fps_min = 5,
+ .fps_max = 25,
+ .framelines = 625,
+ .width = VINO_PAL_WIDTH,
+ .height = VINO_PAL_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ },{
+ .description = "SECAM",
+ .std = V4L2_STD_SECAM,
+ .fps_min = 5,
+ .fps_max = 25,
+ .framelines = 625,
+ .width = VINO_PAL_WIDTH,
+ .height = VINO_PAL_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_PAL,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_PAL
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+ },{
+ .description = "NTSC (D1 input)",
+ .std = V4L2_STD_NTSC,
+ .fps_min = 6,
+ .fps_max = 30,
+ .framelines = 525,
+ .width = VINO_NTSC_WIDTH,
+ .height = VINO_NTSC_HEIGHT,
+ .odd = {
+ .top = VINO_CLIPPING_START_ODD_D1,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_ODD_D1
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ .even = {
+ .top = VINO_CLIPPING_START_EVEN_D1,
+ .left = 0,
+ .bottom = VINO_CLIPPING_START_EVEN_D1
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+ }
+};
+
+#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9
+
+struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain Control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = INDYCAM_AGC_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = INDYCAM_AWB_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = INDYCAM_GAIN_MIN,
+ .maximum = INDYCAM_GAIN_MAX,
+ .step = 1,
+ .default_value = INDYCAM_GAIN_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Saturation",
+ .minimum = INDYCAM_RED_SATURATION_MIN,
+ .maximum = INDYCAM_RED_SATURATION_MAX,
+ .step = 1,
+ .default_value = INDYCAM_RED_SATURATION_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE + 1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Saturation",
+ .minimum = INDYCAM_BLUE_SATURATION_MIN,
+ .maximum = INDYCAM_BLUE_SATURATION_MAX,
+ .step = 1,
+ .default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = INDYCAM_RED_BALANCE_MIN,
+ .maximum = INDYCAM_RED_BALANCE_MAX,
+ .step = 1,
+ .default_value = INDYCAM_RED_BALANCE_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = INDYCAM_BLUE_BALANCE_MIN,
+ .maximum = INDYCAM_BLUE_BALANCE_MAX,
+ .step = 1,
+ .default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Control",
+ .minimum = INDYCAM_SHUTTER_MIN,
+ .maximum = INDYCAM_SHUTTER_MAX,
+ .step = 1,
+ .default_value = INDYCAM_SHUTTER_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = INDYCAM_GAMMA_MIN,
+ .maximum = INDYCAM_GAMMA_MAX,
+ .step = 1,
+ .default_value = INDYCAM_GAMMA_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ }
+};
+
+#define VINO_SAA7191_V4L2_CONTROL_COUNT 2
+
+struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = SAA7191_HUE_MIN,
+ .maximum = SAA7191_HUE_MAX,
+ .step = 1,
+ .default_value = SAA7191_HUE_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ },{
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VTR Time Constant",
+ .minimum = SAA7191_VTRC_MIN,
+ .maximum = SAA7191_VTRC_MAX,
+ .step = 1,
+ .default_value = SAA7191_VTRC_DEFAULT,
+ .flags = 0,
+ .reserved = { 0, 0 },
+ }
+};
+
+/* VINO I2C bus functions */
unsigned i2c_vino_getctrl(void *data)
{
@@ -112,49 +638,49 @@
*/
static int i2c_vino_client_reg(struct i2c_client *client)
{
- int res = 0;
+ int ret = 0;
- down(&Vino->input_lock);
+ spin_lock(&vino_drvdata->input_lock);
switch (client->driver->id) {
case I2C_DRIVERID_SAA7191:
- if (Vino->decoder.driver)
- res = -EBUSY;
+ if (vino_drvdata->decoder.driver)
+ ret = -EBUSY;
else
- Vino->decoder.driver = client;
+ vino_drvdata->decoder.driver = client;
break;
case I2C_DRIVERID_INDYCAM:
- if (Vino->camera.driver)
- res = -EBUSY;
+ if (vino_drvdata->camera.driver)
+ ret = -EBUSY;
else
- Vino->camera.driver = client;
+ vino_drvdata->camera.driver = client;
break;
default:
- res = -ENODEV;
+ ret = -ENODEV;
}
- up(&Vino->input_lock);
+ spin_unlock(&vino_drvdata->input_lock);
- return res;
+ return ret;
}
static int i2c_vino_client_unreg(struct i2c_client *client)
{
- int res = 0;
+ int ret = 0;
- down(&Vino->input_lock);
- if (client == Vino->decoder.driver) {
- if (Vino->decoder.owner)
- res = -EBUSY;
+ spin_lock(&vino_drvdata->input_lock);
+ if (client == vino_drvdata->decoder.driver) {
+ if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
+ ret = -EBUSY;
else
- Vino->decoder.driver = NULL;
- } else if (client == Vino->camera.driver) {
- if (Vino->camera.owner)
- res = -EBUSY;
+ vino_drvdata->decoder.driver = NULL;
+ } else if (client == vino_drvdata->camera.driver) {
+ if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
+ ret = -EBUSY;
else
- Vino->camera.driver = NULL;
+ vino_drvdata->camera.driver = NULL;
}
- up(&Vino->input_lock);
+ spin_unlock(&vino_drvdata->input_lock);
- return res;
+ return ret;
}
static struct i2c_adapter vino_i2c_adapter =
@@ -176,172 +702,3591 @@
return i2c_sgi_del_bus(&vino_i2c_adapter);
}
-
-static void vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int i2c_camera_command(unsigned int cmd, void *arg)
{
+ return vino_drvdata->camera.driver->
+ driver->command(vino_drvdata->camera.driver,
+ cmd, arg);
}
-static int vino_open(struct video_device *dev, int flags)
+static int i2c_decoder_command(unsigned int cmd, void *arg)
{
- struct vino_device *videv = (struct vino_device *)dev;
-
- return 0;
+ return vino_drvdata->decoder.driver->
+ driver->command(vino_drvdata->decoder.driver,
+ cmd, arg);
}
-static void vino_close(struct video_device *dev)
+/* VINO framebuffer/DMA descriptor management */
+
+static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
+ unsigned int count)
{
- struct vino_device *videv = (struct vino_device *)dev;
-}
+ unsigned int i;
-static int vino_mmap(struct video_device *dev, const char *adr,
- unsigned long size)
-{
- struct vino_device *videv = (struct vino_device *)dev;
+ dprintk("vino_free_buffer_with_count(): count = %d\n", count);
- return -EINVAL;
-}
-
-static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
- struct vino_device *videv = (struct vino_device *)dev;
-
- return -EINVAL;
-}
-
-static const struct video_device vino_device = {
- .owner = THIS_MODULE,
- .type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE,
- .hardware = VID_HARDWARE_VINO,
- .name = "VINO",
- .open = vino_open,
- .close = vino_close,
- .ioctl = vino_ioctl,
- .mmap = vino_mmap,
-};
-
-static int __init vino_init(void)
-{
- unsigned long rev;
- int i, ret = 0;
-
- /* VINO is Indy specific beast */
- if (ip22_is_fullhouse())
- return -ENODEV;
-
- /*
- * VINO is in the EISA address space, so the sysid register will tell
- * us if the EISA_PRESENT pin on MC has been pulled low.
- *
- * If EISA_PRESENT is not set we definitely don't have a VINO equiped
- * system.
- */
- if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
- printk(KERN_ERR "VINO not found\n");
- return -ENODEV;
+ for (i = 0; i < count; i++) {
+ mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i]));
+ dma_unmap_single(NULL,
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ free_page(fb->desc_table.virtual[i]);
}
- vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
- if (!vino)
- return -EIO;
+ dma_free_coherent(NULL,
+ VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *
+ sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,
+ fb->desc_table.dma);
+ kfree(fb->desc_table.virtual);
- /* Okay, once we know that VINO is present we'll read its revision
- * safe way. One never knows... */
- if (get_dbe(rev, &(vino->rev_id))) {
- printk(KERN_ERR "VINO: failed to read revision register\n");
- ret = -ENODEV;
- goto out_unmap;
- }
- if (VINO_ID_VALUE(rev) != VINO_CHIP_ID) {
- printk(KERN_ERR "VINO is not VINO (Rev/ID: 0x%04lx)\n", rev);
- ret = -ENODEV;
- goto out_unmap;
- }
- printk(KERN_INFO "VINO Rev: 0x%02lx\n", VINO_REV_NUM(rev));
+ memset(fb, 0, sizeof(struct vino_framebuffer));
+}
- Vino = (struct vino_video *)
- kmalloc(sizeof(struct vino_video), GFP_KERNEL);
- if (!Vino) {
+static void vino_free_buffer(struct vino_framebuffer *fb)
+{
+ vino_free_buffer_with_count(fb, fb->desc_table.page_count);
+}
+
+static int vino_allocate_buffer(struct vino_framebuffer *fb,
+ unsigned int size)
+{
+ unsigned int count, i, j;
+ int ret = 0;
+
+ dprintk("vino_allocate_buffer():\n");
+
+ if (size < 1)
+ return -EINVAL;
+
+ memset(fb, 0, sizeof(struct vino_framebuffer));
+
+ count = ((size / PAGE_SIZE) + 4) & ~3;
+
+ dprintk("vino_allocate_buffer(): size = %d, count = %d\n",
+ size, count);
+
+ /* allocate memory for table with virtual (page) addresses */
+ fb->desc_table.virtual = (unsigned long *)
+ kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+ if (!fb->desc_table.virtual)
+ return -ENOMEM;
+
+ /* allocate memory for table with dma addresses
+ * (has space for four extra descriptors) */
+ fb->desc_table.dma_cpu =
+ dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+ sizeof(dma_addr_t), &fb->desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.dma_cpu) {
ret = -ENOMEM;
- goto out_unmap;
+ goto out_free_virtual;
}
- Vino->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!Vino->dummy_page) {
- ret = -ENOMEM;
- goto out_free_vino;
- }
- for (i = 0; i < 4; i++)
- Vino->dummy_buf[i] = PHYSADDR(Vino->dummy_page);
+ /* allocate pages for the buffer and acquire the according
+ * dma addresses */
+ for (i = 0; i < count; i++) {
+ dma_addr_t dma_data_addr;
- vino->control = 0;
- /* prevent VINO from throwing spurious interrupts */
- vino->a.next_4_desc = PHYSADDR(Vino->dummy_buf);
- vino->b.next_4_desc = PHYSADDR(Vino->dummy_buf);
- udelay(5);
- vino->intr_status = 0;
- /* set threshold level */
- vino->a.fifo_thres = threshold_a;
- vino->b.fifo_thres = threshold_b;
+ fb->desc_table.virtual[i] =
+ get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.virtual[i]) {
+ ret = -ENOBUFS;
+ break;
+ }
- init_MUTEX(&Vino->input_lock);
+ dma_data_addr =
+ dma_map_single(NULL,
+ (void *)fb->desc_table.virtual[i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
- if (request_irq(SGI_VINO_IRQ, vino_interrupt, 0, vinostr, NULL)) {
- printk(KERN_ERR "VINO: irq%02d registration failed\n",
- SGI_VINO_IRQ);
- ret = -EAGAIN;
- goto out_free_page;
+ for (j = 0; j < VINO_PAGE_RATIO; j++) {
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+ dma_data_addr + VINO_PAGE_SIZE * j;
+ }
+
+ mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
}
- ret = vino_i2c_add_bus();
+ /* page_count needs to be set anyway, because the descriptor table has
+ * been allocated according to this number */
+ fb->desc_table.page_count = count;
+
if (ret) {
- printk(KERN_ERR "VINO: I2C bus registration failed\n");
- goto out_free_irq;
+ /* the descriptor with index i doesn't contain
+ * a valid address yet */
+ vino_free_buffer_with_count(fb, i);
+ return ret;
}
- if (video_register_device(&Vino->chA.vdev, VFL_TYPE_GRABBER, -1) < 0) {
- printk("%s, chnl %d: device registration failed.\n",
- Vino->chA.vdev.name, Vino->chA.chan);
- ret = -EINVAL;
- goto out_i2c_del_bus;
+ //fb->size = size;
+ fb->size = count * PAGE_SIZE;
+ fb->data_format = VINO_DATA_FMT_NONE;
+
+ /* set the dma stop-bit for the last (count+1)th descriptor */
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+ return 0;
+
+ out_free_virtual:
+ kfree(fb->desc_table.virtual);
+ return ret;
+}
+
+#if 0
+/* user buffers not fully implemented yet */
+static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
+ void *user,
+ unsigned int size)
+{
+ unsigned int count, i, j;
+ int ret = 0;
+
+ dprintk("vino_prepare_user_buffer():\n");
+
+ if (size < 1)
+ return -EINVAL;
+
+ memset(fb, 0, sizeof(struct vino_framebuffer));
+
+ count = ((size / PAGE_SIZE)) & ~3;
+
+ dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",
+ size, count);
+
+ /* allocate memory for table with virtual (page) addresses */
+ fb->desc_table.virtual = (unsigned long *)
+ kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
+ if (!fb->desc_table.virtual)
+ return -ENOMEM;
+
+ /* allocate memory for table with dma addresses
+ * (has space for four extra descriptors) */
+ fb->desc_table.dma_cpu =
+ dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
+ sizeof(dma_addr_t), &fb->desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.dma_cpu) {
+ ret = -ENOMEM;
+ goto out_free_virtual;
}
- if (video_register_device(&Vino->chB.vdev, VFL_TYPE_GRABBER, -1) < 0) {
- printk("%s, chnl %d: device registration failed.\n",
- Vino->chB.vdev.name, Vino->chB.chan);
- ret = -EINVAL;
- goto out_unregister_vdev;
+
+ /* allocate pages for the buffer and acquire the according
+ * dma addresses */
+ for (i = 0; i < count; i++) {
+ dma_addr_t dma_data_addr;
+
+ fb->desc_table.virtual[i] =
+ get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!fb->desc_table.virtual[i]) {
+ ret = -ENOBUFS;
+ break;
+ }
+
+ dma_data_addr =
+ dma_map_single(NULL,
+ (void *)fb->desc_table.virtual[i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+
+ for (j = 0; j < VINO_PAGE_RATIO; j++) {
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
+ dma_data_addr + VINO_PAGE_SIZE * j;
+ }
+
+ mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));
+ }
+
+ /* page_count needs to be set anyway, because the descriptor table has
+ * been allocated according to this number */
+ fb->desc_table.page_count = count;
+
+ if (ret) {
+ /* the descriptor with index i doesn't contain
+ * a valid address yet */
+ vino_free_buffer_with_count(fb, i);
+ return ret;
+ }
+
+ //fb->size = size;
+ fb->size = count * PAGE_SIZE;
+
+ /* set the dma stop-bit for the last (count+1)th descriptor */
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
+ return 0;
+
+ out_free_virtual:
+ kfree(fb->desc_table.virtual);
+ return ret;
+}
+#endif
+
+static void vino_sync_buffer(struct vino_framebuffer *fb)
+{
+ int i;
+
+ dprintk("vino_sync_buffer():\n");
+
+ for (i = 0; i < fb->desc_table.page_count; i++)
+ dma_sync_single(NULL,
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+}
+
+/* Framebuffer fifo functions (need to be locked externally) */
+
+static void vino_fifo_init(struct vino_framebuffer_fifo *f,
+ unsigned int length)
+{
+ f->length = 0;
+ f->used = 0;
+ f->head = 0;
+ f->tail = 0;
+
+ if (length > VINO_FRAMEBUFFER_MAX_COUNT)
+ length = VINO_FRAMEBUFFER_MAX_COUNT;
+
+ f->length = length;
+}
+
+/* returns true/false */
+static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id)
+{
+ unsigned int i;
+ for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {
+ if (f->data[i] == id)
+ return 1;
}
return 0;
+}
-out_unregister_vdev:
- video_unregister_device(&Vino->chA.vdev);
-out_i2c_del_bus:
- vino_i2c_del_bus();
-out_free_irq:
- free_irq(SGI_VINO_IRQ, NULL);
-out_free_page:
- free_page(Vino->dummy_page);
-out_free_vino:
- kfree(Vino);
-out_unmap:
- iounmap(vino);
+/* returns true/false */
+static int vino_fifo_full(struct vino_framebuffer_fifo *f)
+{
+ return (f->used == f->length);
+}
+
+static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
+{
+ return f->used;
+}
+
+static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id)
+{
+ if (id >= f->length) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ if (vino_fifo_has_id(f, id)) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ if (f->used < f->length) {
+ f->data[f->tail] = id;
+ f->tail = (f->tail + 1) % f->length;
+ f->used++;
+ } else {
+ return VINO_QUEUE_ERROR;
+ }
+
+ return 0;
+}
+
+static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id)
+{
+ if (f->used > 0) {
+ *id = f->data[f->head];
+ } else {
+ return VINO_QUEUE_ERROR;
+ }
+
+ return 0;
+}
+
+static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id)
+{
+ if (f->used > 0) {
+ *id = f->data[f->head];
+ f->head = (f->head + 1) % f->length;
+ f->used--;
+ } else {
+ return VINO_QUEUE_ERROR;
+ }
+
+ return 0;
+}
+
+/* Framebuffer queue functions */
+
+/* execute with queue_lock locked */
+static void vino_queue_free_with_count(struct vino_framebuffer_queue *q,
+ unsigned int length)
+{
+ unsigned int i;
+
+ q->length = 0;
+ memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo));
+ memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo));
+ for (i = 0; i < length; i++) {
+ dprintk("vino_queue_free_with_count(): freeing buffer %d\n",
+ i);
+ vino_free_buffer(q->buffer[i]);
+ kfree(q->buffer[i]);
+ }
+
+ q->type = VINO_MEMORY_NONE;
+ q->magic = 0;
+}
+
+static void vino_queue_free(struct vino_framebuffer_queue *q)
+{
+ dprintk("vino_queue_free():\n");
+
+ if (q->magic != VINO_QUEUE_MAGIC)
+ return;
+ if (q->type != VINO_MEMORY_MMAP)
+ return;
+
+ down(&q->queue_sem);
+
+ vino_queue_free_with_count(q, q->length);
+
+ up(&q->queue_sem);
+}
+
+static int vino_queue_init(struct vino_framebuffer_queue *q,
+ unsigned int *length)
+{
+ unsigned int i;
+ int ret = 0;
+
+ dprintk("vino_queue_init(): length = %d\n", *length);
+
+ if (q->magic == VINO_QUEUE_MAGIC) {
+ dprintk("vino_queue_init(): queue already initialized!\n");
+ return -EINVAL;
+ }
+
+ if (q->type != VINO_MEMORY_NONE) {
+ dprintk("vino_queue_init(): queue already initialized!\n");
+ return -EINVAL;
+ }
+
+ if (*length < 1)
+ return -EINVAL;
+
+ down(&q->queue_sem);
+
+ if (*length > VINO_FRAMEBUFFER_MAX_COUNT)
+ *length = VINO_FRAMEBUFFER_MAX_COUNT;
+
+ q->length = 0;
+
+ for (i = 0; i < *length; i++) {
+ dprintk("vino_queue_init(): allocating buffer %d\n", i);
+ q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer),
+ GFP_KERNEL);
+ if (!q->buffer[i]) {
+ dprintk("vino_queue_init(): kmalloc() failed\n");
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = vino_allocate_buffer(q->buffer[i],
+ VINO_FRAMEBUFFER_SIZE);
+ if (ret) {
+ kfree(q->buffer[i]);
+ dprintk("vino_queue_init(): "
+ "vino_allocate_buffer() failed\n");
+ break;
+ }
+
+ q->buffer[i]->id = i;
+ if (i > 0) {
+ q->buffer[i]->offset = q->buffer[i - 1]->offset +
+ q->buffer[i - 1]->size;
+ } else {
+ q->buffer[i]->offset = 0;
+ }
+
+ spin_lock_init(&q->buffer[i]->state_lock);
+
+ dprintk("vino_queue_init(): buffer = %d, offset = %d, "
+ "size = %d\n", i, q->buffer[i]->offset,
+ q->buffer[i]->size);
+ }
+
+ if (ret) {
+ vino_queue_free_with_count(q, i);
+ *length = 0;
+ } else {
+ q->length = *length;
+ vino_fifo_init(&q->in, q->length);
+ vino_fifo_init(&q->out, q->length);
+ q->type = VINO_MEMORY_MMAP;
+ q->magic = VINO_QUEUE_MAGIC;
+ }
+
+ up(&q->queue_sem);
return ret;
}
-static void __exit vino_exit(void)
+static struct vino_framebuffer *vino_queue_add(struct
+ vino_framebuffer_queue *q,
+ unsigned int id)
{
- video_unregister_device(&Vino->chA.vdev);
- video_unregister_device(&Vino->chB.vdev);
- vino_i2c_del_bus();
- free_irq(SGI_VINO_IRQ, NULL);
- free_page(Vino->dummy_page);
- kfree(Vino);
- iounmap(vino);
+ struct vino_framebuffer *ret = NULL;
+ unsigned int total;
+ unsigned long flags;
+
+ dprintk("vino_queue_add(): id = %d\n", id);
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (id >= q->length)
+ goto out;
+
+ /* not needed?: if (vino_fifo_full(&q->out)) {
+ goto out;
+ }*/
+ /* check that outgoing queue isn't already full
+ * (or that it won't become full) */
+ total = vino_fifo_get_used(&q->in) +
+ vino_fifo_get_used(&q->out);
+ if (total >= q->length)
+ goto out;
+
+ if (vino_fifo_enqueue(&q->in, id))
+ goto out;
+
+ ret = q->buffer[id];
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
}
-module_init(vino_init);
-module_exit(vino_exit);
+static struct vino_framebuffer *vino_queue_transfer(struct
+ vino_framebuffer_queue *q)
+{
+ struct vino_framebuffer *ret = NULL;
+ struct vino_framebuffer *fb;
+ int id;
+ unsigned long flags;
-MODULE_DESCRIPTION("Video4Linux driver for SGI Indy VINO (IndyCam)");
-MODULE_LICENSE("GPL");
+ dprintk("vino_queue_transfer():\n");
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ // now this actually removes an entry from the incoming queue
+ if (vino_fifo_dequeue(&q->in, &id)) {
+ goto out;
+ }
+
+ dprintk("vino_queue_transfer(): id = %d\n", id);
+ fb = q->buffer[id];
+
+ // we have already checked that the outgoing queue is not full, but...
+ if (vino_fifo_enqueue(&q->out, id)) {
+ printk(KERN_ERR "vino_queue_transfer(): "
+ "outgoing queue is full, this shouldn't happen!\n");
+ goto out;
+ }
+
+ ret = fb;
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+/* returns true/false */
+static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ ret = vino_fifo_has_id(&q->in, id);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+/* returns true/false */
+static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ ret = vino_fifo_has_id(&q->out, id);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static int vino_queue_get_incoming(struct vino_framebuffer_queue *q,
+ unsigned int *used)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0) {
+ ret = VINO_QUEUE_ERROR;
+ goto out;
+ }
+
+ *used = vino_fifo_get_used(&q->in);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q,
+ unsigned int *used)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0) {
+ ret = VINO_QUEUE_ERROR;
+ goto out;
+ }
+
+ *used = vino_fifo_get_used(&q->out);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static int vino_queue_get_total(struct vino_framebuffer_queue *q,
+ unsigned int *total)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return VINO_QUEUE_ERROR;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0) {
+ ret = VINO_QUEUE_ERROR;
+ goto out;
+ }
+
+ *total = vino_fifo_get_used(&q->in) +
+ vino_fifo_get_used(&q->out);
+
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct vino_framebuffer *vino_queue_peek(struct
+ vino_framebuffer_queue *q,
+ unsigned int *id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (vino_fifo_peek(&q->in, id)) {
+ goto out;
+ }
+
+ ret = q->buffer[*id];
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct vino_framebuffer *vino_queue_remove(struct
+ vino_framebuffer_queue *q,
+ unsigned int *id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned long flags;
+ dprintk("vino_queue_remove():\n");
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (vino_fifo_dequeue(&q->out, id)) {
+ goto out;
+ }
+
+ dprintk("vino_queue_remove(): id = %d\n", *id);
+ ret = q->buffer[*id];
+out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static struct
+vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q,
+ unsigned int id)
+{
+ struct vino_framebuffer *ret = NULL;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+
+ if (q->length == 0)
+ goto out;
+
+ if (id >= q->length)
+ goto out;
+
+ ret = q->buffer[id];
+ out:
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q)
+{
+ unsigned int length = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return length;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+ length = q->length;
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return length;
+}
+
+static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q)
+{
+ unsigned int i;
+ int ret = 0;
+ unsigned long flags;
+
+ if (q->magic != VINO_QUEUE_MAGIC) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&q->queue_lock, flags);
+ for (i = 0; i < q->length; i++) {
+ if (q->buffer[i]->map_count > 0) {
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&q->queue_lock, flags);
+
+ return ret;
+}
+
+/* VINO functions */
+
+/* execute with input_lock locked */
+static void vino_update_line_size(struct vino_channel_settings *vcs)
+{
+ unsigned int w = vcs->clipping.right - vcs->clipping.left;
+ unsigned int d = vcs->decimation;
+ unsigned int bpp = vino_data_formats[vcs->data_format].bpp;
+ unsigned int lsize;
+
+ dprintk("update_line_size(): before: w = %d, d = %d, "
+ "line_size = %d\n", w, d, vcs->line_size);
+ /* line size must be multiple of 8 bytes */
+ lsize = (bpp * (w / d)) & ~7;
+ w = (lsize / bpp) * d;
+
+ vcs->clipping.right = vcs->clipping.left + w;
+ vcs->line_size = lsize;
+ dprintk("update_line_size(): after: w = %d, d = %d, "
+ "line_size = %d\n", w, d, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_clipping(struct vino_channel_settings *vcs,
+ unsigned int x, unsigned int y,
+ unsigned int w, unsigned int h)
+{
+ unsigned int maxwidth, maxheight;
+ unsigned int d;
+
+ maxwidth = vino_data_norms[vcs->data_norm].width;
+ maxheight = vino_data_norms[vcs->data_norm].height;
+ d = vcs->decimation;
+
+ y &= ~1; /* odd/even fields */
+
+ if (x > maxwidth) {
+ x = 0;
+ }
+ if (y > maxheight) {
+ y = 0;
+ }
+
+ if (((w / d) < VINO_MIN_WIDTH)
+ || ((h / d) < VINO_MIN_HEIGHT)) {
+ w = VINO_MIN_WIDTH * d;
+ h = VINO_MIN_HEIGHT * d;
+ }
+
+ if ((x + w) > maxwidth) {
+ w = maxwidth - x;
+ if ((w / d) < VINO_MIN_WIDTH)
+ x = maxwidth - VINO_MIN_WIDTH * d;
+ }
+ if ((y + h) > maxheight) {
+ h = maxheight - y;
+ if ((h / d) < VINO_MIN_HEIGHT)
+ y = maxheight - VINO_MIN_HEIGHT * d;
+ }
+
+ vcs->clipping.left = x;
+ vcs->clipping.top = y;
+ vcs->clipping.right = x + w;
+ vcs->clipping.bottom = y + h;
+
+ vino_update_line_size(vcs);
+
+ dprintk("clipping %d, %d, %d, %d / %d - %d\n",
+ vcs->clipping.left, vcs->clipping.top, vcs->clipping.right,
+ vcs->clipping.bottom, vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_set_default_clipping(struct vino_channel_settings *vcs)
+{
+ vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width,
+ vino_data_norms[vcs->data_norm].height);
+}
+
+/* execute with input_lock locked */
+static void vino_set_scaling(struct vino_channel_settings *vcs,
+ unsigned int w, unsigned int h)
+{
+ unsigned int x, y, curw, curh, d;
+
+ x = vcs->clipping.left;
+ y = vcs->clipping.top;
+ curw = vcs->clipping.right - vcs->clipping.left;
+ curh = vcs->clipping.bottom - vcs->clipping.top;
+
+ d = max(curw / w, curh / h);
+
+ dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n",
+ w, h, curw, curh, d);
+
+ if (d < 1) {
+ d = 1;
+ }
+ if (d > 8) {
+ d = 8;
+ }
+
+ vcs->decimation = d;
+ vino_set_clipping(vcs, x, y, w * d, h * d);
+
+ dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left,
+ vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom,
+ vcs->decimation, vcs->line_size);
+}
+
+/* execute with input_lock locked */
+static void vino_reset_scaling(struct vino_channel_settings *vcs)
+{
+ vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left,
+ vcs->clipping.bottom - vcs->clipping.top);
+}
+
+/* execute with input_lock locked */
+static void vino_set_framerate(struct vino_channel_settings *vcs,
+ unsigned int fps)
+{
+ unsigned int mask;
+
+ switch (vcs->data_norm) {
+ case VINO_DATA_NORM_NTSC:
+ case VINO_DATA_NORM_D1:
+ fps = (unsigned int)(fps / 6) * 6; // FIXME: round!
+
+ if (fps < vino_data_norms[vcs->data_norm].fps_min)
+ fps = vino_data_norms[vcs->data_norm].fps_min;
+ if (fps > vino_data_norms[vcs->data_norm].fps_max)
+ fps = vino_data_norms[vcs->data_norm].fps_max;
+
+ switch (fps) {
+ case 6:
+ mask = 0x003;
+ break;
+ case 12:
+ mask = 0x0c3;
+ break;
+ case 18:
+ mask = 0x333;
+ break;
+ case 24:
+ mask = 0x3ff;
+ break;
+ case 30:
+ mask = 0xfff;
+ break;
+ default:
+ mask = VINO_FRAMERT_FULL;
+ }
+ vcs->framert_reg = VINO_FRAMERT_RT(mask);
+ break;
+ case VINO_DATA_NORM_PAL:
+ case VINO_DATA_NORM_SECAM:
+ fps = (unsigned int)(fps / 5) * 5; // FIXME: round!
+
+ if (fps < vino_data_norms[vcs->data_norm].fps_min)
+ fps = vino_data_norms[vcs->data_norm].fps_min;
+ if (fps > vino_data_norms[vcs->data_norm].fps_max)
+ fps = vino_data_norms[vcs->data_norm].fps_max;
+
+ switch (fps) {
+ case 5:
+ mask = 0x003;
+ break;
+ case 10:
+ mask = 0x0c3;
+ break;
+ case 15:
+ mask = 0x333;
+ break;
+ case 20:
+ mask = 0x0ff;
+ break;
+ case 25:
+ mask = 0x3ff;
+ break;
+ default:
+ mask = VINO_FRAMERT_FULL;
+ }
+ vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL;
+ break;
+ }
+
+ vcs->fps = fps;
+}
+
+/* execute with input_lock locked */
+static void vino_set_default_framerate(struct vino_channel_settings *vcs)
+{
+ vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
+}
+
+/*
+ * Prepare VINO for DMA transfer...
+ * (execute only with vino_lock and input_lock locked)
+ */
+static int vino_dma_setup(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb)
+{
+ u32 ctrl, intr;
+ struct sgi_vino_channel *ch;
+ const struct vino_data_norm *norm;
+
+ dprintk("vino_dma_setup():\n");
+
+ vcs->field = 0;
+ fb->frame_counter = 0;
+
+ ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+ norm = &vino_data_norms[vcs->data_norm];
+
+ ch->page_index = 0;
+ ch->line_count = 0;
+
+ /* VINO line size register is set 8 bytes less than actual */
+ ch->line_size = vcs->line_size - 8;
+
+ /* let VINO know where to transfer data */
+ ch->start_desc_tbl = fb->desc_table.dma;
+ ch->next_4_desc = fb->desc_table.dma;
+
+ /* give vino time to fetch the first four descriptors, 5 usec
+ * should be more than enough time */
+ udelay(VINO_DESC_FETCH_DELAY);
+
+ /* set the alpha register */
+ ch->alpha = vcs->alpha;
+
+ /* set clipping registers */
+ ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) |
+ VINO_CLIP_EVEN(norm->even.top +
+ vcs->clipping.top / 2) |
+ VINO_CLIP_X(vcs->clipping.left);
+ ch->clip_end = VINO_CLIP_ODD(norm->odd.top +
+ vcs->clipping.bottom / 2 - 1) |
+ VINO_CLIP_EVEN(norm->even.top +
+ vcs->clipping.bottom / 2 - 1) |
+ VINO_CLIP_X(vcs->clipping.right);
+ /* FIXME: end-of-field bug workaround
+ VINO_CLIP_X(VINO_PAL_WIDTH);
+ */
+
+ /* set the size of actual content in the buffer (DECIMATION !) */
+ fb->data_size = ((vcs->clipping.right - vcs->clipping.left) /
+ vcs->decimation) *
+ ((vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation) *
+ vino_data_formats[vcs->data_format].bpp;
+
+ ch->frame_rate = vcs->framert_reg;
+
+ ctrl = vino->control;
+ intr = vino->intr_status;
+
+ if (vcs->channel == VINO_CHANNEL_A) {
+ /* All interrupt conditions for this channel was cleared
+ * so clear the interrupt status register and enable
+ * interrupts */
+ intr &= ~VINO_INTSTAT_A;
+ ctrl |= VINO_CTRL_A_INT;
+
+ /* enable synchronization */
+ ctrl |= VINO_CTRL_A_SYNC_ENBL;
+
+ /* enable frame assembly */
+ ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL;
+
+ /* set decimation used */
+ if (vcs->decimation < 2)
+ ctrl &= ~VINO_CTRL_A_DEC_ENBL;
+ else {
+ ctrl |= VINO_CTRL_A_DEC_ENBL;
+ ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK;
+ ctrl |= (vcs->decimation - 1) <<
+ VINO_CTRL_A_DEC_SCALE_SHIFT;
+ }
+
+ /* select input interface */
+ if (vcs->input == VINO_INPUT_D1)
+ ctrl |= VINO_CTRL_A_SELECT;
+ else
+ ctrl &= ~VINO_CTRL_A_SELECT;
+
+ /* palette */
+ ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB |
+ VINO_CTRL_A_DITHER);
+ } else {
+ intr &= ~VINO_INTSTAT_B;
+ ctrl |= VINO_CTRL_B_INT;
+
+ ctrl |= VINO_CTRL_B_SYNC_ENBL;
+ ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL;
+
+ if (vcs->decimation < 2)
+ ctrl &= ~VINO_CTRL_B_DEC_ENBL;
+ else {
+ ctrl |= VINO_CTRL_B_DEC_ENBL;
+ ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK;
+ ctrl |= (vcs->decimation - 1) <<
+ VINO_CTRL_B_DEC_SCALE_SHIFT;
+
+ }
+ if (vcs->input == VINO_INPUT_D1)
+ ctrl |= VINO_CTRL_B_SELECT;
+ else
+ ctrl &= ~VINO_CTRL_B_SELECT;
+
+ ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB |
+ VINO_CTRL_B_DITHER);
+ }
+
+ /* set palette */
+ fb->data_format = vcs->data_format;
+
+ switch (vcs->data_format) {
+ case VINO_DATA_FMT_GREY:
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY;
+ break;
+ case VINO_DATA_FMT_RGB32:
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_RGB : VINO_CTRL_B_RGB;
+ break;
+ case VINO_DATA_FMT_YUV:
+ /* nothing needs to be done */
+ break;
+ case VINO_DATA_FMT_RGB332:
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER :
+ VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER;
+ break;
+ }
+
+ vino->intr_status = intr;
+ vino->control = ctrl;
+
+ return 0;
+}
+
+/* (execute only with vino_lock locked) */
+static void vino_dma_start(struct vino_channel_settings *vcs)
+{
+ u32 ctrl = vino->control;
+
+ dprintk("vino_dma_start():\n");
+ ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
+ VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL;
+ vino->control = ctrl;
+}
+
+/* (execute only with vino_lock locked) */
+static void vino_dma_stop(struct vino_channel_settings *vcs)
+{
+ u32 ctrl = vino->control;
+
+ ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
+ ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL;
+ vino->control = ctrl;
+ dprintk("vino_dma_stop():\n");
+}
+
+/*
+ * Load dummy page to descriptor registers. This prevents generating of
+ * spurious interrupts. (execute only with vino_lock locked)
+ */
+static void vino_clear_interrupt(struct vino_channel_settings *vcs)
+{
+ struct sgi_vino_channel *ch;
+
+ ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
+
+ ch->page_index = 0;
+ ch->line_count = 0;
+
+ ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma;
+ ch->next_4_desc = vino_drvdata->dummy_desc_table.dma;
+
+ udelay(VINO_DESC_FETCH_DELAY);
+ dprintk("channel %c clear interrupt condition\n",
+ (vcs->channel == VINO_CHANNEL_A) ? 'A':'B');
+}
+
+static int vino_capture(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb)
+{
+ int err = 0;
+ unsigned long flags, flags2;
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+
+ if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+ err = -EBUSY;
+ fb->state = VINO_FRAMEBUFFER_IN_USE;
+
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags2);
+
+ vino_dma_setup(vcs, fb);
+ vino_dma_start(vcs);
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2);
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+ return err;
+}
+
+static
+struct vino_framebuffer *vino_capture_enqueue(struct
+ vino_channel_settings *vcs,
+ unsigned int index)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+
+ dprintk("vino_capture_enqueue():\n");
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+
+ fb = vino_queue_add(&vcs->fb_queue, index);
+ if (fb == NULL) {
+ dprintk("vino_capture_enqueue(): vino_queue_add() failed, "
+ "queue full?\n");
+ goto out;
+ }
+out:
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ return fb;
+}
+
+static int vino_capture_next(struct vino_channel_settings *vcs, int start)
+{
+ struct vino_framebuffer *fb;
+ unsigned int incoming, id;
+ int err = 0;
+ unsigned long flags, flags2;
+
+ dprintk("vino_capture_next():\n");
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+
+ if (start) {
+ /* start capture only if capture isn't in progress already */
+ if (vcs->capturing) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ return 0;
+ }
+
+ } else {
+ /* capture next frame:
+ * stop capture if capturing is not set */
+ if (!vcs->capturing) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ return 0;
+ }
+ }
+
+ err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (err) {
+ dprintk("vino_capture_next(): vino_queue_get_incoming() "
+ "failed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ if (incoming == 0) {
+ dprintk("vino_capture_next(): no buffers available\n");
+ goto out;
+ }
+
+ fb = vino_queue_peek(&vcs->fb_queue, &id);
+ if (fb == NULL) {
+ dprintk("vino_capture_next(): vino_queue_peek() failed\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ spin_lock_irqsave(&fb->state_lock, flags2);
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ spin_unlock_irqrestore(&fb->state_lock, flags2);
+
+ if (start) {
+ vcs->capturing = 1;
+ }
+
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ err = vino_capture(vcs, fb);
+
+ return err;
+
+out:
+ vcs->capturing = 0;
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ return err;
+}
+
+static int vino_is_capturing(struct vino_channel_settings *vcs)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+
+ ret = vcs->capturing;
+
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ return ret;
+}
+
+/* waits until a frame is captured */
+static int vino_wait_for_frame(struct vino_channel_settings *vcs)
+{
+ wait_queue_t wait;
+ int err = 0;
+
+ dprintk("vino_wait_for_frame():\n");
+
+ init_waitqueue_entry(&wait, current);
+ /* add ourselves into wait queue */
+ add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+ /* and set current state */
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /* to ensure that schedule_timeout will return immediately
+ * if VINO interrupt was triggred meanwhile */
+ schedule_timeout(HZ / 10);
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
+
+ dprintk("vino_wait_for_frame(): waiting for frame %s\n",
+ err ? "failed" : "ok");
+
+ return err;
+}
+
+/* the function assumes that PAGE_SIZE % 4 == 0 */
+static void vino_convert_to_rgba(struct vino_framebuffer *fb) {
+ unsigned char *pageptr;
+ unsigned int page, i;
+ unsigned char a;
+
+ for (page = 0; page < fb->desc_table.page_count; page++) {
+ pageptr = (unsigned char *)fb->desc_table.virtual[page];
+
+ for (i = 0; i < PAGE_SIZE; i += 4) {
+ a = pageptr[0];
+ pageptr[0] = pageptr[3];
+ pageptr[1] = pageptr[2];
+ pageptr[2] = pageptr[1];
+ pageptr[3] = a;
+ pageptr += 4;
+ }
+ }
+}
+
+/* checks if the buffer is in correct state and syncs data */
+static int vino_check_buffer(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb)
+{
+ int err = 0;
+ unsigned long flags;
+
+ dprintk("vino_check_buffer():\n");
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ switch (fb->state) {
+ case VINO_FRAMEBUFFER_IN_USE:
+ err = -EIO;
+ break;
+ case VINO_FRAMEBUFFER_READY:
+ vino_sync_buffer(fb);
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ if (!err) {
+ if (vino_pixel_conversion
+ && (fb->data_format == VINO_DATA_FMT_RGB32)) {
+ vino_convert_to_rgba(fb);
+ }
+ } else if (err && (err != -EINVAL)) {
+ dprintk("vino_check_buffer(): buffer not ready\n");
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+ vino_dma_stop(vcs);
+ vino_clear_interrupt(vcs);
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+ }
+
+ return err;
+}
+
+/* forcefully terminates capture */
+static void vino_capture_stop(struct vino_channel_settings *vcs)
+{
+ unsigned int incoming = 0, outgoing = 0, id;
+ unsigned long flags, flags2;
+
+ dprintk("vino_capture_stop():\n");
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+ /* unset capturing to stop queue processing */
+ vcs->capturing = 0;
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags2);
+
+ vino_dma_stop(vcs);
+ vino_clear_interrupt(vcs);
+
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2);
+
+ /* remove all items from the queue */
+ if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_incoming() failed\n");
+ goto out;
+ }
+ while (incoming > 0) {
+ vino_queue_transfer(&vcs->fb_queue);
+
+ if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_incoming() failed\n");
+ goto out;
+ }
+ }
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_outgoing() failed\n");
+ goto out;
+ }
+ while (outgoing > 0) {
+ vino_queue_remove(&vcs->fb_queue, &id);
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("vino_capture_stop(): "
+ "vino_queue_get_outgoing() failed\n");
+ goto out;
+ }
+ }
+
+out:
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+}
+
+static int vino_capture_failed(struct vino_channel_settings *vcs)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+ unsigned int i;
+ int ret;
+
+ dprintk("vino_capture_failed():\n");
+
+ spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
+
+ vino_dma_stop(vcs);
+ vino_clear_interrupt(vcs);
+
+ spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
+
+ ret = vino_queue_get_incoming(&vcs->fb_queue, &i);
+ if (ret == VINO_QUEUE_ERROR) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EINVAL;
+ }
+ if (i == 0) {
+ /* no buffers to process */
+ return 0;
+ }
+
+ fb = vino_queue_peek(&vcs->fb_queue, &i);
+ if (fb == NULL) {
+ dprintk("vino_queue_peek() failed\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ if (fb->state == VINO_FRAMEBUFFER_IN_USE) {
+ fb->state = VINO_FRAMEBUFFER_UNUSED;
+ vino_queue_transfer(&vcs->fb_queue);
+ vino_queue_remove(&vcs->fb_queue, &i);
+ /* we should actually discard the newest frame,
+ * but who cares ... */
+ }
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ return 0;
+}
+
+static void vino_frame_done(struct vino_channel_settings *vcs,
+ unsigned int fc)
+{
+ struct vino_framebuffer *fb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vcs->capture_lock, flags);
+ fb = vino_queue_transfer(&vcs->fb_queue);
+ if (!fb) {
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+ dprintk("vino_frame_done(): vino_queue_transfer() failed!\n");
+ return;
+ }
+ spin_unlock_irqrestore(&vcs->capture_lock, flags);
+
+ fb->frame_counter = fc;
+ do_gettimeofday(&fb->timestamp);
+
+ spin_lock_irqsave(&fb->state_lock, flags);
+ if (fb->state == VINO_FRAMEBUFFER_IN_USE)
+ fb->state = VINO_FRAMEBUFFER_READY;
+ spin_unlock_irqrestore(&fb->state_lock, flags);
+
+ wake_up(&vcs->fb_queue.frame_wait_queue);
+
+ vino_capture_next(vcs, 0);
+}
+
+static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ u32 intr;
+ unsigned int fc_a, fc_b;
+ int done_a = 0;
+ int done_b = 0;
+
+ spin_lock(&vino_drvdata->vino_lock);
+
+ intr = vino->intr_status;
+ fc_a = vino->a.field_counter / 2;
+ fc_b = vino->b.field_counter / 2;
+
+ // TODO: handle error-interrupts in some special way ?
+
+ if (intr & VINO_INTSTAT_A) {
+ if (intr & VINO_INTSTAT_A_EOF) {
+ vino_drvdata->a.field++;
+ if (vino_drvdata->a.field > 1) {
+ vino_dma_stop(&vino_drvdata->a);
+ vino_clear_interrupt(&vino_drvdata->a);
+ vino_drvdata->a.field = 0;
+ done_a = 1;
+ }
+ dprintk("intr: channel A end-of-field interrupt: "
+ "%04x\n", intr);
+ } else {
+ vino_dma_stop(&vino_drvdata->a);
+ vino_clear_interrupt(&vino_drvdata->a);
+ done_a = 1;
+ dprintk("channel A error interrupt: %04x\n", intr);
+ }
+ }
+ if (intr & VINO_INTSTAT_B) {
+ if (intr & VINO_INTSTAT_B_EOF) {
+ vino_drvdata->b.field++;
+ if (vino_drvdata->b.field > 1) {
+ vino_dma_stop(&vino_drvdata->b);
+ vino_clear_interrupt(&vino_drvdata->b);
+ vino_drvdata->b.field = 0;
+ done_b = 1;
+ }
+ dprintk("intr: channel B end-of-field interrupt: "
+ "%04x\n", intr);
+ } else {
+ vino_dma_stop(&vino_drvdata->b);
+ vino_clear_interrupt(&vino_drvdata->b);
+ done_b = 1;
+ dprintk("channel B error interrupt: %04x\n", intr);
+ }
+ }
+
+ /* always remember to clear interrupt status */
+ vino->intr_status = ~intr;
+
+ spin_unlock(&vino_drvdata->vino_lock);
+
+ if (done_a) {
+ vino_frame_done(&vino_drvdata->a, fc_a);
+ dprintk("channel A frame done, interrupt: %d\n", intr);
+ }
+ if (done_b) {
+ vino_frame_done(&vino_drvdata->b, fc_b);
+ dprintk("channel B frame done, interrupt: %d\n", intr);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* VINO video input management */
+
+static int vino_get_saa7191_input(int input)
+{
+ switch (input) {
+ case VINO_INPUT_COMPOSITE:
+ return SAA7191_INPUT_COMPOSITE;
+ case VINO_INPUT_SVIDEO:
+ return SAA7191_INPUT_SVIDEO;
+ default:
+ printk(KERN_ERR "VINO: vino_get_saa7191_input(): "
+ "invalid input!\n");
+ return -1;
+ }
+}
+
+static int vino_get_saa7191_norm(int norm)
+{
+ switch (norm) {
+ case VINO_DATA_NORM_AUTO:
+ return SAA7191_NORM_AUTO;
+ case VINO_DATA_NORM_PAL:
+ return SAA7191_NORM_PAL;
+ case VINO_DATA_NORM_NTSC:
+ return SAA7191_NORM_NTSC;
+ case VINO_DATA_NORM_SECAM:
+ return SAA7191_NORM_SECAM;
+ default:
+ printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
+ "invalid norm!\n");
+ return -1;
+ }
+}
+
+/* execute with input_lock locked */
+static int vino_is_input_owner(struct vino_channel_settings *vcs)
+{
+ switch(vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ return (vino_drvdata->decoder.owner == vcs->channel);
+ case VINO_INPUT_D1:
+ return (vino_drvdata->camera.owner == vcs->channel);
+ default:
+ return 0;
+ }
+}
+
+static int vino_acquire_input(struct vino_channel_settings *vcs)
+{
+ int ret = 0;
+
+ dprintk("vino_acquire_input():\n");
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ /* First try D1 and then SAA7191 */
+ if (vino_drvdata->camera.driver
+ && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
+ if (i2c_use_client(vino_drvdata->camera.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ vino_drvdata->camera.owner = vcs->channel;
+ vcs->input = VINO_INPUT_D1;
+ vcs->data_norm = VINO_DATA_NORM_D1;
+ } else if (vino_drvdata->decoder.driver
+ && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
+ int saa7191_input;
+ int saa7191_norm;
+
+ if (i2c_use_client(vino_drvdata->decoder.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ vino_drvdata->decoder.owner = vcs->channel;
+ vcs->input = VINO_INPUT_COMPOSITE;
+ vcs->data_norm = VINO_DATA_NORM_PAL;
+
+ saa7191_input = vino_get_saa7191_input(vcs->input);
+ i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+
+ saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
+ i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+ } else {
+ vcs->input = (vcs->channel == VINO_CHANNEL_A) ?
+ vino_drvdata->b.input : vino_drvdata->a.input;
+ vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ?
+ vino_drvdata->b.data_norm : vino_drvdata->a.data_norm;
+ }
+
+ if (vcs->input == VINO_INPUT_NONE) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (vino_is_input_owner(vcs)) {
+ vino_set_default_clipping(vcs);
+ vino_set_default_framerate(vcs);
+ }
+
+ dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return ret;
+}
+
+static int vino_set_input(struct vino_channel_settings *vcs, int input)
+{
+ struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+ &vino_drvdata->b : &vino_drvdata->a;
+ int ret = 0;
+
+ dprintk("vino_set_input():\n");
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ if (vcs->input == input)
+ goto out;
+
+ switch(input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ if (!vino_drvdata->decoder.driver) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
+ if (i2c_use_client(vino_drvdata->decoder.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ vino_drvdata->decoder.owner = vcs->channel;
+ }
+
+ if (vino_drvdata->decoder.owner == vcs->channel) {
+ int saa7191_input;
+ int saa7191_norm;
+
+ vcs->input = input;
+ vcs->data_norm = VINO_DATA_NORM_PAL;
+
+ saa7191_input = vino_get_saa7191_input(vcs->input);
+ i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input);
+ saa7191_norm = vino_get_saa7191_norm(vcs->data_norm);
+ i2c_decoder_command(DECODER_SAA7191_SET_NORM,
+ &saa7191_norm);
+ } else {
+ if (vcs2->input != input) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ vcs->input = input;
+ vcs->data_norm = vcs2->data_norm;
+ }
+
+ if (vino_drvdata->camera.owner == vcs->channel) {
+ /* Transfer the ownership or release the input */
+ if (vcs2->input == VINO_INPUT_D1) {
+ vino_drvdata->camera.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->
+ camera.driver);
+ vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ }
+ }
+ break;
+ case VINO_INPUT_D1:
+ if (!vino_drvdata->camera.driver) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
+ if (i2c_use_client(vino_drvdata->camera.driver)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ vino_drvdata->camera.owner = vcs->channel;
+ }
+
+ if (vino_drvdata->decoder.owner == vcs->channel) {
+ /* Transfer the ownership or release the input */
+ if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+ (vcs2->input == VINO_INPUT_SVIDEO)) {
+ vino_drvdata->decoder.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->
+ decoder.driver);
+ vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ }
+ }
+
+ vcs->input = input;
+ vcs->data_norm = VINO_DATA_NORM_D1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+
+ vino_set_default_clipping(vcs);
+ vino_set_default_framerate(vcs);
+
+ dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name);
+
+out:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return ret;
+}
+
+static void vino_release_input(struct vino_channel_settings *vcs)
+{
+ struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
+ &vino_drvdata->b : &vino_drvdata->a;
+
+ dprintk("vino_release_input():\n");
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ /* Release ownership of the channel
+ * and if the other channel takes input from
+ * the same source, transfer the ownership */
+ if (vino_drvdata->camera.owner == vcs->channel) {
+ if (vcs2->input == VINO_INPUT_D1) {
+ vino_drvdata->camera.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->camera.driver);
+ vino_drvdata->camera.owner = VINO_NO_CHANNEL;
+ }
+ } else if (vino_drvdata->decoder.owner == vcs->channel) {
+ if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+ (vcs2->input == VINO_INPUT_SVIDEO)) {
+ vino_drvdata->decoder.owner = vcs2->channel;
+ } else {
+ i2c_release_client(vino_drvdata->decoder.driver);
+ vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
+ }
+ }
+ vcs->input = VINO_INPUT_NONE;
+
+ spin_unlock(&vino_drvdata->input_lock);
+}
+
+/* execute with input_lock locked */
+static int vino_set_data_norm(struct vino_channel_settings *vcs,
+ unsigned int data_norm)
+{
+ int saa7191_norm;
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ /* only one "norm" supported */
+ if (data_norm != VINO_DATA_NORM_D1)
+ return -EINVAL;
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+
+ saa7191_norm = vino_get_saa7191_norm(data_norm);
+
+ i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm);
+ vcs->data_norm = data_norm;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* V4L2 helper functions */
+
+static int vino_find_data_format(__u32 pixelformat)
+{
+ int i;
+
+ for (i = 0; i < VINO_DATA_FMT_COUNT; i++) {
+ if (vino_data_formats[i].pixelformat == pixelformat)
+ return i;
+ }
+
+ return VINO_DATA_FMT_NONE;
+}
+
+static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
+{
+ int data_norm = VINO_DATA_NORM_NONE;
+
+ spin_lock(&vino_drvdata->input_lock);
+ switch(vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ if (index == 0) {
+ data_norm = VINO_DATA_NORM_PAL;
+ } else if (index == 1) {
+ data_norm = VINO_DATA_NORM_NTSC;
+ } else if (index == 2) {
+ data_norm = VINO_DATA_NORM_SECAM;
+ }
+ break;
+ case VINO_INPUT_D1:
+ if (index == 0) {
+ data_norm = VINO_DATA_NORM_D1;
+ }
+ break;
+ }
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return data_norm;
+}
+
+static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+{
+ int input = VINO_INPUT_NONE;
+
+ spin_lock(&vino_drvdata->input_lock);
+ if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_COMPOSITE;
+ break;
+ case 1:
+ input = VINO_INPUT_SVIDEO;
+ break;
+ case 2:
+ input = VINO_INPUT_D1;
+ break;
+ }
+ } else if (vino_drvdata->decoder.driver) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_COMPOSITE;
+ break;
+ case 1:
+ input = VINO_INPUT_SVIDEO;
+ break;
+ }
+ } else if (vino_drvdata->camera.driver) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_D1;
+ break;
+ }
+ }
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return input;
+}
+
+/* execute with input_lock locked */
+static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+{
+ __u32 index = 0;
+ // FIXME: detect when no inputs available
+
+ if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
+ switch (vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ index = 0;
+ break;
+ case VINO_INPUT_SVIDEO:
+ index = 1;
+ break;
+ case VINO_INPUT_D1:
+ index = 2;
+ break;
+ }
+ } else if (vino_drvdata->decoder.driver) {
+ switch (vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ index = 0;
+ break;
+ case VINO_INPUT_SVIDEO:
+ index = 1;
+ break;
+ }
+ } else if (vino_drvdata->camera.driver) {
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ index = 0;
+ break;
+ }
+ }
+
+ return index;
+}
+
+/* V4L2 ioctls */
+
+static void vino_v4l2_querycap(struct v4l2_capability *cap)
+{
+ memset(cap, 0, sizeof(struct v4l2_capability));
+
+ strcpy(cap->driver, vino_driver_name);
+ strcpy(cap->card, vino_driver_description);
+ strcpy(cap->bus_info, vino_bus_name);
+ cap->version = VINO_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING;
+ // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+}
+
+static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+ struct v4l2_input *i)
+{
+ __u32 index = i->index;
+ int input;
+ dprintk("requested index = %d\n", index);
+
+ input = vino_enum_input(vcs, index);
+ if (input == VINO_INPUT_NONE)
+ return -EINVAL;
+
+ memset(i, 0, sizeof(struct v4l2_input));
+
+ i->index = index;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->std = vino_inputs[input].std;
+ strcpy(i->name, vino_inputs[input].name);
+
+ if ((input == VINO_INPUT_COMPOSITE)
+ || (input == VINO_INPUT_SVIDEO)) {
+ struct saa7191_status status;
+ i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
+ i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
+ i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+ struct v4l2_input *i)
+{
+ __u32 index;
+ int input;
+
+ spin_lock(&vino_drvdata->input_lock);
+ input = vcs->input;
+ index = vino_find_input_index(vcs);
+ spin_unlock(&vino_drvdata->input_lock);
+
+ dprintk("input = %d\n", input);
+
+ if (input == VINO_INPUT_NONE) {
+ return -EINVAL;
+ }
+
+ memset(i, 0, sizeof(struct v4l2_input));
+
+ i->index = index;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->std = vino_inputs[input].std;
+ strcpy(i->name, vino_inputs[input].name);
+
+ return 0;
+}
+
+static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
+ struct v4l2_input *i)
+{
+ int input;
+ dprintk("requested input = %d\n", i->index);
+
+ input = vino_enum_input(vcs, i->index);
+ if (input == VINO_INPUT_NONE)
+ return -EINVAL;
+
+ return vino_set_input(vcs, input);
+}
+
+static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
+ struct v4l2_standard *s)
+{
+ int index = s->index;
+ int data_norm = vino_enum_data_norm(vcs, index);
+ dprintk("standard index = %d\n", index);
+
+ if (data_norm == VINO_DATA_NORM_NONE)
+ return -EINVAL;
+
+ dprintk("standard name = %s\n",
+ vino_data_norms[data_norm].description);
+
+ memset(s, 0, sizeof(struct v4l2_standard));
+ s->index = index;
+
+ s->id = vino_data_norms[data_norm].std;
+ s->frameperiod.numerator = 1;
+ s->frameperiod.denominator =
+ vino_data_norms[data_norm].fps_max;
+ s->framelines =
+ vino_data_norms[data_norm].framelines;
+ strcpy(s->name,
+ vino_data_norms[data_norm].description);
+
+ return 0;
+}
+
+static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+ v4l2_std_id *std)
+{
+ spin_lock(&vino_drvdata->input_lock);
+ dprintk("current standard = %d\n", vcs->data_norm);
+ *std = vino_data_norms[vcs->data_norm].std;
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return 0;
+}
+
+static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+ v4l2_std_id *std)
+{
+ int ret = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ /* check if the standard is valid for the current input */
+ if (vino_is_input_owner(vcs)
+ && (vino_inputs[vcs->input].std & (*std))) {
+ dprintk("standard accepted\n");
+
+ /* change the video norm for SAA7191
+ * and accept NTSC for D1 (do nothing) */
+
+ if (vcs->input == VINO_INPUT_D1)
+ goto out;
+
+ if ((*std) & V4L2_STD_PAL) {
+ vino_set_data_norm(vcs, VINO_DATA_NORM_PAL);
+ vcs->data_norm = VINO_DATA_NORM_PAL;
+ } else if ((*std) & V4L2_STD_NTSC) {
+ vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC);
+ vcs->data_norm = VINO_DATA_NORM_NTSC;
+ } else if ((*std) & V4L2_STD_SECAM) {
+ vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM);
+ vcs->data_norm = VINO_DATA_NORM_SECAM;
+ } else {
+ ret = -EINVAL;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+out:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return ret;
+}
+
+static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_fmtdesc *fd)
+{
+ enum v4l2_buf_type type = fd->type;
+ int index = fd->index;
+ dprintk("format index = %d\n", index);
+
+ switch (fd->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if ((fd->index < 0) ||
+ (fd->index >= VINO_DATA_FMT_COUNT))
+ return -EINVAL;
+ dprintk("format name = %s\n",
+ vino_data_formats[index].description);
+
+ memset(fd, 0, sizeof(struct v4l2_fmtdesc));
+ fd->index = index;
+ fd->type = type;
+ fd->pixelformat = vino_data_formats[index].pixelformat;
+ strcpy(fd->description, vino_data_formats[index].description);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_format *f)
+{
+ struct vino_channel_settings tempvcs;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+
+ dprintk("requested: w = %d, h = %d\n",
+ pf->width, pf->height);
+
+ spin_lock(&vino_drvdata->input_lock);
+ memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+ spin_unlock(&vino_drvdata->input_lock);
+
+ tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+ if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+ tempvcs.data_format = VINO_DATA_FMT_RGB32;
+ pf->pixelformat =
+ vino_data_formats[tempvcs.data_format].
+ pixelformat;
+ }
+
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(&tempvcs, pf->width, pf->height);
+
+ dprintk("data format = %s\n",
+ vino_data_formats[tempvcs.data_format].description);
+
+ pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+ tempvcs.decimation;
+ pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
+
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = tempvcs.line_size;
+ pf->sizeimage = tempvcs.line_size *
+ (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+ tempvcs.decimation;
+ pf->colorspace =
+ vino_data_formats[tempvcs.data_format].colorspace;
+
+ pf->priv = 0;
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_format *f)
+{
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+ spin_lock(&vino_drvdata->input_lock);
+
+ pf->width = (vcs->clipping.right - vcs->clipping.left) /
+ vcs->decimation;
+ pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].pixelformat;
+
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
+
+ pf->priv = 0;
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
+ struct v4l2_format *f)
+{
+ int data_format;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+ spin_lock(&vino_drvdata->input_lock);
+
+ if (!vino_is_input_owner(vcs)) {
+ spin_unlock(&vino_drvdata->input_lock);
+ return -EINVAL;
+ }
+
+ data_format = vino_find_data_format(pf->pixelformat);
+ if (data_format == VINO_DATA_FMT_NONE) {
+ vcs->data_format = VINO_DATA_FMT_RGB32;
+ pf->pixelformat =
+ vino_data_formats[vcs->data_format].
+ pixelformat;
+ } else {
+ vcs->data_format = data_format;
+ }
+
+ /* data format must be set before clipping/scaling */
+ vino_set_scaling(vcs, pf->width, pf->height);
+
+ dprintk("data format = %s\n",
+ vino_data_formats[vcs->data_format].description);
+
+ pf->width = vcs->clipping.right - vcs->clipping.left;
+ pf->height = vcs->clipping.bottom - vcs->clipping.top;
+
+ pf->field = V4L2_FIELD_INTERLACED;
+ pf->bytesperline = vcs->line_size;
+ pf->sizeimage = vcs->line_size *
+ (vcs->clipping.bottom - vcs->clipping.top) /
+ vcs->decimation;
+ pf->colorspace =
+ vino_data_formats[vcs->data_format].colorspace;
+
+ pf->priv = 0;
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+ struct v4l2_cropcap *ccap)
+{
+ const struct vino_data_norm *norm;
+
+ switch (ccap->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ spin_lock(&vino_drvdata->input_lock);
+ norm = &vino_data_norms[vcs->data_norm];
+ spin_unlock(&vino_drvdata->input_lock);
+
+ ccap->bounds.left = 0;
+ ccap->bounds.top = 0;
+ ccap->bounds.width = norm->width;
+ ccap->bounds.height = norm->height;
+ memcpy(&ccap->defrect, &ccap->bounds,
+ sizeof(struct v4l2_rect));
+
+ ccap->pixelaspect.numerator = 1;
+ ccap->pixelaspect.denominator = 1;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+ struct v4l2_crop *c)
+{
+ switch (c->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ spin_lock(&vino_drvdata->input_lock);
+
+ c->c.left = vcs->clipping.left;
+ c->c.top = vcs->clipping.top;
+ c->c.width = vcs->clipping.right - vcs->clipping.left;
+ c->c.height = vcs->clipping.bottom - vcs->clipping.top;
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+ struct v4l2_crop *c)
+{
+ switch (c->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ spin_lock(&vino_drvdata->input_lock);
+
+ if (!vino_is_input_owner(vcs)) {
+ spin_unlock(&vino_drvdata->input_lock);
+ return -EINVAL;
+ }
+ vino_set_clipping(vcs, c->c.left, c->c.top,
+ c->c.width, c->c.height);
+
+ spin_unlock(&vino_drvdata->input_lock);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
+ struct v4l2_streamparm *sp)
+{
+ switch (sp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+ memset(cp, 0, sizeof(struct v4l2_captureparm));
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
+
+ spin_lock(&vino_drvdata->input_lock);
+ cp->timeperframe.denominator = vcs->fps;
+ spin_unlock(&vino_drvdata->input_lock);
+
+ // TODO: cp->readbuffers = xxx;
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
+ struct v4l2_streamparm *sp)
+{
+ switch (sp->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ spin_lock(&vino_drvdata->input_lock);
+ if (!vino_is_input_owner(vcs)) {
+ spin_unlock(&vino_drvdata->input_lock);
+ return -EINVAL;
+ }
+
+ if ((cp->timeperframe.numerator == 0) ||
+ (cp->timeperframe.denominator == 0)) {
+ /* reset framerate */
+ vino_set_default_framerate(vcs);
+ } else {
+ vino_set_framerate(vcs, cp->timeperframe.denominator /
+ cp->timeperframe.numerator);
+ }
+ spin_unlock(&vino_drvdata->input_lock);
+
+ // TODO: set buffers according to cp->readbuffers
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
+ struct v4l2_requestbuffers *rb)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (rb->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ // TODO: check queue type
+ if (rb->memory != V4L2_MEMORY_MMAP) {
+ dprintk("type not mmap\n");
+ return -EINVAL;
+ }
+
+ if (vino_is_capturing(vcs)) {
+ dprintk("busy, capturing\n");
+ return -EBUSY;
+ }
+
+ dprintk("count = %d\n", rb->count);
+ if (rb->count > 0) {
+ if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+ dprintk("busy, buffers still mapped\n");
+ return -EBUSY;
+ } else {
+ vino_queue_free(&vcs->fb_queue);
+ vino_queue_init(&vcs->fb_queue, &rb->count);
+ }
+ } else {
+ vino_capture_stop(vcs);
+ vino_queue_free(&vcs->fb_queue);
+ }
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
+ struct vino_framebuffer *fb,
+ struct v4l2_buffer *b)
+{
+ if (vino_queue_outgoing_contains(&vcs->fb_queue,
+ fb->id)) {
+ b->flags &= ~V4L2_BUF_FLAG_QUEUED;
+ b->flags |= V4L2_BUF_FLAG_DONE;
+ } else if (vino_queue_incoming_contains(&vcs->fb_queue,
+ fb->id)) {
+ b->flags &= ~V4L2_BUF_FLAG_DONE;
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+ } else {
+ b->flags &= ~(V4L2_BUF_FLAG_DONE |
+ V4L2_BUF_FLAG_QUEUED);
+ }
+
+ b->flags &= ~(V4L2_BUF_FLAG_TIMECODE);
+
+ if (fb->map_count > 0)
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ b->index = fb->id;
+ b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ?
+ V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+ b->m.offset = fb->offset;
+ b->bytesused = fb->data_size;
+ b->length = fb->size;
+ b->field = V4L2_FIELD_INTERLACED;
+ b->sequence = fb->frame_counter;
+ memcpy(&b->timestamp, &fb->timestamp,
+ sizeof(struct timeval));
+ // b->input ?
+
+ dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n",
+ fb->id, fb->size, fb->data_size, fb->offset);
+}
+
+static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
+ struct v4l2_buffer *b)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct vino_framebuffer *fb;
+
+ // TODO: check queue type
+ if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+ dprintk("invalid index = %d\n",
+ b->index);
+ return -EINVAL;
+ }
+
+ fb = vino_queue_get_buffer(&vcs->fb_queue,
+ b->index);
+ if (fb == NULL) {
+ dprintk("vino_queue_get_buffer() failed");
+ return -EINVAL;
+ }
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
+ struct v4l2_buffer *b)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct vino_framebuffer *fb;
+ int ret;
+
+ // TODO: check queue type
+ if (b->memory != V4L2_MEMORY_MMAP) {
+ dprintk("type not mmap\n");
+ return -EINVAL;
+ }
+
+ fb = vino_capture_enqueue(vcs, b->index);
+ if (fb == NULL)
+ return -EINVAL;
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+
+ if (vcs->streaming) {
+ ret = vino_capture_next(vcs, 1);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
+ struct v4l2_buffer *b,
+ unsigned int nonblocking)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct vino_framebuffer *fb;
+ unsigned int incoming, outgoing;
+ int err;
+
+ // TODO: check queue type
+
+ err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (err) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EIO;
+ }
+ err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+ if (err) {
+ dprintk("vino_queue_get_outgoing() failed\n");
+ return -EIO;
+ }
+
+ dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
+
+ if (outgoing == 0) {
+ if (incoming == 0) {
+ dprintk("no incoming or outgoing buffers\n");
+ return -EINVAL;
+ }
+ if (nonblocking) {
+ dprintk("non-blocking I/O was selected and "
+ "there are no buffers to dequeue\n");
+ return -EAGAIN;
+ }
+
+ err = vino_wait_for_frame(vcs);
+ if (err) {
+ err = vino_wait_for_frame(vcs);
+ if (err) {
+ /* interrupted */
+ vino_capture_failed(vcs);
+ return -EIO;
+ }
+ }
+ }
+
+ fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+ if (fb == NULL) {
+ dprintk("vino_queue_remove() failed\n");
+ return -EINVAL;
+ }
+
+ err = vino_check_buffer(vcs, fb);
+ if (err)
+ return -EIO;
+
+ vino_v4l2_get_buffer_status(vcs, fb, b);
+ break;
+ }
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+{
+ unsigned int incoming;
+ int ret;
+ if (vcs->reading)
+ return -EBUSY;
+
+ if (vcs->streaming)
+ return 0;
+
+ // TODO: check queue type
+
+ if (vino_queue_get_length(&vcs->fb_queue) < 1) {
+ dprintk("no buffers allocated\n");
+ return -EINVAL;
+ }
+
+ ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+ if (ret) {
+ dprintk("vino_queue_get_incoming() failed\n");
+ return -EINVAL;
+ }
+
+ vcs->streaming = 1;
+
+ if (incoming > 0) {
+ ret = vino_capture_next(vcs, 1);
+ if (ret) {
+ vcs->streaming = 0;
+
+ dprintk("couldn't start capture\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+{
+ if (vcs->reading)
+ return -EBUSY;
+
+ if (!vcs->streaming)
+ return 0;
+
+ vino_capture_stop(vcs);
+ vcs->streaming = 0;
+
+ return 0;
+}
+
+static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+ struct v4l2_queryctrl *queryctrl)
+{
+ int i;
+ int err = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+ if (vino_indycam_v4l2_controls[i].id ==
+ queryctrl->id) {
+ memcpy(queryctrl,
+ &vino_indycam_v4l2_controls[i],
+ sizeof(struct v4l2_queryctrl));
+ goto found;
+ }
+ }
+
+ err = -EINVAL;
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+ if (vino_saa7191_v4l2_controls[i].id ==
+ queryctrl->id) {
+ memcpy(queryctrl,
+ &vino_saa7191_v4l2_controls[i],
+ sizeof(struct v4l2_queryctrl));
+ goto found;
+ }
+ }
+
+ err = -EINVAL;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ found:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return err;
+}
+
+static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+ struct v4l2_control *control)
+{
+ struct indycam_control indycam_ctrl;
+ struct saa7191_control saa7191_ctrl;
+ int err = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ i2c_camera_command(DECODER_INDYCAM_GET_CONTROLS,
+ &indycam_ctrl);
+
+ switch(control->id) {
+ case V4L2_CID_AUTOGAIN:
+ control->value = indycam_ctrl.agc;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ control->value = indycam_ctrl.awb;
+ break;
+ case V4L2_CID_GAIN:
+ control->value = indycam_ctrl.gain;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ control->value = indycam_ctrl.red_saturation;
+ break;
+ case V4L2_CID_PRIVATE_BASE + 1:
+ control->value = indycam_ctrl.blue_saturation;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ control->value = indycam_ctrl.red_balance;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ control->value = indycam_ctrl.blue_balance;
+ break;
+ case V4L2_CID_EXPOSURE:
+ control->value = indycam_ctrl.shutter;
+ break;
+ case V4L2_CID_GAMMA:
+ control->value = indycam_ctrl.gamma;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ i2c_decoder_command(DECODER_SAA7191_GET_CONTROLS,
+ &saa7191_ctrl);
+
+ switch(control->id) {
+ case V4L2_CID_HUE:
+ control->value = saa7191_ctrl.hue;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ control->value = saa7191_ctrl.vtrc;
+ break;
+ default:
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return err;
+}
+
+static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+ struct v4l2_control *control)
+{
+ struct indycam_control indycam_ctrl;
+ struct saa7191_control saa7191_ctrl;
+ int i;
+ int err = 0;
+
+ spin_lock(&vino_drvdata->input_lock);
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+ if (vino_indycam_v4l2_controls[i].id ==
+ control->id) {
+ if ((control->value >=
+ vino_indycam_v4l2_controls[i].minimum)
+ && (control->value <=
+ vino_indycam_v4l2_controls[i].
+ maximum)) {
+ goto ok1;
+ } else {
+ err = -ERANGE;
+ goto error;
+ }
+ }
+ }
+ err = -EINVAL;
+ goto error;
+
+ok1:
+ indycam_ctrl.agc = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.awb = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.shutter = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.gain = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.red_balance = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.blue_balance = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.red_saturation = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.blue_saturation = INDYCAM_VALUE_UNCHANGED;
+ indycam_ctrl.gamma = INDYCAM_VALUE_UNCHANGED;
+
+ switch(control->id) {
+ case V4L2_CID_AUTOGAIN:
+ indycam_ctrl.agc = control->value;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ indycam_ctrl.awb = control->value;
+ break;
+ case V4L2_CID_GAIN:
+ indycam_ctrl.gain = control->value;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ indycam_ctrl.red_saturation = control->value;
+ break;
+ case V4L2_CID_PRIVATE_BASE + 1:
+ indycam_ctrl.blue_saturation = control->value;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ indycam_ctrl.red_balance = control->value;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ indycam_ctrl.blue_balance = control->value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ indycam_ctrl.shutter = control->value;
+ break;
+ case V4L2_CID_GAMMA:
+ indycam_ctrl.gamma = control->value;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err)
+ i2c_camera_command(DECODER_INDYCAM_SET_CONTROLS,
+ &indycam_ctrl);
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+ if (vino_saa7191_v4l2_controls[i].id ==
+ control->id) {
+ if ((control->value >=
+ vino_saa7191_v4l2_controls[i].minimum)
+ && (control->value <=
+ vino_saa7191_v4l2_controls[i].
+ maximum)) {
+ goto ok2;
+ } else {
+ err = -ERANGE;
+ goto error;
+ }
+ }
+ }
+ err = -EINVAL;
+ goto error;
+
+ok2:
+ saa7191_ctrl.hue = SAA7191_VALUE_UNCHANGED;
+ saa7191_ctrl.vtrc = SAA7191_VALUE_UNCHANGED;
+
+ switch(control->id) {
+ case V4L2_CID_HUE:
+ saa7191_ctrl.hue = control->value;
+ break;
+ case V4L2_CID_PRIVATE_BASE:
+ saa7191_ctrl.vtrc = control->value;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err)
+ i2c_decoder_command(DECODER_SAA7191_SET_CONTROLS,
+ &saa7191_ctrl);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+error:
+ spin_unlock(&vino_drvdata->input_lock);
+
+ return err;
+}
+
+/* File operations */
+
+static int vino_open(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ int ret = 0;
+ dprintk("open(): channel = %c\n",
+ (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
+
+ down(&vcs->sem);
+
+ if (vcs->users) {
+ dprintk("open(): driver busy\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = vino_acquire_input(vcs);
+ if (ret) {
+ dprintk("open(): vino_acquire_input() failed\n");
+ goto out;
+ }
+
+ vcs->users++;
+
+ out:
+ up(&vcs->sem);
+
+ dprintk("open(): %s!\n", ret ? "failed" : "complete");
+
+ return ret;
+}
+
+static int vino_close(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ dprintk("close():\n");
+
+ down(&vcs->sem);
+
+ vcs->users--;
+
+ if (!vcs->users) {
+ vino_release_input(vcs);
+
+ /* stop DMA and free buffers */
+ vino_capture_stop(vcs);
+ vino_queue_free(&vcs->fb_queue);
+ }
+
+ up(&vcs->sem);
+
+ return 0;
+}
+
+static void vino_vm_open(struct vm_area_struct *vma)
+{
+ struct vino_framebuffer *fb = vma->vm_private_data;
+
+ fb->map_count++;
+ dprintk("vino_vm_open(): count = %d\n", fb->map_count);
+}
+
+static void vino_vm_close(struct vm_area_struct *vma)
+{
+ struct vino_framebuffer *fb = vma->vm_private_data;
+
+ fb->map_count--;
+ dprintk("vino_vm_close(): count = %d\n", fb->map_count);
+}
+
+static struct vm_operations_struct vino_vm_ops = {
+ .open = vino_vm_open,
+ .close = vino_vm_close,
+};
+
+static int vino_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ struct vino_framebuffer *fb = NULL;
+ unsigned int i, length;
+ int ret = 0;
+
+ dprintk("mmap():\n");
+
+ // TODO: reject mmap if already mapped
+
+ if (down_interruptible(&vcs->sem))
+ return -EINTR;
+
+ if (vcs->reading) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ // TODO: check queue type
+
+ if (!(vma->vm_flags & VM_WRITE)) {
+ dprintk("mmap(): app bug: PROT_WRITE please\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!(vma->vm_flags & VM_SHARED)) {
+ dprintk("mmap(): app bug: MAP_SHARED please\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* find the correct buffer using offset */
+ length = vino_queue_get_length(&vcs->fb_queue);
+ if (length == 0) {
+ dprintk("mmap(): queue not initialized\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < length; i++) {
+ fb = vino_queue_get_buffer(&vcs->fb_queue, i);
+ if (fb == NULL) {
+ dprintk("mmap(): vino_queue_get_buffer() failed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (fb->offset == offset)
+ goto found;
+ }
+
+ dprintk("mmap(): invalid offset = %lu\n", offset);
+ ret = -EINVAL;
+ goto out;
+
+found:
+ dprintk("mmap(): buffer = %d\n", i);
+
+ if (size > (fb->desc_table.page_count * PAGE_SIZE)) {
+ dprintk("mmap(): failed: size = %lu > %lu\n",
+ size, fb->desc_table.page_count * PAGE_SIZE);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < fb->desc_table.page_count; i++) {
+ unsigned long pfn =
+ virt_to_phys((void *)fb->desc_table.virtual[i]) >>
+ PAGE_SHIFT;
+
+ if (size < PAGE_SIZE)
+ break;
+
+ // protection was: PAGE_READONLY
+ if (remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+ vma->vm_page_prot)) {
+ dprintk("mmap(): remap_pfn_range() failed\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ start += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ fb->map_count = 1;
+
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_flags &= ~VM_IO;
+ vma->vm_private_data = fb;
+ vma->vm_file = file;
+ vma->vm_ops = &vino_vm_ops;
+
+out:
+ up(&vcs->sem);
+
+ return ret;
+}
+
+static unsigned int vino_poll(struct file *file, poll_table *pt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ unsigned int outgoing;
+ unsigned int ret = 0;
+
+ // lock mutex (?)
+ // TODO: this has to be corrected for different read modes
+
+ dprintk("poll():\n");
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("poll(): vino_queue_get_outgoing() failed\n");
+ ret = POLLERR;
+ goto error;
+ }
+ if (outgoing > 0)
+ goto over;
+
+ poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt);
+
+ if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
+ dprintk("poll(): vino_queue_get_outgoing() failed\n");
+ ret = POLLERR;
+ goto error;
+ }
+
+over:
+ dprintk("poll(): data %savailable\n",
+ (outgoing > 0) ? "" : "not ");
+ if (outgoing > 0) {
+ ret = POLLIN | POLLRDNORM;
+ }
+
+error:
+
+ return ret;
+}
+
+static int vino_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+
+ switch (_IOC_TYPE(cmd)) {
+ case 'v':
+ dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
+ break;
+ case 'V':
+ dprintk("ioctl(): V4L2 %s (0x%08x)\n",
+ v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
+ break;
+ default:
+ dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
+ }
+
+ switch (cmd) {
+ /* TODO: V4L1 interface (use compatibility layer?) */
+ /* V4L2 interface */
+ case VIDIOC_QUERYCAP: {
+ vino_v4l2_querycap(arg);
+ break;
+ }
+ case VIDIOC_ENUMINPUT: {
+ return vino_v4l2_enuminput(vcs, arg);
+ }
+ case VIDIOC_G_INPUT: {
+ return vino_v4l2_g_input(vcs, arg);
+ }
+ case VIDIOC_S_INPUT: {
+ return vino_v4l2_s_input(vcs, arg);
+ }
+ case VIDIOC_ENUMSTD: {
+ return vino_v4l2_enumstd(vcs, arg);
+ }
+ case VIDIOC_G_STD: {
+ return vino_v4l2_g_std(vcs, arg);
+ }
+ case VIDIOC_S_STD: {
+ return vino_v4l2_s_std(vcs, arg);
+ }
+ case VIDIOC_ENUM_FMT: {
+ return vino_v4l2_enum_fmt(vcs, arg);
+ }
+ case VIDIOC_TRY_FMT: {
+ return vino_v4l2_try_fmt(vcs, arg);
+ }
+ case VIDIOC_G_FMT: {
+ return vino_v4l2_g_fmt(vcs, arg);
+ }
+ case VIDIOC_S_FMT: {
+ return vino_v4l2_s_fmt(vcs, arg);
+ }
+ case VIDIOC_CROPCAP: {
+ return vino_v4l2_cropcap(vcs, arg);
+ }
+ case VIDIOC_G_CROP: {
+ return vino_v4l2_g_crop(vcs, arg);
+ }
+ case VIDIOC_S_CROP: {
+ return vino_v4l2_s_crop(vcs, arg);
+ }
+ case VIDIOC_G_PARM: {
+ return vino_v4l2_g_parm(vcs, arg);
+ }
+ case VIDIOC_S_PARM: {
+ return vino_v4l2_s_parm(vcs, arg);
+ }
+ case VIDIOC_REQBUFS: {
+ return vino_v4l2_reqbufs(vcs, arg);
+ }
+ case VIDIOC_QUERYBUF: {
+ return vino_v4l2_querybuf(vcs, arg);
+ }
+ case VIDIOC_QBUF: {
+ return vino_v4l2_qbuf(vcs, arg);
+ }
+ case VIDIOC_DQBUF: {
+ return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
+ }
+ case VIDIOC_STREAMON: {
+ return vino_v4l2_streamon(vcs);
+ }
+ case VIDIOC_STREAMOFF: {
+ return vino_v4l2_streamoff(vcs);
+ }
+ case VIDIOC_QUERYCTRL: {
+ return vino_v4l2_queryctrl(vcs, arg);
+ }
+ case VIDIOC_G_CTRL: {
+ return vino_v4l2_g_ctrl(vcs, arg);
+ }
+ case VIDIOC_S_CTRL: {
+ return vino_v4l2_s_ctrl(vcs, arg);
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int vino_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct vino_channel_settings *vcs = video_get_drvdata(dev);
+ int ret;
+
+ if (down_interruptible(&vcs->sem))
+ return -EINTR;
+
+ ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
+
+ up(&vcs->sem);
+
+ return ret;
+}
+
+/* Initialization and cleanup */
+
+// __initdata
+static int vino_init_stage = 0;
+
+static struct file_operations vino_fops = {
+ .owner = THIS_MODULE,
+ .open = vino_open,
+ .release = vino_close,
+ .ioctl = vino_ioctl,
+ .mmap = vino_mmap,
+ .poll = vino_poll,
+ .llseek = no_llseek,
+};
+
+static struct video_device v4l_device_template = {
+ .name = "NOT SET",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ .hardware = VID_HARDWARE_VINO,
+ .fops = &vino_fops,
+ .minor = -1,
+};
+
+static void vino_module_cleanup(int stage)
+{
+ switch(stage) {
+ case 10:
+ video_unregister_device(vino_drvdata->b.v4l_device);
+ vino_drvdata->b.v4l_device = NULL;
+ case 9:
+ video_unregister_device(vino_drvdata->a.v4l_device);
+ vino_drvdata->a.v4l_device = NULL;
+ case 8:
+ vino_i2c_del_bus();
+ case 7:
+ free_irq(SGI_VINO_IRQ, NULL);
+ case 6:
+ if (vino_drvdata->b.v4l_device) {
+ video_device_release(vino_drvdata->b.v4l_device);
+ vino_drvdata->b.v4l_device = NULL;
+ }
+ case 5:
+ if (vino_drvdata->a.v4l_device) {
+ video_device_release(vino_drvdata->a.v4l_device);
+ vino_drvdata->a.v4l_device = NULL;
+ }
+ case 4:
+ /* all entries in dma_cpu dummy table have the same address */
+ dma_unmap_single(NULL,
+ vino_drvdata->dummy_desc_table.dma_cpu[0],
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT
+ * sizeof(dma_addr_t),
+ (void *)vino_drvdata->
+ dummy_desc_table.dma_cpu,
+ vino_drvdata->dummy_desc_table.dma);
+ case 3:
+ free_page(vino_drvdata->dummy_page);
+ case 2:
+ kfree(vino_drvdata);
+ case 1:
+ iounmap(vino);
+ case 0:
+ break;
+ default:
+ dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n",
+ stage);
+ }
+}
+
+static int vino_probe(void)
+{
+ unsigned long rev_id;
+
+ if (ip22_is_fullhouse()) {
+ printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n");
+ return -ENODEV;
+ }
+
+ if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
+ printk(KERN_ERR "VINO is not found (EISA BUS not present)\n");
+ return -ENODEV;
+ }
+
+ vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
+ if (!vino) {
+ printk(KERN_ERR "VINO: ioremap() failed\n");
+ return -EIO;
+ }
+ vino_init_stage++;
+
+ if (get_dbe(rev_id, &(vino->rev_id))) {
+ printk(KERN_ERR "Failed to read VINO revision register\n");
+ vino_module_cleanup(vino_init_stage);
+ return -ENODEV;
+ }
+
+ if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) {
+ printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n",
+ rev_id);
+ vino_module_cleanup(vino_init_stage);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "VINO with chip ID %ld, revision %ld found\n",
+ VINO_ID_VALUE(rev_id), VINO_REV_NUM(rev_id));
+
+ return 0;
+}
+
+static int vino_init(void)
+{
+ dma_addr_t dma_dummy_address;
+ int i;
+
+ vino_drvdata = (struct vino_settings *)
+ kmalloc(sizeof(struct vino_settings), GFP_KERNEL);
+ if (!vino_drvdata) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ memset(vino_drvdata, 0, sizeof(struct vino_settings));
+ vino_init_stage++;
+
+ /* create a dummy dma descriptor */
+ vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!vino_drvdata->dummy_page) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ vino_init_stage++;
+
+ // TODO: use page_count in dummy_desc_table
+
+ vino_drvdata->dummy_desc_table.dma_cpu =
+ dma_alloc_coherent(NULL,
+ VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t),
+ &vino_drvdata->dummy_desc_table.dma,
+ GFP_KERNEL | GFP_DMA);
+ if (!vino_drvdata->dummy_desc_table.dma_cpu) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ vino_init_stage++;
+
+ dma_dummy_address = dma_map_single(NULL,
+ (void *)vino_drvdata->dummy_page,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) {
+ vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address;
+ }
+
+ /* initialize VINO */
+
+ vino->control = 0;
+ vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+ vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma;
+ udelay(VINO_DESC_FETCH_DELAY);
+
+ vino->intr_status = 0;
+
+ vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+ vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
+
+ return 0;
+}
+
+static int vino_init_channel_settings(struct vino_channel_settings *vcs,
+ unsigned int channel, const char *name)
+{
+ vcs->channel = channel;
+ vcs->input = VINO_INPUT_NONE;
+ vcs->alpha = 0;
+ vcs->users = 0;
+ vcs->data_format = VINO_DATA_FMT_GREY;
+ vcs->data_norm = VINO_DATA_NORM_NTSC;
+ vcs->decimation = 1;
+ vino_set_default_clipping(vcs);
+ vino_set_default_framerate(vcs);
+
+ vcs->capturing = 0;
+
+ init_MUTEX(&vcs->sem);
+ spin_lock_init(&vcs->capture_lock);
+
+ init_MUTEX(&vcs->fb_queue.queue_sem);
+ spin_lock_init(&vcs->fb_queue.queue_lock);
+ init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
+
+ vcs->v4l_device = video_device_alloc();
+ if (!vcs->v4l_device) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ vino_init_stage++;
+
+ memcpy(vcs->v4l_device, &v4l_device_template,
+ sizeof(struct video_device));
+ strcpy(vcs->v4l_device->name, name);
+ vcs->v4l_device->release = video_device_release;
+
+ video_set_drvdata(vcs->v4l_device, vcs);
+
+ return 0;
+}
+
+static int __init vino_module_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "SGI VINO driver version %s\n",
+ VINO_MODULE_VERSION);
+
+ ret = vino_probe();
+ if (ret)
+ return ret;
+
+ ret = vino_init();
+ if (ret)
+ return ret;
+
+ /* initialize data structures */
+
+ spin_lock_init(&vino_drvdata->vino_lock);
+ spin_lock_init(&vino_drvdata->input_lock);
+
+ ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
+ vino_v4l_device_name_a);
+ if (ret)
+ return ret;
+
+ ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
+ vino_v4l_device_name_b);
+ if (ret)
+ return ret;
+
+ /* initialize hardware and register V4L devices */
+
+ ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0,
+ vino_driver_description, NULL);
+ if (ret) {
+ printk(KERN_ERR "VINO: requesting IRQ %02d failed\n",
+ SGI_VINO_IRQ);
+ vino_module_cleanup(vino_init_stage);
+ return -EAGAIN;
+ }
+ vino_init_stage++;
+
+ ret = vino_i2c_add_bus();
+ if (ret) {
+ printk(KERN_ERR "VINO I2C bus registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return ret;
+ }
+ vino_init_stage++;
+
+ ret = video_register_device(vino_drvdata->a.v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "VINO channel A Video4Linux-device "
+ "registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return -EINVAL;
+ }
+ vino_init_stage++;
+
+ ret = video_register_device(vino_drvdata->b.v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "VINO channel B Video4Linux-device "
+ "registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return -EINVAL;
+ }
+ vino_init_stage++;
+
+#if defined(CONFIG_KMOD) && defined(MODULE)
+ request_module("saa7191");
+ request_module("indycam");
+#endif
+
+ dprintk("init complete!\n");
+
+ return 0;
+}
+
+static void __exit vino_module_exit(void)
+{
+ dprintk("exiting, stage = %d ...\n", vino_init_stage);
+ vino_module_cleanup(vino_init_stage);
+ dprintk("cleanup complete, exit!\n");
+}
+
+module_init(vino_module_init);
+module_exit(vino_module_exit);
diff --git a/drivers/media/video/vino.h b/drivers/media/video/vino.h
index d2fce47..de2d615 100644
--- a/drivers/media/video/vino.h
+++ b/drivers/media/video/vino.h
@@ -1,13 +1,19 @@
/*
+ * Driver for the VINO (Video In No Out) system found in SGI Indys.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
* Copyright (C) 1999 Ulf Karlsson <ulfc@bun.falkenberg.se>
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
*/
-#ifndef VINO_H
-#define VINO_H
+#ifndef _VINO_H_
+#define _VINO_H_
#define VINO_BASE 0x00080000 /* Vino is in the EISA address space,
* but it is not an EISA bus card */
+#define VINO_PAGE_SIZE 4096
struct sgi_vino_channel {
u32 _pad_alpha;
@@ -21,8 +27,9 @@
u32 _pad_clip_end;
volatile u32 clip_end;
+#define VINO_FRAMERT_FULL 0xfff
#define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */
-#define VINO_FRAMERT_RT(x) (((x) & 0x1fff) << 1) /* bits 1:12 */
+#define VINO_FRAMERT_RT(x) (((x) & 0xfff) << 1) /* bits 1:12 */
u32 _pad_frame_rate;
volatile u32 frame_rate;
@@ -67,18 +74,18 @@
volatile u32 rev_id;
#define VINO_CTRL_LITTLE_ENDIAN (1<<0)
-#define VINO_CTRL_A_FIELD_TRANS_INT (1<<1) /* Field transferred int */
-#define VINO_CTRL_A_FIFO_OF_INT (1<<2) /* FIFO overflow int */
-#define VINO_CTRL_A_END_DESC_TBL_INT (1<<3) /* End of desc table int */
-#define VINO_CTRL_A_INT (VINO_CTRL_A_FIELD_TRANS_INT | \
- VINO_CTRL_A_FIFO_OF_INT | \
- VINO_CTRL_A_END_DESC_TBL_INT)
-#define VINO_CTRL_B_FIELD_TRANS_INT (1<<4) /* Field transferred int */
-#define VINO_CTRL_B_FIFO_OF_INT (1<<5) /* FIFO overflow int */
-#define VINO_CTRL_B_END_DESC_TBL_INT (1<<6) /* End of desc table int */
-#define VINO_CTRL_B_INT (VINO_CTRL_B_FIELD_TRANS_INT | \
- VINO_CTRL_B_FIFO_OF_INT | \
- VINO_CTRL_B_END_DESC_TBL_INT)
+#define VINO_CTRL_A_EOF_INT (1<<1) /* Field transferred int */
+#define VINO_CTRL_A_FIFO_INT (1<<2) /* FIFO overflow int */
+#define VINO_CTRL_A_EOD_INT (1<<3) /* End of desc table int */
+#define VINO_CTRL_A_INT (VINO_CTRL_A_EOF_INT | \
+ VINO_CTRL_A_FIFO_INT | \
+ VINO_CTRL_A_EOD_INT)
+#define VINO_CTRL_B_EOF_INT (1<<4) /* Field transferred int */
+#define VINO_CTRL_B_FIFO_INT (1<<5) /* FIFO overflow int */
+#define VINO_CTRL_B_EOD_INT (1<<6) /* End of desc table int */
+#define VINO_CTRL_B_INT (VINO_CTRL_B_EOF_INT | \
+ VINO_CTRL_B_FIFO_INT | \
+ VINO_CTRL_B_EOD_INT)
#define VINO_CTRL_A_DMA_ENBL (1<<7)
#define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8)
#define VINO_CTRL_A_SYNC_ENBL (1<<9)
@@ -104,18 +111,18 @@
u32 _pad_control;
volatile u32 control;
-#define VINO_INTSTAT_A_FIELD_TRANS (1<<0) /* Field transferred int */
-#define VINO_INTSTAT_A_FIFO_OF (1<<1) /* FIFO overflow int */
-#define VINO_INTSTAT_A_END_DESC_TBL (1<<2) /* End of desc table int */
-#define VINO_INTSTAT_A (VINO_INTSTAT_A_FIELD_TRANS | \
- VINO_INTSTAT_A_FIFO_OF | \
- VINO_INTSTAT_A_END_DESC_TBL)
-#define VINO_INTSTAT_B_FIELD_TRANS (1<<3) /* Field transferred int */
-#define VINO_INTSTAT_B_FIFO_OF (1<<4) /* FIFO overflow int */
-#define VINO_INTSTAT_B_END_DESC_TBL (1<<5) /* End of desc table int */
-#define VINO_INTSTAT_B (VINO_INTSTAT_B_FIELD_TRANS | \
- VINO_INTSTAT_B_FIFO_OF | \
- VINO_INTSTAT_B_END_DESC_TBL)
+#define VINO_INTSTAT_A_EOF (1<<0) /* Field transferred int */
+#define VINO_INTSTAT_A_FIFO (1<<1) /* FIFO overflow int */
+#define VINO_INTSTAT_A_EOD (1<<2) /* End of desc table int */
+#define VINO_INTSTAT_A (VINO_INTSTAT_A_EOF | \
+ VINO_INTSTAT_A_FIFO | \
+ VINO_INTSTAT_A_EOD)
+#define VINO_INTSTAT_B_EOF (1<<3) /* Field transferred int */
+#define VINO_INTSTAT_B_FIFO (1<<4) /* FIFO overflow int */
+#define VINO_INTSTAT_B_EOD (1<<5) /* End of desc table int */
+#define VINO_INTSTAT_B (VINO_INTSTAT_B_EOF | \
+ VINO_INTSTAT_B_FIFO | \
+ VINO_INTSTAT_B_EOD)
u32 _pad_intr_status;
volatile u32 intr_status;
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 5dbd9f6..4437bde 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -576,7 +576,6 @@
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
- .force = &ignore,
};
static struct i2c_driver vpx3220_i2c_driver;
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 2574308..eed2ace 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -737,7 +737,7 @@
};
static struct i2c_adapter zoran_i2c_adapter_template = {
- I2C_DEVNAME("zr36057"),
+ .name = "zr36057",
.id = I2C_HW_B_ZR36067,
.algo = NULL,
.client_register = zoran_i2c_client_register,
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 9f98334..b61e3d1 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -6,7 +6,7 @@
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.07
+ * mpi.h Version: 01.05.08
*
* Version History
* ---------------
@@ -71,6 +71,9 @@
* 03-11-05 01.05.07 Removed function codes for SCSI IO 32 and
* TargetAssistExtended requests.
* Removed EEDP IOCStatus codes.
+ * 06-24-05 01.05.08 Added function codes for SCSI IO 32 and
+ * TargetAssistExtended requests.
+ * Added EEDP IOCStatus codes.
* --------------------------------------------------------------------------
*/
@@ -101,7 +104,7 @@
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x09)
+#define MPI_HEADER_VERSION_UNIT (0x0A)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
@@ -292,10 +295,13 @@
#define MPI_FUNCTION_DIAG_BUFFER_POST (0x1D)
#define MPI_FUNCTION_DIAG_RELEASE (0x1E)
+#define MPI_FUNCTION_SCSI_IO_32 (0x1F)
+
#define MPI_FUNCTION_LAN_SEND (0x20)
#define MPI_FUNCTION_LAN_RECEIVE (0x21)
#define MPI_FUNCTION_LAN_RESET (0x22)
+#define MPI_FUNCTION_TARGET_ASSIST_EXTENDED (0x23)
#define MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24)
#define MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25)
@@ -681,6 +687,15 @@
#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C)
/****************************************************************************/
+/* For use by SCSI Initiator and SCSI Target end-to-end data protection */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_EEDP_GUARD_ERROR (0x004D)
+#define MPI_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E)
+#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F)
+
+
+/****************************************************************************/
/* SCSI Target values */
/****************************************************************************/
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index 15b12b0..d833989 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.08
+ * mpi_cnfg.h Version: 01.05.09
*
* Version History
* ---------------
@@ -232,6 +232,23 @@
* New physical mapping mode in SAS IO Unit Page 2.
* Added CONFIG_PAGE_SAS_ENCLOSURE_0.
* Added Slot and Enclosure fields to SAS Device Page 0.
+ * 06-24-05 01.05.09 Added EEDP defines to IOC Page 1.
+ * Added more RAID type defines to IOC Page 2.
+ * Added Port Enable Delay settings to BIOS Page 1.
+ * Added Bad Block Table Full define to RAID Volume Page 0.
+ * Added Previous State defines to RAID Physical Disk
+ * Page 0.
+ * Added Max Sata Targets define for DiscoveryStatus field
+ * of SAS IO Unit Page 0.
+ * Added Device Self Test to Control Flags of SAS IO Unit
+ * Page 1.
+ * Added Direct Attach Starting Slot Number define for SAS
+ * IO Unit Page 2.
+ * Added new fields in SAS Device Page 2 for enclosure
+ * mapping.
+ * Added OwnerDevHandle and Flags field to SAS PHY Page 0.
+ * Added IOC GPIO Flags define to SAS Enclosure Page 0.
+ * Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT.
* --------------------------------------------------------------------------
*/
@@ -477,6 +494,7 @@
#define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626)
#define MPI_MANUFACTPAGE_DEVICEID_FC939X (0x0642)
#define MPI_MANUFACTPAGE_DEVICEID_FC949X (0x0640)
+#define MPI_MANUFACTPAGE_DEVICEID_FC949ES (0x0646)
/* SCSI */
#define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030)
#define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031)
@@ -769,9 +787,13 @@
} CONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1,
IOCPage1_t, MPI_POINTER pIOCPage1_t;
-#define MPI_IOCPAGE1_PAGEVERSION (0x02)
+#define MPI_IOCPAGE1_PAGEVERSION (0x03)
/* defines for the Flags field */
+#define MPI_IOCPAGE1_EEDP_MODE_MASK (0x07000000)
+#define MPI_IOCPAGE1_EEDP_MODE_OFF (0x00000000)
+#define MPI_IOCPAGE1_EEDP_MODE_T10 (0x01000000)
+#define MPI_IOCPAGE1_EEDP_MODE_LSI_1 (0x02000000)
#define MPI_IOCPAGE1_INITIATOR_CONTEXT_REPLY_DISABLE (0x00000010)
#define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001)
@@ -795,6 +817,11 @@
#define MPI_RAID_VOL_TYPE_IS (0x00)
#define MPI_RAID_VOL_TYPE_IME (0x01)
#define MPI_RAID_VOL_TYPE_IM (0x02)
+#define MPI_RAID_VOL_TYPE_RAID_5 (0x03)
+#define MPI_RAID_VOL_TYPE_RAID_6 (0x04)
+#define MPI_RAID_VOL_TYPE_RAID_10 (0x05)
+#define MPI_RAID_VOL_TYPE_RAID_50 (0x06)
+#define MPI_RAID_VOL_TYPE_UNKNOWN (0xFF)
/* IOC Page 2 Volume Flags values */
@@ -820,13 +847,17 @@
} CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
IOCPage2_t, MPI_POINTER pIOCPage2_t;
-#define MPI_IOCPAGE2_PAGEVERSION (0x02)
+#define MPI_IOCPAGE2_PAGEVERSION (0x03)
/* IOC Page 2 Capabilities flags */
#define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT (0x00000001)
#define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT (0x00000002)
#define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT (0x00000010)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000020)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT (0x00000040)
#define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000)
#define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000)
#define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000)
@@ -945,7 +976,7 @@
} CONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1,
BIOSPage1_t, MPI_POINTER pBIOSPage1_t;
-#define MPI_BIOSPAGE1_PAGEVERSION (0x01)
+#define MPI_BIOSPAGE1_PAGEVERSION (0x02)
/* values for the BiosOptions field */
#define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400)
@@ -954,6 +985,8 @@
#define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
/* values for the IOCSettings field */
+#define MPI_BIOSPAGE1_IOCSET_MASK_PORT_ENABLE_DELAY (0x00F00000)
+#define MPI_BIOSPAGE1_IOCSET_SHIFT_PORT_ENABLE_DELAY (20)
#define MPI_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000)
#define MPI_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000)
#define MPI_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000)
@@ -1167,6 +1200,7 @@
#define MPI_BIOSPAGE2_FORM_PCI_SLOT_NUMBER (0x03)
#define MPI_BIOSPAGE2_FORM_FC_WWN (0x04)
#define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05)
+#define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06)
/****************************************************************************
@@ -1957,11 +1991,11 @@
RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t;
/* RAID Volume Page 0 VolumeStatus defines */
-
#define MPI_RAIDVOL0_STATUS_FLAG_ENABLED (0x01)
#define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED (0x02)
#define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x04)
#define MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x08)
+#define MPI_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x10)
#define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL (0x00)
#define MPI_RAIDVOL0_STATUS_STATE_DEGRADED (0x01)
@@ -2025,7 +2059,7 @@
} CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
-#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x04)
+#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x05)
/* values for RAID Volume Page 0 InactiveStatus field */
#define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00)
@@ -2104,6 +2138,8 @@
#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01)
#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02)
#define MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x04)
+#define MPI_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00)
+#define MPI_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x08)
#define MPI_PHYSDISK0_STATUS_ONLINE (0x00)
#define MPI_PHYSDISK0_STATUS_MISSING (0x01)
@@ -2132,7 +2168,7 @@
} CONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0,
RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t;
-#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x01)
+#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x02)
typedef struct _RAID_PHYS_DISK1_PATH
@@ -2263,7 +2299,7 @@
} CONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0,
SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t;
-#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x02)
+#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x03)
/* values for SAS IO Unit Page 0 PortFlags */
#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08)
@@ -2299,6 +2335,7 @@
#define MPI_SAS_IOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200)
#define MPI_SAS_IOUNIT0_DS_TABLE_LINK (0x00000400)
#define MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800)
+#define MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS (0x00001000)
typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA
@@ -2336,6 +2373,7 @@
#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x04)
/* values for SAS IO Unit Page 1 ControlFlags */
+#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000)
#define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX (0x4000)
#define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX (0x2000)
#define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000)
@@ -2345,9 +2383,8 @@
#define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9)
#define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x00)
#define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x01)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x10)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x02)
-#define MPI_SAS_IOUNIT1_CONTROL_AUTO_PORT_SAME_SAS_ADDR (0x0100)
#define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080)
#define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040)
#define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020)
@@ -2390,7 +2427,7 @@
} CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2,
SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t;
-#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x03)
+#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x04)
/* values for SAS IO Unit Page 2 Status field */
#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02)
@@ -2406,6 +2443,7 @@
#define MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP (0x02)
#define MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT (0x10)
+#define MPI_SAS_IOUNIT2_FLAGS_DA_STARTING_SLOT (0x20)
typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3
@@ -2584,11 +2622,19 @@
{
CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */
U64 PhysicalIdentifier; /* 08h */
- U32 Reserved1; /* 10h */
+ U32 EnclosureMapping; /* 10h */
} CONFIG_PAGE_SAS_DEVICE_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_2,
SasDevicePage2_t, MPI_POINTER pSasDevicePage2_t;
-#define MPI_SASDEVICE2_PAGEVERSION (0x00)
+#define MPI_SASDEVICE2_PAGEVERSION (0x01)
+
+/* defines for SAS Device Page 2 EnclosureMapping field */
+#define MPI_SASDEVICE2_ENC_MAP_MASK_MISSING_COUNT (0x0000000F)
+#define MPI_SASDEVICE2_ENC_MAP_SHIFT_MISSING_COUNT (0)
+#define MPI_SASDEVICE2_ENC_MAP_MASK_NUM_SLOTS (0x000007F0)
+#define MPI_SASDEVICE2_ENC_MAP_SHIFT_NUM_SLOTS (4)
+#define MPI_SASDEVICE2_ENC_MAP_MASK_START_INDEX (0x001FF800)
+#define MPI_SASDEVICE2_ENC_MAP_SHIFT_START_INDEX (11)
/****************************************************************************
@@ -2598,7 +2644,8 @@
typedef struct _CONFIG_PAGE_SAS_PHY_0
{
CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */
- U32 Reserved1; /* 08h */
+ U16 OwnerDevHandle; /* 08h */
+ U16 Reserved1; /* 0Ah */
U64 SASAddress; /* 0Ch */
U16 AttachedDevHandle; /* 14h */
U8 AttachedPhyIdentifier; /* 16h */
@@ -2607,12 +2654,12 @@
U8 ProgrammedLinkRate; /* 20h */
U8 HwLinkRate; /* 21h */
U8 ChangeCount; /* 22h */
- U8 Reserved3; /* 23h */
+ U8 Flags; /* 23h */
U32 PhyInfo; /* 24h */
} CONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0,
SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t;
-#define MPI_SASPHY0_PAGEVERSION (0x00)
+#define MPI_SASPHY0_PAGEVERSION (0x01)
/* values for SAS PHY Page 0 ProgrammedLinkRate field */
#define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK (0xF0)
@@ -2632,6 +2679,9 @@
#define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5 (0x08)
#define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0 (0x09)
+/* values for SAS PHY Page 0 Flags field */
+#define MPI_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01)
+
/* values for SAS PHY Page 0 PhyInfo field */
#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000)
#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000)
@@ -2690,7 +2740,7 @@
} CONFIG_PAGE_SAS_ENCLOSURE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_ENCLOSURE_0,
SasEnclosurePage0_t, MPI_POINTER pSasEnclosurePage0_t;
-#define MPI_SASENCLOSURE0_PAGEVERSION (0x00)
+#define MPI_SASENCLOSURE0_PAGEVERSION (0x01)
/* values for SAS Enclosure Page 0 Flags field */
#define MPI_SAS_ENCLS0_FLAGS_SEP_BUS_ID_VALID (0x0020)
@@ -2702,6 +2752,7 @@
#define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002)
#define MPI_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003)
#define MPI_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
+#define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
/****************************************************************************
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index c9edbee..1a30ef1 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -6,17 +6,17 @@
Copyright (c) 2000-2005 LSI Logic Corporation.
---------------------------------------
- Header Set Release Version: 01.05.09
+ Header Set Release Version: 01.05.10
Header Set Release Date: 03-11-05
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.07 01.05.06
- mpi_ioc.h 01.05.08 01.05.07
- mpi_cnfg.h 01.05.08 01.05.07
- mpi_init.h 01.05.04 01.05.03
- mpi_targ.h 01.05.04 01.05.03
+ mpi.h 01.05.08 01.05.07
+ mpi_ioc.h 01.05.09 01.05.08
+ mpi_cnfg.h 01.05.09 01.05.08
+ mpi_init.h 01.05.05 01.05.04
+ mpi_targ.h 01.05.05 01.05.04
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
mpi_raid.h 01.05.02 01.05.02
@@ -24,7 +24,7 @@
mpi_inb.h 01.05.01 01.05.01
mpi_sas.h 01.05.01 01.05.01
mpi_type.h 01.05.01 01.05.01
- mpi_history.txt 01.05.09 01.05.08
+ mpi_history.txt 01.05.09 01.05.09
* Date Version Description
@@ -88,6 +88,9 @@
* 03-11-05 01.05.07 Removed function codes for SCSI IO 32 and
* TargetAssistExtended requests.
* Removed EEDP IOCStatus codes.
+ * 06-24-05 01.05.08 Added function codes for SCSI IO 32 and
+ * TargetAssistExtended requests.
+ * Added EEDP IOCStatus codes.
* --------------------------------------------------------------------------
mpi_ioc.h
@@ -159,6 +162,8 @@
* Reply and IOC Init Request.
* 03-11-05 01.05.08 Added family code for 1068E family.
* Removed IOCFacts Reply EEDP Capability bit.
+ * 06-24-05 01.05.09 Added 5 new IOCFacts Reply IOCCapabilities bits.
+ * Added Max SATA Targets to SAS Discovery Error event.
* --------------------------------------------------------------------------
mpi_cnfg.h
@@ -380,6 +385,23 @@
* New physical mapping mode in SAS IO Unit Page 2.
* Added CONFIG_PAGE_SAS_ENCLOSURE_0.
* Added Slot and Enclosure fields to SAS Device Page 0.
+ * 06-24-05 01.05.09 Added EEDP defines to IOC Page 1.
+ * Added more RAID type defines to IOC Page 2.
+ * Added Port Enable Delay settings to BIOS Page 1.
+ * Added Bad Block Table Full define to RAID Volume Page 0.
+ * Added Previous State defines to RAID Physical Disk
+ * Page 0.
+ * Added Max Sata Targets define for DiscoveryStatus field
+ * of SAS IO Unit Page 0.
+ * Added Device Self Test to Control Flags of SAS IO Unit
+ * Page 1.
+ * Added Direct Attach Starting Slot Number define for SAS
+ * IO Unit Page 2.
+ * Added new fields in SAS Device Page 2 for enclosure
+ * mapping.
+ * Added OwnerDevHandle and Flags field to SAS PHY Page 0.
+ * Added IOC GPIO Flags define to SAS Enclosure Page 0.
+ * Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT.
* --------------------------------------------------------------------------
mpi_init.h
@@ -418,6 +440,8 @@
* Modified SCSI Enclosure Processor Request and Reply to
* support Enclosure/Slot addressing rather than WWID
* addressing.
+ * 06-24-05 01.05.05 Added SCSI IO 32 structures and defines.
+ * Added four new defines for SEP SlotStatus.
* --------------------------------------------------------------------------
mpi_targ.h
@@ -461,6 +485,7 @@
* 10-05-04 01.05.02 MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added.
* 02-22-05 01.05.03 Changed a comment.
* 03-11-05 01.05.04 Removed TargetAssistExtended Request.
+ * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines.
* --------------------------------------------------------------------------
mpi_fc.h
@@ -571,20 +596,20 @@
mpi_history.txt Parts list history
-Filename 01.05.09
----------- --------
-mpi.h 01.05.07
-mpi_ioc.h 01.05.08
-mpi_cnfg.h 01.05.08
-mpi_init.h 01.05.04
-mpi_targ.h 01.05.04
-mpi_fc.h 01.05.01
-mpi_lan.h 01.05.01
-mpi_raid.h 01.05.02
-mpi_tool.h 01.05.03
-mpi_inb.h 01.05.01
-mpi_sas.h 01.05.01
-mpi_type.h 01.05.01
+Filename 01.05.10 01.05.09
+---------- -------- --------
+mpi.h 01.05.08 01.05.07
+mpi_ioc.h 01.05.09 01.05.08
+mpi_cnfg.h 01.05.09 01.05.08
+mpi_init.h 01.05.05 01.05.04
+mpi_targ.h 01.05.05 01.05.04
+mpi_fc.h 01.05.01 01.05.01
+mpi_lan.h 01.05.01 01.05.01
+mpi_raid.h 01.05.02 01.05.02
+mpi_tool.h 01.05.03 01.05.03
+mpi_inb.h 01.05.01 01.05.01
+mpi_sas.h 01.05.01 01.05.01
+mpi_type.h 01.05.01 01.05.01
Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03
---------- -------- -------- -------- -------- -------- --------
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index aca0358..d5af75a 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -6,7 +6,7 @@
* Title: MPI initiator mode messages and structures
* Creation Date: June 8, 2000
*
- * mpi_init.h Version: 01.05.04
+ * mpi_init.h Version: 01.05.05
*
* Version History
* ---------------
@@ -48,6 +48,8 @@
* Modified SCSI Enclosure Processor Request and Reply to
* support Enclosure/Slot addressing rather than WWID
* addressing.
+ * 06-24-05 01.05.05 Added SCSI IO 32 structures and defines.
+ * Added four new defines for SEP SlotStatus.
* --------------------------------------------------------------------------
*/
@@ -203,6 +205,197 @@
/****************************************************************************/
+/* SCSI IO 32 messages and associated structures */
+/****************************************************************************/
+
+typedef struct
+{
+ U8 CDB[20]; /* 00h */
+ U32 PrimaryReferenceTag; /* 14h */
+ U16 PrimaryApplicationTag; /* 18h */
+ U16 PrimaryApplicationTagMask; /* 1Ah */
+ U32 TransferLength; /* 1Ch */
+} MPI_SCSI_IO32_CDB_EEDP32, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_EEDP32,
+ MpiScsiIo32CdbEedp32_t, MPI_POINTER pMpiScsiIo32CdbEedp32_t;
+
+typedef struct
+{
+ U8 CDB[16]; /* 00h */
+ U32 DataLength; /* 10h */
+ U32 PrimaryReferenceTag; /* 14h */
+ U16 PrimaryApplicationTag; /* 18h */
+ U16 PrimaryApplicationTagMask; /* 1Ah */
+ U32 TransferLength; /* 1Ch */
+} MPI_SCSI_IO32_CDB_EEDP16, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_EEDP16,
+ MpiScsiIo32CdbEedp16_t, MPI_POINTER pMpiScsiIo32CdbEedp16_t;
+
+typedef union
+{
+ U8 CDB32[32];
+ MPI_SCSI_IO32_CDB_EEDP32 EEDP32;
+ MPI_SCSI_IO32_CDB_EEDP16 EEDP16;
+ SGE_SIMPLE_UNION SGE;
+} MPI_SCSI_IO32_CDB_UNION, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_UNION,
+ MpiScsiIo32Cdb_t, MPI_POINTER pMpiScsiIo32Cdb_t;
+
+typedef struct
+{
+ U8 TargetID; /* 00h */
+ U8 Bus; /* 01h */
+ U16 Reserved1; /* 02h */
+ U32 Reserved2; /* 04h */
+} MPI_SCSI_IO32_BUS_TARGET_ID_FORM, MPI_POINTER PTR_MPI_SCSI_IO32_BUS_TARGET_ID_FORM,
+ MpiScsiIo32BusTargetIdForm_t, MPI_POINTER pMpiScsiIo32BusTargetIdForm_t;
+
+typedef union
+{
+ MPI_SCSI_IO32_BUS_TARGET_ID_FORM SCSIID;
+ U64 WWID;
+} MPI_SCSI_IO32_ADDRESS, MPI_POINTER PTR_MPI_SCSI_IO32_ADDRESS,
+ MpiScsiIo32Address_t, MPI_POINTER pMpiScsiIo32Address_t;
+
+typedef struct _MSG_SCSI_IO32_REQUEST
+{
+ U8 Port; /* 00h */
+ U8 Reserved1; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U8 CDBLength; /* 04h */
+ U8 SenseBufferLength; /* 05h */
+ U8 Flags; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U8 LUN[8]; /* 0Ch */
+ U32 Control; /* 14h */
+ MPI_SCSI_IO32_CDB_UNION CDB; /* 18h */
+ U32 DataLength; /* 38h */
+ U32 BidirectionalDataLength; /* 3Ch */
+ U32 SecondaryReferenceTag; /* 40h */
+ U16 SecondaryApplicationTag; /* 44h */
+ U16 Reserved2; /* 46h */
+ U16 EEDPFlags; /* 48h */
+ U16 ApplicationTagTranslationMask; /* 4Ah */
+ U32 EEDPBlockSize; /* 4Ch */
+ MPI_SCSI_IO32_ADDRESS DeviceAddress; /* 50h */
+ U8 SGLOffset0; /* 58h */
+ U8 SGLOffset1; /* 59h */
+ U8 SGLOffset2; /* 5Ah */
+ U8 SGLOffset3; /* 5Bh */
+ U32 Reserved3; /* 5Ch */
+ U32 Reserved4; /* 60h */
+ U32 SenseBufferLowAddr; /* 64h */
+ SGE_IO_UNION SGL; /* 68h */
+} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST,
+ SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t;
+
+/* SCSI IO 32 MsgFlags bits */
+#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH (0x01)
+#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_32 (0x00)
+#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_64 (0x01)
+
+#define MPI_SCSIIO32_MSGFLGS_SENSE_LOCATION (0x02)
+#define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_HOST (0x00)
+#define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_IOC (0x02)
+
+#define MPI_SCSIIO32_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04)
+#define MPI_SCSIIO32_MSGFLGS_SGL_OFFSETS_CHAINS (0x08)
+#define MPI_SCSIIO32_MSGFLGS_MULTICAST (0x10)
+#define MPI_SCSIIO32_MSGFLGS_BIDIRECTIONAL (0x20)
+#define MPI_SCSIIO32_MSGFLGS_LARGE_CDB (0x40)
+
+/* SCSI IO 32 Flags bits */
+#define MPI_SCSIIO32_FLAGS_FORM_MASK (0x03)
+#define MPI_SCSIIO32_FLAGS_FORM_SCSIID (0x00)
+#define MPI_SCSIIO32_FLAGS_FORM_WWID (0x01)
+
+/* SCSI IO 32 LUN fields */
+#define MPI_SCSIIO32_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF)
+#define MPI_SCSIIO32_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000)
+#define MPI_SCSIIO32_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF)
+#define MPI_SCSIIO32_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000)
+#define MPI_SCSIIO32_LUN_LEVEL_1_WORD (0xFF00)
+#define MPI_SCSIIO32_LUN_LEVEL_1_DWORD (0x0000FF00)
+
+/* SCSI IO 32 Control bits */
+#define MPI_SCSIIO32_CONTROL_DATADIRECTION_MASK (0x03000000)
+#define MPI_SCSIIO32_CONTROL_NODATATRANSFER (0x00000000)
+#define MPI_SCSIIO32_CONTROL_WRITE (0x01000000)
+#define MPI_SCSIIO32_CONTROL_READ (0x02000000)
+#define MPI_SCSIIO32_CONTROL_BIDIRECTIONAL (0x03000000)
+
+#define MPI_SCSIIO32_CONTROL_ADDCDBLEN_MASK (0xFC000000)
+#define MPI_SCSIIO32_CONTROL_ADDCDBLEN_SHIFT (26)
+
+#define MPI_SCSIIO32_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
+#define MPI_SCSIIO32_CONTROL_SIMPLEQ (0x00000000)
+#define MPI_SCSIIO32_CONTROL_HEADOFQ (0x00000100)
+#define MPI_SCSIIO32_CONTROL_ORDEREDQ (0x00000200)
+#define MPI_SCSIIO32_CONTROL_ACAQ (0x00000400)
+#define MPI_SCSIIO32_CONTROL_UNTAGGED (0x00000500)
+#define MPI_SCSIIO32_CONTROL_NO_DISCONNECT (0x00000700)
+
+#define MPI_SCSIIO32_CONTROL_TASKMANAGE_MASK (0x00FF0000)
+#define MPI_SCSIIO32_CONTROL_OBSOLETE (0x00800000)
+#define MPI_SCSIIO32_CONTROL_CLEAR_ACA_RSV (0x00400000)
+#define MPI_SCSIIO32_CONTROL_TARGET_RESET (0x00200000)
+#define MPI_SCSIIO32_CONTROL_LUN_RESET_RSV (0x00100000)
+#define MPI_SCSIIO32_CONTROL_RESERVED (0x00080000)
+#define MPI_SCSIIO32_CONTROL_CLR_TASK_SET_RSV (0x00040000)
+#define MPI_SCSIIO32_CONTROL_ABORT_TASK_SET (0x00020000)
+#define MPI_SCSIIO32_CONTROL_RESERVED2 (0x00010000)
+
+/* SCSI IO 32 EEDPFlags */
+#define MPI_SCSIIO32_EEDPFLAGS_MASK_OP (0x0007)
+#define MPI_SCSIIO32_EEDPFLAGS_NOOP_OP (0x0000)
+#define MPI_SCSIIO32_EEDPFLAGS_CHK_OP (0x0001)
+#define MPI_SCSIIO32_EEDPFLAGS_STRIP_OP (0x0002)
+#define MPI_SCSIIO32_EEDPFLAGS_CHKRM_OP (0x0003)
+#define MPI_SCSIIO32_EEDPFLAGS_INSERT_OP (0x0004)
+#define MPI_SCSIIO32_EEDPFLAGS_REPLACE_OP (0x0006)
+#define MPI_SCSIIO32_EEDPFLAGS_CHKREGEN_OP (0x0007)
+
+#define MPI_SCSIIO32_EEDPFLAGS_PASS_REF_TAG (0x0008)
+#define MPI_SCSIIO32_EEDPFLAGS_8_9THS_MODE (0x0010)
+
+#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_MASK (0x0700)
+#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_GUARD (0x0100)
+#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_REFTAG (0x0200)
+#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_LBATAG (0x0400)
+#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_SHIFT (8)
+
+#define MPI_SCSIIO32_EEDPFLAGS_INC_SEC_APPTAG (0x1000)
+#define MPI_SCSIIO32_EEDPFLAGS_INC_PRI_APPTAG (0x2000)
+#define MPI_SCSIIO32_EEDPFLAGS_INC_SEC_REFTAG (0x4000)
+#define MPI_SCSIIO32_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
+
+
+/* SCSIIO32 IO reply structure */
+typedef struct _MSG_SCSIIO32_IO_REPLY
+{
+ U8 Port; /* 00h */
+ U8 Reserved1; /* 01h */
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U8 CDBLength; /* 04h */
+ U8 SenseBufferLength; /* 05h */
+ U8 Flags; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U8 SCSIStatus; /* 0Ch */
+ U8 SCSIState; /* 0Dh */
+ U16 IOCStatus; /* 0Eh */
+ U32 IOCLogInfo; /* 10h */
+ U32 TransferCount; /* 14h */
+ U32 SenseCount; /* 18h */
+ U32 ResponseInfo; /* 1Ch */
+ U16 TaskTag; /* 20h */
+ U16 Reserved2; /* 22h */
+ U32 BidirectionalTransferCount; /* 24h */
+} MSG_SCSIIO32_IO_REPLY, MPI_POINTER PTR_MSG_SCSIIO32_IO_REPLY,
+ SCSIIO32Reply_t, MPI_POINTER pSCSIIO32Reply_t;
+
+
+/****************************************************************************/
/* SCSI Task Management messages */
/****************************************************************************/
@@ -310,10 +503,14 @@
#define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080)
#define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100)
#define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
+#define MPI_SEP_REQ_SLOTSTATUS_REQ_CONSISTENCY_CHECK (0x00001000)
+#define MPI_SEP_REQ_SLOTSTATUS_DISABLE (0x00002000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQ_RESERVED_DEVICE (0x00004000)
#define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000)
#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT (0x00080000)
#define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE (0x00400000)
+#define MPI_SEP_REQ_SLOTSTATUS_ACTIVE (0x00800000)
#define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000)
#define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS (0x08000000)
#define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF (0x10000000)
@@ -352,11 +549,15 @@
#define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080)
#define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100)
#define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
+#define MPI_SEP_REPLY_SLOTSTATUS_CONSISTENCY_CHECK (0x00001000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DISABLE (0x00002000)
+#define MPI_SEP_REPLY_SLOTSTATUS_RESERVED_DEVICE (0x00004000)
#define MPI_SEP_REPLY_SLOTSTATUS_REPORT (0x00010000)
#define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
#define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000)
#define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY (0x00080000)
#define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE (0x00400000)
+#define MPI_SEP_REPLY_SLOTSTATUS_ACTIVE (0x00800000)
#define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED (0x01000000)
#define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED (0x02000000)
#define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000)
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index f91eb4e..93b70e2 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.08
+ * mpi_ioc.h Version: 01.05.09
*
* Version History
* ---------------
@@ -81,6 +81,8 @@
* Reply and IOC Init Request.
* 03-11-05 01.05.08 Added family code for 1068E family.
* Removed IOCFacts Reply EEDP Capability bit.
+ * 06-24-05 01.05.09 Added 5 new IOCFacts Reply IOCCapabilities bits.
+ * Added Max SATA Targets to SAS Discovery Error event.
* --------------------------------------------------------------------------
*/
@@ -261,7 +263,11 @@
#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008)
#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010)
#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020)
-
+#define MPI_IOCFACTS_CAPABILITY_EEDP (0x00000040)
+#define MPI_IOCFACTS_CAPABILITY_BIDIRECTIONAL (0x00000080)
+#define MPI_IOCFACTS_CAPABILITY_MULTICAST (0x00000100)
+#define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (0x00000200)
+#define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (0x00000400)
/*****************************************************************************
@@ -677,6 +683,7 @@
#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE (0x00000200)
#define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE (0x00000400)
#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800)
+#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000)
/*****************************************************************************
diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
index 623901f..3f46285 100644
--- a/drivers/message/fusion/lsi/mpi_targ.h
+++ b/drivers/message/fusion/lsi/mpi_targ.h
@@ -6,7 +6,7 @@
* Title: MPI Target mode messages and structures
* Creation Date: June 22, 2000
*
- * mpi_targ.h Version: 01.05.04
+ * mpi_targ.h Version: 01.05.05
*
* Version History
* ---------------
@@ -53,6 +53,7 @@
* 10-05-04 01.05.02 MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added.
* 02-22-05 01.05.03 Changed a comment.
* 03-11-05 01.05.04 Removed TargetAssistExtended Request.
+ * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines.
* --------------------------------------------------------------------------
*/
@@ -371,6 +372,77 @@
/****************************************************************************/
+/* Target Assist Extended Request */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_ASSIST_EXT_REQUEST
+{
+ U8 StatusCode; /* 00h */
+ U8 TargetAssistFlags; /* 01h */
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U16 QueueTag; /* 04h */
+ U8 Reserved1; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U32 ReplyWord; /* 0Ch */
+ U8 LUN[8]; /* 10h */
+ U32 RelativeOffset; /* 18h */
+ U32 Reserved2; /* 1Ch */
+ U32 Reserved3; /* 20h */
+ U32 PrimaryReferenceTag; /* 24h */
+ U16 PrimaryApplicationTag; /* 28h */
+ U16 PrimaryApplicationTagMask; /* 2Ah */
+ U32 Reserved4; /* 2Ch */
+ U32 DataLength; /* 30h */
+ U32 BidirectionalDataLength; /* 34h */
+ U32 SecondaryReferenceTag; /* 38h */
+ U16 SecondaryApplicationTag; /* 3Ch */
+ U16 Reserved5; /* 3Eh */
+ U16 EEDPFlags; /* 40h */
+ U16 ApplicationTagTranslationMask; /* 42h */
+ U32 EEDPBlockSize; /* 44h */
+ U8 SGLOffset0; /* 48h */
+ U8 SGLOffset1; /* 49h */
+ U8 SGLOffset2; /* 4Ah */
+ U8 SGLOffset3; /* 4Bh */
+ U32 Reserved6; /* 4Ch */
+ SGE_IO_UNION SGL[1]; /* 50h */
+} MSG_TARGET_ASSIST_EXT_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_EXT_REQUEST,
+ TargetAssistExtRequest_t, MPI_POINTER pTargetAssistExtRequest_t;
+
+/* see the defines after MSG_TARGET_ASSIST_REQUEST for TargetAssistFlags */
+
+/* defines for the MsgFlags field */
+#define TARGET_ASSIST_EXT_MSGFLAGS_BIDIRECTIONAL (0x20)
+#define TARGET_ASSIST_EXT_MSGFLAGS_MULTICAST (0x10)
+#define TARGET_ASSIST_EXT_MSGFLAGS_SGL_OFFSET_CHAINS (0x08)
+
+/* defines for the EEDPFlags field */
+#define TARGET_ASSIST_EXT_EEDP_MASK_OP (0x0007)
+#define TARGET_ASSIST_EXT_EEDP_NOOP_OP (0x0000)
+#define TARGET_ASSIST_EXT_EEDP_CHK_OP (0x0001)
+#define TARGET_ASSIST_EXT_EEDP_STRIP_OP (0x0002)
+#define TARGET_ASSIST_EXT_EEDP_CHKRM_OP (0x0003)
+#define TARGET_ASSIST_EXT_EEDP_INSERT_OP (0x0004)
+#define TARGET_ASSIST_EXT_EEDP_REPLACE_OP (0x0006)
+#define TARGET_ASSIST_EXT_EEDP_CHKREGEN_OP (0x0007)
+
+#define TARGET_ASSIST_EXT_EEDP_PASS_REF_TAG (0x0008)
+
+#define TARGET_ASSIST_EXT_EEDP_T10_CHK_MASK (0x0700)
+#define TARGET_ASSIST_EXT_EEDP_T10_CHK_GUARD (0x0100)
+#define TARGET_ASSIST_EXT_EEDP_T10_CHK_APPTAG (0x0200)
+#define TARGET_ASSIST_EXT_EEDP_T10_CHK_REFTAG (0x0400)
+#define TARGET_ASSIST_EXT_EEDP_T10_CHK_SHIFT (8)
+
+#define TARGET_ASSIST_EXT_EEDP_INC_SEC_APPTAG (0x1000)
+#define TARGET_ASSIST_EXT_EEDP_INC_PRI_APPTAG (0x2000)
+#define TARGET_ASSIST_EXT_EEDP_INC_SEC_REFTAG (0x4000)
+#define TARGET_ASSIST_EXT_EEDP_INC_PRI_REFTAG (0x8000)
+
+
+/****************************************************************************/
/* Target Status Send Request */
/****************************************************************************/
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index ffbe6f4..f517d06 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -218,8 +218,7 @@
* (also referred to as a IO Controller or IOC).
* This routine must clear the interrupt from the adapter and does
* so by reading the reply FIFO. Multiple replies may be processed
- * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
- * which is currently set to 32 in mptbase.h.
+ * per single call to this routine.
*
* This routine handles register-level access of the adapter but
* dispatches (calls) a protocol-specific callback routine to handle
@@ -279,11 +278,11 @@
cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
- dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x\n",
- ioc->name, mr, req_idx));
+ dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
+ ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
DBG_DUMP_REPLY_FRAME(mr)
- /* Check/log IOC log info
+ /* Check/log IOC log info
*/
ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
@@ -345,7 +344,7 @@
if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
|| (mf < ioc->req_frames)) ) {
printk(MYIOC_s_WARN_FMT
- "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
+ "mpt_interrupt: Invalid mf (%p)!\n", ioc->name, (void *)mf);
cb_idx = 0;
pa = 0;
freeme = 0;
@@ -399,7 +398,7 @@
* @mf: Pointer to original MPT request frame
* @reply: Pointer to MPT reply frame (NULL if TurboReply)
*
- * Returns 1 indicating original alloc'd request frame ptr
+ * Returns 1 indicating original alloc'd request frame ptr
* should be freed, or 0 if it shouldn't.
*/
static int
@@ -408,28 +407,17 @@
int freereq = 1;
u8 func;
- dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
+ dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
- if ((mf == NULL) ||
- (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
- printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
- ioc->name, (void *)mf);
- return 1;
- }
-
- if (reply == NULL) {
- dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
- ioc->name));
- return 1;
- }
-
+#if defined(MPT_DEBUG_MSG_FRAME)
if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
DBG_DUMP_REQUEST_FRAME_HDR(mf)
}
+#endif
func = reply->u.hdr.Function;
- dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
+ dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
ioc->name, func));
if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
@@ -448,8 +436,14 @@
* Hmmm... It seems that EventNotificationReply is an exception
* to the rule of one reply per request.
*/
- if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
+ if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
freereq = 0;
+ devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
+ ioc->name, pEvReply));
+ } else {
+ devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
+ ioc->name, pEvReply));
+ }
#ifdef CONFIG_PROC_FS
// LogEvent(ioc, pEvReply);
@@ -491,10 +485,21 @@
pCfg->status = status;
if (status == MPI_IOCSTATUS_SUCCESS) {
- pCfg->hdr->PageVersion = pReply->Header.PageVersion;
- pCfg->hdr->PageLength = pReply->Header.PageLength;
- pCfg->hdr->PageNumber = pReply->Header.PageNumber;
- pCfg->hdr->PageType = pReply->Header.PageType;
+ if ((pReply->Header.PageType &
+ MPI_CONFIG_PAGETYPE_MASK) ==
+ MPI_CONFIG_PAGETYPE_EXTENDED) {
+ pCfg->cfghdr.ehdr->ExtPageLength =
+ le16_to_cpu(pReply->ExtPageLength);
+ pCfg->cfghdr.ehdr->ExtPageType =
+ pReply->ExtPageType;
+ }
+ pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
+
+ /* If this is a regular header, save PageLength. */
+ /* LMP Do this better so not using a reserved field! */
+ pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
+ pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
+ pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
}
}
@@ -705,7 +710,7 @@
if (dd_cbfunc->remove)
dd_cbfunc->remove(ioc->pcidev);
}
-
+
MptDeviceDriverHandlers[cb_idx] = NULL;
}
@@ -818,7 +823,7 @@
}
#endif
- mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
+ mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
}
@@ -920,7 +925,7 @@
/* Make sure there are no doorbells */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-
+
CHIPREG_WRITE32(&ioc->chip->Doorbell,
((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
@@ -935,14 +940,14 @@
return -5;
dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
- ioc->name, ii));
+ ioc->name, ii));
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
return -2;
}
-
+
/* Send request via doorbell handshake */
req_as_bytes = (u8 *) req;
for (ii = 0; ii < reqBytes/4; ii++) {
@@ -988,9 +993,9 @@
if (ioc->id == iocid) {
*iocpp =ioc;
return iocid;
- }
+ }
}
-
+
*iocpp = NULL;
return -1;
}
@@ -1032,9 +1037,9 @@
if (pci_enable_device(pdev))
return r;
-
+
dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
-
+
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
dprintk((KERN_INFO MYNAM
": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
@@ -1059,7 +1064,7 @@
ioc->alloc_total = sizeof(MPT_ADAPTER);
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
-
+
ioc->pcidev = pdev;
ioc->diagPending = 0;
spin_lock_init(&ioc->diagLock);
@@ -1088,7 +1093,7 @@
/* Find lookup slot. */
INIT_LIST_HEAD(&ioc->list);
ioc->id = mpt_ids++;
-
+
mem_phys = msize = 0;
port = psize = 0;
for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
@@ -1143,7 +1148,7 @@
ioc->prod_name = "LSIFC909";
ioc->bus_type = FC;
}
- if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
+ else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
ioc->prod_name = "LSIFC929";
ioc->bus_type = FC;
}
@@ -1322,7 +1327,7 @@
remove_proc_entry(pname, NULL);
sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
remove_proc_entry(pname, NULL);
-
+
/* call per device driver remove entry point */
for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
if(MptDeviceDriverHandlers[ii] &&
@@ -1330,7 +1335,7 @@
MptDeviceDriverHandlers[ii]->remove(pdev);
}
}
-
+
/* Disable interrupts! */
CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
@@ -1403,7 +1408,7 @@
u32 device_state = pdev->current_state;
int recovery_state;
int ii;
-
+
printk(MYIOC_s_INFO_FMT
"pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
ioc->name, pdev, pci_name(pdev), device_state);
@@ -1534,7 +1539,7 @@
if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
break;
}
-
+
if (ii == 5) {
dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
@@ -1542,7 +1547,7 @@
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
MptDisplayIocCapabilities(ioc);
}
-
+
if (alt_ioc_ready) {
if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
@@ -1613,7 +1618,7 @@
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt) */
- dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+ dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
ioc->alt_ioc->active = 1;
@@ -1670,7 +1675,7 @@
/* Find IM volumes
*/
- if (ioc->facts.MsgVersion >= 0x0102)
+ if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
mpt_findImVolumes(ioc);
/* Check, and possibly reset, the coalescing value
@@ -1700,7 +1705,7 @@
}
if (alt_ioc_ready && MptResetHandlers[ii]) {
- dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+ drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
ioc->name, ioc->alt_ioc->name, ii));
rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
handlers++;
@@ -1733,8 +1738,8 @@
dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
" searching for devfn match on %x or %x\n",
- ioc->name, pci_name(pdev), pdev->devfn,
- func-1, func+1));
+ ioc->name, pci_name(pdev), pdev->bus->number,
+ pdev->devfn, func-1, func+1));
peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
if (!peer) {
@@ -1861,36 +1866,39 @@
static void
mpt_adapter_dispose(MPT_ADAPTER *ioc)
{
- if (ioc != NULL) {
- int sz_first, sz_last;
+ int sz_first, sz_last;
- sz_first = ioc->alloc_total;
+ if (ioc == NULL)
+ return;
- mpt_adapter_disable(ioc);
+ sz_first = ioc->alloc_total;
- if (ioc->pci_irq != -1) {
- free_irq(ioc->pci_irq, ioc);
- ioc->pci_irq = -1;
- }
+ mpt_adapter_disable(ioc);
- if (ioc->memmap != NULL)
- iounmap(ioc->memmap);
+ if (ioc->pci_irq != -1) {
+ free_irq(ioc->pci_irq, ioc);
+ ioc->pci_irq = -1;
+ }
+
+ if (ioc->memmap != NULL) {
+ iounmap(ioc->memmap);
+ ioc->memmap = NULL;
+ }
#if defined(CONFIG_MTRR) && 0
- if (ioc->mtrr_reg > 0) {
- mtrr_del(ioc->mtrr_reg, 0, 0);
- dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
- }
+ if (ioc->mtrr_reg > 0) {
+ mtrr_del(ioc->mtrr_reg, 0, 0);
+ dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
+ }
#endif
- /* Zap the adapter lookup ptr! */
- list_del(&ioc->list);
+ /* Zap the adapter lookup ptr! */
+ list_del(&ioc->list);
- sz_last = ioc->alloc_total;
- dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
- kfree(ioc);
- }
+ sz_last = ioc->alloc_total;
+ dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+ kfree(ioc);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1977,7 +1985,7 @@
}
/* Is it already READY? */
- if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
+ if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
return 0;
/*
@@ -1995,7 +2003,7 @@
* Hmmm... Did it get left operational?
*/
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
- dinitprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
+ dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
ioc->name));
/* Check WhoInit.
@@ -2004,8 +2012,8 @@
* Else, fall through to KickStart case
*/
whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
- dprintk((KERN_WARNING MYNAM
- ": whoinit 0x%x\n statefault %d force %d\n",
+ dinitprintk((KERN_INFO MYNAM
+ ": whoinit 0x%x statefault %d force %d\n",
whoinit, statefault, force));
if (whoinit == MPI_WHOINIT_PCI_PEER)
return -4;
@@ -2140,8 +2148,8 @@
get_facts.Function = MPI_FUNCTION_IOC_FACTS;
/* Assert: All other get_facts fields are zero! */
- dinitprintk((MYIOC_s_INFO_FMT
- "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
+ dinitprintk((MYIOC_s_INFO_FMT
+ "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
ioc->name, req_sz, reply_sz));
/* No non-zero fields in the get_facts request are greater than
@@ -2174,7 +2182,7 @@
facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
- status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
+ status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
/* CHECKME! IOCStatus, IOCLogInfo */
facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
@@ -2221,7 +2229,7 @@
if ( sz & 0x02 )
sz += 2;
facts->FWImageSize = sz;
-
+
if (!facts->RequestFrameSize) {
/* Something is wrong! */
printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
@@ -2240,7 +2248,7 @@
ioc->NBShiftFactor = shiftFactor;
dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
ioc->name, vv, shiftFactor, r));
-
+
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
/*
* Set values for this IOC's request & reply frame sizes,
@@ -2261,7 +2269,7 @@
return r;
}
} else {
- printk(MYIOC_s_ERR_FMT
+ printk(MYIOC_s_ERR_FMT
"Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
RequestFrameSize)/sizeof(u32)));
@@ -2413,9 +2421,11 @@
dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
ioc->name, &ioc_init));
-
- if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
+
+ if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
+ printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
return r;
+ }
/* YIKES! SUPER IMPORTANT!!!
* Poll IocState until _OPERATIONAL while IOC is doing
@@ -2440,7 +2450,7 @@
state = mpt_GetIocState(ioc, 1);
count++;
}
- dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+ dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
return r;
@@ -2529,7 +2539,7 @@
int sz;
sz = ioc->facts.FWImageSize;
- dinitprintk((KERN_WARNING MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
pci_free_consistent(ioc->pcidev, sz,
ioc->cached_fw, ioc->cached_fw_dma);
@@ -2573,9 +2583,9 @@
mpt_alloc_fw_memory(ioc, sz);
- dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
-
+
if (ioc->cached_fw == NULL) {
/* Major Failure.
*/
@@ -2605,14 +2615,14 @@
mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
- dinitprintk((KERN_WARNING MYNAM "Sending FW Upload (req @ %p) sgeoffset=%d \n",
+ dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
prequest, sgeoffset));
DBG_DUMP_FW_REQUEST_FRAME(prequest)
ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
- dinitprintk((KERN_WARNING MYNAM "FW Upload completed rc=%x \n", ii));
+ dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
cmdStatus = -EFAULT;
if (ii == 0) {
@@ -2627,10 +2637,10 @@
cmdStatus = 0;
}
}
- dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
+ dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
ioc->name, cmdStatus));
-
+
if (cmdStatus) {
ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
@@ -2761,8 +2771,8 @@
fwSize = (pExtImage->ImageSize + 3) >> 2;
ptrFw = (u32 *)pExtImage;
- ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x bytes @ %p load_addr=%x\n",
- ioc->name, fwSize*4, ptrFw, load_addr));
+ ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
+ ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
while (fwSize--) {
@@ -2845,9 +2855,9 @@
* 0 else
*
* Returns:
- * 1 - hard reset, READY
- * 0 - no reset due to History bit, READY
- * -1 - no reset due to History bit but not READY
+ * 1 - hard reset, READY
+ * 0 - no reset due to History bit, READY
+ * -1 - no reset due to History bit but not READY
* OR reset but failed to come READY
* -2 - no reset, could not enter DIAG mode
* -3 - reset but bad FW bit
@@ -2990,7 +3000,7 @@
*
*/
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
- mdelay (1);
+ mdelay(1);
/*
* Now hit the reset bit in the Diagnostic register
@@ -3170,7 +3180,7 @@
u32 state;
int cntdn, count;
- drsprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+ drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
ioc->name, reset_type));
CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
@@ -3374,6 +3384,9 @@
ioc->reply_frames = (MPT_FRAME_HDR *) mem;
ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
+ dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
+ ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
+
alloc_dma += reply_sz;
mem += reply_sz;
@@ -3382,7 +3395,7 @@
ioc->req_frames = (MPT_FRAME_HDR *) mem;
ioc->req_frames_dma = alloc_dma;
- dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffers @ %p[%p]\n",
+ dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
ioc->name, mem, (void *)(ulong)alloc_dma));
ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
@@ -3408,7 +3421,7 @@
ioc->ChainBuffer = mem;
ioc->ChainBufferDMA = alloc_dma;
- dinitprintk((KERN_INFO MYNAM " :%s.ChainBuffers @ %p(%p)\n",
+ dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
/* Initialize the free chain Q.
@@ -3513,7 +3526,7 @@
*/
static int
mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
- int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
+ int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
{
MPIDefaultReply_t *mptReply;
int failcnt = 0;
@@ -3588,7 +3601,7 @@
*/
if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
failcnt++;
-
+
dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
@@ -3747,7 +3760,7 @@
}
dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
- ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
+ ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
/*
@@ -3819,7 +3832,7 @@
hdr.PageLength = 0;
hdr.PageNumber = 0;
hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.physAddr = -1;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
@@ -3863,7 +3876,7 @@
hdr.PageLength = 0;
hdr.PageNumber = 1;
hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.physAddr = -1;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
@@ -3930,7 +3943,7 @@
hdr.PageLength = 0;
hdr.PageNumber = 0;
hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.physAddr = -1;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
@@ -4012,7 +4025,7 @@
hdr.PageLength = 0;
hdr.PageNumber = 2;
hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.physAddr = -1;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
@@ -4102,7 +4115,7 @@
header.PageLength = 0;
header.PageNumber = 0;
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = portnum;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4122,6 +4135,8 @@
ioc->spi_data.minSyncFactor = MPT_ASYNC;
ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
rc = 1;
+ ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
+ ioc->name, ioc->spi_data.minSyncFactor));
} else {
/* Save the Port Page 0 data
*/
@@ -4131,7 +4146,7 @@
if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
- dinitprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
+ ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
ioc->name, pPP0->Capabilities));
}
ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4140,6 +4155,8 @@
ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
ioc->spi_data.minSyncFactor = (u8) (data >> 8);
+ ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
+ ioc->name, ioc->spi_data.minSyncFactor));
} else {
ioc->spi_data.maxSyncOffset = 0;
ioc->spi_data.minSyncFactor = MPT_ASYNC;
@@ -4152,8 +4169,11 @@
if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
(ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
- if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
+ if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
ioc->spi_data.minSyncFactor = MPT_ULTRA;
+ ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
+ ioc->name, ioc->spi_data.minSyncFactor));
+ }
}
}
if (pbuf) {
@@ -4168,7 +4188,7 @@
header.PageLength = 0;
header.PageNumber = 2;
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = portnum;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4236,7 +4256,7 @@
header.PageLength = 0;
header.PageNumber = 1;
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = portnum;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4245,8 +4265,8 @@
if (mpt_config(ioc, &cfg) != 0)
return -EFAULT;
- ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
- ioc->spi_data.sdp1length = cfg.hdr->PageLength;
+ ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
+ ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
header.PageVersion = 0;
header.PageLength = 0;
@@ -4255,8 +4275,8 @@
if (mpt_config(ioc, &cfg) != 0)
return -EFAULT;
- ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
- ioc->spi_data.sdp0length = cfg.hdr->PageLength;
+ ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
+ ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
@@ -4298,7 +4318,7 @@
header.PageLength = 0;
header.PageNumber = 2;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4394,7 +4414,7 @@
header.PageLength = 0;
header.PageNumber = 3;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4446,7 +4466,7 @@
header.PageLength = 0;
header.PageNumber = 4;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4498,7 +4518,7 @@
header.PageLength = 0;
header.PageNumber = 1;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
- cfg.hdr = &header;
+ cfg.cfghdr.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -4580,13 +4600,13 @@
evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
if (evnp == NULL) {
- dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
+ devtprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
ioc->name));
return 0;
}
memset(evnp, 0, sizeof(*evnp));
- dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+ devtprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
evnp->ChainOffset = 0;
@@ -4610,8 +4630,10 @@
EventAck_t *pAck;
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
- printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
- ioc->name);
+ printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
+ "request frame for Event=%x EventContext=%x EventData=%x!\n",
+ ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
+ le32_to_cpu(evnp->Data[0]));
return -1;
}
memset(pAck, 0, sizeof(*pAck));
@@ -4647,10 +4669,11 @@
mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
{
Config_t *pReq;
+ ConfigExtendedPageHeader_t *pExtHdr = NULL;
MPT_FRAME_HDR *mf;
unsigned long flags;
int ii, rc;
- u32 flagsLength;
+ int flagsLength;
int in_isr;
/* Prevent calling wait_event() (below), if caller happens
@@ -4675,16 +4698,30 @@
pReq->Reserved = 0;
pReq->ChainOffset = 0;
pReq->Function = MPI_FUNCTION_CONFIG;
+
+ /* Assume page type is not extended and clear "reserved" fields. */
pReq->ExtPageLength = 0;
pReq->ExtPageType = 0;
pReq->MsgFlags = 0;
+
for (ii=0; ii < 8; ii++)
pReq->Reserved2[ii] = 0;
- pReq->Header.PageVersion = pCfg->hdr->PageVersion;
- pReq->Header.PageLength = pCfg->hdr->PageLength;
- pReq->Header.PageNumber = pCfg->hdr->PageNumber;
- pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
+ pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
+ pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
+ pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
+ pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
+
+ if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
+ pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
+ pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
+ pReq->ExtPageType = pExtHdr->ExtPageType;
+ pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+
+ /* Page Length must be treated as a reserved field for the extended header. */
+ pReq->Header.PageLength = 0;
+ }
+
pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
/* Add a SGE to the config request.
@@ -4694,13 +4731,21 @@
else
flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
- flagsLength |= pCfg->hdr->PageLength * 4;
+ if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
+ flagsLength |= pExtHdr->ExtPageLength * 4;
+
+ dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+ ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
+ }
+ else {
+ flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
+
+ dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+ ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+ }
mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
- dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
- ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
-
/* Append pCfg pointer to end of mf
*/
*((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
@@ -4789,8 +4834,8 @@
pReq->Reserved3 = 0;
pReq->NumAddressBytes = 0x01;
pReq->Reserved4 = 0;
- pReq->DataLength = 0x04;
- pdev = (struct pci_dev *) ioc->pcidev;
+ pReq->DataLength = cpu_to_le16(0x04);
+ pdev = ioc->pcidev;
if (pdev->devfn & 1)
pReq->DeviceAddr = 0xB2;
else
@@ -5504,6 +5549,8 @@
* If needed, send (a single) EventAck.
*/
if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
+ devtprintk((MYIOC_s_WARN_FMT
+ "EventAck required\n",ioc->name));
if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
ioc->name, ii));
@@ -5584,7 +5631,7 @@
case 0x00080000:
desc = "Outbound DMA Overrun";
break;
-
+
case 0x00090000:
desc = "Task Management";
break;
@@ -5600,7 +5647,7 @@
case 0x000C0000:
desc = "Untagged Table Size";
break;
-
+
}
printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
@@ -5692,7 +5739,7 @@
break;
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
- /* This error is checked in scsi_io_done(). Skip.
+ /* This error is checked in scsi_io_done(). Skip.
desc = "SCSI Data Underrun";
*/
break;
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 848fb236..f4827d9 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -915,7 +915,10 @@
typedef struct _x_config_parms {
struct list_head linkage; /* linked list */
struct timer_list timer; /* timer function for this request */
- ConfigPageHeader_t *hdr;
+ union {
+ ConfigExtendedPageHeader_t *ehdr;
+ ConfigPageHeader_t *hdr;
+ } cfghdr;
dma_addr_t physAddr;
int wait_done; /* wait for this request */
u32 pageAddr; /* properly formatted */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 05ea594..7577c24 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -242,7 +242,7 @@
/* Set the command status to GOOD if IOC Status is GOOD
* OR if SCSI I/O cmd and data underrun or recovered error.
*/
- iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
+ iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
if (iocStatus == MPI_IOCSTATUS_SUCCESS)
ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
@@ -2324,7 +2324,7 @@
hdr.PageLength = 0;
hdr.PageNumber = 0;
hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
@@ -2333,7 +2333,7 @@
strncpy(karg.serial_number, " ", 24);
if (mpt_config(ioc, &cfg) == 0) {
- if (cfg.hdr->PageLength > 0) {
+ if (cfg.cfghdr.hdr->PageLength > 0) {
/* Issue the second config page request */
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
@@ -2479,7 +2479,7 @@
hdr.PageNumber = 0;
hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
cfg.timeout = 0;
@@ -2527,15 +2527,15 @@
hdr.PageNumber = 3;
hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
- cfg.hdr = &hdr;
+ cfg.cfghdr.hdr = &hdr;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
cfg.timeout = 0;
cfg.physAddr = -1;
- if ((mpt_config(ioc, &cfg) == 0) && (cfg.hdr->PageLength > 0)) {
+ if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) {
/* Issue the second config page request */
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
- data_sz = (int) cfg.hdr->PageLength * 4;
+ data_sz = (int) cfg.cfghdr.hdr->PageLength * 4;
pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent(
ioc->pcidev, data_sz, &page_dma);
if (pg3_alloc) {
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index b9d4f78..4a003dc 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -281,12 +281,12 @@
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
chain_idx = offset / ioc->req_sz;
rc = SUCCESS;
- dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
- ioc->name, *retIndex, chainBuf));
+ dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+ ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
} else {
rc = FAILED;
chain_idx = MPT_HOST_NO_CHAIN;
- dfailprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
+ dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
ioc->name));
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -432,7 +432,7 @@
*/
pReq->ChainOffset = 0;
RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
- dsgprintk((MYIOC_s_ERR_FMT
+ dsgprintk((MYIOC_s_INFO_FMT
"Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
ioc->RequestNB[req_idx] = RequestNB;
}
@@ -491,11 +491,12 @@
/* NOTE: psge points to the beginning of the chain element
* in current buffer. Get a chain buffer.
*/
- dsgprintk((MYIOC_s_INFO_FMT
- "calling getFreeChainBuffer SCSI cmd=%02x (%p)\n",
- ioc->name, pReq->CDB[0], SCpnt));
- if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED)
+ if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
+ dfailprintk((MYIOC_s_INFO_FMT
+ "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
+ ioc->name, pReq->CDB[0], SCpnt));
return FAILED;
+ }
/* Update the tracking arrays.
* If chainSge == NULL, update ReqToChain, else ChainToChain
@@ -577,14 +578,20 @@
return 1;
}
- dmfprintk((MYIOC_s_INFO_FMT
- "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
- ioc->name, mf, mr, sc, req_idx));
-
sc->result = DID_OK << 16; /* Set default reply as OK */
pScsiReq = (SCSIIORequest_t *) mf;
pScsiReply = (SCSIIOReply_t *) mr;
+ if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
+ dmfprintk((MYIOC_s_INFO_FMT
+ "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
+ ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
+ }else{
+ dmfprintk((MYIOC_s_INFO_FMT
+ "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
+ ioc->name, mf, mr, sc, req_idx));
+ }
+
if (pScsiReply == NULL) {
/* special context reply handling */
;
@@ -658,8 +665,8 @@
/* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
} else if ( xfer_cnt == 0 ) {
- /* A CRC Error causes this condition; retry */
- sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+ /* A CRC Error causes this condition; retry */
+ sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
(CHECK_CONDITION << 1);
sc->sense_buffer[0] = 0x70;
sc->sense_buffer[2] = NO_SENSE;
@@ -668,7 +675,9 @@
} else {
sc->result = DID_SOFT_ERROR << 16;
}
- dreplyprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target));
+ dreplyprintk((KERN_NOTICE
+ "RESIDUAL_MISMATCH: result=%x on id=%d\n",
+ sc->result, sc->device->id));
break;
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
@@ -796,7 +805,6 @@
return 1;
}
-
/*
* mptscsih_flush_running_cmds - For each command found, search
* Scsi_Host instance taskQ and reply to OS.
@@ -1017,7 +1025,7 @@
scsi_host_put(host);
mpt_detach(pdev);
-
+
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1072,7 +1080,7 @@
MPT_SCSI_HOST *hd;
mpt_resume(pdev);
-
+
if(!host)
return 0;
@@ -1214,8 +1222,8 @@
int size = 0;
if (func) {
- /*
- * write is not supported
+ /*
+ * write is not supported
*/
} else {
if (start)
@@ -1535,17 +1543,17 @@
*/
if (mptscsih_tm_pending_wait(hd) == FAILED) {
if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
- dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: "
+ dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
"Timed out waiting for last TM (%d) to complete! \n",
hd->ioc->name, hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
- dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: "
+ dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
"Timed out waiting for last TM (%d) to complete! \n",
hd->ioc->name, hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
- dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: "
+ dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
"Timed out waiting for last TM (%d) to complete! \n",
hd->ioc->name, hd->tmPending));
if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
@@ -1631,8 +1639,7 @@
if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
hd->ioc->name));
- //return FAILED;
- return -999;
+ return FAILED;
}
dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
hd->ioc->name, mf));
@@ -1661,9 +1668,8 @@
pScsiTm->TaskMsgContext = ctx2abort;
- dtmprintk((MYIOC_s_INFO_FMT
- "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
- hd->ioc->name, ctx2abort, type));
+ dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
+ hd->ioc->name, ctx2abort, type));
DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
@@ -1902,13 +1908,13 @@
/* If we can't locate the host to reset, then we failed. */
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+ dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
"Can't locate host! (sc=%p)\n",
SCpnt ) );
return FAILED;
}
- printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
+ printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
hd->ioc->name, SCpnt);
/* If our attempts to reset the host failed, then return a failed
@@ -1924,7 +1930,7 @@
hd->tmState = TM_STATE_NONE;
}
- dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+ dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
"Status = %s\n",
(status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
@@ -1951,8 +1957,8 @@
if (hd->tmState == TM_STATE_NONE) {
hd->tmState = TM_STATE_IN_PROGRESS;
hd->tmPending = 1;
- status = SUCCESS;
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ status = SUCCESS;
break;
}
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
@@ -1980,7 +1986,7 @@
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
if(hd->tmPending == 0) {
status = SUCCESS;
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
break;
}
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
@@ -2318,10 +2324,10 @@
if (pTarget == NULL) {
/* Driver doesn't know about this device.
* Kernel may generate a "Dummy Lun 0" which
- * may become a real Lun if a
+ * may become a real Lun if a
* "scsi add-single-device" command is executed
- * while the driver is active (hot-plug a
- * device). LSI Raid controllers need
+ * while the driver is active (hot-plug a
+ * device). LSI Raid controllers need
* queue_depth set to DEV_HIGH for this reason.
*/
scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
@@ -2691,7 +2697,7 @@
* If the peripheral qualifier filter is enabled then if the target reports a 0x1
* (i.e. The targer is capable of supporting the specified peripheral device type
* on this logical unit; however, the physical device is not currently connected
- * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
+ * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
* capable of supporting a physical device on this logical unit). This is to work
* around a bug in th emid-layer in some distributions in which the mid-layer will
* continue to try to communicate to the LUN and evntually create a dummy LUN.
@@ -3194,8 +3200,8 @@
/* Get a MF for this command.
*/
if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
- dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
- ioc->name));
+ dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
+ ioc->name));
return -EAGAIN;
}
@@ -3289,7 +3295,7 @@
/* Get a MF for this command.
*/
if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
- dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
+ dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
ioc->name));
return -EAGAIN;
}
@@ -3447,7 +3453,7 @@
* some type of error occurred.
*/
MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
- if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+ if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
completionCode = MPT_SCANDV_GOOD;
else
completionCode = MPT_SCANDV_SOME_ERROR;
@@ -3955,7 +3961,7 @@
header1.PageLength = ioc->spi_data.sdp1length;
header1.PageNumber = 1;
header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
- cfg.hdr = &header1;
+ cfg.cfghdr.hdr = &header1;
cfg.physAddr = cfg1_dma_addr;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
cfg.dir = 1;
@@ -3996,9 +4002,9 @@
dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
"offset=0 negoFlags=%x request=%x config=%x\n",
id, flags, requested, configuration));
- pcfg1Data->RequestedParameters = le32_to_cpu(requested);
+ pcfg1Data->RequestedParameters = cpu_to_le32(requested);
pcfg1Data->Reserved = 0;
- pcfg1Data->Configuration = le32_to_cpu(configuration);
+ pcfg1Data->Configuration = cpu_to_le32(configuration);
cfg.pageAddr = (bus<<8) | id;
mpt_config(hd->ioc, &cfg);
}
@@ -4353,7 +4359,7 @@
/* Prep cfg structure
*/
cfg.pageAddr = (bus<<8) | id;
- cfg.hdr = NULL;
+ cfg.cfghdr.hdr = NULL;
/* Prep SDP0 header
*/
@@ -4399,7 +4405,7 @@
pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
cfg1_dma_addr = dvbuf_dma + sz;
- /* Skip this ID? Set cfg.hdr to force config page write
+ /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
*/
{
ScsiCfgData *pspi_data = &hd->ioc->spi_data;
@@ -4417,7 +4423,7 @@
dv.cmd = MPT_SET_MAX;
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
- cfg.hdr = &header1;
+ cfg.cfghdr.hdr = &header1;
/* Save the final negotiated settings to
* SCSI device page 1.
@@ -4483,7 +4489,7 @@
dv.cmd = MPT_SET_MIN;
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
- cfg.hdr = &header1;
+ cfg.cfghdr.hdr = &header1;
cfg.physAddr = cfg1_dma_addr;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
cfg.dir = 1;
@@ -4596,8 +4602,8 @@
if ((pbuf1[56] & 0x02) == 0) {
pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
- ddvprintk((MYIOC_s_NOTE_FMT
- "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
+ ddvprintk((MYIOC_s_NOTE_FMT
+ "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
ioc->name, id, pbuf1[56]));
}
}
@@ -4637,7 +4643,7 @@
u32 sdp0_info;
u32 sdp0_nego;
- cfg.hdr = &header0;
+ cfg.cfghdr.hdr = &header0;
cfg.physAddr = cfg0_dma_addr;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
@@ -4673,7 +4679,7 @@
if (!firstPass)
doFallback = 1;
} else {
- ddvprintk((MYIOC_s_NOTE_FMT
+ ddvprintk((MYIOC_s_NOTE_FMT
"DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
mptscsih_initTarget(hd,
@@ -4689,8 +4695,8 @@
} else if (rc == MPT_SCANDV_ISSUE_SENSE)
doFallback = 1; /* set fallback flag */
- else if ((rc == MPT_SCANDV_DID_RESET) ||
- (rc == MPT_SCANDV_SENSE) ||
+ else if ((rc == MPT_SCANDV_DID_RESET) ||
+ (rc == MPT_SCANDV_SENSE) ||
(rc == MPT_SCANDV_FALLBACK))
doFallback = 1; /* set fallback flag */
else
@@ -4722,7 +4728,7 @@
* 4) release
* 5) update nego parms to target struct
*/
- cfg.hdr = &header1;
+ cfg.cfghdr.hdr = &header1;
cfg.physAddr = cfg1_dma_addr;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
cfg.dir = 1;
@@ -5121,12 +5127,12 @@
/* Set if cfg1_dma_addr contents is valid
*/
- if ((cfg.hdr != NULL) && (retcode == 0)){
+ if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
/* If disk, not U320, disable QAS
*/
if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
- ddvprintk((MYIOC_s_NOTE_FMT
+ ddvprintk((MYIOC_s_NOTE_FMT
"noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
}
@@ -5137,7 +5143,7 @@
* skip save of the final negotiated settings to
* SCSI device page 1.
*
- cfg.hdr = &header1;
+ cfg.cfghdr.hdr = &header1;
cfg.physAddr = cfg1_dma_addr;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
cfg.dir = 1;
@@ -5248,7 +5254,7 @@
/* Update tmax values with those from Device Page 0.*/
pPage0 = (SCSIDevicePage0_t *) pPage;
if (pPage0) {
- val = cpu_to_le32(pPage0->NegotiatedParameters);
+ val = le32_to_cpu(pPage0->NegotiatedParameters);
dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
@@ -5276,12 +5282,12 @@
dv->now.offset, &val, &configuration, dv->now.flags);
dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
- pPage1->RequestedParameters = le32_to_cpu(val);
+ pPage1->RequestedParameters = cpu_to_le32(val);
pPage1->Reserved = 0;
- pPage1->Configuration = le32_to_cpu(configuration);
+ pPage1->Configuration = cpu_to_le32(configuration);
}
- ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x request=%x configuration=%x\n",
+ ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
break;
@@ -5301,9 +5307,9 @@
offset, &val, &configuration, negoFlags);
dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
id, width, factor, offset, negoFlags, val, configuration));
- pPage1->RequestedParameters = le32_to_cpu(val);
+ pPage1->RequestedParameters = cpu_to_le32(val);
pPage1->Reserved = 0;
- pPage1->Configuration = le32_to_cpu(configuration);
+ pPage1->Configuration = cpu_to_le32(configuration);
}
ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
id, width, factor, offset, val, configuration, negoFlags));
@@ -5377,12 +5383,12 @@
if (pPage1) {
mptscsih_setDevicePage1Flags (width, factor, offset, &val,
&configuration, dv->now.flags);
- dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x flags=%x request=%x config=%x\n",
+ dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
id, width, offset, factor, dv->now.flags, val, configuration));
- pPage1->RequestedParameters = le32_to_cpu(val);
+ pPage1->RequestedParameters = cpu_to_le32(val);
pPage1->Reserved = 0;
- pPage1->Configuration = le32_to_cpu(configuration);
+ pPage1->Configuration = cpu_to_le32(configuration);
}
ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index dfa8806..587d127 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -162,15 +162,15 @@
u8 *mem;
int error=0;
int r;
-
+
if ((r = mpt_attach(pdev,id)) != 0)
return r;
-
+
ioc = pci_get_drvdata(pdev);
ioc->DoneCtx = mptspiDoneCtx;
ioc->TaskCtx = mptspiTaskCtx;
ioc->InternalCtx = mptspiInternalCtx;
-
+
/* Added sanity check on readiness of the MPT adapter.
*/
if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c
index 9148045..7e98434 100644
--- a/drivers/misc/ibmasm/uart.c
+++ b/drivers/misc/ibmasm/uart.c
@@ -25,15 +25,15 @@
#include <linux/termios.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
-#include <linux/serial.h>
#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
#include "ibmasm.h"
#include "lowlevel.h"
void ibmasm_register_uart(struct service_processor *sp)
{
- struct serial_struct serial;
+ struct uart_port uport;
void __iomem *iomem_base;
iomem_base = sp->base_address + SCOUT_COM_B_BASE;
@@ -47,14 +47,14 @@
return;
}
- memset(&serial, 0, sizeof(serial));
- serial.irq = sp->irq;
- serial.baud_base = 3686400 / 16;
- serial.flags = UPF_AUTOPROBE | UPF_SHARE_IRQ;
- serial.io_type = UPIO_MEM;
- serial.iomem_base = iomem_base;
+ memset(&uport, 0, sizeof(struct uart_port));
+ uport.irq = sp->irq;
+ uport.uartclk = 3686400;
+ uport.flags = UPF_AUTOPROBE | UPF_SHARE_IRQ;
+ uport.iotype = UPIO_MEM;
+ uport.membase = iomem_base;
- sp->serial_line = register_serial(&serial);
+ sp->serial_line = serial8250_register_port(&uport);
if (sp->serial_line < 0) {
dev_err(sp->dev, "Failed to register serial port\n");
return;
@@ -68,5 +68,5 @@
return;
disable_uart_interrupts(sp->base_address);
- unregister_serial(sp->serial_line);
+ serial8250_unregister_port(sp->serial_line);
}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 3c59048..0a117c6 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -2,6 +2,8 @@
* linux/drivers/mmc/mmc.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,6 +18,8 @@
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -172,7 +176,81 @@
EXPORT_SYMBOL(mmc_wait_for_cmd);
+/**
+ * mmc_wait_for_app_cmd - start an application command and wait for
+ completion
+ * @host: MMC host to start command
+ * @rca: RCA to send MMC_APP_CMD to
+ * @cmd: MMC command to start
+ * @retries: maximum number of retries
+ *
+ * Sends a MMC_APP_CMD, checks the card response, sends the command
+ * in the parameter and waits for it to complete. Return any error
+ * that occurred while the command was executing. Do not attempt to
+ * parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+ struct mmc_command *cmd, int retries)
+{
+ struct mmc_request mrq;
+ struct mmc_command appcmd;
+ int i, err;
+
+ BUG_ON(host->card_busy == NULL);
+ BUG_ON(retries < 0);
+
+ err = MMC_ERR_INVALID;
+
+ /*
+ * We have to resend MMC_APP_CMD for each attempt so
+ * we cannot use the retries field in mmc_command.
+ */
+ for (i = 0;i <= retries;i++) {
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ appcmd.opcode = MMC_APP_CMD;
+ appcmd.arg = rca << 16;
+ appcmd.flags = MMC_RSP_R1;
+ appcmd.retries = 0;
+ memset(appcmd.resp, 0, sizeof(appcmd.resp));
+ appcmd.data = NULL;
+
+ mrq.cmd = &appcmd;
+ appcmd.data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ if (appcmd.error) {
+ err = appcmd.error;
+ continue;
+ }
+
+ /* Check that card supported application commands */
+ if (!(appcmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = 0;
+
+ mrq.cmd = cmd;
+ cmd->data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ err = cmd->error;
+ if (cmd->error == MMC_ERR_NONE)
+ break;
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
/**
* __mmc_claim_host - exclusively claim a host
@@ -206,16 +284,10 @@
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (card != (void *)-1 && host->card_selected != card) {
- struct mmc_command cmd;
-
- host->card_selected = card;
-
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (card != (void *)-1) {
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE)
+ return err;
}
return err;
@@ -245,6 +317,63 @@
EXPORT_SYMBOL(mmc_release_host);
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(host->card_busy == NULL);
+
+ if (host->card_selected == card)
+ return MMC_ERR_NONE;
+
+ host->card_selected = card;
+
+ cmd.opcode = MMC_SELECT_CARD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ /*
+ * Default bus width is 1 bit.
+ */
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+
+ /*
+ * We can only change the bus width of the selected
+ * card so therefore we have to put the handling
+ * here.
+ */
+ if (host->caps & MMC_CAP_4_BIT_DATA) {
+ /*
+ * The card is in 1 bit mode by default so
+ * we only need to change if it supports the
+ * wider version.
+ */
+ if (mmc_card_sd(card) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ struct mmc_command cmd;
+ cmd.opcode = SD_APP_SET_BUS_WIDTH;
+ cmd.arg = SD_BUS_WIDTH_4;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+ CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ }
+ }
+
+ host->ops->set_ios(host, &host->ios);
+
+ return MMC_ERR_NONE;
+}
+
/*
* Ensure that no card is selected.
*/
@@ -322,48 +451,69 @@
memset(&card->cid, 0, sizeof(struct mmc_cid));
- /*
- * The selection of the format here is guesswork based upon
- * information people have sent to date.
- */
- switch (card->csd.mmca_vsn) {
- case 0: /* MMC v1.? */
- case 1: /* MMC v1.4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
+ if (mmc_card_sd(card)) {
+ /*
+ * SD doesn't currently have a version field so we will
+ * have to assume we can parse this.
+ */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
+ card->cid.year = UNSTUFF_BITS(resp, 12, 8);
+ card->cid.month = UNSTUFF_BITS(resp, 8, 4);
- case 2: /* MMC v2.x ? */
- case 3: /* MMC v3.x ? */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
+ card->cid.year += 2000; /* SD cards year offset */
+ } else {
+ /*
+ * The selection of the format here is based upon published
+ * specs from sandisk and from what people have reported.
+ */
+ switch (card->csd.mmca_vsn) {
+ case 0: /* MMC v1.0 - v1.2 */
+ case 1: /* MMC v1.4 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
+ card->cid.month = UNSTUFF_BITS(resp, 12, 4);
+ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ break;
- default:
- printk("%s: card has unknown MMCA version %d\n",
- mmc_hostname(card->host), card->csd.mmca_vsn);
- mmc_card_set_bad(card);
- break;
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
+ card->cid.month = UNSTUFF_BITS(resp, 12, 4);
+ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ break;
+
+ default:
+ printk("%s: card has unknown MMCA version %d\n",
+ mmc_hostname(card->host), card->csd.mmca_vsn);
+ mmc_card_set_bad(card);
+ break;
+ }
}
}
@@ -376,34 +526,86 @@
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
- /*
- * We only understand CSD structure v1.1 and v2.
- * v2 has extra information in bits 15, 11 and 10.
- */
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 1 && csd_struct != 2) {
- printk("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
+ if (mmc_card_sd(card)) {
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 0) {
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ } else {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
+ */
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 1 && csd_struct != 2) {
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ }
+}
+
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+ struct sd_scr *scr = &card->scr;
+ unsigned int scr_struct;
+ u32 resp[4];
+
+ BUG_ON(!mmc_card_sd(card));
+
+ resp[3] = card->raw_scr[1];
+ resp[2] = card->raw_scr[0];
+
+ scr_struct = UNSTUFF_BITS(resp, 60, 4);
+ if (scr_struct != 0) {
+ printk("%s: unrecognised SCR structure version %d\n",
+ mmc_hostname(card->host), scr_struct);
mmc_card_set_bad(card);
return;
}
- csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
}
/*
@@ -457,6 +659,11 @@
{
struct mmc_command cmd;
+ host->ios.chip_select = MMC_CS_HIGH;
+ host->ops->set_ios(host, &host->ios);
+
+ mmc_delay(1);
+
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = MMC_RSP_NONE;
@@ -464,6 +671,11 @@
mmc_wait_for_cmd(host, &cmd, 0);
mmc_delay(1);
+
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ops->set_ios(host, &host->ios);
+
+ mmc_delay(1);
}
/*
@@ -475,7 +687,9 @@
host->ios.vdd = bit;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
mmc_delay(1);
@@ -492,7 +706,9 @@
host->ios.clock = 0;
host->ios.vdd = 0;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_OFF;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
}
@@ -524,6 +740,34 @@
return err;
}
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ cmd.opcode = SD_APP_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_R3;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ break;
+
+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ break;
+
+ err = MMC_ERR_TIMEOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[0];
+
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -567,13 +811,38 @@
card->state &= ~MMC_STATE_DEAD;
- cmd.opcode = MMC_SET_RELATIVE_ADDR;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ if (host->mode == MMC_MODE_SD) {
+ mmc_card_set_sd(card);
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(card);
+ cmd.opcode = SD_SEND_RELATIVE_ADDR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(card);
+ else {
+ card->rca = cmd.resp[0] >> 16;
+
+ if (!host->ops->get_ro) {
+ printk(KERN_WARNING "%s: host does not "
+ "support reading read-only "
+ "switch. assuming write-enable.\n",
+ mmc_hostname(host));
+ } else {
+ if (host->ops->get_ro(host))
+ mmc_card_set_readonly(card);
+ }
+ }
+ } else {
+ cmd.opcode = MMC_SET_RELATIVE_ADDR;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(card);
+ }
}
}
@@ -605,6 +874,79 @@
}
}
+static void mmc_read_scrs(struct mmc_host *host)
+{
+ int err;
+ struct mmc_card *card;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+
+ struct scatterlist sg;
+
+ list_for_each_entry(card, &host->cards, node) {
+ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+ continue;
+ if (!mmc_card_sd(card))
+ continue;
+
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SEND_SCR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 10;
+ data.timeout_clks = card->csd.tacc_clks * 10;
+ data.blksz_bits = 3;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, (u8*)card->raw_scr, 8);
+
+ err = mmc_wait_for_req(host, &mrq);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ card->raw_scr[0] = ntohl(card->raw_scr[0]);
+ card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+ mmc_decode_scr(card);
+ }
+
+ mmc_deselect_cards(host);
+}
+
static unsigned int mmc_calculate_clock(struct mmc_host *host)
{
struct mmc_card *card;
@@ -657,12 +999,24 @@
int err;
u32 ocr;
+ host->mode = MMC_MODE_SD;
+
mmc_power_up(host);
mmc_idle_cards(host);
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err != MMC_ERR_NONE)
- return;
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+
+ /*
+ * If we fail to detect any SD cards then try
+ * searching for MMC cards.
+ */
+ if (err != MMC_ERR_NONE) {
+ host->mode = MMC_MODE_MMC;
+
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (err != MMC_ERR_NONE)
+ return;
+ }
host->ocr = mmc_select_voltage(host, ocr);
@@ -702,7 +1056,10 @@
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
- mmc_send_op_cond(host, host->ocr, NULL);
+ if (host->mode == MMC_MODE_SD)
+ mmc_send_app_op_cond(host, host->ocr, NULL);
+ else
+ mmc_send_op_cond(host, host->ocr, NULL);
mmc_discover_cards(host);
@@ -713,6 +1070,9 @@
host->ops->set_ios(host, &host->ios);
mmc_read_csds(host);
+
+ if (host->mode == MMC_MODE_SD)
+ mmc_read_scrs(host);
}
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index d4eee99..fa83f15 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -95,6 +95,10 @@
if (md->usage == 2)
check_disk_change(inode->i_bdev);
ret = 0;
+
+ if ((filp->f_mode & FMODE_WRITE) &&
+ mmc_card_readonly(md->queue.card))
+ ret = -EROFS;
}
return ret;
@@ -403,9 +407,10 @@
if (err)
goto out;
- printk(KERN_INFO "%s: %s %s %dKiB\n",
+ printk(KERN_INFO "%s: %s %s %dKiB %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- (card->csd.capacity << card->csd.read_blkbits) / 1024);
+ (card->csd.capacity << card->csd.read_blkbits) / 1024,
+ mmc_card_readonly(card)?"(ro)":"");
mmc_set_drvdata(card, md);
add_disk(md->disk);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index ad89498..3f4a66c 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -34,6 +34,7 @@
card->raw_cid[2], card->raw_cid[3]);
MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -57,6 +58,8 @@
__ATTR_NULL
};
+static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
+
static void mmc_release_card(struct device *dev)
{
@@ -207,10 +210,20 @@
*/
int mmc_register_card(struct mmc_card *card)
{
+ int ret;
+
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
"%s:%04x", mmc_hostname(card->host), card->rca);
- return device_add(&card->dev);
+ ret = device_add(&card->dev);
+ if (ret == 0) {
+ if (mmc_card_sd(card)) {
+ ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
+ if (ret)
+ device_del(&card->dev);
+ }
+ }
+ return ret;
}
/*
@@ -219,8 +232,12 @@
*/
void mmc_remove_card(struct mmc_card *card)
{
- if (mmc_card_present(card))
+ if (mmc_card_present(card)) {
+ if (mmc_card_sd(card))
+ device_remove_file(&card->dev, &mmc_dev_attr_scr);
+
device_del(&card->dev);
+ }
put_device(&card->dev);
}
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index b78beb1..e99a53b 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -362,6 +362,16 @@
pxamci_start_cmd(host, mrq->cmd, cmdat);
}
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+ struct pxamci_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc->dev);
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct pxamci_host *host = mmc_priv(mmc);
@@ -401,6 +411,7 @@
static struct mmc_host_ops pxamci_ops = {
.request = pxamci_request,
+ .get_ro = pxamci_get_ro,
.set_ios = pxamci_set_ios,
};
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 402c2d6..dec01d3 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -42,7 +42,7 @@
#include "wbsd.h"
#define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.3"
+#define DRIVER_VERSION "1.4"
#ifdef CONFIG_MMC_DEBUG
#define DBG(x...) \
@@ -720,11 +720,28 @@
* calculate CRC.
*
* Space for CRC must be included in the size.
+ * Two bytes are needed for each data line.
*/
- blksize = (1 << data->blksz_bits) + 2;
+ if (host->bus_width == MMC_BUS_WIDTH_1)
+ {
+ blksize = (1 << data->blksz_bits) + 2;
+
+ wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+ wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ }
+ else if (host->bus_width == MMC_BUS_WIDTH_4)
+ {
+ blksize = (1 << data->blksz_bits) + 2 * 4;
- wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
- wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
+ | WBSD_DATA_WIDTH);
+ wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ }
+ else
+ {
+ data->error = MMC_ERR_INVALID;
+ return;
+ }
/*
* Clear the FIFO. This is needed even for DMA
@@ -960,8 +977,9 @@
struct wbsd_host* host = mmc_priv(mmc);
u8 clk, setup, pwr;
- DBGF("clock %uHz busmode %u powermode %u Vdd %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+ DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+ ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
+ ios->vdd, ios->bus_width);
spin_lock_bh(&host->lock);
@@ -1003,30 +1021,63 @@
/*
* MMC cards need to have pin 1 high during init.
- * Init time corresponds rather nicely with the bus mode.
* It wreaks havoc with the card detection though so
- * that needs to be disabed.
+ * that needs to be disabled.
*/
setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- if ((ios->power_mode == MMC_POWER_ON) &&
- (ios->bus_mode == MMC_BUSMODE_OPENDRAIN))
+ if (ios->chip_select == MMC_CS_HIGH)
{
+ BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
setup |= WBSD_DAT3_H;
host->flags |= WBSD_FIGNORE_DETECT;
}
else
{
setup &= ~WBSD_DAT3_H;
- host->flags &= ~WBSD_FIGNORE_DETECT;
+
+ /*
+ * We cannot resume card detection immediatly
+ * because of capacitance and delays in the chip.
+ */
+ mod_timer(&host->ignore_timer, jiffies + HZ/100);
}
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+ /*
+ * Store bus width for later. Will be used when
+ * setting up the data transfer.
+ */
+ host->bus_width = ios->bus_width;
+
spin_unlock_bh(&host->lock);
}
+static int wbsd_get_ro(struct mmc_host* mmc)
+{
+ struct wbsd_host* host = mmc_priv(mmc);
+ u8 csr;
+
+ spin_lock_bh(&host->lock);
+
+ csr = inb(host->base + WBSD_CSR);
+ csr |= WBSD_MSLED;
+ outb(csr, host->base + WBSD_CSR);
+
+ mdelay(1);
+
+ csr = inb(host->base + WBSD_CSR);
+ csr &= ~WBSD_MSLED;
+ outb(csr, host->base + WBSD_CSR);
+
+ spin_unlock_bh(&host->lock);
+
+ return csr & WBSD_WRPT;
+}
+
static struct mmc_host_ops wbsd_ops = {
.request = wbsd_request,
.set_ios = wbsd_set_ios,
+ .get_ro = wbsd_get_ro,
};
/*****************************************************************************\
@@ -1036,6 +1087,31 @@
\*****************************************************************************/
/*
+ * Helper function to reset detection ignore
+ */
+
+static void wbsd_reset_ignore(unsigned long data)
+{
+ struct wbsd_host *host = (struct wbsd_host*)data;
+
+ BUG_ON(host == NULL);
+
+ DBG("Resetting card detection ignore\n");
+
+ spin_lock_bh(&host->lock);
+
+ host->flags &= ~WBSD_FIGNORE_DETECT;
+
+ /*
+ * Card status might have changed during the
+ * blackout.
+ */
+ tasklet_schedule(&host->card_tasklet);
+
+ spin_unlock_bh(&host->lock);
+}
+
+/*
* Helper function for card detection
*/
static void wbsd_detect_card(unsigned long data)
@@ -1097,7 +1173,7 @@
* Delay card detection to allow electrical connections
* to stabilise.
*/
- mod_timer(&host->timer, jiffies + HZ/2);
+ mod_timer(&host->detect_timer, jiffies + HZ/2);
}
spin_unlock(&host->lock);
@@ -1124,6 +1200,8 @@
mmc_detect_change(host->mmc);
}
+ else
+ spin_unlock(&host->lock);
}
static void wbsd_tasklet_fifo(unsigned long param)
@@ -1324,15 +1402,20 @@
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
spin_lock_init(&host->lock);
/*
- * Set up detection timer
+ * Set up timers
*/
- init_timer(&host->timer);
- host->timer.data = (unsigned long)host;
- host->timer.function = wbsd_detect_card;
+ init_timer(&host->detect_timer);
+ host->detect_timer.data = (unsigned long)host;
+ host->detect_timer.function = wbsd_detect_card;
+
+ init_timer(&host->ignore_timer);
+ host->ignore_timer.data = (unsigned long)host;
+ host->ignore_timer.function = wbsd_reset_ignore;
/*
* Maximum number of segments. Worst case is one sector per segment
@@ -1370,7 +1453,8 @@
host = mmc_priv(mmc);
BUG_ON(host == NULL);
- del_timer_sync(&host->timer);
+ del_timer_sync(&host->ignore_timer);
+ del_timer_sync(&host->detect_timer);
mmc_free_host(mmc);
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 661a9f6..9005b52 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -106,6 +106,8 @@
#define WBSD_CLK_16M 0x02
#define WBSD_CLK_24M 0x03
+#define WBSD_DATA_WIDTH 0x01
+
#define WBSD_DAT3_H 0x08
#define WBSD_FIFO_RESET 0x04
#define WBSD_SOFT_RESET 0x02
@@ -164,6 +166,7 @@
int firsterr; /* See fifo functions */
u8 clk; /* Current clock speed */
+ unsigned char bus_width; /* Current bus width */
int config; /* Config port */
u8 unlock_code; /* Code to unlock config */
@@ -181,5 +184,6 @@
struct tasklet_struct finish_tasklet;
struct tasklet_struct block_tasklet;
- struct timer_list timer; /* Card detection timer */
+ struct timer_list detect_timer; /* Card detection timer */
+ struct timer_list ignore_timer; /* Ignore detection timer */
};
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index eee5115..04e5431 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -526,6 +526,7 @@
do {
if (this->dev_ready(mtd))
return;
+ touch_softlockup_watchdog();
} while (time_before(jiffies, timeo));
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 07746b9..455ba91 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -973,6 +973,11 @@
netif_device_detach(dev);
vortex_down(dev, 1);
}
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ free_irq(dev->irq, dev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
return 0;
}
@@ -980,8 +985,19 @@
static int vortex_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct vortex_private *vp = netdev_priv(dev);
- if (dev && dev->priv) {
+ if (dev && vp) {
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
+ if (request_irq(dev->irq, vp->full_bus_master_rx ?
+ &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
+ printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
+ pci_disable_device(pdev);
+ return -EBUSY;
+ }
if (netif_running(dev)) {
vortex_up(dev);
netif_device_attach(dev);
@@ -1873,6 +1889,7 @@
{
spin_lock_bh(&vp->lock);
mii_status = mdio_read(dev, vp->phys[0], 1);
+ mii_status = mdio_read(dev, vp->phys[0], 1);
ok = 1;
if (vortex_debug > 2)
printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e0239a1..6bb9232 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -397,7 +397,7 @@
If you're not building a kernel for a Sun 3, say N.
config SUN3_82586
- tristate "Sun3 on-board Intel 82586 support"
+ bool "Sun3 on-board Intel 82586 support"
depends on NET_ETHERNET && SUN3
help
This driver enables support for the on-board Intel 82586 based
@@ -447,7 +447,7 @@
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
- depends on NET_ETHERNET && PCI && SGI_IP27
+ depends on NET_ETHERNET && PCI && SGI_IP27 && BROKEN
select CRC32
select MII
help
@@ -1924,12 +1924,15 @@
If in doubt, say Y.
config SIS190
- tristate "SiS190 gigabit ethernet support"
+ tristate "SiS190/SiS191 gigabit ethernet support"
depends on PCI
select CRC32
select MII
---help---
- Say Y here if you have a SiS 190 PCI Gigabit Ethernet adapter.
+ Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
+ a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to
+ appear in lan on motherboard designs which are based on SiS 965
+ and SiS 966 south bridge.
To compile this driver as a module, choose M here: the module
will be called sis190. This is recommended.
@@ -2055,6 +2058,13 @@
To compile this driver as a module, choose M here: the module
will be called bnx2. This is recommended.
+config SPIDER_NET
+ tristate "Spider Gigabit Ethernet driver"
+ depends on PCI && PPC_BPA
+ help
+ This driver supports the Gigabit Ethernet chips present on the
+ Cell Processor-Based Blades from IBM.
+
config GIANFAR
tristate "Gianfar Ethernet"
depends on 85xx || 83xx
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5baafcd..8645c84 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -54,6 +54,8 @@
obj-$(CONFIG_FEALNX) += fealnx.o
obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_BNX2) += bnx2.o
+spidernet-y += spider_net.o spider_net_ethtool.o sungem_phy.o
+obj-$(CONFIG_SPIDER_NET) += spidernet.o
obj-$(CONFIG_TC35815) += tc35815.o
obj-$(CONFIG_SKGE) += skge.o
obj-$(CONFIG_SK98LIN) += sk98lin/
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 91791ba..8a0af54 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -275,7 +275,7 @@
return 0;
out2:
if (ei_status.reg0)
- iounmap((void *)dev->mem_start);
+ iounmap(ei_status.mem);
out1:
free_irq(dev->irq, dev);
out:
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 4f9f69e..12ef52c 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -597,7 +597,7 @@
struct ArcProto *proto;
int txbuf;
unsigned long flags;
- int freeskb = 0;
+ int freeskb, retval;
BUGMSG(D_DURING,
"transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n",
@@ -615,7 +615,7 @@
if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) {
BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n");
dev_kfree_skb(skb);
- return 0; /* don't try again */
+ return NETDEV_TX_OK; /* don't try again */
}
/* We're busy transmitting a packet... */
@@ -623,8 +623,11 @@
spin_lock_irqsave(&lp->lock, flags);
AINTMASK(0);
-
- txbuf = get_arcbuf(dev);
+ if(lp->next_tx == -1)
+ txbuf = get_arcbuf(dev);
+ else {
+ txbuf = -1;
+ }
if (txbuf != -1) {
if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
!proto->ack_tx) {
@@ -638,6 +641,8 @@
lp->outgoing.skb = skb;
lp->outgoing.pkt = pkt;
+ freeskb = 0;
+
if (proto->continue_tx &&
proto->continue_tx(dev, txbuf)) {
BUGMSG(D_NORMAL,
@@ -645,10 +650,12 @@
"(proto='%c')\n", proto->suffix);
}
}
-
+ retval = NETDEV_TX_OK;
+ dev->trans_start = jiffies;
lp->next_tx = txbuf;
} else {
- freeskb = 1;
+ retval = NETDEV_TX_BUSY;
+ freeskb = 0;
}
BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS());
@@ -664,7 +671,7 @@
if (freeskb) {
dev_kfree_skb(skb);
}
- return 0; /* no need to try again */
+ return retval; /* no need to try again */
}
@@ -690,7 +697,6 @@
/* start sending */
ACOMMAND(TXcmd | (lp->cur_tx << 3));
- dev->trans_start = jiffies;
lp->stats.tx_packets++;
lp->lasttrans_dest = lp->lastload_dest;
lp->lastload_dest = 0;
@@ -917,6 +923,9 @@
BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n",
status);
+ /* MYRECON bit is at bit 7 of diagstatus */
+ if(diagstatus & 0x80)
+ BUGMSG(D_RECON,"Put out that recon myself\n");
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index ad01121..e01b6a7 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -235,7 +235,7 @@
#define MEM lp->mem
#define DREG IO->data
#define AREG IO->addr
-#define REGA(a) ( AREG = (a), DREG )
+#define REGA(a) (*( AREG = (a), &DREG ))
/* Definitions for packet buffer access: */
#define PKT_BUF_SZ 1544
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 7babf6a..55a72c7 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -2004,14 +2004,14 @@
}
static int
-bnx2_set_power_state(struct bnx2 *bp, int state)
+bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
{
u16 pmcsr;
pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
switch (state) {
- case 0: {
+ case PCI_D0: {
u32 val;
pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
@@ -2032,7 +2032,7 @@
REG_WR(bp, BNX2_RPM_CONFIG, val);
break;
}
- case 3: {
+ case PCI_D3hot: {
int i;
u32 val, wol_msg;
@@ -3886,7 +3886,7 @@
struct bnx2 *bp = dev->priv;
int rc;
- bnx2_set_power_state(bp, 0);
+ bnx2_set_power_state(bp, PCI_D0);
bnx2_disable_int(bp);
rc = bnx2_alloc_mem(bp);
@@ -4197,7 +4197,7 @@
bnx2_free_mem(bp);
bp->link_up = 0;
netif_carrier_off(bp->dev);
- bnx2_set_power_state(bp, 3);
+ bnx2_set_power_state(bp, PCI_D3hot);
return 0;
}
@@ -5203,7 +5203,7 @@
BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
- bnx2_set_power_state(bp, 0);
+ bnx2_set_power_state(bp, PCI_D0);
bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
@@ -5495,7 +5495,7 @@
}
static int
-bnx2_suspend(struct pci_dev *pdev, u32 state)
+bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct bnx2 *bp = dev->priv;
@@ -5513,7 +5513,7 @@
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
bnx2_reset_chip(bp, reset_code);
bnx2_free_skbs(bp);
- bnx2_set_power_state(bp, state);
+ bnx2_set_power_state(bp, pci_choose_state(pdev, state));
return 0;
}
@@ -5526,7 +5526,7 @@
if (!netif_running(dev))
return 0;
- bnx2_set_power_state(bp, 0);
+ bnx2_set_power_state(bp, PCI_D0);
netif_device_attach(dev);
bnx2_init_nic(bp);
bnx2_netif_start(bp);
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index f093488..bf3e7b6 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -88,7 +88,7 @@
static inline u8 *t1_get_next_mcaddr(struct t1_rx_mode *rm)
{
- u8 *addr = 0;
+ u8 *addr = NULL;
if (rm->idx++ < rm->dev->mc_count) {
addr = rm->list->dmi_addr;
@@ -190,7 +190,7 @@
struct peespi;
struct adapter {
- u8 *regs;
+ u8 __iomem *regs;
struct pci_dev *pdev;
unsigned long registered_device_map;
unsigned long open_device_map;
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 28ae478..349ebe7 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -824,7 +824,7 @@
static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
struct adapter *adapter = dev->priv;
- struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data;
+ struct mii_ioctl_data *data = if_mii(req);
switch (cmd) {
case SIOCGMIIPHY:
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 6440a89..e54fc10 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -1140,7 +1140,7 @@
}
static int
-dm9000_drv_suspend(struct device *dev, u32 state, u32 level)
+dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level)
{
struct net_device *ndev = dev_get_drvdata(dev);
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 93e9f87..51c2b3a 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -1270,7 +1270,7 @@
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
- uint8_t *hw_addr;
+ uint8_t __iomem *hw_addr;
uint8_t *flash_address;
e1000_mac_type mac_type;
e1000_phy_type phy_type;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 9b596e0..7c8a0a2 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -162,7 +162,7 @@
static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
static void e1000_restore_vlan(struct e1000_adapter *adapter);
-static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
+static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
#ifdef CONFIG_PM
static int e1000_resume(struct pci_dev *pdev);
#endif
@@ -3642,7 +3642,7 @@
}
static int
-e1000_suspend(struct pci_dev *pdev, uint32_t state)
+e1000_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3726,9 +3726,7 @@
}
pci_disable_device(pdev);
-
- state = (state > 0) ? 3 : 0;
- pci_set_power_state(pdev, state);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
@@ -3741,13 +3739,13 @@
struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t manc, ret_val, swsm;
- pci_set_power_state(pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
ret_val = pci_enable_device(pdev);
pci_set_master(pdev);
- pci_enable_wake(pdev, 3, 0);
- pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
e1000_reset(adapter);
E1000_WRITE_REG(&adapter->hw, WUS, ~0);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 7d93948..d6eefdb 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -1372,7 +1372,7 @@
/* synchronized against open : rtnl_lock() held by caller */
if (netif_running(dev)) {
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
/*
* It seems that the nic preloads valid ring entries into an
* internal buffer. The procedure for flushing everything is
@@ -1423,7 +1423,7 @@
static void nv_copy_mac_to_hw(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 mac[2];
mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index d9df1d9..bc9a3bf 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -204,6 +204,10 @@
#define RUN_AT(x) (jiffies + (x))
+#ifndef ADDRLEN
+#define ADDRLEN 32
+#endif
+
/* Condensed bus+endian portability operations. */
#if ADDRLEN == 64
#define cpu_to_leXX(addr) cpu_to_le64(addr)
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 10125a1..dd89bda 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -4,10 +4,10 @@
* Description: Driver for the SMC Infrared Communications Controller
* Status: Experimental.
* Author: Daniele Peri (peri@csai.unipa.it)
- * Created at:
- * Modified at:
- * Modified by:
- *
+ * Created at:
+ * Modified at:
+ * Modified by:
+ *
* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
* Copyright (c) 2002 Jean Tourrilhes
@@ -17,26 +17,26 @@
*
* Copyright (c) 2001 Stefani Seibold
* Copyright (c) 1999-2001 Dag Brattli
- * Copyright (c) 1998-1999 Thomas Davis,
+ * Copyright (c) 1998-1999 Thomas Davis,
*
* and irport.c:
*
* Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, 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
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
+ *
+ * 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
*
********************************************************************/
@@ -68,24 +68,42 @@
#include "smsc-ircc2.h"
#include "smsc-sio.h"
+
+MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
+MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
+MODULE_LICENSE("GPL");
+
+static int ircc_dma = 255;
+module_param(ircc_dma, int, 0);
+MODULE_PARM_DESC(ircc_dma, "DMA channel");
+
+static int ircc_irq = 255;
+module_param(ircc_irq, int, 0);
+MODULE_PARM_DESC(ircc_irq, "IRQ line");
+
+static int ircc_fir;
+module_param(ircc_fir, int, 0);
+MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
+
+static int ircc_sir;
+module_param(ircc_sir, int, 0);
+MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
+
+static int ircc_cfg;
+module_param(ircc_cfg, int, 0);
+MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
+
+static int ircc_transceiver;
+module_param(ircc_transceiver, int, 0);
+MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
+
/* Types */
struct smsc_transceiver {
char *name;
- void (*set_for_speed)(int fir_base, u32 speed);
+ void (*set_for_speed)(int fir_base, u32 speed);
int (*probe)(int fir_base);
};
-typedef struct smsc_transceiver smsc_transceiver_t;
-
-#if 0
-struct smc_chip {
- char *name;
- u16 flags;
- u8 devid;
- u8 rev;
-};
-typedef struct smc_chip smc_chip_t;
-#endif
struct smsc_chip {
char *name;
@@ -96,20 +114,18 @@
u8 devid;
u8 rev;
};
-typedef struct smsc_chip smsc_chip_t;
struct smsc_chip_address {
unsigned int cfg_base;
unsigned int type;
};
-typedef struct smsc_chip_address smsc_chip_address_t;
/* Private data for each instance */
struct smsc_ircc_cb {
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct net_device_stats stats;
struct irlap_cb *irlap; /* The link layer we are binded to */
-
+
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
@@ -119,7 +135,7 @@
struct qos_info qos; /* QoS capabilities for this device */
spinlock_t lock; /* For serializing operations */
-
+
__u32 new_speed;
__u32 flags; /* Interface flags */
@@ -127,18 +143,20 @@
int tx_len; /* Number of frames in tx_buff */
int transceiver;
- struct pm_dev *pmdev;
+ struct platform_device *pldev;
};
/* Constants */
-static const char *driver_name = "smsc-ircc2";
-#define DIM(x) (sizeof(x)/(sizeof(*(x))))
+#define SMSC_IRCC2_DRIVER_NAME "smsc-ircc2"
+
#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600
#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1
-#define SMSC_IRCC2_C_NET_TIMEOUT 0
+#define SMSC_IRCC2_C_NET_TIMEOUT 0
#define SMSC_IRCC2_C_SIR_STOP 0
+static const char *driver_name = SMSC_IRCC2_DRIVER_NAME;
+
/* Prototypes */
static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
@@ -147,15 +165,15 @@
static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase);
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase);
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self);
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self);
static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self);
static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs);
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase);
-static void smsc_ircc_change_speed(void *priv, u32 speed);
-static void smsc_ircc_set_sir_speed(void *priv, u32 speed);
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs);
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self);
+static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed);
+static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed);
static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev);
static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
@@ -171,7 +189,6 @@
static void smsc_ircc_timeout(struct net_device *dev);
#endif
static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev);
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
@@ -179,9 +196,9 @@
/* Probing */
static int __init smsc_ircc_look_for_chips(void);
-static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type);
-static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
static int __init smsc_superio_fdc(unsigned short cfg_base);
static int __init smsc_superio_lpc(unsigned short cfg_base);
@@ -196,21 +213,26 @@
/* Power Management */
-static void smsc_ircc_suspend(struct smsc_ircc_cb *self);
-static void smsc_ircc_wakeup(struct smsc_ircc_cb *self);
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level);
+static int smsc_ircc_resume(struct device *dev, u32 level);
+static struct device_driver smsc_ircc_driver = {
+ .name = SMSC_IRCC2_DRIVER_NAME,
+ .bus = &platform_bus_type,
+ .suspend = smsc_ircc_suspend,
+ .resume = smsc_ircc_resume,
+};
/* Transceivers for SMSC-ircc */
-static smsc_transceiver_t smsc_transceivers[]=
+static struct smsc_transceiver smsc_transceivers[] =
{
- { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800},
- { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select},
- { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc},
- { NULL, NULL}
+ { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800 },
+ { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select },
+ { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc },
+ { NULL, NULL }
};
-#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (DIM(smsc_transceivers)-1)
+#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (ARRAY_SIZE(smsc_transceivers) - 1)
/* SMC SuperIO chipsets definitions */
@@ -221,7 +243,7 @@
#define FIR 4 /* SuperIO Chip has fast IRDA */
#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
-static smsc_chip_t __initdata fdc_chips_flat[]=
+static struct smsc_chip __initdata fdc_chips_flat[] =
{
/* Base address 0x3f0 or 0x370 */
{ "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */
@@ -235,7 +257,7 @@
{ NULL }
};
-static smsc_chip_t __initdata fdc_chips_paged[]=
+static struct smsc_chip __initdata fdc_chips_paged[] =
{
/* Base address 0x3f0 or 0x370 */
{ "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 },
@@ -254,7 +276,7 @@
{ NULL }
};
-static smsc_chip_t __initdata lpc_chips_flat[]=
+static struct smsc_chip __initdata lpc_chips_flat[] =
{
/* Base address 0x2E or 0x4E */
{ "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 },
@@ -262,7 +284,7 @@
{ NULL }
};
-static smsc_chip_t __initdata lpc_chips_paged[]=
+static struct smsc_chip __initdata lpc_chips_paged[] =
{
/* Base address 0x2E or 0x4E */
{ "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 },
@@ -281,33 +303,25 @@
#define SMSCSIO_TYPE_FLAT 4
#define SMSCSIO_TYPE_PAGED 8
-static smsc_chip_address_t __initdata possible_addresses[]=
+static struct smsc_chip_address __initdata possible_addresses[] =
{
- {0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
- {0,0}
+ { 0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
+ { 0, 0 }
};
/* Globals */
-static struct smsc_ircc_cb *dev_self[] = { NULL, NULL};
-
-static int ircc_irq=255;
-static int ircc_dma=255;
-static int ircc_fir=0;
-static int ircc_sir=0;
-static int ircc_cfg=0;
-static int ircc_transceiver=0;
-
-static unsigned short dev_count=0;
+static struct smsc_ircc_cb *dev_self[] = { NULL, NULL };
+static unsigned short dev_count;
static inline void register_bank(int iobase, int bank)
{
- outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),
- iobase+IRCC_MASTER);
+ outb(((inb(iobase + IRCC_MASTER) & 0xf0) | (bank & 0x07)),
+ iobase + IRCC_MASTER);
}
@@ -327,34 +341,44 @@
*/
static int __init smsc_ircc_init(void)
{
- int ret=-ENODEV;
+ int ret;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- dev_count=0;
-
- if ((ircc_fir>0)&&(ircc_sir>0)) {
+ ret = driver_register(&smsc_ircc_driver);
+ if (ret) {
+ IRDA_ERROR("%s, Can't register driver!\n", driver_name);
+ return ret;
+ }
+
+ dev_count = 0;
+
+ if (ircc_fir > 0 && ircc_sir > 0) {
IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
- if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0)
- return 0;
+ if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
+ ret = -ENODEV;
+ } else {
+ ret = -ENODEV;
- return -ENODEV;
- }
+ /* try user provided configuration register base address */
+ if (ircc_cfg > 0) {
+ IRDA_MESSAGE(" Overriding configuration address "
+ "0x%04x\n", ircc_cfg);
+ if (!smsc_superio_fdc(ircc_cfg))
+ ret = 0;
+ if (!smsc_superio_lpc(ircc_cfg))
+ ret = 0;
+ }
- /* try user provided configuration register base address */
- if (ircc_cfg>0) {
- IRDA_MESSAGE(" Overriding configuration address 0x%04x\n",
- ircc_cfg);
- if (!smsc_superio_fdc(ircc_cfg))
- ret = 0;
- if (!smsc_superio_lpc(ircc_cfg))
+ if (smsc_ircc_look_for_chips() > 0)
ret = 0;
}
-
- if(smsc_ircc_look_for_chips()>0) ret = 0;
-
+
+ if (ret)
+ driver_unregister(&smsc_ircc_driver);
+
return ret;
}
@@ -369,15 +393,15 @@
struct smsc_ircc_cb *self;
struct net_device *dev;
int err;
-
+
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
err = smsc_ircc_present(fir_base, sir_base);
- if(err)
+ if (err)
goto err_out;
-
+
err = -ENOMEM;
- if (dev_count > DIM(dev_self)) {
+ if (dev_count >= ARRAY_SIZE(dev_self)) {
IRDA_WARNING("%s(), too many devices!\n", __FUNCTION__);
goto err_out1;
}
@@ -396,14 +420,14 @@
dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
#if SMSC_IRCC2_C_NET_TIMEOUT
dev->tx_timeout = smsc_ircc_timeout;
- dev->watchdog_timeo = HZ*2; /* Allow enough time for speed change */
+ dev->watchdog_timeo = HZ * 2; /* Allow enough time for speed change */
#endif
dev->open = smsc_ircc_net_open;
dev->stop = smsc_ircc_net_close;
dev->do_ioctl = smsc_ircc_net_ioctl;
dev->get_stats = smsc_ircc_net_get_stats;
-
- self = dev->priv;
+
+ self = netdev_priv(dev);
self->netdev = dev;
/* Make ifconfig display some details */
@@ -411,10 +435,10 @@
dev->irq = self->io.irq = irq;
/* Need to store self somewhere */
- dev_self[dev_count++] = self;
+ dev_self[dev_count] = self;
spin_lock_init(&self->lock);
- self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
+ self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
self->rx_buff.head =
@@ -442,33 +466,40 @@
self->rx_buff.state = OUTSIDE_FRAME;
self->tx_buff.data = self->tx_buff.head;
self->rx_buff.data = self->rx_buff.head;
-
+
smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
-
smsc_ircc_setup_qos(self);
-
smsc_ircc_init_chip(self);
-
- if(ircc_transceiver > 0 &&
- ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
+
+ if (ircc_transceiver > 0 &&
+ ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
self->transceiver = ircc_transceiver;
else
smsc_ircc_probe_transceiver(self);
err = register_netdev(self->netdev);
- if(err) {
+ if (err) {
IRDA_ERROR("%s, Network device registration failed!\n",
driver_name);
goto err_out4;
}
- self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc);
- if (self->pmdev)
- self->pmdev->data = self;
+ self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME,
+ dev_count, NULL, 0);
+ if (IS_ERR(self->pldev)) {
+ err = PTR_ERR(self->pldev);
+ goto err_out5;
+ }
+ dev_set_drvdata(&self->pldev->dev, self);
IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+ dev_count++;
return 0;
+
+ err_out5:
+ unregister_netdev(self->netdev);
+
err_out4:
dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
@@ -477,7 +508,7 @@
self->rx_buff.head, self->rx_buff_dma);
err_out2:
free_netdev(self->netdev);
- dev_self[--dev_count] = NULL;
+ dev_self[dev_count] = NULL;
err_out1:
release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
@@ -511,16 +542,16 @@
register_bank(fir_base, 3);
- high = inb(fir_base+IRCC_ID_HIGH);
- low = inb(fir_base+IRCC_ID_LOW);
- chip = inb(fir_base+IRCC_CHIP_ID);
- version = inb(fir_base+IRCC_VERSION);
- config = inb(fir_base+IRCC_INTERFACE);
+ high = inb(fir_base + IRCC_ID_HIGH);
+ low = inb(fir_base + IRCC_ID_LOW);
+ chip = inb(fir_base + IRCC_CHIP_ID);
+ version = inb(fir_base + IRCC_VERSION);
+ config = inb(fir_base + IRCC_INTERFACE);
dma = config & IRCC_INTERFACE_DMA_MASK;
irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
- if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
- IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
+ if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
+ IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
__FUNCTION__, fir_base);
goto out3;
}
@@ -529,6 +560,7 @@
chip & 0x0f, version, fir_base, sir_base, dma, irq);
return 0;
+
out3:
release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
out2:
@@ -543,16 +575,16 @@
* Setup I/O
*
*/
-static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
- unsigned int fir_base, unsigned int sir_base,
+static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
+ unsigned int fir_base, unsigned int sir_base,
u8 dma, u8 irq)
{
unsigned char config, chip_dma, chip_irq;
register_bank(fir_base, 3);
- config = inb(fir_base+IRCC_INTERFACE);
- chip_dma = config & IRCC_INTERFACE_DMA_MASK;
- chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
+ config = inb(fir_base + IRCC_INTERFACE);
+ chip_dma = config & IRCC_INTERFACE_DMA_MASK;
+ chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
self->io.fir_base = fir_base;
self->io.sir_base = sir_base;
@@ -566,17 +598,15 @@
IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
driver_name, chip_irq, irq);
self->io.irq = irq;
- }
- else
+ } else
self->io.irq = chip_irq;
-
+
if (dma < 255) {
if (dma != chip_dma)
IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
driver_name, chip_dma, dma);
self->io.dma = dma;
- }
- else
+ } else
self->io.dma = chip_dma;
}
@@ -591,7 +621,7 @@
{
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
-
+
self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
@@ -608,43 +638,43 @@
*/
static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
{
- int iobase, ir_mode, ctrl, fast;
-
- IRDA_ASSERT( self != NULL, return; );
- iobase = self->io.fir_base;
+ int iobase, ir_mode, ctrl, fast;
+ IRDA_ASSERT(self != NULL, return;);
+
+ iobase = self->io.fir_base;
ir_mode = IRCC_CFGA_IRDA_SIR_A;
ctrl = 0;
fast = 0;
register_bank(iobase, 0);
- outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
- outb(0x00, iobase+IRCC_MASTER);
+ outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
register_bank(iobase, 1);
- outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode),
- iobase+IRCC_SCE_CFGA);
+ outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode),
+ iobase + IRCC_SCE_CFGA);
#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
- outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
- iobase+IRCC_SCE_CFGB);
-#else
- outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
- iobase+IRCC_SCE_CFGB);
-#endif
- (void) inb(iobase+IRCC_FIFO_THRESHOLD);
- outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase+IRCC_FIFO_THRESHOLD);
-
+ outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ iobase + IRCC_SCE_CFGB);
+#else
+ outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ iobase + IRCC_SCE_CFGB);
+#endif
+ (void) inb(iobase + IRCC_FIFO_THRESHOLD);
+ outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD);
+
register_bank(iobase, 4);
- outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
-
+ outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL);
+
register_bank(iobase, 0);
- outb(fast, iobase+IRCC_LCR_A);
+ outb(fast, iobase + IRCC_LCR_A);
smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
-
+
/* Power on device */
- outb(0x00, iobase+IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
}
/*
@@ -662,12 +692,12 @@
IRDA_ASSERT(dev != NULL, return -1;);
- self = dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
-
+
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
@@ -703,14 +733,14 @@
default:
ret = -EOPNOTSUPP;
}
-
+
return ret;
}
static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) dev->priv;
-
+ struct smsc_ircc_cb *self = netdev_priv(dev);
+
return &self->stats;
}
@@ -724,11 +754,9 @@
static void smsc_ircc_timeout(struct net_device *dev)
{
- struct smsc_ircc_cb *self;
+ struct smsc_ircc_cb *self = netdev_priv(dev);
unsigned long flags;
- self = (struct smsc_ircc_cb *) dev->priv;
-
IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n",
dev->name, self->io.speed);
spin_lock_irqsave(&self->lock, flags);
@@ -751,26 +779,23 @@
{
struct smsc_ircc_cb *self;
unsigned long flags;
- int iobase;
s32 speed;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
IRDA_ASSERT(dev != NULL, return 0;);
-
- self = (struct smsc_ircc_cb *) dev->priv;
+
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
- iobase = self->io.sir_base;
-
netif_stop_queue(dev);
-
+
/* Make sure test of self->io.speed & speed change are atomic */
spin_lock_irqsave(&self->lock, flags);
/* Check if we need to change the speed */
speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
+ if (speed != self->io.speed && speed != -1) {
/* Check for empty frame */
if (!skb->len) {
/*
@@ -787,27 +812,26 @@
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
- } else {
- self->new_speed = speed;
}
+ self->new_speed = speed;
}
/* Init tx buffer */
self->tx_buff.data = self->tx_buff.head;
/* Copy skb to tx_buff while wrapping, stuffing and making CRC */
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
+ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
-
+
self->stats.tx_bytes += self->tx_buff.len;
/* Turn on transmit finished interrupt. Will fire immediately! */
- outb(UART_IER_THRI, iobase+UART_IER);
+ outb(UART_IER_THRI, self->io.sir_base + UART_IER);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
-
+
return 0;
}
@@ -826,9 +850,9 @@
self->io.speed = speed;
- switch(speed) {
+ switch (speed) {
default:
- case 576000:
+ case 576000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
ctrl = IRCC_CRC;
fast = 0;
@@ -853,14 +877,14 @@
Now in tranceiver!
/* This causes an interrupt */
register_bank(fir_base, 0);
- outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast, fir_base+IRCC_LCR_A);
+ outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast, fir_base + IRCC_LCR_A);
#endif
-
+
register_bank(fir_base, 1);
- outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base+IRCC_SCE_CFGA);
-
+ outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA);
+
register_bank(fir_base, 4);
- outb((inb(fir_base+IRCC_CONTROL) & 0x30) | ctrl, fir_base+IRCC_CONTROL);
+ outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL);
}
/*
@@ -885,31 +909,31 @@
/* Reset everything */
/* Install FIR transmit handler */
- dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
+ dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
/* Clear FIFO */
- outb(inb(fir_base+IRCC_LCR_A)|IRCC_LCR_A_FIFO_RESET, fir_base+IRCC_LCR_A);
+ outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A);
/* Enable interrupt */
- /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);*/
+ /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/
register_bank(fir_base, 1);
- /* Select the TX/RX interface */
+ /* Select the TX/RX interface */
#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */
- outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
- fir_base+IRCC_SCE_CFGB);
-#else
- outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
- fir_base+IRCC_SCE_CFGB);
-#endif
- (void) inb(fir_base+IRCC_FIFO_THRESHOLD);
+ outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ fir_base + IRCC_SCE_CFGB);
+#else
+ outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ fir_base + IRCC_SCE_CFGB);
+#endif
+ (void) inb(fir_base + IRCC_FIFO_THRESHOLD);
/* Enable SCE interrupts */
- outb(0, fir_base+IRCC_MASTER);
+ outb(0, fir_base + IRCC_MASTER);
register_bank(fir_base, 0);
- outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, fir_base+IRCC_MASTER);
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER);
}
/*
@@ -923,13 +947,13 @@
int fir_base;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-
+
IRDA_ASSERT(self != NULL, return;);
fir_base = self->io.fir_base;
register_bank(fir_base, 0);
- /*outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);*/
- outb(inb(fir_base+IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base+IRCC_LCR_B);
+ /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/
+ outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B);
}
@@ -941,18 +965,15 @@
* This function *must* be called with spinlock held, because it may
* be called from the irq handler. - Jean II
*/
-static void smsc_ircc_change_speed(void *priv, u32 speed)
+static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed)
{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
struct net_device *dev;
- int iobase;
int last_speed_was_sir;
-
+
IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed);
IRDA_ASSERT(self != NULL, return;);
dev = self->netdev;
- iobase = self->io.fir_base;
last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED;
@@ -961,30 +982,30 @@
speed= 1152000;
self->io.speed = speed;
last_speed_was_sir = 0;
- smsc_ircc_fir_start(self);
+ smsc_ircc_fir_start(self);
#endif
-
- if(self->io.speed == 0)
+
+ if (self->io.speed == 0)
smsc_ircc_sir_start(self);
#if 0
- if(!last_speed_was_sir) speed = self->io.speed;
+ if (!last_speed_was_sir) speed = self->io.speed;
#endif
- if(self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed);
+ if (self->io.speed != speed)
+ smsc_ircc_set_transceiver_for_speed(self, speed);
self->io.speed = speed;
-
- if(speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
- if(!last_speed_was_sir) {
+
+ if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+ if (!last_speed_was_sir) {
smsc_ircc_fir_stop(self);
smsc_ircc_sir_start(self);
}
- smsc_ircc_set_sir_speed(self, speed);
- }
- else {
- if(last_speed_was_sir) {
- #if SMSC_IRCC2_C_SIR_STOP
+ smsc_ircc_set_sir_speed(self, speed);
+ } else {
+ if (last_speed_was_sir) {
+ #if SMSC_IRCC2_C_SIR_STOP
smsc_ircc_sir_stop(self);
#endif
smsc_ircc_fir_start(self);
@@ -994,13 +1015,13 @@
#if 0
self->tx_buff.len = 10;
self->tx_buff.data = self->tx_buff.head;
-
- smsc_ircc_dma_xmit(self, iobase, 4000);
+
+ smsc_ircc_dma_xmit(self, 4000);
#endif
/* Be ready for incoming frames */
- smsc_ircc_dma_receive(self, iobase);
+ smsc_ircc_dma_receive(self);
}
-
+
netif_wake_queue(dev);
}
@@ -1010,10 +1031,9 @@
* Set speed of IrDA port to specified baudrate
*
*/
-void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
+void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed)
{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
- int iobase;
+ int iobase;
int fcr; /* FIFO control reg */
int lcr; /* Line control reg */
int divisor;
@@ -1022,38 +1042,36 @@
IRDA_ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
-
+
/* Update accounting for new speed */
self->io.speed = speed;
/* Turn off interrupts */
- outb(0, iobase+UART_IER);
+ outb(0, iobase + UART_IER);
- divisor = SMSC_IRCC2_MAX_SIR_SPEED/speed;
-
+ divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed;
+
fcr = UART_FCR_ENABLE_FIFO;
- /*
+ /*
* Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
* almost 1,7 ms at 19200 bps. At speeds above that we can just forget
- * about this timeout since it will always be fast enough.
+ * about this timeout since it will always be fast enough.
*/
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
-
+ fcr |= self->io.speed < 38400 ?
+ UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
+
/* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8;
-
- outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
- outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */
- outb(divisor >> 8, iobase+UART_DLM);
- outb(lcr, iobase+UART_LCR); /* Set 8N1 */
- outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
+
+ outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
+ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
+ outb(divisor >> 8, iobase + UART_DLM);
+ outb(lcr, iobase + UART_LCR); /* Set 8N1 */
+ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
/* Turn on interrups */
- outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed);
}
@@ -1070,15 +1088,12 @@
struct smsc_ircc_cb *self;
unsigned long flags;
s32 speed;
- int iobase;
int mtt;
IRDA_ASSERT(dev != NULL, return 0;);
- self = (struct smsc_ircc_cb *) dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
- iobase = self->io.fir_base;
-
netif_stop_queue(dev);
/* Make sure test of self->io.speed & speed change are atomic */
@@ -1086,30 +1101,31 @@
/* Check if we need to change the speed after this frame */
speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
+ if (speed != self->io.speed && speed != -1) {
/* Check for empty frame */
if (!skb->len) {
/* Note : you should make sure that speed changes
* are not going to corrupt any outgoing frame.
* Look at nsc-ircc for the gory details - Jean II */
- smsc_ircc_change_speed(self, speed);
+ smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
- } else
- self->new_speed = speed;
+ }
+
+ self->new_speed = speed;
}
-
+
memcpy(self->tx_buff.head, skb->data, skb->len);
self->tx_buff.len = skb->len;
self->tx_buff.data = self->tx_buff.head;
-
- mtt = irda_get_mtt(skb);
+
+ mtt = irda_get_mtt(skb);
if (mtt) {
int bofs;
- /*
+ /*
* Compute how many BOFs (STA or PA's) we need to waste the
* min turn time given the speed of the link.
*/
@@ -1117,11 +1133,12 @@
if (bofs > 4095)
bofs = 4095;
- smsc_ircc_dma_xmit(self, iobase, bofs);
+ smsc_ircc_dma_xmit(self, bofs);
} else {
/* Transmit frame */
- smsc_ircc_dma_xmit(self, iobase, 0);
+ smsc_ircc_dma_xmit(self, 0);
}
+
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -1129,43 +1146,44 @@
}
/*
- * Function smsc_ircc_dma_xmit (self, iobase)
+ * Function smsc_ircc_dma_xmit (self, bofs)
*
* Transmit data using DMA
*
*/
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs)
{
+ int iobase = self->io.fir_base;
u8 ctrl;
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 1
/* Disable Rx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
#endif
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
self->io.direction = IO_XMIT;
/* Set BOF additional count for generating the min turn time */
register_bank(iobase, 4);
- outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
- ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
- outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
+ outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO);
+ ctrl = inb(iobase + IRCC_CONTROL) & 0xf0;
+ outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI);
/* Set max Tx frame size */
- outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
- outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
+ outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI);
+ outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO);
/*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/
-
+
/* Enable burst mode chip Tx DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
- IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
/* Setup DMA controller (must be done after enabling chip DMA) */
irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len,
@@ -1174,50 +1192,52 @@
/* Enable interrupt */
register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
+
/* Enable transmit */
- outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
+ outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase + IRCC_LCR_B);
}
/*
* Function smsc_ircc_dma_xmit_complete (self)
*
- * The transfer of a frame in finished. This function will only be called
+ * The transfer of a frame in finished. This function will only be called
* by the interrupt handler
*
*/
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self)
{
+ int iobase = self->io.fir_base;
+
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 0
/* Disable Tx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
#endif
- register_bank(self->io.fir_base, 1);
- outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- self->io.fir_base+IRCC_SCE_CFGB);
+ register_bank(iobase, 1);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
/* Check for underrun! */
register_bank(iobase, 0);
- if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
+ if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) {
self->stats.tx_errors++;
self->stats.tx_fifo_errors++;
/* Reset error condition */
register_bank(iobase, 0);
- outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
- outb(0x00, iobase+IRCC_MASTER);
+ outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
} else {
self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.len;
+ self->stats.tx_bytes += self->tx_buff.len;
}
/* Check if it's time to change the speed */
if (self->new_speed) {
- smsc_ircc_change_speed(self, self->new_speed);
+ smsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
}
@@ -1231,31 +1251,32 @@
* if it starts to receive a frame.
*
*/
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase)
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self)
{
+ int iobase = self->io.fir_base;
#if 0
/* Turn off chip DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
#endif
-
+
/* Disable Tx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
/* Turn off chip DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase + IRCC_SCE_CFGB);
self->io.direction = IO_RECV;
self->rx_buff.data = self->rx_buff.head;
/* Set max Rx frame size */
register_bank(iobase, 4);
- outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
- outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
+ outb((2050 >> 8) & 0x0f, iobase + IRCC_RX_SIZE_HI);
+ outb(2050 & 0xff, iobase + IRCC_RX_SIZE_LO);
/* Setup DMA controller */
irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
@@ -1263,83 +1284,83 @@
/* Enable burst mode chip Rx DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
- IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
/* Enable interrupt */
register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
/* Enable receiver */
register_bank(iobase, 0);
- outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
- iobase+IRCC_LCR_B);
-
+ outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
+ iobase + IRCC_LCR_B);
+
return 0;
}
/*
- * Function smsc_ircc_dma_receive_complete(self, iobase)
+ * Function smsc_ircc_dma_receive_complete(self)
*
* Finished with receiving frames
*
*/
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase)
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self)
{
struct sk_buff *skb;
int len, msgcnt, lsr;
-
+ int iobase = self->io.fir_base;
+
register_bank(iobase, 0);
-
+
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
#if 0
/* Disable Rx */
register_bank(iobase, 0);
- outb(0x00, iobase+IRCC_LCR_B);
+ outb(0x00, iobase + IRCC_LCR_B);
#endif
register_bank(iobase, 0);
- outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR);
- lsr= inb(iobase+IRCC_LSR);
- msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
+ outb(inb(iobase + IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase + IRCC_LSAR);
+ lsr= inb(iobase + IRCC_LSR);
+ msgcnt = inb(iobase + IRCC_LCR_B) & 0x08;
IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__,
get_dma_residue(self->io.dma));
len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
- /* Look for errors
- */
-
- if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
+ /* Look for errors */
+ if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
self->stats.rx_errors++;
- if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++;
- if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++;
- if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++;
- if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++;
+ if (lsr & IRCC_LSR_FRAME_ERROR)
+ self->stats.rx_frame_errors++;
+ if (lsr & IRCC_LSR_CRC_ERROR)
+ self->stats.rx_crc_errors++;
+ if (lsr & IRCC_LSR_SIZE_ERROR)
+ self->stats.rx_length_errors++;
+ if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN))
+ self->stats.rx_length_errors++;
return;
}
- /* Remove CRC */
- if (self->io.speed < 4000000)
- len -= 2;
- else
- len -= 4;
- if ((len < 2) || (len > 2050)) {
+ /* Remove CRC */
+ len -= self->io.speed < 4000000 ? 2 : 4;
+
+ if (len < 2 || len > 2050) {
IRDA_WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
return;
}
IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
- skb = dev_alloc_skb(len+1);
- if (!skb) {
+ skb = dev_alloc_skb(len + 1);
+ if (!skb) {
IRDA_WARNING("%s(), memory squeeze, dropping frame.\n",
__FUNCTION__);
return;
- }
+ }
/* Make sure IP header gets aligned */
- skb_reserve(skb, 1);
+ skb_reserve(skb, 1);
memcpy(skb_put(skb, len), self->rx_buff.data, len);
self->stats.rx_packets++;
@@ -1357,7 +1378,7 @@
* Receive one frame from the infrared port
*
*/
-static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
+static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
{
int boguscount = 0;
int iobase;
@@ -1366,20 +1387,20 @@
iobase = self->io.sir_base;
- /*
- * Receive all characters in Rx FIFO, unwrap and unstuff them.
- * async_unwrap_char will deliver all found frames
+ /*
+ * Receive all characters in Rx FIFO, unwrap and unstuff them.
+ * async_unwrap_char will deliver all found frames
*/
do {
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
- inb(iobase+UART_RX));
+ async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+ inb(iobase + UART_RX));
/* Make sure we don't stay here to long */
if (boguscount++ > 32) {
IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__);
break;
}
- } while (inb(iobase+UART_LSR) & UART_LSR_DR);
+ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
}
@@ -1397,18 +1418,19 @@
irqreturn_t ret = IRQ_NONE;
if (dev == NULL) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n",
driver_name, irq);
goto irq_ret;
}
- self = (struct smsc_ircc_cb *) dev->priv;
+
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return IRQ_NONE;);
/* Serialise the interrupt handler in various CPUs, stop Tx path */
- spin_lock(&self->lock);
+ spin_lock(&self->lock);
/* Check if we should use the SIR interrupt handler */
- if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+ if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
ret = smsc_ircc_interrupt_sir(dev);
goto irq_ret_unlock;
}
@@ -1416,25 +1438,25 @@
iobase = self->io.fir_base;
register_bank(iobase, 0);
- iir = inb(iobase+IRCC_IIR);
- if (iir == 0)
+ iir = inb(iobase + IRCC_IIR);
+ if (iir == 0)
goto irq_ret_unlock;
ret = IRQ_HANDLED;
/* Disable interrupts */
- outb(0, iobase+IRCC_IER);
- lcra = inb(iobase+IRCC_LCR_A);
- lsr = inb(iobase+IRCC_LSR);
-
+ outb(0, iobase + IRCC_IER);
+ lcra = inb(iobase + IRCC_LCR_A);
+ lsr = inb(iobase + IRCC_LSR);
+
IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);
if (iir & IRCC_IIR_EOM) {
if (self->io.direction == IO_RECV)
- smsc_ircc_dma_receive_complete(self, iobase);
+ smsc_ircc_dma_receive_complete(self);
else
- smsc_ircc_dma_xmit_complete(self, iobase);
-
- smsc_ircc_dma_receive(self, iobase);
+ smsc_ircc_dma_xmit_complete(self);
+
+ smsc_ircc_dma_receive(self);
}
if (iir & IRCC_IIR_ACTIVE_FRAME) {
@@ -1444,7 +1466,7 @@
/* Enable interrupts again */
register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
irq_ret_unlock:
spin_unlock(&self->lock);
@@ -1459,7 +1481,7 @@
*/
static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
{
- struct smsc_ircc_cb *self = dev->priv;
+ struct smsc_ircc_cb *self = netdev_priv(dev);
int boguscount = 0;
int iobase;
int iir, lsr;
@@ -1469,14 +1491,14 @@
iobase = self->io.sir_base;
- iir = inb(iobase+UART_IIR) & UART_IIR_ID;
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
if (iir == 0)
return IRQ_NONE;
while (iir) {
/* Clear interrupt */
- lsr = inb(iobase+UART_LSR);
+ lsr = inb(iobase + UART_LSR);
- IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
__FUNCTION__, iir, lsr, iobase);
switch (iir) {
@@ -1496,13 +1518,13 @@
IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",
__FUNCTION__, iir);
break;
- }
-
+ }
+
/* Make sure we don't stay here to long */
if (boguscount++ > 100)
break;
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
/*spin_unlock(&self->lock);*/
return IRQ_HANDLED;
@@ -1529,7 +1551,7 @@
get_dma_residue(self->io.dma));
status = (self->rx_buff.state != OUTSIDE_FRAME);
-
+
return status;
}
#endif /* unused */
@@ -1544,19 +1566,16 @@
static int smsc_ircc_net_open(struct net_device *dev)
{
struct smsc_ircc_cb *self;
- int iobase;
char hwname[16];
unsigned long flags;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = (struct smsc_ircc_cb *) dev->priv;
- IRDA_ASSERT(self != NULL, return 0;);
-
- iobase = self->io.fir_base;
- if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
+ IRDA_ASSERT(dev != NULL, return -1;);
+ self = netdev_priv(dev);
+ IRDA_ASSERT(self != NULL, return 0;);
+
+ if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
(void *) dev)) {
IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
__FUNCTION__, self->io.irq);
@@ -1568,14 +1587,14 @@
self->io.speed = 0;
smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
spin_unlock_irqrestore(&self->lock, flags);
-
+
/* Give self a hardware name */
/* It would be cool to offer the chip revision here - Jean II */
sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);
- /*
+ /*
* Open new IrLAP layer instance, now that everything should be
- * initialized properly
+ * initialized properly
*/
self->irlap = irlap_open(dev, &self->qos, hwname);
@@ -1590,7 +1609,7 @@
__FUNCTION__, self->io.dma);
return -EAGAIN;
}
-
+
netif_start_queue(dev);
return 0;
@@ -1605,73 +1624,53 @@
static int smsc_ircc_net_close(struct net_device *dev)
{
struct smsc_ircc_cb *self;
- int iobase;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
-
+
IRDA_ASSERT(dev != NULL, return -1;);
- self = (struct smsc_ircc_cb *) dev->priv;
+ self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
-
- iobase = self->io.fir_base;
/* Stop device */
netif_stop_queue(dev);
-
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
self->irlap = NULL;
free_irq(self->io.irq, dev);
-
disable_dma(self->io.dma);
-
free_dma(self->io.dma);
return 0;
}
-
-static void smsc_ircc_suspend(struct smsc_ircc_cb *self)
+static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level)
{
+ struct smsc_ircc_cb *self = dev_get_drvdata(dev);
+
IRDA_MESSAGE("%s, Suspending\n", driver_name);
- if (self->io.suspended)
- return;
+ if (level == SUSPEND_DISABLE && !self->io.suspended) {
+ smsc_ircc_net_close(self->netdev);
+ self->io.suspended = 1;
+ }
- smsc_ircc_net_close(self->netdev);
-
- self->io.suspended = 1;
+ return 0;
}
-static void smsc_ircc_wakeup(struct smsc_ircc_cb *self)
+static int smsc_ircc_resume(struct device *dev, u32 level)
{
- if (!self->io.suspended)
- return;
+ struct smsc_ircc_cb *self = dev_get_drvdata(dev);
- /* The code was doing a "cli()" here, but this can't be right.
- * If you need protection, do it in net_open with a spinlock
- * or give a good reason. - Jean II */
+ if (level == RESUME_ENABLE && self->io.suspended) {
- smsc_ircc_net_open(self->netdev);
-
- IRDA_MESSAGE("%s, Waking up\n", driver_name);
-}
+ smsc_ircc_net_open(self->netdev);
+ self->io.suspended = 0;
-static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data;
- if (self) {
- switch (rqst) {
- case PM_SUSPEND:
- smsc_ircc_suspend(self);
- break;
- case PM_RESUME:
- smsc_ircc_wakeup(self);
- break;
- }
- }
+ IRDA_MESSAGE("%s, Waking up\n", driver_name);
+ }
return 0;
}
@@ -1690,10 +1689,7 @@
IRDA_ASSERT(self != NULL, return -1;);
- iobase = self->io.fir_base;
-
- if (self->pmdev)
- pm_unregister(self->pmdev);
+ platform_device_unregister(self->pldev);
/* Remove netdevice */
unregister_netdev(self->netdev);
@@ -1702,15 +1698,16 @@
spin_lock_irqsave(&self->lock, flags);
/* Stop interrupts */
+ iobase = self->io.fir_base;
register_bank(iobase, 0);
- outb(0, iobase+IRCC_IER);
- outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
- outb(0x00, iobase+IRCC_MASTER);
+ outb(0, iobase + IRCC_IER);
+ outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
+ outb(0x00, iobase + IRCC_MASTER);
#if 0
/* Reset to SIR mode */
register_bank(iobase, 1);
- outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
- outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
+ outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase + IRCC_SCE_CFGA);
+ outb(IRCC_CFGB_IR, iobase + IRCC_SCE_CFGB);
#endif
spin_unlock_irqrestore(&self->lock, flags);
@@ -1720,7 +1717,7 @@
release_region(self->io.fir_base, self->io.fir_ext);
- IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
+ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
self->io.sir_base);
release_region(self->io.sir_base, self->io.sir_ext);
@@ -1728,7 +1725,7 @@
if (self->tx_buff.head)
dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
-
+
if (self->rx_buff.head)
dma_free_coherent(NULL, self->rx_buff.truesize,
self->rx_buff.head, self->rx_buff_dma);
@@ -1744,10 +1741,12 @@
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- for (i=0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
if (dev_self[i])
smsc_ircc_close(dev_self[i]);
}
+
+ driver_unregister(&smsc_ircc_driver);
}
/*
@@ -1763,34 +1762,34 @@
IRDA_DEBUG(3, "%s\n", __FUNCTION__);
- IRDA_ASSERT(self != NULL, return;);
- dev= self->netdev;
- IRDA_ASSERT(dev != NULL, return;);
+ IRDA_ASSERT(self != NULL, return;);
+ dev = self->netdev;
+ IRDA_ASSERT(dev != NULL, return;);
dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
fir_base = self->io.fir_base;
sir_base = self->io.sir_base;
/* Reset everything */
- outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);
+ outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);
#if SMSC_IRCC2_C_SIR_STOP
/*smsc_ircc_sir_stop(self);*/
#endif
register_bank(fir_base, 1);
- outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA);
+ outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA);
/* Initialize UART */
- outb(UART_LCR_WLEN8, sir_base+UART_LCR); /* Reset DLAB */
- outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR);
-
+ outb(UART_LCR_WLEN8, sir_base + UART_LCR); /* Reset DLAB */
+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR);
+
/* Turn on interrups */
- outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER);
+ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER);
IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__);
- outb(0x00, fir_base+IRCC_MASTER);
+ outb(0x00, fir_base + IRCC_MASTER);
}
#if SMSC_IRCC2_C_SIR_STOP
@@ -1802,10 +1801,10 @@
iobase = self->io.sir_base;
/* Reset UART */
- outb(0, iobase+UART_MCR);
-
+ outb(0, iobase + UART_MCR);
+
/* Turn off interrupts */
- outb(0, iobase+UART_IER);
+ outb(0, iobase + UART_IER);
}
#endif
@@ -1831,16 +1830,16 @@
/* Finished with frame? */
if (self->tx_buff.len > 0) {
/* Write data left in transmit buffer */
- actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
+ actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
self->tx_buff.data, self->tx_buff.len);
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
} else {
-
+
/*if (self->tx_buff.len ==0) {*/
-
- /*
- * Now serial buffer is almost free & we can start
+
+ /*
+ * Now serial buffer is almost free & we can start
* transmission of another packet. But first we must check
* if we need to change the speed of the hardware
*/
@@ -1856,21 +1855,19 @@
}
self->stats.tx_packets++;
- if(self->io.speed <= 115200) {
- /*
- * Reset Rx FIFO to make sure that all reflected transmit data
- * is discarded. This is needed for half duplex operation
- */
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
+ if (self->io.speed <= 115200) {
+ /*
+ * Reset Rx FIFO to make sure that all reflected transmit data
+ * is discarded. This is needed for half duplex operation
+ */
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
+ fcr |= self->io.speed < 38400 ?
+ UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
- outb(fcr, iobase+UART_FCR);
+ outb(fcr, iobase + UART_FCR);
- /* Turn on receive interrupts */
- outb(UART_IER_RDI, iobase+UART_IER);
+ /* Turn on receive interrupts */
+ outb(UART_IER_RDI, iobase + UART_IER);
}
}
}
@@ -1884,17 +1881,17 @@
static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0;
-
+
/* Tx FIFO should be empty! */
- if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) {
IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
return 0;
}
-
+
/* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
+ while (fifo_size-- > 0 && actual < len) {
/* Transmit next byte */
- outb(buf[actual], iobase+UART_TX);
+ outb(buf[actual], iobase + UART_TX);
actual++;
}
return actual;
@@ -1921,20 +1918,21 @@
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
{
unsigned int i;
-
+
IRDA_ASSERT(self != NULL, return;);
-
- for(i=0; smsc_transceivers[i].name!=NULL; i++)
- if((*smsc_transceivers[i].probe)(self->io.fir_base)) {
+
+ for (i = 0; smsc_transceivers[i].name != NULL; i++)
+ if (smsc_transceivers[i].probe(self->io.fir_base)) {
IRDA_MESSAGE(" %s transceiver found\n",
smsc_transceivers[i].name);
- self->transceiver= i+1;
+ self->transceiver= i + 1;
return;
}
+
IRDA_MESSAGE("No transceiver found. Defaulting to %s\n",
smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
-
- self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
+
+ self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
}
@@ -1947,9 +1945,10 @@
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed)
{
unsigned int trx;
-
+
trx = self->transceiver;
- if(trx>0) (*smsc_transceivers[trx-1].set_for_speed)(self->io.fir_base, speed);
+ if (trx > 0)
+ smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed);
}
/*
@@ -1977,16 +1976,14 @@
static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
{
- int iobase;
+ int iobase = self->io.sir_base;
int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;
-
- iobase = self->io.sir_base;
-
+
/* Calibrated busy loop */
- while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
+ while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT))
udelay(1);
- if(count == 0)
+ if (count == 0)
IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
}
@@ -1998,40 +1995,42 @@
static int __init smsc_ircc_look_for_chips(void)
{
- smsc_chip_address_t *address;
- char *type;
+ struct smsc_chip_address *address;
+ char *type;
unsigned int cfg_base, found;
-
+
found = 0;
address = possible_addresses;
-
- while(address->cfg_base){
+
+ while (address->cfg_base) {
cfg_base = address->cfg_base;
-
+
/*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __FUNCTION__, cfg_base, address->type);*/
-
- if( address->type & SMSCSIO_TYPE_FDC){
+
+ if (address->type & SMSCSIO_TYPE_FDC) {
type = "FDC";
- if((address->type) & SMSCSIO_TYPE_FLAT) {
- if(!smsc_superio_flat(fdc_chips_flat,cfg_base, type)) found++;
- }
- if((address->type) & SMSCSIO_TYPE_PAGED) {
- if(!smsc_superio_paged(fdc_chips_paged,cfg_base, type)) found++;
- }
+ if (address->type & SMSCSIO_TYPE_FLAT)
+ if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type))
+ found++;
+
+ if (address->type & SMSCSIO_TYPE_PAGED)
+ if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type))
+ found++;
}
- if( address->type & SMSCSIO_TYPE_LPC){
+ if (address->type & SMSCSIO_TYPE_LPC) {
type = "LPC";
- if((address->type) & SMSCSIO_TYPE_FLAT) {
- if(!smsc_superio_flat(lpc_chips_flat,cfg_base,type)) found++;
- }
- if((address->type) & SMSCSIO_TYPE_PAGED) {
- if(!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) found++;
- }
+ if (address->type & SMSCSIO_TYPE_FLAT)
+ if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type))
+ found++;
+
+ if (address->type & SMSCSIO_TYPE_PAGED)
+ if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type))
+ found++;
}
address++;
}
return found;
-}
+}
/*
* Function smsc_superio_flat (chip, base, type)
@@ -2039,7 +2038,7 @@
* Try to get configuration of a smc SuperIO chip with flat register model
*
*/
-static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfgbase, char *type)
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type)
{
unsigned short firbase, sirbase;
u8 mode, dma, irq;
@@ -2047,39 +2046,37 @@
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type)==NULL)
+ if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL)
return ret;
outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);
- mode = inb(cfgbase+1);
-
+ mode = inb(cfgbase + 1);
+
/*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __FUNCTION__, mode);*/
-
- if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
+
+ if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
IRDA_WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
- sirbase = inb(cfgbase+1) << 2;
+ sirbase = inb(cfgbase + 1) << 2;
- /* FIR iobase */
+ /* FIR iobase */
outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);
- firbase = inb(cfgbase+1) << 3;
+ firbase = inb(cfgbase + 1) << 3;
/* DMA */
outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);
- dma = inb(cfgbase+1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
-
+ dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
+
/* IRQ */
outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
- irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
+ irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
- if (firbase) {
- if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
- ret=0;
- }
-
+ if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
+ ret = 0;
+
/* Exit configuration */
outb(SMSCSIO_CFGEXITKEY, cfgbase);
@@ -2092,26 +2089,26 @@
* Try to get configuration of a smc SuperIO chip with paged register model
*
*/
-static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type)
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type)
{
unsigned short fir_io, sir_io;
int ret = -ENODEV;
-
+
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
- if (smsc_ircc_probe(cfg_base,0x20,chips,type)==NULL)
+ if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL)
return ret;
-
+
/* Select logical device (UART2) */
outb(0x07, cfg_base);
outb(0x05, cfg_base + 1);
-
+
/* SIR iobase */
outb(0x60, cfg_base);
- sir_io = inb(cfg_base + 1) << 8;
+ sir_io = inb(cfg_base + 1) << 8;
outb(0x61, cfg_base);
sir_io |= inb(cfg_base + 1);
-
+
/* Read FIR base */
outb(0x62, cfg_base);
fir_io = inb(cfg_base + 1) << 8;
@@ -2119,11 +2116,9 @@
fir_io |= inb(cfg_base + 1);
outb(0x2b, cfg_base); /* ??? */
- if (fir_io) {
- if (smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
- ret=0;
- }
-
+ if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
+ ret = 0;
+
/* Exit configuration */
outb(SMSCSIO_CFGEXITKEY, cfg_base);
@@ -2131,21 +2126,17 @@
}
-static int __init smsc_access(unsigned short cfg_base,unsigned char reg)
+static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
{
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
outb(reg, cfg_base);
-
- if (inb(cfg_base)!=reg)
- return -1;
-
- return 0;
+ return inb(cfg_base) != reg ? -1 : 0;
}
-static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type)
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
{
- u8 devid,xdevid,rev;
+ u8 devid, xdevid, rev;
IRDA_DEBUG(1, "%s\n", __FUNCTION__);
@@ -2158,7 +2149,7 @@
outb(reg, cfg_base);
- xdevid=inb(cfg_base+1);
+ xdevid = inb(cfg_base + 1);
/* Enter configuration */
@@ -2168,51 +2159,49 @@
if (smsc_access(cfg_base,0x55)) /* send second key and check */
return NULL;
#endif
-
+
/* probe device ID */
- if (smsc_access(cfg_base,reg))
+ if (smsc_access(cfg_base, reg))
return NULL;
- devid=inb(cfg_base+1);
-
- if (devid==0) /* typical value for unused port */
- return NULL;
+ devid = inb(cfg_base + 1);
- if (devid==0xff) /* typical value for unused port */
+ if (devid == 0 || devid == 0xff) /* typical values for unused port */
return NULL;
/* probe revision ID */
- if (smsc_access(cfg_base,reg+1))
+ if (smsc_access(cfg_base, reg + 1))
return NULL;
- rev=inb(cfg_base+1);
+ rev = inb(cfg_base + 1);
- if (rev>=128) /* i think this will make no sense */
+ if (rev >= 128) /* i think this will make no sense */
return NULL;
- if (devid==xdevid) /* protection against false positives */
+ if (devid == xdevid) /* protection against false positives */
return NULL;
/* Check for expected device ID; are there others? */
- while(chip->devid!=devid) {
+ while (chip->devid != devid) {
chip++;
- if (chip->name==NULL)
+ if (chip->name == NULL)
return NULL;
}
- IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
+ IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",
+ devid, rev, cfg_base, type, chip->name);
- if (chip->rev>rev){
- IRDA_MESSAGE("Revision higher than expected\n");
+ if (chip->rev > rev) {
+ IRDA_MESSAGE("Revision higher than expected\n");
return NULL;
}
-
- if (chip->flags&NoIRDA)
+
+ if (chip->flags & NoIRDA)
IRDA_MESSAGE("chipset does not support IRDA\n");
return chip;
@@ -2226,8 +2215,8 @@
IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
__FUNCTION__, cfg_base);
} else {
- if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")
- ||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
+ if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") ||
+ !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC"))
ret = 0;
release_region(cfg_base, 2);
@@ -2244,9 +2233,10 @@
IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
__FUNCTION__, cfg_base);
} else {
- if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")
- ||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
+ if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") ||
+ !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC"))
ret = 0;
+
release_region(cfg_base, 2);
}
return ret;
@@ -2269,18 +2259,23 @@
static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed)
{
unsigned long jiffies_now, jiffies_timeout;
- u8 val;
-
- jiffies_now= jiffies;
- jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
-
+ u8 val;
+
+ jiffies_now = jiffies;
+ jiffies_timeout = jiffies + SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
+
/* ATC */
register_bank(fir_base, 4);
- outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);
- while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));
- if(val)
+ outb((inb(fir_base + IRCC_ATC) & IRCC_ATC_MASK) | IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE,
+ fir_base + IRCC_ATC);
+
+ while ((val = (inb(fir_base + IRCC_ATC) & IRCC_ATC_nPROGREADY)) &&
+ !time_after(jiffies, jiffies_timeout))
+ /* empty */;
+
+ if (val)
IRDA_WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
- inb(fir_base+IRCC_ATC));
+ inb(fir_base + IRCC_ATC));
}
/*
@@ -2298,34 +2293,32 @@
/*
* Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed)
*
- * Set transceiver
+ * Set transceiver
*
*/
static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed)
{
- u8 fast_mode;
-
- switch(speed)
- {
- default:
- case 576000 :
- fast_mode = 0;
+ u8 fast_mode;
+
+ switch (speed) {
+ default:
+ case 576000 :
+ fast_mode = 0;
break;
- case 1152000 :
- case 4000000 :
+ case 1152000 :
+ case 4000000 :
fast_mode = IRCC_LCR_A_FAST;
break;
-
}
register_bank(fir_base, 0);
- outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+ outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
}
/*
* Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base)
*
- * Probe transceiver
+ * Probe transceiver
*
*/
@@ -2337,35 +2330,34 @@
/*
* Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed)
*
- * Set transceiver
+ * Set transceiver
*
*/
static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed)
{
- u8 fast_mode;
-
- switch(speed)
- {
- default:
- case 576000 :
- fast_mode = 0;
+ u8 fast_mode;
+
+ switch (speed) {
+ default:
+ case 576000 :
+ fast_mode = 0;
break;
- case 1152000 :
- case 4000000 :
+ case 1152000 :
+ case 4000000 :
fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;
break;
-
+
}
/* This causes an interrupt */
register_bank(fir_base, 0);
- outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+ outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
}
/*
* Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base)
*
- * Probe transceiver
+ * Probe transceiver
*
*/
@@ -2377,20 +2369,3 @@
module_init(smsc_ircc_init);
module_exit(smsc_ircc_cleanup);
-
-MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
-MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
-MODULE_LICENSE("GPL");
-
-module_param(ircc_dma, int, 0);
-MODULE_PARM_DESC(ircc_dma, "DMA channel");
-module_param(ircc_irq, int, 0);
-MODULE_PARM_DESC(ircc_irq, "IRQ line");
-module_param(ircc_fir, int, 0);
-MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
-module_param(ircc_sir, int, 0);
-MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
-module_param(ircc_cfg, int, 0);
-MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
-module_param(ircc_transceiver, int, 0);
-MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h
index 458611c..0c36286 100644
--- a/drivers/net/irda/smsc-ircc2.h
+++ b/drivers/net/irda/smsc-ircc2.h
@@ -1,5 +1,5 @@
/*********************************************************************
- * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
+ * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
*
* Description: Definitions for the SMC IrCC chipset
* Status: Experimental.
@@ -9,25 +9,25 @@
* All Rights Reserved.
*
* Based on smc-ircc.h:
- *
+ *
* Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
* Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
* 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
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
+ *
+ * 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
*
********************************************************************/
@@ -112,10 +112,10 @@
#define IRCC_CFGA_COM 0x00
#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87
-#define IRCC_CFGA_IRDA_SIR_A 0x08
-#define IRCC_CFGA_ASK_SIR 0x10
-#define IRCC_CFGA_IRDA_SIR_B 0x18
-#define IRCC_CFGA_IRDA_HDLC 0x20
+#define IRCC_CFGA_IRDA_SIR_A 0x08
+#define IRCC_CFGA_ASK_SIR 0x10
+#define IRCC_CFGA_IRDA_SIR_B 0x18
+#define IRCC_CFGA_IRDA_HDLC 0x20
#define IRCC_CFGA_IRDA_4PPM 0x28
#define IRCC_CFGA_CONSUMER 0x30
#define IRCC_CFGA_RAW_IR 0x38
@@ -130,7 +130,7 @@
#define IRCC_CFGB_LPBCK_TX_CRC 0x10
#define IRCC_CFGB_NOWAIT 0x08
#define IRCC_CFGB_STRING_MOVE 0x04
-#define IRCC_CFGB_DMA_BURST 0x02
+#define IRCC_CFGB_DMA_BURST 0x02
#define IRCC_CFGB_DMA_ENABLE 0x01
#define IRCC_CFGB_MUX_COM 0x00
@@ -141,11 +141,11 @@
/* Register block 3 - Identification Registers! */
#define IRCC_ID_HIGH 0x00 /* 0x10 */
#define IRCC_ID_LOW 0x01 /* 0xB8 */
-#define IRCC_CHIP_ID 0x02 /* 0xF1 */
+#define IRCC_CHIP_ID 0x02 /* 0xF1 */
#define IRCC_VERSION 0x03 /* 0x01 */
#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
-#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
-#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
/* Register block 4 - IrDA */
#define IRCC_CONTROL 0x00
@@ -163,10 +163,10 @@
/* Register block 5 - IrDA */
#define IRCC_ATC 0x00
-#define IRCC_ATC_nPROGREADY 0x80
-#define IRCC_ATC_SPEED 0x40
-#define IRCC_ATC_ENABLE 0x20
-#define IRCC_ATC_MASK 0xE0
+#define IRCC_ATC_nPROGREADY 0x80
+#define IRCC_ATC_SPEED 0x40
+#define IRCC_ATC_ENABLE 0x20
+#define IRCC_ATC_MASK 0xE0
#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01
@@ -178,8 +178,8 @@
*/
#define SMSC_IRCC2_MAX_SIR_SPEED 115200
-#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
-#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
+#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
+#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
#define SMSC_IRCC2_FIFO_SIZE 16
#define SMSC_IRCC2_FIFO_THRESHOLD 64
/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 006e4f5..6d9de62 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1749,11 +1749,6 @@
struct net_device *ndev = pci_get_drvdata(pdev);
vlsi_irda_dev_t *idev;
- if (state < 1 || state > 3 ) {
- IRDA_ERROR("%s - %s: invalid pm state request: %u\n",
- __FUNCTION__, PCIDEV_NAME(pdev), state);
- return 0;
- }
if (!ndev) {
IRDA_ERROR("%s - %s: no netdevice \n",
__FUNCTION__, PCIDEV_NAME(pdev));
@@ -1762,12 +1757,12 @@
idev = ndev->priv;
down(&idev->sem);
if (pdev->current_state != 0) { /* already suspended */
- if (state > pdev->current_state) { /* simply go deeper */
- pci_set_power_state(pdev,state);
- pdev->current_state = state;
+ if (state.event > pdev->current_state) { /* simply go deeper */
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pdev->current_state = state.event;
}
else
- IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state);
+ IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event);
up(&idev->sem);
return 0;
}
@@ -1781,8 +1776,8 @@
idev->new_baud = idev->baud;
}
- pci_set_power_state(pdev,state);
- pdev->current_state = state;
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pdev->current_state = state.event;
idev->resume_ok = 1;
up(&idev->sem);
return 0;
@@ -1807,8 +1802,8 @@
return 0;
}
- pci_set_power_state(pdev, 0);
- pdev->current_state = 0;
+ pci_set_power_state(pdev, PCI_D0);
+ pdev->current_state = PM_EVENT_ON;
if (!idev->resume_ok) {
/* should be obsolete now - but used to happen due to:
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 183ba97..3d56cf5 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -4,6 +4,7 @@
* Copyright (C) 2001 Kyle A. Lucke (klucke@us.ibm.com), IBM Corp.
* Substantially cleaned up by:
* Copyright (C) 2003 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ * Copyright (C) 2004-2005 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
@@ -79,12 +80,55 @@
#include <asm/iommu.h>
#include <asm/vio.h>
-#include "iseries_veth.h"
+#undef DEBUG
MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm.com>");
MODULE_DESCRIPTION("iSeries Virtual ethernet driver");
MODULE_LICENSE("GPL");
+#define VETH_EVENT_CAP (0)
+#define VETH_EVENT_FRAMES (1)
+#define VETH_EVENT_MONITOR (2)
+#define VETH_EVENT_FRAMES_ACK (3)
+
+#define VETH_MAX_ACKS_PER_MSG (20)
+#define VETH_MAX_FRAMES_PER_MSG (6)
+
+struct veth_frames_data {
+ u32 addr[VETH_MAX_FRAMES_PER_MSG];
+ u16 len[VETH_MAX_FRAMES_PER_MSG];
+ u32 eofmask;
+};
+#define VETH_EOF_SHIFT (32-VETH_MAX_FRAMES_PER_MSG)
+
+struct veth_frames_ack_data {
+ u16 token[VETH_MAX_ACKS_PER_MSG];
+};
+
+struct veth_cap_data {
+ u8 caps_version;
+ u8 rsvd1;
+ u16 num_buffers;
+ u16 ack_threshold;
+ u16 rsvd2;
+ u32 ack_timeout;
+ u32 rsvd3;
+ u64 rsvd4[3];
+};
+
+struct veth_lpevent {
+ struct HvLpEvent base_event;
+ union {
+ struct veth_cap_data caps_data;
+ struct veth_frames_data frames_data;
+ struct veth_frames_ack_data frames_ack_data;
+ } u;
+
+};
+
+#define DRV_NAME "iseries_veth"
+#define DRV_VERSION "2.0"
+
#define VETH_NUMBUFFERS (120)
#define VETH_ACKTIMEOUT (1000000) /* microseconds */
#define VETH_MAX_MCAST (12)
@@ -113,9 +157,9 @@
struct veth_msg {
struct veth_msg *next;
- struct VethFramesData data;
+ struct veth_frames_data data;
int token;
- unsigned long in_use;
+ int in_use;
struct sk_buff *skb;
struct device *dev;
};
@@ -125,23 +169,28 @@
struct work_struct statemachine_wq;
struct veth_msg *msgs;
int num_events;
- struct VethCapData local_caps;
+ struct veth_cap_data local_caps;
+ struct kobject kobject;
struct timer_list ack_timer;
+ struct timer_list reset_timer;
+ unsigned int reset_timeout;
+ unsigned long last_contact;
+ int outstanding_tx;
+
spinlock_t lock;
unsigned long state;
HvLpInstanceId src_inst;
HvLpInstanceId dst_inst;
- struct VethLpEvent cap_event, cap_ack_event;
+ struct veth_lpevent cap_event, cap_ack_event;
u16 pending_acks[VETH_MAX_ACKS_PER_MSG];
u32 num_pending_acks;
int num_ack_events;
- struct VethCapData remote_caps;
+ struct veth_cap_data remote_caps;
u32 ack_timeout;
- spinlock_t msg_stack_lock;
struct veth_msg *msg_stack_head;
};
@@ -151,15 +200,17 @@
u64 mac_addr;
HvLpIndexMap lpar_map;
- spinlock_t pending_gate;
- struct sk_buff *pending_skb;
- HvLpIndexMap pending_lpmask;
+ /* queue_lock protects the stopped_map and dev's queue. */
+ spinlock_t queue_lock;
+ HvLpIndexMap stopped_map;
+ /* mcast_gate protects promiscuous, num_mcast & mcast_addr. */
rwlock_t mcast_gate;
int promiscuous;
- int all_mcast;
int num_mcast;
u64 mcast_addr[VETH_MAX_MCAST];
+
+ struct kobject kobject;
};
static HvLpIndex this_lp;
@@ -168,44 +219,56 @@
static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
-static void veth_flush_pending(struct veth_lpar_connection *cnx);
-static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
-static void veth_timed_ack(unsigned long connectionPtr);
+static void veth_wake_queues(struct veth_lpar_connection *cnx);
+static void veth_stop_queues(struct veth_lpar_connection *cnx);
+static void veth_receive(struct veth_lpar_connection *, struct veth_lpevent *);
+static void veth_release_connection(struct kobject *kobject);
+static void veth_timed_ack(unsigned long ptr);
+static void veth_timed_reset(unsigned long ptr);
/*
* Utility functions
*/
-#define veth_printk(prio, fmt, args...) \
- printk(prio "%s: " fmt, __FILE__, ## args)
+#define veth_info(fmt, args...) \
+ printk(KERN_INFO DRV_NAME ": " fmt, ## args)
#define veth_error(fmt, args...) \
- printk(KERN_ERR "(%s:%3.3d) ERROR: " fmt, __FILE__, __LINE__ , ## args)
+ printk(KERN_ERR DRV_NAME ": Error: " fmt, ## args)
+#ifdef DEBUG
+#define veth_debug(fmt, args...) \
+ printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
+#else
+#define veth_debug(fmt, args...) do {} while (0)
+#endif
+
+/* You must hold the connection's lock when you call this function. */
static inline void veth_stack_push(struct veth_lpar_connection *cnx,
struct veth_msg *msg)
{
- unsigned long flags;
-
- spin_lock_irqsave(&cnx->msg_stack_lock, flags);
msg->next = cnx->msg_stack_head;
cnx->msg_stack_head = msg;
- spin_unlock_irqrestore(&cnx->msg_stack_lock, flags);
}
+/* You must hold the connection's lock when you call this function. */
static inline struct veth_msg *veth_stack_pop(struct veth_lpar_connection *cnx)
{
- unsigned long flags;
struct veth_msg *msg;
- spin_lock_irqsave(&cnx->msg_stack_lock, flags);
msg = cnx->msg_stack_head;
if (msg)
cnx->msg_stack_head = cnx->msg_stack_head->next;
- spin_unlock_irqrestore(&cnx->msg_stack_lock, flags);
+
return msg;
}
+/* You must hold the connection's lock when you call this function. */
+static inline int veth_stack_is_empty(struct veth_lpar_connection *cnx)
+{
+ return cnx->msg_stack_head == NULL;
+}
+
static inline HvLpEvent_Rc
veth_signalevent(struct veth_lpar_connection *cnx, u16 subtype,
HvLpEvent_AckInd ackind, HvLpEvent_AckType acktype,
@@ -249,7 +312,7 @@
struct veth_allocation vc = { COMPLETION_INITIALIZER(vc.c), 0 };
mf_allocate_lp_events(rlp, HvLpEvent_Type_VirtualLan,
- sizeof(struct VethLpEvent), number,
+ sizeof(struct veth_lpevent), number,
&veth_complete_allocation, &vc);
wait_for_completion(&vc.c);
@@ -257,6 +320,137 @@
}
/*
+ * sysfs support
+ */
+
+struct veth_cnx_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct veth_lpar_connection *, char *buf);
+ ssize_t (*store)(struct veth_lpar_connection *, const char *buf);
+};
+
+static ssize_t veth_cnx_attribute_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct veth_cnx_attribute *cnx_attr;
+ struct veth_lpar_connection *cnx;
+
+ cnx_attr = container_of(attr, struct veth_cnx_attribute, attr);
+ cnx = container_of(kobj, struct veth_lpar_connection, kobject);
+
+ if (!cnx_attr->show)
+ return -EIO;
+
+ return cnx_attr->show(cnx, buf);
+}
+
+#define CUSTOM_CNX_ATTR(_name, _format, _expression) \
+static ssize_t _name##_show(struct veth_lpar_connection *cnx, char *buf)\
+{ \
+ return sprintf(buf, _format, _expression); \
+} \
+struct veth_cnx_attribute veth_cnx_attr_##_name = __ATTR_RO(_name)
+
+#define SIMPLE_CNX_ATTR(_name) \
+ CUSTOM_CNX_ATTR(_name, "%lu\n", (unsigned long)cnx->_name)
+
+SIMPLE_CNX_ATTR(outstanding_tx);
+SIMPLE_CNX_ATTR(remote_lp);
+SIMPLE_CNX_ATTR(num_events);
+SIMPLE_CNX_ATTR(src_inst);
+SIMPLE_CNX_ATTR(dst_inst);
+SIMPLE_CNX_ATTR(num_pending_acks);
+SIMPLE_CNX_ATTR(num_ack_events);
+CUSTOM_CNX_ATTR(ack_timeout, "%d\n", jiffies_to_msecs(cnx->ack_timeout));
+CUSTOM_CNX_ATTR(reset_timeout, "%d\n", jiffies_to_msecs(cnx->reset_timeout));
+CUSTOM_CNX_ATTR(state, "0x%.4lX\n", cnx->state);
+CUSTOM_CNX_ATTR(last_contact, "%d\n", cnx->last_contact ?
+ jiffies_to_msecs(jiffies - cnx->last_contact) : 0);
+
+#define GET_CNX_ATTR(_name) (&veth_cnx_attr_##_name.attr)
+
+static struct attribute *veth_cnx_default_attrs[] = {
+ GET_CNX_ATTR(outstanding_tx),
+ GET_CNX_ATTR(remote_lp),
+ GET_CNX_ATTR(num_events),
+ GET_CNX_ATTR(reset_timeout),
+ GET_CNX_ATTR(last_contact),
+ GET_CNX_ATTR(state),
+ GET_CNX_ATTR(src_inst),
+ GET_CNX_ATTR(dst_inst),
+ GET_CNX_ATTR(num_pending_acks),
+ GET_CNX_ATTR(num_ack_events),
+ GET_CNX_ATTR(ack_timeout),
+ NULL
+};
+
+static struct sysfs_ops veth_cnx_sysfs_ops = {
+ .show = veth_cnx_attribute_show
+};
+
+static struct kobj_type veth_lpar_connection_ktype = {
+ .release = veth_release_connection,
+ .sysfs_ops = &veth_cnx_sysfs_ops,
+ .default_attrs = veth_cnx_default_attrs
+};
+
+struct veth_port_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct veth_port *, char *buf);
+ ssize_t (*store)(struct veth_port *, const char *buf);
+};
+
+static ssize_t veth_port_attribute_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct veth_port_attribute *port_attr;
+ struct veth_port *port;
+
+ port_attr = container_of(attr, struct veth_port_attribute, attr);
+ port = container_of(kobj, struct veth_port, kobject);
+
+ if (!port_attr->show)
+ return -EIO;
+
+ return port_attr->show(port, buf);
+}
+
+#define CUSTOM_PORT_ATTR(_name, _format, _expression) \
+static ssize_t _name##_show(struct veth_port *port, char *buf) \
+{ \
+ return sprintf(buf, _format, _expression); \
+} \
+struct veth_port_attribute veth_port_attr_##_name = __ATTR_RO(_name)
+
+#define SIMPLE_PORT_ATTR(_name) \
+ CUSTOM_PORT_ATTR(_name, "%lu\n", (unsigned long)port->_name)
+
+SIMPLE_PORT_ATTR(promiscuous);
+SIMPLE_PORT_ATTR(num_mcast);
+CUSTOM_PORT_ATTR(lpar_map, "0x%X\n", port->lpar_map);
+CUSTOM_PORT_ATTR(stopped_map, "0x%X\n", port->stopped_map);
+CUSTOM_PORT_ATTR(mac_addr, "0x%lX\n", port->mac_addr);
+
+#define GET_PORT_ATTR(_name) (&veth_port_attr_##_name.attr)
+static struct attribute *veth_port_default_attrs[] = {
+ GET_PORT_ATTR(mac_addr),
+ GET_PORT_ATTR(lpar_map),
+ GET_PORT_ATTR(stopped_map),
+ GET_PORT_ATTR(promiscuous),
+ GET_PORT_ATTR(num_mcast),
+ NULL
+};
+
+static struct sysfs_ops veth_port_sysfs_ops = {
+ .show = veth_port_attribute_show
+};
+
+static struct kobj_type veth_port_ktype = {
+ .sysfs_ops = &veth_port_sysfs_ops,
+ .default_attrs = veth_port_default_attrs
+};
+
+/*
* LPAR connection code
*/
@@ -266,7 +460,7 @@
}
static void veth_take_cap(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
unsigned long flags;
@@ -278,7 +472,7 @@
HvLpEvent_Type_VirtualLan);
if (cnx->state & VETH_STATE_GOTCAPS) {
- veth_error("Received a second capabilities from lpar %d\n",
+ veth_error("Received a second capabilities from LPAR %d.\n",
cnx->remote_lp);
event->base_event.xRc = HvLpEvent_Rc_BufferNotAvailable;
HvCallEvent_ackLpEvent((struct HvLpEvent *) event);
@@ -291,13 +485,13 @@
}
static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
unsigned long flags;
spin_lock_irqsave(&cnx->lock, flags);
if (cnx->state & VETH_STATE_GOTCAPACK) {
- veth_error("Received a second capabilities ack from lpar %d\n",
+ veth_error("Received a second capabilities ack from LPAR %d.\n",
cnx->remote_lp);
} else {
memcpy(&cnx->cap_ack_event, event,
@@ -309,19 +503,24 @@
}
static void veth_take_monitor_ack(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
unsigned long flags;
spin_lock_irqsave(&cnx->lock, flags);
- veth_printk(KERN_DEBUG, "Monitor ack returned for lpar %d\n",
- cnx->remote_lp);
- cnx->state |= VETH_STATE_RESET;
- veth_kick_statemachine(cnx);
+ veth_debug("cnx %d: lost connection.\n", cnx->remote_lp);
+
+ /* Avoid kicking the statemachine once we're shutdown.
+ * It's unnecessary and it could break veth_stop_connection(). */
+
+ if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
+ cnx->state |= VETH_STATE_RESET;
+ veth_kick_statemachine(cnx);
+ }
spin_unlock_irqrestore(&cnx->lock, flags);
}
-static void veth_handle_ack(struct VethLpEvent *event)
+static void veth_handle_ack(struct veth_lpevent *event)
{
HvLpIndex rlp = event->base_event.xTargetLp;
struct veth_lpar_connection *cnx = veth_cnx[rlp];
@@ -329,58 +528,67 @@
BUG_ON(! cnx);
switch (event->base_event.xSubtype) {
- case VethEventTypeCap:
+ case VETH_EVENT_CAP:
veth_take_cap_ack(cnx, event);
break;
- case VethEventTypeMonitor:
+ case VETH_EVENT_MONITOR:
veth_take_monitor_ack(cnx, event);
break;
default:
- veth_error("Unknown ack type %d from lpar %d\n",
- event->base_event.xSubtype, rlp);
+ veth_error("Unknown ack type %d from LPAR %d.\n",
+ event->base_event.xSubtype, rlp);
};
}
-static void veth_handle_int(struct VethLpEvent *event)
+static void veth_handle_int(struct veth_lpevent *event)
{
HvLpIndex rlp = event->base_event.xSourceLp;
struct veth_lpar_connection *cnx = veth_cnx[rlp];
unsigned long flags;
- int i;
+ int i, acked = 0;
BUG_ON(! cnx);
switch (event->base_event.xSubtype) {
- case VethEventTypeCap:
+ case VETH_EVENT_CAP:
veth_take_cap(cnx, event);
break;
- case VethEventTypeMonitor:
+ case VETH_EVENT_MONITOR:
/* do nothing... this'll hang out here til we're dead,
* and the hypervisor will return it for us. */
break;
- case VethEventTypeFramesAck:
+ case VETH_EVENT_FRAMES_ACK:
spin_lock_irqsave(&cnx->lock, flags);
+
for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) {
u16 msgnum = event->u.frames_ack_data.token[i];
- if (msgnum < VETH_NUMBUFFERS)
+ if (msgnum < VETH_NUMBUFFERS) {
veth_recycle_msg(cnx, cnx->msgs + msgnum);
+ cnx->outstanding_tx--;
+ acked++;
+ }
}
+
+ if (acked > 0) {
+ cnx->last_contact = jiffies;
+ veth_wake_queues(cnx);
+ }
+
spin_unlock_irqrestore(&cnx->lock, flags);
- veth_flush_pending(cnx);
break;
- case VethEventTypeFrames:
+ case VETH_EVENT_FRAMES:
veth_receive(cnx, event);
break;
default:
- veth_error("Unknown interrupt type %d from lpar %d\n",
- event->base_event.xSubtype, rlp);
+ veth_error("Unknown interrupt type %d from LPAR %d.\n",
+ event->base_event.xSubtype, rlp);
};
}
static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
{
- struct VethLpEvent *veth_event = (struct VethLpEvent *)event;
+ struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
if (event->xFlags.xFunction == HvLpEvent_Function_Ack)
veth_handle_ack(veth_event);
@@ -390,7 +598,7 @@
static int veth_process_caps(struct veth_lpar_connection *cnx)
{
- struct VethCapData *remote_caps = &cnx->remote_caps;
+ struct veth_cap_data *remote_caps = &cnx->remote_caps;
int num_acks_needed;
/* Convert timer to jiffies */
@@ -400,8 +608,8 @@
|| (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG)
|| (remote_caps->ack_threshold == 0)
|| (cnx->ack_timeout == 0) ) {
- veth_error("Received incompatible capabilities from lpar %d\n",
- cnx->remote_lp);
+ veth_error("Received incompatible capabilities from LPAR %d.\n",
+ cnx->remote_lp);
return HvLpEvent_Rc_InvalidSubtypeData;
}
@@ -418,8 +626,8 @@
cnx->num_ack_events += num;
if (cnx->num_ack_events < num_acks_needed) {
- veth_error("Couldn't allocate enough ack events for lpar %d\n",
- cnx->remote_lp);
+ veth_error("Couldn't allocate enough ack events "
+ "for LPAR %d.\n", cnx->remote_lp);
return HvLpEvent_Rc_BufferNotAvailable;
}
@@ -440,15 +648,15 @@
restart:
if (cnx->state & VETH_STATE_RESET) {
- int i;
-
- del_timer(&cnx->ack_timer);
-
if (cnx->state & VETH_STATE_OPEN)
HvCallEvent_closeLpEventPath(cnx->remote_lp,
HvLpEvent_Type_VirtualLan);
- /* reset ack data */
+ /*
+ * Reset ack data. This prevents the ack_timer actually
+ * doing anything, even if it runs one more time when
+ * we drop the lock below.
+ */
memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
cnx->num_pending_acks = 0;
@@ -458,14 +666,32 @@
| VETH_STATE_SENTCAPACK | VETH_STATE_READY);
/* Clean up any leftover messages */
- if (cnx->msgs)
+ if (cnx->msgs) {
+ int i;
for (i = 0; i < VETH_NUMBUFFERS; ++i)
veth_recycle_msg(cnx, cnx->msgs + i);
+ }
+
+ cnx->outstanding_tx = 0;
+ veth_wake_queues(cnx);
+
+ /* Drop the lock so we can do stuff that might sleep or
+ * take other locks. */
spin_unlock_irq(&cnx->lock);
- veth_flush_pending(cnx);
+
+ del_timer_sync(&cnx->ack_timer);
+ del_timer_sync(&cnx->reset_timer);
+
spin_lock_irq(&cnx->lock);
+
if (cnx->state & VETH_STATE_RESET)
goto restart;
+
+ /* Hack, wait for the other end to reset itself. */
+ if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
+ schedule_delayed_work(&cnx->statemachine_wq, 5 * HZ);
+ goto out;
+ }
}
if (cnx->state & VETH_STATE_SHUTDOWN)
@@ -488,7 +714,7 @@
if ( (cnx->state & VETH_STATE_OPEN)
&& !(cnx->state & VETH_STATE_SENTMON) ) {
- rc = veth_signalevent(cnx, VethEventTypeMonitor,
+ rc = veth_signalevent(cnx, VETH_EVENT_MONITOR,
HvLpEvent_AckInd_DoAck,
HvLpEvent_AckType_DeferredAck,
0, 0, 0, 0, 0, 0);
@@ -498,9 +724,8 @@
} else {
if ( (rc != HvLpEvent_Rc_PartitionDead)
&& (rc != HvLpEvent_Rc_PathClosed) )
- veth_error("Error sending monitor to "
- "lpar %d, rc=%x\n",
- rlp, (int) rc);
+ veth_error("Error sending monitor to LPAR %d, "
+ "rc = %d\n", rlp, rc);
/* Oh well, hope we get a cap from the other
* end and do better when that kicks us */
@@ -512,7 +737,7 @@
&& !(cnx->state & VETH_STATE_SENTCAPS)) {
u64 *rawcap = (u64 *)&cnx->local_caps;
- rc = veth_signalevent(cnx, VethEventTypeCap,
+ rc = veth_signalevent(cnx, VETH_EVENT_CAP,
HvLpEvent_AckInd_DoAck,
HvLpEvent_AckType_ImmediateAck,
0, rawcap[0], rawcap[1], rawcap[2],
@@ -523,9 +748,9 @@
} else {
if ( (rc != HvLpEvent_Rc_PartitionDead)
&& (rc != HvLpEvent_Rc_PathClosed) )
- veth_error("Error sending caps to "
- "lpar %d, rc=%x\n",
- rlp, (int) rc);
+ veth_error("Error sending caps to LPAR %d, "
+ "rc = %d\n", rlp, rc);
+
/* Oh well, hope we get a cap from the other
* end and do better when that kicks us */
goto out;
@@ -534,7 +759,7 @@
if ((cnx->state & VETH_STATE_GOTCAPS)
&& !(cnx->state & VETH_STATE_SENTCAPACK)) {
- struct VethCapData *remote_caps = &cnx->remote_caps;
+ struct veth_cap_data *remote_caps = &cnx->remote_caps;
memcpy(remote_caps, &cnx->cap_event.u.caps_data,
sizeof(*remote_caps));
@@ -565,10 +790,8 @@
add_timer(&cnx->ack_timer);
cnx->state |= VETH_STATE_READY;
} else {
- veth_printk(KERN_ERR, "Caps rejected (rc=%d) by "
- "lpar %d\n",
- cnx->cap_ack_event.base_event.xRc,
- rlp);
+ veth_error("Caps rejected by LPAR %d, rc = %d\n",
+ rlp, cnx->cap_ack_event.base_event.xRc);
goto cant_cope;
}
}
@@ -581,8 +804,8 @@
/* FIXME: we get here if something happens we really can't
* cope with. The link will never work once we get here, and
* all we can do is not lock the rest of the system up */
- veth_error("Badness on connection to lpar %d (state=%04lx) "
- " - shutting down\n", rlp, cnx->state);
+ veth_error("Unrecoverable error on connection to LPAR %d, shutting down"
+ " (state = 0x%04lx)\n", rlp, cnx->state);
cnx->state |= VETH_STATE_SHUTDOWN;
spin_unlock_irq(&cnx->lock);
}
@@ -591,7 +814,7 @@
{
struct veth_lpar_connection *cnx;
struct veth_msg *msgs;
- int i;
+ int i, rc;
if ( (rlp == this_lp)
|| ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
@@ -605,22 +828,36 @@
cnx->remote_lp = rlp;
spin_lock_init(&cnx->lock);
INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx);
+
init_timer(&cnx->ack_timer);
cnx->ack_timer.function = veth_timed_ack;
cnx->ack_timer.data = (unsigned long) cnx;
+
+ init_timer(&cnx->reset_timer);
+ cnx->reset_timer.function = veth_timed_reset;
+ cnx->reset_timer.data = (unsigned long) cnx;
+ cnx->reset_timeout = 5 * HZ * (VETH_ACKTIMEOUT / 1000000);
+
memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
veth_cnx[rlp] = cnx;
+ /* This gets us 1 reference, which is held on behalf of the driver
+ * infrastructure. It's released at module unload. */
+ kobject_init(&cnx->kobject);
+ cnx->kobject.ktype = &veth_lpar_connection_ktype;
+ rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
+ if (rc != 0)
+ return rc;
+
msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
if (! msgs) {
- veth_error("Can't allocate buffers for lpar %d\n", rlp);
+ veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
return -ENOMEM;
}
cnx->msgs = msgs;
memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
- spin_lock_init(&cnx->msg_stack_lock);
for (i = 0; i < VETH_NUMBUFFERS; i++) {
msgs[i].token = i;
@@ -630,8 +867,7 @@
cnx->num_events = veth_allocate_events(rlp, 2 + VETH_NUMBUFFERS);
if (cnx->num_events < (2 + VETH_NUMBUFFERS)) {
- veth_error("Can't allocate events for lpar %d, only got %d\n",
- rlp, cnx->num_events);
+ veth_error("Can't allocate enough events for LPAR %d.\n", rlp);
return -ENOMEM;
}
@@ -642,11 +878,9 @@
return 0;
}
-static void veth_stop_connection(u8 rlp)
+static void veth_stop_connection(struct veth_lpar_connection *cnx)
{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
+ if (!cnx)
return;
spin_lock_irq(&cnx->lock);
@@ -654,12 +888,23 @@
veth_kick_statemachine(cnx);
spin_unlock_irq(&cnx->lock);
- flush_scheduled_work();
+ /* There's a slim chance the reset code has just queued the
+ * statemachine to run in five seconds. If so we need to cancel
+ * that and requeue the work to run now. */
+ if (cancel_delayed_work(&cnx->statemachine_wq)) {
+ spin_lock_irq(&cnx->lock);
+ veth_kick_statemachine(cnx);
+ spin_unlock_irq(&cnx->lock);
+ }
- /* FIXME: not sure if this is necessary - will already have
- * been deleted by the state machine, just want to make sure
- * its not running any more */
- del_timer_sync(&cnx->ack_timer);
+ /* Wait for the state machine to run. */
+ flush_scheduled_work();
+}
+
+static void veth_destroy_connection(struct veth_lpar_connection *cnx)
+{
+ if (!cnx)
+ return;
if (cnx->num_events > 0)
mf_deallocate_lp_events(cnx->remote_lp,
@@ -671,18 +916,18 @@
HvLpEvent_Type_VirtualLan,
cnx->num_ack_events,
NULL, NULL);
-}
-
-static void veth_destroy_connection(u8 rlp)
-{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
- return;
kfree(cnx->msgs);
+ veth_cnx[cnx->remote_lp] = NULL;
kfree(cnx);
- veth_cnx[rlp] = NULL;
+}
+
+static void veth_release_connection(struct kobject *kobj)
+{
+ struct veth_lpar_connection *cnx;
+ cnx = container_of(kobj, struct veth_lpar_connection, kobject);
+ veth_stop_connection(cnx);
+ veth_destroy_connection(cnx);
}
/*
@@ -726,17 +971,15 @@
write_lock_irqsave(&port->mcast_gate, flags);
- if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
- dev->name);
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+ (dev->mc_count > VETH_MAX_MCAST)) {
port->promiscuous = 1;
- } else if ( (dev->flags & IFF_ALLMULTI)
- || (dev->mc_count > VETH_MAX_MCAST) ) {
- port->all_mcast = 1;
} else {
struct dev_mc_list *dmi = dev->mc_list;
int i;
+ port->promiscuous = 0;
+
/* Update table */
port->num_mcast = 0;
@@ -758,9 +1001,10 @@
static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strncpy(info->driver, "veth", sizeof(info->driver) - 1);
+ strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
info->driver[sizeof(info->driver) - 1] = '\0';
- strncpy(info->version, "1.0", sizeof(info->version) - 1);
+ strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+ info->version[sizeof(info->version) - 1] = '\0';
}
static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -791,49 +1035,6 @@
.get_link = veth_get_link,
};
-static void veth_tx_timeout(struct net_device *dev)
-{
- struct veth_port *port = (struct veth_port *)dev->priv;
- struct net_device_stats *stats = &port->stats;
- unsigned long flags;
- int i;
-
- stats->tx_errors++;
-
- spin_lock_irqsave(&port->pending_gate, flags);
-
- if (!port->pending_lpmask) {
- spin_unlock_irqrestore(&port->pending_gate, flags);
- return;
- }
-
- printk(KERN_WARNING "%s: Tx timeout! Resetting lp connections: %08x\n",
- dev->name, port->pending_lpmask);
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
- struct veth_lpar_connection *cnx = veth_cnx[i];
-
- if (! (port->pending_lpmask & (1<<i)))
- continue;
-
- /* If we're pending on it, we must be connected to it,
- * so we should certainly have a structure for it. */
- BUG_ON(! cnx);
-
- /* Theoretically we could be kicking a connection
- * which doesn't deserve it, but in practice if we've
- * had a Tx timeout, the pending_lpmask will have
- * exactly one bit set - the connection causing the
- * problem. */
- spin_lock(&cnx->lock);
- cnx->state |= VETH_STATE_RESET;
- veth_kick_statemachine(cnx);
- spin_unlock(&cnx->lock);
- }
-
- spin_unlock_irqrestore(&port->pending_gate, flags);
-}
-
static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
{
struct net_device *dev;
@@ -848,8 +1049,9 @@
port = (struct veth_port *) dev->priv;
- spin_lock_init(&port->pending_gate);
+ spin_lock_init(&port->queue_lock);
rwlock_init(&port->mcast_gate);
+ port->stopped_map = 0;
for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
HvLpVirtualLanIndexMap map;
@@ -882,22 +1084,24 @@
dev->set_multicast_list = veth_set_multicast_list;
SET_ETHTOOL_OPS(dev, &ops);
- dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000);
- dev->tx_timeout = veth_tx_timeout;
-
SET_NETDEV_DEV(dev, vdev);
rc = register_netdev(dev);
if (rc != 0) {
- veth_printk(KERN_ERR,
- "Failed to register ethernet device for vlan %d\n",
- vlan);
+ veth_error("Failed registering net device for vlan%d.\n", vlan);
free_netdev(dev);
return NULL;
}
- veth_printk(KERN_DEBUG, "%s attached to iSeries vlan %d (lpar_map=0x%04x)\n",
- dev->name, vlan, port->lpar_map);
+ kobject_init(&port->kobject);
+ port->kobject.parent = &dev->class_dev.kobj;
+ port->kobject.ktype = &veth_port_ktype;
+ kobject_set_name(&port->kobject, "veth_port");
+ if (0 != kobject_add(&port->kobject))
+ veth_error("Failed adding port for %s to sysfs.\n", dev->name);
+
+ veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
+ dev->name, vlan, port->lpar_map);
return dev;
}
@@ -912,98 +1116,95 @@
struct veth_lpar_connection *cnx = veth_cnx[rlp];
struct veth_port *port = (struct veth_port *) dev->priv;
HvLpEvent_Rc rc;
- u32 dma_address, dma_length;
struct veth_msg *msg = NULL;
- int err = 0;
unsigned long flags;
- if (! cnx) {
- port->stats.tx_errors++;
- dev_kfree_skb(skb);
+ if (! cnx)
return 0;
- }
spin_lock_irqsave(&cnx->lock, flags);
if (! (cnx->state & VETH_STATE_READY))
- goto drop;
+ goto no_error;
- if ((skb->len - 14) > VETH_MAX_MTU)
+ if ((skb->len - ETH_HLEN) > VETH_MAX_MTU)
goto drop;
msg = veth_stack_pop(cnx);
-
- if (! msg) {
- err = 1;
+ if (! msg)
goto drop;
- }
- dma_length = skb->len;
- dma_address = dma_map_single(port->dev, skb->data,
- dma_length, DMA_TO_DEVICE);
+ msg->in_use = 1;
+ msg->skb = skb_get(skb);
- if (dma_mapping_error(dma_address))
+ msg->data.addr[0] = dma_map_single(port->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(msg->data.addr[0]))
goto recycle_and_drop;
- /* Is it really necessary to check the length and address
- * fields of the first entry here? */
- msg->skb = skb;
msg->dev = port->dev;
- msg->data.addr[0] = dma_address;
- msg->data.len[0] = dma_length;
+ msg->data.len[0] = skb->len;
msg->data.eofmask = 1 << VETH_EOF_SHIFT;
- set_bit(0, &(msg->in_use));
- rc = veth_signaldata(cnx, VethEventTypeFrames, msg->token, &msg->data);
+
+ rc = veth_signaldata(cnx, VETH_EVENT_FRAMES, msg->token, &msg->data);
if (rc != HvLpEvent_Rc_Good)
goto recycle_and_drop;
+ /* If the timer's not already running, start it now. */
+ if (0 == cnx->outstanding_tx)
+ mod_timer(&cnx->reset_timer, jiffies + cnx->reset_timeout);
+
+ cnx->last_contact = jiffies;
+ cnx->outstanding_tx++;
+
+ if (veth_stack_is_empty(cnx))
+ veth_stop_queues(cnx);
+
+ no_error:
spin_unlock_irqrestore(&cnx->lock, flags);
return 0;
recycle_and_drop:
- msg->skb = NULL;
- /* need to set in use to make veth_recycle_msg in case this
- * was a mapping failure */
- set_bit(0, &msg->in_use);
veth_recycle_msg(cnx, msg);
drop:
- port->stats.tx_errors++;
- dev_kfree_skb(skb);
spin_unlock_irqrestore(&cnx->lock, flags);
- return err;
+ return 1;
}
-static HvLpIndexMap veth_transmit_to_many(struct sk_buff *skb,
+static void veth_transmit_to_many(struct sk_buff *skb,
HvLpIndexMap lpmask,
struct net_device *dev)
{
struct veth_port *port = (struct veth_port *) dev->priv;
- int i;
- int rc;
+ int i, success, error;
+
+ success = error = 0;
for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
if ((lpmask & (1 << i)) == 0)
continue;
- rc = veth_transmit_to_one(skb_get(skb), i, dev);
- if (! rc)
- lpmask &= ~(1<<i);
+ if (veth_transmit_to_one(skb, i, dev))
+ error = 1;
+ else
+ success = 1;
}
- if (! lpmask) {
+ if (error)
+ port->stats.tx_errors++;
+
+ if (success) {
port->stats.tx_packets++;
port->stats.tx_bytes += skb->len;
}
-
- return lpmask;
}
static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned char *frame = skb->data;
struct veth_port *port = (struct veth_port *) dev->priv;
- unsigned long flags;
HvLpIndexMap lpmask;
if (! (frame[0] & 0x01)) {
@@ -1020,44 +1221,27 @@
lpmask = port->lpar_map;
}
- spin_lock_irqsave(&port->pending_gate, flags);
+ veth_transmit_to_many(skb, lpmask, dev);
- lpmask = veth_transmit_to_many(skb, lpmask, dev);
-
- dev->trans_start = jiffies;
-
- if (! lpmask) {
- dev_kfree_skb(skb);
- } else {
- if (port->pending_skb) {
- veth_error("%s: Tx while skb was pending!\n",
- dev->name);
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&port->pending_gate, flags);
- return 1;
- }
-
- port->pending_skb = skb;
- port->pending_lpmask = lpmask;
- netif_stop_queue(dev);
- }
-
- spin_unlock_irqrestore(&port->pending_gate, flags);
+ dev_kfree_skb(skb);
return 0;
}
+/* You must hold the connection's lock when you call this function. */
static void veth_recycle_msg(struct veth_lpar_connection *cnx,
struct veth_msg *msg)
{
u32 dma_address, dma_length;
- if (test_and_clear_bit(0, &msg->in_use)) {
+ if (msg->in_use) {
+ msg->in_use = 0;
dma_address = msg->data.addr[0];
dma_length = msg->data.len[0];
- dma_unmap_single(msg->dev, dma_address, dma_length,
- DMA_TO_DEVICE);
+ if (!dma_mapping_error(dma_address))
+ dma_unmap_single(msg->dev, dma_address, dma_length,
+ DMA_TO_DEVICE);
if (msg->skb) {
dev_kfree_skb_any(msg->skb);
@@ -1066,15 +1250,16 @@
memset(&msg->data, 0, sizeof(msg->data));
veth_stack_push(cnx, msg);
- } else
- if (cnx->state & VETH_STATE_OPEN)
- veth_error("Bogus frames ack from lpar %d (#%d)\n",
- cnx->remote_lp, msg->token);
+ } else if (cnx->state & VETH_STATE_OPEN) {
+ veth_error("Non-pending frame (# %d) acked by LPAR %d.\n",
+ cnx->remote_lp, msg->token);
+ }
}
-static void veth_flush_pending(struct veth_lpar_connection *cnx)
+static void veth_wake_queues(struct veth_lpar_connection *cnx)
{
int i;
+
for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
struct net_device *dev = veth_dev[i];
struct veth_port *port;
@@ -1088,22 +1273,79 @@
if (! (port->lpar_map & (1<<cnx->remote_lp)))
continue;
- spin_lock_irqsave(&port->pending_gate, flags);
- if (port->pending_skb) {
- port->pending_lpmask =
- veth_transmit_to_many(port->pending_skb,
- port->pending_lpmask,
- dev);
- if (! port->pending_lpmask) {
- dev_kfree_skb_any(port->pending_skb);
- port->pending_skb = NULL;
- netif_wake_queue(dev);
- }
+ spin_lock_irqsave(&port->queue_lock, flags);
+
+ port->stopped_map &= ~(1 << cnx->remote_lp);
+
+ if (0 == port->stopped_map && netif_queue_stopped(dev)) {
+ veth_debug("cnx %d: woke queue for %s.\n",
+ cnx->remote_lp, dev->name);
+ netif_wake_queue(dev);
}
- spin_unlock_irqrestore(&port->pending_gate, flags);
+ spin_unlock_irqrestore(&port->queue_lock, flags);
}
}
+static void veth_stop_queues(struct veth_lpar_connection *cnx)
+{
+ int i;
+
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+ struct net_device *dev = veth_dev[i];
+ struct veth_port *port;
+
+ if (! dev)
+ continue;
+
+ port = (struct veth_port *)dev->priv;
+
+ /* If this cnx is not on the vlan for this port, continue */
+ if (! (port->lpar_map & (1 << cnx->remote_lp)))
+ continue;
+
+ spin_lock(&port->queue_lock);
+
+ netif_stop_queue(dev);
+ port->stopped_map |= (1 << cnx->remote_lp);
+
+ veth_debug("cnx %d: stopped queue for %s, map = 0x%x.\n",
+ cnx->remote_lp, dev->name, port->stopped_map);
+
+ spin_unlock(&port->queue_lock);
+ }
+}
+
+static void veth_timed_reset(unsigned long ptr)
+{
+ struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)ptr;
+ unsigned long trigger_time, flags;
+
+ /* FIXME is it possible this fires after veth_stop_connection()?
+ * That would reschedule the statemachine for 5 seconds and probably
+ * execute it after the module's been unloaded. Hmm. */
+
+ spin_lock_irqsave(&cnx->lock, flags);
+
+ if (cnx->outstanding_tx > 0) {
+ trigger_time = cnx->last_contact + cnx->reset_timeout;
+
+ if (trigger_time < jiffies) {
+ cnx->state |= VETH_STATE_RESET;
+ veth_kick_statemachine(cnx);
+ veth_error("%d packets not acked by LPAR %d within %d "
+ "seconds, resetting.\n",
+ cnx->outstanding_tx, cnx->remote_lp,
+ cnx->reset_timeout / HZ);
+ } else {
+ /* Reschedule the timer */
+ trigger_time = jiffies + cnx->reset_timeout;
+ mod_timer(&cnx->reset_timer, trigger_time);
+ }
+ }
+
+ spin_unlock_irqrestore(&cnx->lock, flags);
+}
+
/*
* Rx path
*/
@@ -1117,12 +1359,9 @@
if ( (mac_addr == port->mac_addr) || (mac_addr == 0xffffffffffff0000) )
return 1;
- if (! (((char *) &mac_addr)[0] & 0x01))
- return 0;
-
read_lock_irqsave(&port->mcast_gate, flags);
- if (port->promiscuous || port->all_mcast) {
+ if (port->promiscuous) {
wanted = 1;
goto out;
}
@@ -1175,21 +1414,21 @@
{
HvLpEvent_Rc rc;
- rc = veth_signaldata(cnx, VethEventTypeFramesAck,
+ rc = veth_signaldata(cnx, VETH_EVENT_FRAMES_ACK,
0, &cnx->pending_acks);
if (rc != HvLpEvent_Rc_Good)
- veth_error("Error 0x%x acking frames from lpar %d!\n",
- (unsigned)rc, cnx->remote_lp);
+ veth_error("Failed acking frames from LPAR %d, rc = %d\n",
+ cnx->remote_lp, (int)rc);
cnx->num_pending_acks = 0;
memset(&cnx->pending_acks, 0xff, sizeof(cnx->pending_acks));
}
static void veth_receive(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
- struct VethFramesData *senddata = &event->u.frames_data;
+ struct veth_frames_data *senddata = &event->u.frames_data;
int startchunk = 0;
int nchunks;
unsigned long flags;
@@ -1216,9 +1455,10 @@
/* make sure that we have at least 1 EOF entry in the
* remaining entries */
if (! (senddata->eofmask >> (startchunk + VETH_EOF_SHIFT))) {
- veth_error("missing EOF frag in event "
- "eofmask=0x%x startchunk=%d\n",
- (unsigned) senddata->eofmask, startchunk);
+ veth_error("Missing EOF fragment in event "
+ "eofmask = 0x%x startchunk = %d\n",
+ (unsigned)senddata->eofmask,
+ startchunk);
break;
}
@@ -1237,8 +1477,9 @@
/* nchunks == # of chunks in this frame */
if ((length - ETH_HLEN) > VETH_MAX_MTU) {
- veth_error("Received oversize frame from lpar %d "
- "(length=%d)\n", cnx->remote_lp, length);
+ veth_error("Received oversize frame from LPAR %d "
+ "(length = %d)\n",
+ cnx->remote_lp, length);
continue;
}
@@ -1331,15 +1572,33 @@
static int veth_remove(struct vio_dev *vdev)
{
- int i = vdev->unit_address;
+ struct veth_lpar_connection *cnx;
struct net_device *dev;
+ struct veth_port *port;
+ int i;
- dev = veth_dev[i];
- if (dev != NULL) {
- veth_dev[i] = NULL;
- unregister_netdev(dev);
- free_netdev(dev);
+ dev = veth_dev[vdev->unit_address];
+
+ if (! dev)
+ return 0;
+
+ port = netdev_priv(dev);
+
+ for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+ cnx = veth_cnx[i];
+
+ if (cnx && (port->lpar_map & (1 << i))) {
+ /* Drop our reference to connections on our VLAN */
+ kobject_put(&cnx->kobject);
+ }
}
+
+ veth_dev[vdev->unit_address] = NULL;
+ kobject_del(&port->kobject);
+ kobject_put(&port->kobject);
+ unregister_netdev(dev);
+ free_netdev(dev);
+
return 0;
}
@@ -1347,6 +1606,7 @@
{
int i = vdev->unit_address;
struct net_device *dev;
+ struct veth_port *port;
dev = veth_probe_one(i, &vdev->dev);
if (dev == NULL) {
@@ -1355,11 +1615,23 @@
}
veth_dev[i] = dev;
- /* Start the state machine on each connection, to commence
- * link negotiation */
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++)
- if (veth_cnx[i])
- veth_kick_statemachine(veth_cnx[i]);
+ port = (struct veth_port*)netdev_priv(dev);
+
+ /* Start the state machine on each connection on this vlan. If we're
+ * the first dev to do so this will commence link negotiation */
+ for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+ struct veth_lpar_connection *cnx;
+
+ if (! (port->lpar_map & (1 << i)))
+ continue;
+
+ cnx = veth_cnx[i];
+ if (!cnx)
+ continue;
+
+ kobject_get(&cnx->kobject);
+ veth_kick_statemachine(cnx);
+ }
return 0;
}
@@ -1375,7 +1647,7 @@
MODULE_DEVICE_TABLE(vio, veth_device_table);
static struct vio_driver veth_driver = {
- .name = "iseries_veth",
+ .name = DRV_NAME,
.id_table = veth_device_table,
.probe = veth_probe,
.remove = veth_remove
@@ -1388,29 +1660,29 @@
void __exit veth_module_cleanup(void)
{
int i;
+ struct veth_lpar_connection *cnx;
- /* Stop the queues first to stop any new packets being sent. */
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
- if (veth_dev[i])
- netif_stop_queue(veth_dev[i]);
-
- /* Stop the connections before we unregister the driver. This
- * ensures there's no skbs lying around holding the device open. */
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
- veth_stop_connection(i);
-
+ /* Disconnect our "irq" to stop events coming from the Hypervisor. */
HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
- /* Hypervisor callbacks may have scheduled more work while we
- * were stoping connections. Now that we've disconnected from
- * the hypervisor make sure everything's finished. */
+ /* Make sure any work queued from Hypervisor callbacks is finished. */
flush_scheduled_work();
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ cnx = veth_cnx[i];
+
+ if (!cnx)
+ continue;
+
+ /* Remove the connection from sysfs */
+ kobject_del(&cnx->kobject);
+ /* Drop the driver's reference to the connection */
+ kobject_put(&cnx->kobject);
+ }
+
+ /* Unregister the driver, which will close all the netdevs and stop
+ * the connections when they're no longer referenced. */
vio_unregister_driver(&veth_driver);
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
- veth_destroy_connection(i);
-
}
module_exit(veth_module_cleanup);
@@ -1423,15 +1695,37 @@
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
rc = veth_init_connection(i);
- if (rc != 0) {
- veth_module_cleanup();
- return rc;
- }
+ if (rc != 0)
+ goto error;
}
HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan,
&veth_handle_event);
- return vio_register_driver(&veth_driver);
+ rc = vio_register_driver(&veth_driver);
+ if (rc != 0)
+ goto error;
+
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ struct kobject *kobj;
+
+ if (!veth_cnx[i])
+ continue;
+
+ kobj = &veth_cnx[i]->kobject;
+ kobj->parent = &veth_driver.driver.kobj;
+ /* If the add failes, complain but otherwise continue */
+ if (0 != kobject_add(kobj))
+ veth_error("cnx %d: Failed adding to sysfs.\n", i);
+ }
+
+ return 0;
+
+error:
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ veth_destroy_connection(veth_cnx[i]);
+ }
+
+ return rc;
}
module_init(veth_module_init);
diff --git a/drivers/net/iseries_veth.h b/drivers/net/iseries_veth.h
deleted file mode 100644
index d9370f7..0000000
--- a/drivers/net/iseries_veth.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* File veth.h created by Kyle A. Lucke on Mon Aug 7 2000. */
-
-#ifndef _ISERIES_VETH_H
-#define _ISERIES_VETH_H
-
-#define VethEventTypeCap (0)
-#define VethEventTypeFrames (1)
-#define VethEventTypeMonitor (2)
-#define VethEventTypeFramesAck (3)
-
-#define VETH_MAX_ACKS_PER_MSG (20)
-#define VETH_MAX_FRAMES_PER_MSG (6)
-
-struct VethFramesData {
- u32 addr[VETH_MAX_FRAMES_PER_MSG];
- u16 len[VETH_MAX_FRAMES_PER_MSG];
- u32 eofmask;
-};
-#define VETH_EOF_SHIFT (32-VETH_MAX_FRAMES_PER_MSG)
-
-struct VethFramesAckData {
- u16 token[VETH_MAX_ACKS_PER_MSG];
-};
-
-struct VethCapData {
- u8 caps_version;
- u8 rsvd1;
- u16 num_buffers;
- u16 ack_threshold;
- u16 rsvd2;
- u32 ack_timeout;
- u32 rsvd3;
- u64 rsvd4[3];
-};
-
-struct VethLpEvent {
- struct HvLpEvent base_event;
- union {
- struct VethCapData caps_data;
- struct VethFramesData frames_data;
- struct VethFramesAckData frames_ack_data;
- } u;
-
-};
-
-#endif /* _ISERIES_VETH_H */
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index fb6b232..7c9dbc8 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -58,11 +58,10 @@
#define INT_CAUSE_UNMASK_ALL 0x0007ffff
#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff
-#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK
#define INT_CAUSE_MASK_ALL 0x00000000
+#define INT_CAUSE_MASK_ALL_EXT 0x00000000
#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL
#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT
-#endif
#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1)
@@ -259,14 +258,13 @@
static void mv643xx_eth_set_rx_mode(struct net_device *dev)
{
struct mv643xx_private *mp = netdev_priv(dev);
- u32 config_reg;
- config_reg = ethernet_get_config_reg(mp->port_num);
if (dev->flags & IFF_PROMISC)
- config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+ mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
else
- config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
- ethernet_set_config_reg(mp->port_num, config_reg);
+ mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+
+ mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config);
}
/*
@@ -369,15 +367,6 @@
dev_kfree_skb_irq(pkt_info.return_info);
released = 0;
-
- /*
- * Decrement the number of outstanding skbs counter on
- * the TX queue.
- */
- if (mp->tx_ring_skbs == 0)
- panic("ERROR - TX outstanding SKBs"
- " counter is corrupted");
- mp->tx_ring_skbs--;
} else
dma_unmap_page(NULL, pkt_info.buf_ptr,
pkt_info.byte_cnt, DMA_TO_DEVICE);
@@ -412,15 +401,13 @@
struct pkt_info pkt_info;
#ifdef MV643XX_NAPI
- while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {
+ while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
#else
while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
#endif
mp->rx_ring_skbs--;
received_packets++;
-#ifdef MV643XX_NAPI
- budget--;
-#endif
+
/* Update statistics. Note byte count includes 4 byte CRC count */
stats->rx_packets++;
stats->rx_bytes += pkt_info.byte_cnt;
@@ -1044,9 +1031,6 @@
DMA_TO_DEVICE);
dev_kfree_skb_irq(pkt_info.return_info);
-
- if (mp->tx_ring_skbs)
- mp->tx_ring_skbs--;
} else
dma_unmap_page(NULL, pkt_info.buf_ptr,
pkt_info.byte_cnt, DMA_TO_DEVICE);
@@ -1189,7 +1173,6 @@
pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
DMA_TO_DEVICE);
pkt_info.return_info = skb;
- mp->tx_ring_skbs++;
status = eth_port_send(mp, &pkt_info);
if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
printk(KERN_ERR "%s: Error on transmitting packet\n",
@@ -1274,7 +1257,6 @@
pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
ETH_TX_LAST_DESC;
pkt_info.return_info = skb;
- mp->tx_ring_skbs++;
} else {
pkt_info.return_info = 0;
}
@@ -1311,7 +1293,6 @@
pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len,
DMA_TO_DEVICE);
pkt_info.return_info = skb;
- mp->tx_ring_skbs++;
status = eth_port_send(mp, &pkt_info);
if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
printk(KERN_ERR "%s: Error on transmitting packet\n",
@@ -1356,6 +1337,43 @@
return &mp->stats;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static inline void mv643xx_enable_irq(struct mv643xx_private *mp)
+{
+ int port_num = mp->port_num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mp->lock, flags);
+ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+ INT_CAUSE_UNMASK_ALL);
+ mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+ INT_CAUSE_UNMASK_ALL_EXT);
+ spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static inline void mv643xx_disable_irq(struct mv643xx_private *mp)
+{
+ int port_num = mp->port_num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mp->lock, flags);
+ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+ INT_CAUSE_MASK_ALL);
+ mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+ INT_CAUSE_MASK_ALL_EXT);
+ spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static void mv643xx_netpoll(struct net_device *netdev)
+{
+ struct mv643xx_private *mp = netdev_priv(netdev);
+
+ mv643xx_disable_irq(mp);
+ mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
+ mv643xx_enable_irq(mp);
+}
+#endif
+
/*/
* mv643xx_eth_probe
*
@@ -1406,6 +1424,10 @@
dev->weight = 64;
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = mv643xx_netpoll;
+#endif
+
dev->watchdog_timeo = 2 * HZ;
dev->tx_queue_len = mp->tx_ring_size;
dev->base_addr = 0;
@@ -1883,6 +1905,9 @@
/* Enable port Rx. */
mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
mp->port_rx_queue_command);
+
+ /* Disable port bandwidth limits by clearing MTU register */
+ mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
}
/*
@@ -2292,34 +2317,6 @@
mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
}
-/*
- * ethernet_set_config_reg - Set specified bits in configuration register.
- *
- * DESCRIPTION:
- * This function sets specified bits in the given ethernet
- * configuration register.
- *
- * INPUT:
- * unsigned int eth_port_num Ethernet Port number.
- * unsigned int value 32 bit value.
- *
- * OUTPUT:
- * The set bits in the value parameter are set in the configuration
- * register.
- *
- * RETURN:
- * None.
- *
- */
-static void ethernet_set_config_reg(unsigned int eth_port_num,
- unsigned int value)
-{
- unsigned int eth_config_reg;
-
- eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num));
- eth_config_reg |= value;
- mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg);
-}
static int eth_port_autoneg_supported(unsigned int eth_port_num)
{
@@ -2346,31 +2343,6 @@
}
/*
- * ethernet_get_config_reg - Get the port configuration register
- *
- * DESCRIPTION:
- * This function returns the configuration register value of the given
- * ethernet port.
- *
- * INPUT:
- * unsigned int eth_port_num Ethernet Port number.
- *
- * OUTPUT:
- * None.
- *
- * RETURN:
- * Port configuration register value.
- */
-static unsigned int ethernet_get_config_reg(unsigned int eth_port_num)
-{
- unsigned int eth_config_reg;
-
- eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG
- (eth_port_num));
- return eth_config_reg;
-}
-
-/*
* eth_port_read_smi_reg - Read PHY registers
*
* DESCRIPTION:
@@ -2528,6 +2500,9 @@
return ETH_ERROR;
}
+ mp->tx_ring_skbs++;
+ BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+
/* Get the Tx Desc ring indexes */
tx_desc_curr = mp->tx_curr_desc_q;
tx_desc_used = mp->tx_used_desc_q;
@@ -2594,6 +2569,9 @@
if (mp->tx_resource_err)
return ETH_QUEUE_FULL;
+ mp->tx_ring_skbs++;
+ BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+
/* Get the Tx Desc ring indexes */
tx_desc_curr = mp->tx_curr_desc_q;
tx_desc_used = mp->tx_used_desc_q;
@@ -2694,6 +2672,9 @@
/* Any Tx return cancels the Tx resource error status */
mp->tx_resource_err = 0;
+ BUG_ON(mp->tx_ring_skbs == 0);
+ mp->tx_ring_skbs--;
+
return ETH_OK;
}
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 7678b59..bcfda51 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -408,10 +408,6 @@
static void eth_port_reset(unsigned int eth_port_num);
static void eth_port_start(struct mv643xx_private *mp);
-static void ethernet_set_config_reg(unsigned int eth_port_num,
- unsigned int value);
-static unsigned int ethernet_get_config_reg(unsigned int eth_port_num);
-
/* Port MAC address routines */
static void eth_port_uc_addr_set(unsigned int eth_port_num,
unsigned char *p_addr);
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 6c92f09..73501d8 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -26,9 +26,6 @@
Updated to EISA probing API 5/2003 by Marc Zyngier.
*/
-static const char *version =
- "ne3210.c: Driver revision v0.03, 30/09/98\n";
-
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
@@ -197,7 +194,7 @@
ei_status.priv = phys_mem;
if (ei_debug > 0)
- printk(version);
+ printk("ne3210 loaded.\n");
ei_status.reset_8390 = &ne3210_reset_8390;
ei_status.block_input = &ne3210_block_input;
@@ -360,12 +357,12 @@
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-int ne3210_init(void)
+static int ne3210_init(void)
{
return eisa_driver_register (&ne3210_eisa_driver);
}
-void ne3210_cleanup(void)
+static void ne3210_cleanup(void)
{
eisa_driver_unregister (&ne3210_eisa_driver);
}
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 6a2fe35..14f4de1 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -6,7 +6,7 @@
config PHYLIB
tristate "PHY Device support and infrastructure"
- depends on NET_ETHERNET
+ depends on NET_ETHERNET && (BROKEN || !ARCH_S390)
help
Ethernet controllers are usually attached to PHY
devices. This option provides infrastructure for
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 41f62c0..9063067 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -128,7 +128,7 @@
/* Suspend and resume. Copied from platform_suspend and
* platform_resume
*/
-static int mdio_bus_suspend(struct device * dev, u32 state)
+static int mdio_bus_suspend(struct device * dev, pm_message_t state)
{
int ret = 0;
struct device_driver *drv = dev->driver;
@@ -170,7 +170,7 @@
return bus_register(&mdio_bus_type);
}
-void __exit mdio_bus_exit(void)
+void mdio_bus_exit(void)
{
bus_unregister(&mdio_bus_type);
}
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 2234a8f..7cefe55 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,5 +1,5 @@
/************************************************************************
- * regs.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
* Copyright(c) 2002-2005 Neterion Inc.
* This software may be used and distributed according to the terms of
@@ -713,13 +713,16 @@
u64 mc_err_reg;
#define MC_ERR_REG_ECC_DB_ERR_L BIT(14)
#define MC_ERR_REG_ECC_DB_ERR_U BIT(15)
+#define MC_ERR_REG_MIRI_ECC_DB_ERR_0 BIT(18)
+#define MC_ERR_REG_MIRI_ECC_DB_ERR_1 BIT(20)
#define MC_ERR_REG_MIRI_CRI_ERR_0 BIT(22)
#define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23)
#define MC_ERR_REG_SM_ERR BIT(31)
-#define MC_ERR_REG_ECC_ALL_SNG (BIT(6) | \
- BIT(7) | BIT(17) | BIT(19))
-#define MC_ERR_REG_ECC_ALL_DBL (BIT(14) | \
- BIT(15) | BIT(18) | BIT(20))
+#define MC_ERR_REG_ECC_ALL_SNG (BIT(2) | BIT(3) | BIT(4) | BIT(5) |\
+ BIT(6) | BIT(7) | BIT(17) | BIT(19))
+#define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\
+ BIT(13) | BIT(14) | BIT(15) |\
+ BIT(18) | BIT(20))
u64 mc_err_mask;
u64 mc_err_alarm;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 7ca7822..c829e6a 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,5 +1,5 @@
/************************************************************************
- * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
* Copyright(c) 2002-2005 Neterion Inc.
* This software may be used and distributed according to the terms of
@@ -28,7 +28,7 @@
* explaination of all the variables.
* rx_ring_num : This can be used to program the number of receive rings used
* in the driver.
- * rx_ring_len: This defines the number of descriptors each ring can have. This
+ * rx_ring_sz: This defines the number of descriptors each ring can have. This
* is also an array of size 8.
* tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
* tx_fifo_len: This too is an array of 8. Each element defines the number of
@@ -67,7 +67,7 @@
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
-static char s2io_driver_version[] = "Version 2.0.3.1";
+static char s2io_driver_version[] = "Version 2.0.8.1";
static inline int RXD_IS_UP2DT(RxD_t *rxdp)
{
@@ -354,7 +354,7 @@
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
#ifdef CONFIG_2BUFF_MODE
- u64 tmp;
+ unsigned long tmp;
buffAdd_t *ba;
#endif
@@ -404,7 +404,7 @@
config->tx_cfg[i].fifo_len - 1;
mac_control->fifos[i].fifo_no = i;
mac_control->fifos[i].nic = nic;
- mac_control->fifos[i].max_txds = MAX_SKB_FRAGS;
+ mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1;
for (j = 0; j < page_num; j++) {
int k = 0;
@@ -418,6 +418,26 @@
DBG_PRINT(ERR_DBG, "failed for TxDL\n");
return -ENOMEM;
}
+ /* If we got a zero DMA address(can happen on
+ * certain platforms like PPC), reallocate.
+ * Store virtual address of page we don't want,
+ * to be freed later.
+ */
+ if (!tmp_p) {
+ mac_control->zerodma_virt_addr = tmp_v;
+ DBG_PRINT(INIT_DBG,
+ "%s: Zero DMA address for TxDL. ", dev->name);
+ DBG_PRINT(INIT_DBG,
+ "Virtual address %llx\n", (u64)tmp_v);
+ tmp_v = pci_alloc_consistent(nic->pdev,
+ PAGE_SIZE, &tmp_p);
+ if (!tmp_v) {
+ DBG_PRINT(ERR_DBG,
+ "pci_alloc_consistent ");
+ DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ return -ENOMEM;
+ }
+ }
while (k < lst_per_page) {
int l = (j * lst_per_page) + k;
if (l == config->tx_cfg[i].fifo_len)
@@ -542,18 +562,18 @@
(BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_0_org)
return -ENOMEM;
- tmp = (u64) ba->ba_0_org;
+ tmp = (unsigned long) ba->ba_0_org;
tmp += ALIGN_SIZE;
- tmp &= ~((u64) ALIGN_SIZE);
+ tmp &= ~((unsigned long) ALIGN_SIZE);
ba->ba_0 = (void *) tmp;
ba->ba_1_org = (void *) kmalloc
(BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_1_org)
return -ENOMEM;
- tmp = (u64) ba->ba_1_org;
+ tmp = (unsigned long) ba->ba_1_org;
tmp += ALIGN_SIZE;
- tmp &= ~((u64) ALIGN_SIZE);
+ tmp &= ~((unsigned long) ALIGN_SIZE);
ba->ba_1 = (void *) tmp;
k++;
}
@@ -600,7 +620,7 @@
mac_info_t *mac_control;
struct config_param *config;
int lst_size, lst_per_page;
-
+ struct net_device *dev = nic->dev;
if (!nic)
return;
@@ -616,9 +636,10 @@
lst_per_page);
for (j = 0; j < page_num; j++) {
int mem_blks = (j * lst_per_page);
- if ((!mac_control->fifos[i].list_info) ||
- (!mac_control->fifos[i].list_info[mem_blks].
- list_virt_addr))
+ if (!mac_control->fifos[i].list_info)
+ return;
+ if (!mac_control->fifos[i].list_info[mem_blks].
+ list_virt_addr)
break;
pci_free_consistent(nic->pdev, PAGE_SIZE,
mac_control->fifos[i].
@@ -628,6 +649,18 @@
list_info[mem_blks].
list_phy_addr);
}
+ /* If we got a zero DMA address during allocation,
+ * free the page now
+ */
+ if (mac_control->zerodma_virt_addr) {
+ pci_free_consistent(nic->pdev, PAGE_SIZE,
+ mac_control->zerodma_virt_addr,
+ (dma_addr_t)0);
+ DBG_PRINT(INIT_DBG,
+ "%s: Freeing TxDL with zero DMA addr. ", dev->name);
+ DBG_PRINT(INIT_DBG, "Virtual address %llx\n",
+ (u64)(mac_control->zerodma_virt_addr));
+ }
kfree(mac_control->fifos[i].list_info);
}
@@ -686,7 +719,7 @@
static int s2io_verify_pci_mode(nic_t *nic)
{
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ XENA_dev_config_t __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
@@ -704,7 +737,7 @@
*/
static int s2io_print_pci_mode(nic_t *nic)
{
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ XENA_dev_config_t __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
struct config_param *config = &nic->config;
@@ -1403,7 +1436,7 @@
writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
/* Disable RMAC PAD STRIPPING */
- add = (void *) &bar0->mac_cfg;
+ add = &bar0->mac_cfg;
val64 = readq(&bar0->mac_cfg);
val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
@@ -1934,7 +1967,7 @@
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
- writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
+ writeq(val64, (void __iomem *)bar0 + 0x2700);
}
/*
@@ -2395,7 +2428,7 @@
int pkt_cnt = 0, org_pkts_to_process;
mac_info_t *mac_control;
struct config_param *config;
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ XENA_dev_config_t __iomem *bar0 = nic->bar0;
u64 val64;
int i;
@@ -2479,9 +2512,10 @@
#endif
spin_lock(&nic->rx_lock);
if (atomic_read(&nic->card_state) == CARD_DOWN) {
- DBG_PRINT(ERR_DBG, "%s: %s going down for reset\n",
+ DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
__FUNCTION__, dev->name);
spin_unlock(&nic->rx_lock);
+ return;
}
get_info = ring_data->rx_curr_get_info;
@@ -2596,8 +2630,14 @@
if (txdlp->Control_1 & TXD_T_CODE) {
unsigned long long err;
err = txdlp->Control_1 & TXD_T_CODE;
- DBG_PRINT(ERR_DBG, "***TxD error %llx\n",
- err);
+ if ((err >> 48) == 0xA) {
+ DBG_PRINT(TX_DBG, "TxD returned due \
+ to loss of link\n");
+ }
+ else {
+ DBG_PRINT(ERR_DBG, "***TxD error \
+ %llx\n", err);
+ }
}
skb = (struct sk_buff *) ((unsigned long)
@@ -2689,12 +2729,16 @@
if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
nic->mac_control.stats_info->sw_stat.
double_ecc_errs++;
- DBG_PRINT(ERR_DBG, "%s: Device indicates ",
+ DBG_PRINT(INIT_DBG, "%s: Device indicates ",
dev->name);
- DBG_PRINT(ERR_DBG, "double ECC error!!\n");
+ DBG_PRINT(INIT_DBG, "double ECC error!!\n");
if (nic->device_type != XFRAME_II_DEVICE) {
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
+ /* Reset XframeI only if critical error */
+ if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+ MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
+ netif_stop_queue(dev);
+ schedule_work(&nic->rst_timer_task);
+ }
}
} else {
nic->mac_control.stats_info->sw_stat.
@@ -2706,7 +2750,8 @@
val64 = readq(&bar0->serr_source);
if (val64 & SERR_SOURCE_ANY) {
DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
- DBG_PRINT(ERR_DBG, "serious error!!\n");
+ DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
+ (unsigned long long)val64);
netif_stop_queue(dev);
schedule_work(&nic->rst_timer_task);
}
@@ -2831,7 +2876,7 @@
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
- writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
+ writeq(val64, (void __iomem *)bar0 + 0x2700);
}
/*
@@ -3130,7 +3175,7 @@
queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
/* Avoid "put" pointer going beyond "get" pointer */
if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
- DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n");
+ DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
netif_stop_queue(dev);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&sp->tx_lock, flags);
@@ -3234,7 +3279,7 @@
static void s2io_txpic_intr_handle(nic_t *sp)
{
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->pic_int_status);
@@ -3528,7 +3573,7 @@
val64 = readq(&bar0->mac_cfg);
sp->promisc_flg = 1;
- DBG_PRINT(ERR_DBG, "%s: entered promiscuous mode\n",
+ DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
dev->name);
} else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
/* Remove the NIC from promiscuous mode */
@@ -3543,7 +3588,7 @@
val64 = readq(&bar0->mac_cfg);
sp->promisc_flg = 0;
- DBG_PRINT(ERR_DBG, "%s: left promiscuous mode\n",
+ DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
dev->name);
}
@@ -5325,7 +5370,7 @@
break;
}
}
- config->max_txds = MAX_SKB_FRAGS;
+ config->max_txds = MAX_SKB_FRAGS + 1;
/* Rx side parameters. */
if (rx_ring_sz[0] == 0)
@@ -5525,9 +5570,14 @@
if (sp->device_type & XFRAME_II_DEVICE) {
DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
dev->name);
- DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n",
+ DBG_PRINT(ERR_DBG, "(rev %d), %s",
get_xena_rev_id(sp->pdev),
s2io_driver_version);
+#ifdef CONFIG_2BUFF_MODE
+ DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
+#endif
+
+ DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
sp->def_mac_addr[0].mac_addr[0],
sp->def_mac_addr[0].mac_addr[1],
@@ -5544,9 +5594,13 @@
} else {
DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
dev->name);
- DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n",
+ DBG_PRINT(ERR_DBG, "(rev %d), %s",
get_xena_rev_id(sp->pdev),
s2io_driver_version);
+#ifdef CONFIG_2BUFF_MODE
+ DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
+#endif
+ DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
sp->def_mac_addr[0].mac_addr[0],
sp->def_mac_addr[0].mac_addr[1],
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index bc64d96..89151cb 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,5 +1,5 @@
/************************************************************************
- * s2io.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
* Copyright(c) 2002-2005 Neterion Inc.
* This software may be used and distributed according to the terms of
@@ -622,6 +622,9 @@
/* Fifo specific structure */
fifo_info_t fifos[MAX_TX_FIFOS];
+ /* Save virtual address of TxD page with zero DMA addr(if any) */
+ void *zerodma_virt_addr;
+
/* rx side stuff */
/* Ring specific structure */
ring_info_t rings[MAX_RX_RINGS];
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index bf3440a..92f7552 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -179,14 +179,6 @@
TxInterFrameGapShift = 24,
TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
- /* StationControl */
- _1000bpsF = 0x1c00,
- _1000bpsH = 0x0c00,
- _100bpsF = 0x1800,
- _100bpsH = 0x0800,
- _10bpsF = 0x1400,
- _10bpsH = 0x0400,
-
LinkStatus = 0x02, // unused
FullDup = 0x01, // unused
@@ -279,6 +271,12 @@
EEPROMMACAddr = 0x03
};
+enum sis190_feature {
+ F_HAS_RGMII = 1,
+ F_PHY_88E1111 = 2,
+ F_PHY_BCM5461 = 4
+};
+
struct sis190_private {
void __iomem *mmio_addr;
struct pci_dev *pci_dev;
@@ -300,6 +298,7 @@
u32 msg_enable;
struct mii_if_info mii_if;
struct list_head first_phy;
+ u32 features;
};
struct sis190_phy {
@@ -321,24 +320,25 @@
const char *name;
u16 id[2];
unsigned int type;
+ u32 feature;
} mii_chip_table[] = {
- { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN },
- { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN },
- { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN },
- { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN },
+ { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 },
+ { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 },
+ { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 },
+ { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN, 0 },
{ NULL, }
};
const static struct {
const char *name;
- u8 version; /* depend on docs */
- u32 RxConfigMask; /* clear the bits supported by this chip */
} sis_chip_info[] = {
- { DRV_NAME, 0x00, 0xff7e1880, },
+ { "SiS 190 PCI Fast Ethernet adapter" },
+ { "SiS 191 PCI Gigabit Ethernet adapter" },
};
static struct pci_device_id sis190_pci_tbl[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
{ 0, },
};
@@ -360,7 +360,7 @@
MODULE_LICENSE("GPL");
static const u32 sis190_intr_mask =
- RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt;
+ RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange;
/*
* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
@@ -879,11 +879,6 @@
SIS_W32(IntrStatus, 0xffffffff);
SIS_W32(IntrMask, 0x0);
- /*
- * Default is 100Mbps.
- * A bit strange: 100Mbps is 0x1801 elsewhere -- FR 2005/06/09
- */
- SIS_W16(StationControl, 0x1901);
SIS_W32(GMIIControl, 0x0);
SIS_W32(TxMacControl, 0x60);
SIS_W16(RxMacControl, 0x02);
@@ -923,35 +918,30 @@
BMSR_ANEGCOMPLETE)) {
net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n",
dev->name);
+ netif_carrier_off(dev);
mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
} else {
/* Rejoice ! */
struct {
int val;
+ u32 ctl;
const char *msg;
- u16 ctl;
} reg31[] = {
- { LPA_1000XFULL | LPA_SLCT,
- "1000 Mbps Full Duplex",
- 0x01 | _1000bpsF },
- { LPA_1000XHALF | LPA_SLCT,
- "1000 Mbps Half Duplex",
- 0x01 | _1000bpsH },
- { LPA_100FULL,
- "100 Mbps Full Duplex",
- 0x01 | _100bpsF },
- { LPA_100HALF,
- "100 Mbps Half Duplex",
- 0x01 | _100bpsH },
- { LPA_10FULL,
- "10 Mbps Full Duplex",
- 0x01 | _10bpsF },
- { LPA_10HALF,
- "10 Mbps Half Duplex",
- 0x01 | _10bpsH },
- { 0, "unknown", 0x0000 }
- }, *p;
+ { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000,
+ "1000 Mbps Full Duplex" },
+ { LPA_1000XHALF | LPA_SLCT, 0x07000c00,
+ "1000 Mbps Half Duplex" },
+ { LPA_100FULL, 0x04000800 | 0x00001000,
+ "100 Mbps Full Duplex" },
+ { LPA_100HALF, 0x04000800,
+ "100 Mbps Half Duplex" },
+ { LPA_10FULL, 0x04000400 | 0x00001000,
+ "10 Mbps Full Duplex" },
+ { LPA_10HALF, 0x04000400,
+ "10 Mbps Half Duplex" },
+ { 0, 0x04000400, "unknown" }
+ }, *p;
u16 adv;
val = mdio_read(ioaddr, phy_id, 0x1f);
@@ -964,12 +954,29 @@
val &= adv;
- for (p = reg31; p->ctl; p++) {
+ for (p = reg31; p->val; p++) {
if ((val & p->val) == p->val)
break;
}
- if (p->ctl)
- SIS_W16(StationControl, p->ctl);
+
+ p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
+
+ if ((tp->features & F_HAS_RGMII) &&
+ (tp->features & F_PHY_BCM5461)) {
+ // Set Tx Delay in RGMII mode.
+ mdio_write(ioaddr, phy_id, 0x18, 0xf1c7);
+ udelay(200);
+ mdio_write(ioaddr, phy_id, 0x1c, 0x8c00);
+ p->ctl |= 0x03000000;
+ }
+
+ SIS_W32(StationControl, p->ctl);
+
+ if (tp->features & F_HAS_RGMII) {
+ SIS_W32(RGDelay, 0x0441);
+ SIS_W32(RGDelay, 0x0440);
+ }
+
net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name,
p->msg);
netif_carrier_on(dev);
@@ -1308,6 +1315,7 @@
phy->type = (p->type == MIX) ?
((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
LAN : HOME) : p->type;
+ tp->features |= p->feature;
} else
phy->type = UNKNOWN;
@@ -1316,6 +1324,25 @@
(phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id);
}
+static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
+{
+ if (tp->features & F_PHY_88E1111) {
+ void __iomem *ioaddr = tp->mmio_addr;
+ int phy_id = tp->mii_if.phy_id;
+ u16 reg[2][2] = {
+ { 0x808b, 0x0ce1 },
+ { 0x808f, 0x0c60 }
+ }, *p;
+
+ p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1];
+
+ mdio_write(ioaddr, phy_id, 0x1b, p[0]);
+ udelay(200);
+ mdio_write(ioaddr, phy_id, 0x14, p[1]);
+ udelay(200);
+ }
+}
+
/**
* sis190_mii_probe - Probe MII PHY for sis190
* @dev: the net device to probe for
@@ -1366,6 +1393,8 @@
/* Select default PHY for mac */
sis190_default_phy(dev);
+ sis190_mii_probe_88e1111_fixup(tp);
+
mii_if->dev = dev;
mii_if->mdio_read = __mdio_read;
mii_if->mdio_write = __mdio_write;
@@ -1505,6 +1534,11 @@
netif_wake_queue(dev);
}
+static void sis190_set_rgmii(struct sis190_private *tp, u8 reg)
+{
+ tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0;
+}
+
static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
struct net_device *dev)
{
@@ -1532,6 +1566,8 @@
((u16 *)dev->dev_addr)[0] = le16_to_cpu(w);
}
+ sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
+
return 0;
}
@@ -1577,6 +1613,8 @@
outb(0x12, 0x78);
reg = inb(0x79);
+ sis190_set_rgmii(tp, reg);
+
/* Restore the value to ISA Bridge */
pci_write_config_byte(isa_bridge, 0x48, tmp8);
pci_dev_put(isa_bridge);
@@ -1799,6 +1837,9 @@
dev->dev_addr[2], dev->dev_addr[3],
dev->dev_addr[4], dev->dev_addr[5]);
+ net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
+ (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
+
netif_carrier_off(dev);
sis190_set_speed_auto(dev);
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index a9b06b8..ac9ce65 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -986,7 +986,7 @@
})
#endif
-#if SMC_CAN_USE_DATACS
+#ifdef SMC_CAN_USE_DATACS
#define SMC_PUSH_DATA(p, l) \
if ( lp->datacs ) { \
unsigned char *__ptr = (p); \
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
new file mode 100644
index 0000000..4e19220
--- /dev/null
+++ b/drivers/net/spider_net.c
@@ -0,0 +1,2334 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ * Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/firmware.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <asm/bitops.h>
+#include <asm/pci-bridge.h>
+#include <net/checksum.h>
+
+#include "spider_net.h"
+
+MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \
+ "<Jens.Osterkamp@de.ibm.com>");
+MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
+static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
+
+module_param(rx_descriptors, int, 0644);
+module_param(tx_descriptors, int, 0644);
+
+MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
+ "in rx chains");
+MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
+ "in tx chain");
+
+char spider_net_driver_name[] = "spidernet";
+
+static struct pci_device_id spider_net_pci_tbl[] = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
+
+/**
+ * spider_net_read_reg - reads an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to read from
+ *
+ * returns the content of the specified SMMIO register.
+ */
+static u32
+spider_net_read_reg(struct spider_net_card *card, u32 reg)
+{
+ u32 value;
+
+ value = readl(card->regs + reg);
+ value = le32_to_cpu(value);
+
+ return value;
+}
+
+/**
+ * spider_net_write_reg - writes to an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to write to
+ * @value: value to write into the specified SMMIO register
+ */
+static void
+spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
+{
+ value = cpu_to_le32(value);
+ writel(value, card->regs + reg);
+}
+
+/**
+ * spider_net_write_reg_sync - writes to an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to write to
+ * @value: value to write into the specified SMMIO register
+ *
+ * Unlike spider_net_write_reg, this will also make sure the
+ * data arrives on the card by reading the reg again.
+ */
+static void
+spider_net_write_reg_sync(struct spider_net_card *card, u32 reg, u32 value)
+{
+ value = cpu_to_le32(value);
+ writel(value, card->regs + reg);
+ (void)readl(card->regs + reg);
+}
+
+/**
+ * spider_net_rx_irq_off - switch off rx irq on this spider card
+ * @card: device structure
+ *
+ * switches off rx irq by masking them out in the GHIINTnMSK register
+ */
+static void
+spider_net_rx_irq_off(struct spider_net_card *card)
+{
+ u32 regvalue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->intmask_lock, flags);
+ regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+ regvalue &= ~SPIDER_NET_RXINT;
+ spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+ spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/** spider_net_write_phy - write to phy register
+ * @netdev: adapter to be written to
+ * @mii_id: id of MII
+ * @reg: PHY register
+ * @val: value to be written to phy register
+ *
+ * spider_net_write_phy_register writes to an arbitrary PHY
+ * register via the spider GPCWOPCMD register. We assume the queue does
+ * not run full (not more than 15 commands outstanding).
+ **/
+static void
+spider_net_write_phy(struct net_device *netdev, int mii_id,
+ int reg, int val)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ u32 writevalue;
+
+ writevalue = ((u32)mii_id << 21) |
+ ((u32)reg << 16) | ((u32)val);
+
+ spider_net_write_reg(card, SPIDER_NET_GPCWOPCMD, writevalue);
+}
+
+/** spider_net_read_phy - read from phy register
+ * @netdev: network device to be read from
+ * @mii_id: id of MII
+ * @reg: PHY register
+ *
+ * Returns value read from PHY register
+ *
+ * spider_net_write_phy reads from an arbitrary PHY
+ * register via the spider GPCROPCMD register
+ **/
+static int
+spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ u32 readvalue;
+
+ readvalue = ((u32)mii_id << 21) | ((u32)reg << 16);
+ spider_net_write_reg(card, SPIDER_NET_GPCROPCMD, readvalue);
+
+ /* we don't use semaphores to wait for an SPIDER_NET_GPROPCMPINT
+ * interrupt, as we poll for the completion of the read operation
+ * in spider_net_read_phy. Should take about 50 us */
+ do {
+ readvalue = spider_net_read_reg(card, SPIDER_NET_GPCROPCMD);
+ } while (readvalue & SPIDER_NET_GPREXEC);
+
+ readvalue &= SPIDER_NET_GPRDAT_MASK;
+
+ return readvalue;
+}
+
+/**
+ * spider_net_rx_irq_on - switch on rx irq on this spider card
+ * @card: device structure
+ *
+ * switches on rx irq by enabling them in the GHIINTnMSK register
+ */
+static void
+spider_net_rx_irq_on(struct spider_net_card *card)
+{
+ u32 regvalue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->intmask_lock, flags);
+ regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+ regvalue |= SPIDER_NET_RXINT;
+ spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+ spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/**
+ * spider_net_tx_irq_off - switch off tx irq on this spider card
+ * @card: device structure
+ *
+ * switches off tx irq by masking them out in the GHIINTnMSK register
+ */
+static void
+spider_net_tx_irq_off(struct spider_net_card *card)
+{
+ u32 regvalue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->intmask_lock, flags);
+ regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+ regvalue &= ~SPIDER_NET_TXINT;
+ spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+ spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/**
+ * spider_net_tx_irq_on - switch on tx irq on this spider card
+ * @card: device structure
+ *
+ * switches on tx irq by enabling them in the GHIINTnMSK register
+ */
+static void
+spider_net_tx_irq_on(struct spider_net_card *card)
+{
+ u32 regvalue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->intmask_lock, flags);
+ regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
+ regvalue |= SPIDER_NET_TXINT;
+ spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue);
+ spin_unlock_irqrestore(&card->intmask_lock, flags);
+}
+
+/**
+ * spider_net_set_promisc - sets the unicast address or the promiscuous mode
+ * @card: card structure
+ *
+ * spider_net_set_promisc sets the unicast destination address filter and
+ * thus either allows for non-promisc mode or promisc mode
+ */
+static void
+spider_net_set_promisc(struct spider_net_card *card)
+{
+ u32 macu, macl;
+ struct net_device *netdev = card->netdev;
+
+ if (netdev->flags & IFF_PROMISC) {
+ /* clear destination entry 0 */
+ spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, 0);
+ spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, 0);
+ spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
+ SPIDER_NET_PROMISC_VALUE);
+ } else {
+ macu = netdev->dev_addr[0];
+ macu <<= 8;
+ macu |= netdev->dev_addr[1];
+ memcpy(&macl, &netdev->dev_addr[2], sizeof(macl));
+
+ macu |= SPIDER_NET_UA_DESCR_VALUE;
+ spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, macu);
+ spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, macl);
+ spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
+ SPIDER_NET_NONPROMISC_VALUE);
+ }
+}
+
+/**
+ * spider_net_get_mac_address - read mac address from spider card
+ * @card: device structure
+ *
+ * reads MAC address from GMACUNIMACU and GMACUNIMACL registers
+ */
+static int
+spider_net_get_mac_address(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ u32 macl, macu;
+
+ macl = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACL);
+ macu = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACU);
+
+ netdev->dev_addr[0] = (macu >> 24) & 0xff;
+ netdev->dev_addr[1] = (macu >> 16) & 0xff;
+ netdev->dev_addr[2] = (macu >> 8) & 0xff;
+ netdev->dev_addr[3] = macu & 0xff;
+ netdev->dev_addr[4] = (macl >> 8) & 0xff;
+ netdev->dev_addr[5] = macl & 0xff;
+
+ if (!is_valid_ether_addr(&netdev->dev_addr[0]))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * spider_net_get_descr_status -- returns the status of a descriptor
+ * @descr: descriptor to look at
+ *
+ * returns the status as in the dmac_cmd_status field of the descriptor
+ */
+static enum spider_net_descr_status
+spider_net_get_descr_status(struct spider_net_descr *descr)
+{
+ u32 cmd_status;
+ rmb();
+ cmd_status = descr->dmac_cmd_status;
+ rmb();
+ cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT;
+ /* no need to mask out any bits, as cmd_status is 32 bits wide only
+ * (and unsigned) */
+ return cmd_status;
+}
+
+/**
+ * spider_net_set_descr_status -- sets the status of a descriptor
+ * @descr: descriptor to change
+ * @status: status to set in the descriptor
+ *
+ * changes the status to the specified value. Doesn't change other bits
+ * in the status
+ */
+static void
+spider_net_set_descr_status(struct spider_net_descr *descr,
+ enum spider_net_descr_status status)
+{
+ u32 cmd_status;
+ /* read the status */
+ mb();
+ cmd_status = descr->dmac_cmd_status;
+ /* clean the upper 4 bits */
+ cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO;
+ /* add the status to it */
+ cmd_status |= ((u32)status)<<SPIDER_NET_DESCR_IND_PROC_SHIFT;
+ /* and write it back */
+ descr->dmac_cmd_status = cmd_status;
+ wmb();
+}
+
+/**
+ * spider_net_free_chain - free descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ *
+ */
+static void
+spider_net_free_chain(struct spider_net_card *card,
+ struct spider_net_descr_chain *chain)
+{
+ struct spider_net_descr *descr;
+
+ for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
+ pci_unmap_single(card->pdev, descr->bus_addr,
+ SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+ descr->bus_addr = 0;
+ }
+}
+
+/**
+ * spider_net_init_chain - links descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ * @start_descr: address of descriptor array
+ * @no: number of descriptors
+ *
+ * we manage a circular list that mirrors the hardware structure,
+ * except that the hardware uses bus addresses.
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_init_chain(struct spider_net_card *card,
+ struct spider_net_descr_chain *chain,
+ struct spider_net_descr *start_descr, int no)
+{
+ int i;
+ struct spider_net_descr *descr;
+
+ spin_lock_init(&card->chain_lock);
+
+ descr = start_descr;
+ memset(descr, 0, sizeof(*descr) * no);
+
+ /* set up the hardware pointers in each descriptor */
+ for (i=0; i<no; i++, descr++) {
+ spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+
+ descr->bus_addr =
+ pci_map_single(card->pdev, descr,
+ SPIDER_NET_DESCR_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+
+ if (descr->bus_addr == DMA_ERROR_CODE)
+ goto iommu_error;
+
+ descr->next = descr + 1;
+ descr->prev = descr - 1;
+
+ }
+ /* do actual circular list */
+ (descr-1)->next = start_descr;
+ start_descr->prev = descr-1;
+
+ descr = start_descr;
+ for (i=0; i < no; i++, descr++) {
+ descr->next_descr_addr = descr->next->bus_addr;
+ }
+
+ chain->head = start_descr;
+ chain->tail = start_descr;
+
+ return 0;
+
+iommu_error:
+ descr = start_descr;
+ for (i=0; i < no; i++, descr++)
+ if (descr->bus_addr)
+ pci_unmap_single(card->pdev, descr->bus_addr,
+ SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+ return -ENOMEM;
+}
+
+/**
+ * spider_net_free_rx_chain_contents - frees descr contents in rx chain
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static void
+spider_net_free_rx_chain_contents(struct spider_net_card *card)
+{
+ struct spider_net_descr *descr;
+
+ descr = card->rx_chain.head;
+ while (descr->next != card->rx_chain.head) {
+ if (descr->skb) {
+ dev_kfree_skb(descr->skb);
+ pci_unmap_single(card->pdev, descr->buf_addr,
+ SPIDER_NET_MAX_MTU,
+ PCI_DMA_BIDIRECTIONAL);
+ }
+ descr = descr->next;
+ }
+}
+
+/**
+ * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * @card: card structure
+ * @descr: descriptor to re-init
+ *
+ * return 0 on succes, <0 on failure
+ *
+ * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
+ * Activate the descriptor state-wise
+ */
+static int
+spider_net_prepare_rx_descr(struct spider_net_card *card,
+ struct spider_net_descr *descr)
+{
+ int error = 0;
+ int offset;
+ int bufsize;
+
+ /* we need to round up the buffer size to a multiple of 128 */
+ bufsize = (SPIDER_NET_MAX_MTU + SPIDER_NET_RXBUF_ALIGN - 1) &
+ (~(SPIDER_NET_RXBUF_ALIGN - 1));
+
+ /* and we need to have it 128 byte aligned, therefore we allocate a
+ * bit more */
+ /* allocate an skb */
+ descr->skb = dev_alloc_skb(bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
+ if (!descr->skb) {
+ if (net_ratelimit())
+ if (netif_msg_rx_err(card))
+ pr_err("Not enough memory to allocate "
+ "rx buffer\n");
+ return -ENOMEM;
+ }
+ descr->buf_size = bufsize;
+ descr->result_size = 0;
+ descr->valid_size = 0;
+ descr->data_status = 0;
+ descr->data_error = 0;
+
+ offset = ((unsigned long)descr->skb->data) &
+ (SPIDER_NET_RXBUF_ALIGN - 1);
+ if (offset)
+ skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
+ /* io-mmu-map the skb */
+ descr->buf_addr = pci_map_single(card->pdev, descr->skb->data,
+ SPIDER_NET_MAX_MTU,
+ PCI_DMA_BIDIRECTIONAL);
+ if (descr->buf_addr == DMA_ERROR_CODE) {
+ dev_kfree_skb_any(descr->skb);
+ if (netif_msg_rx_err(card))
+ pr_err("Could not iommu-map rx buffer\n");
+ spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ } else {
+ descr->dmac_cmd_status = SPIDER_NET_DMAC_RX_CARDOWNED;
+ }
+
+ return error;
+}
+
+/**
+ * spider_net_enable_rxctails - sets RX dmac chain tail addresses
+ * @card: card structure
+ *
+ * spider_net_enable_rxctails sets the RX DMAC chain tail adresses in the
+ * chip by writing to the appropriate register. DMA is enabled in
+ * spider_net_enable_rxdmac.
+ */
+static void
+spider_net_enable_rxchtails(struct spider_net_card *card)
+{
+ /* assume chain is aligned correctly */
+ spider_net_write_reg(card, SPIDER_NET_GDADCHA ,
+ card->rx_chain.tail->bus_addr);
+}
+
+/**
+ * spider_net_enable_rxdmac - enables a receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
+ * in the GDADMACCNTR register
+ */
+static void
+spider_net_enable_rxdmac(struct spider_net_card *card)
+{
+ spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+ SPIDER_NET_DMA_RX_VALUE);
+}
+
+/**
+ * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
+ * @card: card structure
+ *
+ * refills descriptors in all chains (last used chain first): allocates skbs
+ * and iommu-maps them.
+ */
+static void
+spider_net_refill_rx_chain(struct spider_net_card *card)
+{
+ struct spider_net_descr_chain *chain;
+ int count = 0;
+ unsigned long flags;
+
+ chain = &card->rx_chain;
+
+ spin_lock_irqsave(&card->chain_lock, flags);
+ while (spider_net_get_descr_status(chain->head) ==
+ SPIDER_NET_DESCR_NOT_IN_USE) {
+ if (spider_net_prepare_rx_descr(card, chain->head))
+ break;
+ count++;
+ chain->head = chain->head->next;
+ }
+ spin_unlock_irqrestore(&card->chain_lock, flags);
+
+ /* could be optimized, only do that, if we know the DMA processing
+ * has terminated */
+ if (count)
+ spider_net_enable_rxdmac(card);
+}
+
+/**
+ * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_alloc_rx_skbs(struct spider_net_card *card)
+{
+ int result;
+ struct spider_net_descr_chain *chain;
+
+ result = -ENOMEM;
+
+ chain = &card->rx_chain;
+ /* put at least one buffer into the chain. if this fails,
+ * we've got a problem. if not, spider_net_refill_rx_chain
+ * will do the rest at the end of this function */
+ if (spider_net_prepare_rx_descr(card, chain->head))
+ goto error;
+ else
+ chain->head = chain->head->next;
+
+ /* this will allocate the rest of the rx buffers; if not, it's
+ * business as usual later on */
+ spider_net_refill_rx_chain(card);
+ return 0;
+
+error:
+ spider_net_free_rx_chain_contents(card);
+ return result;
+}
+
+/**
+ * spider_net_release_tx_descr - processes a used tx descriptor
+ * @card: card structure
+ * @descr: descriptor to release
+ *
+ * releases a used tx descriptor (unmapping, freeing of skb)
+ */
+static void
+spider_net_release_tx_descr(struct spider_net_card *card,
+ struct spider_net_descr *descr)
+{
+ struct sk_buff *skb;
+
+ /* unmap the skb */
+ skb = descr->skb;
+ pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
+ PCI_DMA_BIDIRECTIONAL);
+
+ dev_kfree_skb_any(skb);
+
+ /* set status to not used */
+ spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+}
+
+/**
+ * spider_net_release_tx_chain - processes sent tx descriptors
+ * @card: adapter structure
+ * @brutal: if set, don't care about whether descriptor seems to be in use
+ *
+ * releases the tx descriptors that spider has finished with (if non-brutal)
+ * or simply release tx descriptors (if brutal)
+ */
+static void
+spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+{
+ struct spider_net_descr_chain *tx_chain = &card->tx_chain;
+ enum spider_net_descr_status status;
+
+ spider_net_tx_irq_off(card);
+
+ /* no lock for chain needed, if this is only executed once at a time */
+again:
+ for (;;) {
+ status = spider_net_get_descr_status(tx_chain->tail);
+ switch (status) {
+ case SPIDER_NET_DESCR_CARDOWNED:
+ if (!brutal) goto out;
+ /* fallthrough, if we release the descriptors
+ * brutally (then we don't care about
+ * SPIDER_NET_DESCR_CARDOWNED) */
+ case SPIDER_NET_DESCR_RESPONSE_ERROR:
+ case SPIDER_NET_DESCR_PROTECTION_ERROR:
+ case SPIDER_NET_DESCR_FORCE_END:
+ if (netif_msg_tx_err(card))
+ pr_err("%s: forcing end of tx descriptor "
+ "with status x%02x\n",
+ card->netdev->name, status);
+ card->netdev_stats.tx_dropped++;
+ break;
+
+ case SPIDER_NET_DESCR_COMPLETE:
+ card->netdev_stats.tx_packets++;
+ card->netdev_stats.tx_bytes +=
+ tx_chain->tail->skb->len;
+ break;
+
+ default: /* any other value (== SPIDER_NET_DESCR_NOT_IN_USE) */
+ goto out;
+ }
+ spider_net_release_tx_descr(card, tx_chain->tail);
+ tx_chain->tail = tx_chain->tail->next;
+ }
+out:
+ netif_wake_queue(card->netdev);
+
+ if (!brutal) {
+ /* switch on tx irqs (while we are still in the interrupt
+ * handler, so we don't get an interrupt), check again
+ * for done descriptors. This results in fewer interrupts */
+ spider_net_tx_irq_on(card);
+ status = spider_net_get_descr_status(tx_chain->tail);
+ switch (status) {
+ case SPIDER_NET_DESCR_RESPONSE_ERROR:
+ case SPIDER_NET_DESCR_PROTECTION_ERROR:
+ case SPIDER_NET_DESCR_FORCE_END:
+ case SPIDER_NET_DESCR_COMPLETE:
+ goto again;
+ default:
+ break;
+ }
+ }
+
+}
+
+/**
+ * spider_net_get_multicast_hash - generates hash for multicast filter table
+ * @addr: multicast address
+ *
+ * returns the hash value.
+ *
+ * spider_net_get_multicast_hash calculates a hash value for a given multicast
+ * address, that is used to set the multicast filter tables
+ */
+static u8
+spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr)
+{
+ /* FIXME: an addr of 01:00:5e:00:00:01 must result in 0xa9,
+ * ff:ff:ff:ff:ff:ff must result in 0xfd */
+ u32 crc;
+ u8 hash;
+
+ crc = crc32_be(~0, addr, netdev->addr_len);
+
+ hash = (crc >> 27);
+ hash <<= 3;
+ hash |= crc & 7;
+
+ return hash;
+}
+
+/**
+ * spider_net_set_multi - sets multicast addresses and promisc flags
+ * @netdev: interface device structure
+ *
+ * spider_net_set_multi configures multicast addresses as needed for the
+ * netdev interface. It also sets up multicast, allmulti and promisc
+ * flags appropriately
+ */
+static void
+spider_net_set_multi(struct net_device *netdev)
+{
+ struct dev_mc_list *mc;
+ u8 hash;
+ int i;
+ u32 reg;
+ struct spider_net_card *card = netdev_priv(netdev);
+ unsigned long bitmask[SPIDER_NET_MULTICAST_HASHES / BITS_PER_LONG] =
+ {0, };
+
+ spider_net_set_promisc(card);
+
+ if (netdev->flags & IFF_ALLMULTI) {
+ for (i = 0; i < SPIDER_NET_MULTICAST_HASHES; i++) {
+ set_bit(i, bitmask);
+ }
+ goto write_hash;
+ }
+
+ /* well, we know, what the broadcast hash value is: it's xfd
+ hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
+ set_bit(0xfd, bitmask);
+
+ for (mc = netdev->mc_list; mc; mc = mc->next) {
+ hash = spider_net_get_multicast_hash(netdev, mc->dmi_addr);
+ set_bit(hash, bitmask);
+ }
+
+write_hash:
+ for (i = 0; i < SPIDER_NET_MULTICAST_HASHES / 4; i++) {
+ reg = 0;
+ if (test_bit(i * 4, bitmask))
+ reg += 0x08;
+ reg <<= 8;
+ if (test_bit(i * 4 + 1, bitmask))
+ reg += 0x08;
+ reg <<= 8;
+ if (test_bit(i * 4 + 2, bitmask))
+ reg += 0x08;
+ reg <<= 8;
+ if (test_bit(i * 4 + 3, bitmask))
+ reg += 0x08;
+
+ spider_net_write_reg(card, SPIDER_NET_GMRMHFILnR + i * 4, reg);
+ }
+}
+
+/**
+ * spider_net_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_disable_rxdmac terminates processing on the DMA controller by
+ * turing off DMA and issueing a force end
+ */
+static void
+spider_net_disable_rxdmac(struct spider_net_card *card)
+{
+ spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+ SPIDER_NET_DMA_RX_FEND_VALUE);
+}
+
+/**
+ * spider_net_stop - called upon ifconfig down
+ * @netdev: interface device structure
+ *
+ * always returns 0
+ */
+int
+spider_net_stop(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+
+ netif_poll_disable(netdev);
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ /* disable/mask all interrupts */
+ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+
+ /* free_irq(netdev->irq, netdev);*/
+ free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_DMA_TX_FEND_VALUE);
+
+ /* turn off DMA, force end */
+ spider_net_disable_rxdmac(card);
+
+ /* release chains */
+ spider_net_release_tx_chain(card, 1);
+
+ spider_net_free_chain(card, &card->tx_chain);
+ spider_net_free_chain(card, &card->rx_chain);
+
+ return 0;
+}
+
+/**
+ * spider_net_get_next_tx_descr - returns the next available tx descriptor
+ * @card: device structure to get descriptor from
+ *
+ * returns the address of the next descriptor, or NULL if not available.
+ */
+static struct spider_net_descr *
+spider_net_get_next_tx_descr(struct spider_net_card *card)
+{
+ /* check, if head points to not-in-use descr */
+ if ( spider_net_get_descr_status(card->tx_chain.head) ==
+ SPIDER_NET_DESCR_NOT_IN_USE ) {
+ return card->tx_chain.head;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * spider_net_set_txdescr_cmdstat - sets the tx descriptor command field
+ * @descr: descriptor structure to fill out
+ * @skb: packet to consider
+ *
+ * fills out the command and status field of the descriptor structure,
+ * depending on hardware checksum settings. This function assumes a wmb()
+ * has executed before.
+ */
+static void
+spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr,
+ struct sk_buff *skb)
+{
+ if (skb->ip_summed != CHECKSUM_HW) {
+ descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
+ return;
+ }
+
+ /* is packet ip?
+ * if yes: tcp? udp? */
+ if (skb->protocol == htons(ETH_P_IP)) {
+ if (skb->nh.iph->protocol == IPPROTO_TCP) {
+ descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_TCPCS;
+ } else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+ descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_UDPCS;
+ } else { /* the stack should checksum non-tcp and non-udp
+ packets on his own: NETIF_F_IP_CSUM */
+ descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
+ }
+ }
+}
+
+/**
+ * spider_net_prepare_tx_descr - fill tx descriptor with skb data
+ * @card: card structure
+ * @descr: descriptor structure to fill out
+ * @skb: packet to use
+ *
+ * returns 0 on success, <0 on failure.
+ *
+ * fills out the descriptor structure with skb data and len. Copies data,
+ * if needed (32bit DMA!)
+ */
+static int
+spider_net_prepare_tx_descr(struct spider_net_card *card,
+ struct spider_net_descr *descr,
+ struct sk_buff *skb)
+{
+ descr->buf_addr = pci_map_single(card->pdev, skb->data,
+ skb->len, PCI_DMA_BIDIRECTIONAL);
+ if (descr->buf_addr == DMA_ERROR_CODE) {
+ if (netif_msg_tx_err(card))
+ pr_err("could not iommu-map packet (%p, %i). "
+ "Dropping packet\n", skb->data, skb->len);
+ return -ENOMEM;
+ }
+
+ descr->buf_size = skb->len;
+ descr->skb = skb;
+ descr->data_status = 0;
+
+ /* make sure the above values are in memory before we change the
+ * status */
+ wmb();
+
+ spider_net_set_txdescr_cmdstat(descr,skb);
+
+ return 0;
+}
+
+/**
+ * spider_net_kick_tx_dma - enables TX DMA processing
+ * @card: card structure
+ * @descr: descriptor address to enable TX processing at
+ *
+ * spider_net_kick_tx_dma writes the current tx chain head as start address
+ * of the tx descriptor chain and enables the transmission DMA engine
+ */
+static void
+spider_net_kick_tx_dma(struct spider_net_card *card,
+ struct spider_net_descr *descr)
+{
+ /* this is the only descriptor in the output chain.
+ * Enable TX DMA */
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+ descr->bus_addr);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_DMA_TX_VALUE);
+}
+
+/**
+ * spider_net_xmit - transmits a frame over the device
+ * @skb: packet to send out
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ struct spider_net_descr *descr;
+ int result;
+
+ descr = spider_net_get_next_tx_descr(card);
+
+ if (!descr) {
+ netif_stop_queue(netdev);
+
+ descr = spider_net_get_next_tx_descr(card);
+ if (!descr)
+ goto error;
+ else
+ netif_start_queue(netdev);
+ }
+
+ result = spider_net_prepare_tx_descr(card, descr, skb);
+ if (result)
+ goto error;
+
+ card->tx_chain.head = card->tx_chain.head->next;
+
+ /* make sure the status from spider_net_prepare_tx_descr is in
+ * memory before we check out the previous descriptor */
+ wmb();
+
+ if (spider_net_get_descr_status(descr->prev) !=
+ SPIDER_NET_DESCR_CARDOWNED)
+ spider_net_kick_tx_dma(card, descr);
+
+ return NETDEV_TX_OK;
+
+error:
+ card->netdev_stats.tx_dropped++;
+ return NETDEV_TX_LOCKED;
+}
+
+/**
+ * spider_net_do_ioctl - called for device ioctls
+ * @netdev: interface device structure
+ * @ifr: request parameter structure for ioctl
+ * @cmd: command code for ioctl
+ *
+ * returns 0 on success, <0 on failure. Currently, we have no special ioctls.
+ * -EOPNOTSUPP is returned, if an unknown ioctl was requested
+ */
+static int
+spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/**
+ * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
+ * @descr: descriptor to process
+ * @card: card structure
+ *
+ * returns 1 on success, 0 if no packet was passed to the stack
+ *
+ * iommu-unmaps the skb, fills out skb structure and passes the data to the
+ * stack. The descriptor state is not changed.
+ */
+static int
+spider_net_pass_skb_up(struct spider_net_descr *descr,
+ struct spider_net_card *card)
+{
+ struct sk_buff *skb;
+ struct net_device *netdev;
+ u32 data_status, data_error;
+
+ data_status = descr->data_status;
+ data_error = descr->data_error;
+
+ netdev = card->netdev;
+
+ /* check for errors in the data_error flag */
+ if ((data_error & SPIDER_NET_DATA_ERROR_MASK) &&
+ netif_msg_rx_err(card))
+ pr_err("error in received descriptor found, "
+ "data_status=x%08x, data_error=x%08x\n",
+ data_status, data_error);
+
+ /* prepare skb, unmap descriptor */
+ skb = descr->skb;
+ pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_MTU,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* the cases we'll throw away the packet immediately */
+ if (data_error & SPIDER_NET_DESTROY_RX_FLAGS)
+ return 0;
+
+ skb->dev = netdev;
+ skb_put(skb, descr->valid_size);
+
+ /* the card seems to add 2 bytes of junk in front
+ * of the ethernet frame */
+#define SPIDER_MISALIGN 2
+ skb_pull(skb, SPIDER_MISALIGN);
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ /* checksum offload */
+ if (card->options.rx_csum) {
+ if ( (data_status & SPIDER_NET_DATA_STATUS_CHK_MASK) &&
+ (!(data_error & SPIDER_NET_DATA_ERROR_CHK_MASK)) )
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
+ if (data_status & SPIDER_NET_VLAN_PACKET) {
+ /* further enhancements: HW-accel VLAN
+ * vlan_hwaccel_receive_skb
+ */
+ }
+
+ /* pass skb up to stack */
+ netif_receive_skb(skb);
+
+ /* update netdevice statistics */
+ card->netdev_stats.rx_packets++;
+ card->netdev_stats.rx_bytes += skb->len;
+
+ return 1;
+}
+
+/**
+ * spider_net_decode_descr - processes an rx descriptor
+ * @card: card structure
+ *
+ * returns 1 if a packet has been sent to the stack, otherwise 0
+ *
+ * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * the packet up to the stack
+ */
+static int
+spider_net_decode_one_descr(struct spider_net_card *card)
+{
+ enum spider_net_descr_status status;
+ struct spider_net_descr *descr;
+ struct spider_net_descr_chain *chain;
+ int result;
+
+ chain = &card->rx_chain;
+ descr = chain->tail;
+
+ status = spider_net_get_descr_status(descr);
+
+ if (status == SPIDER_NET_DESCR_CARDOWNED) {
+ /* nothing in the descriptor yet */
+ return 0;
+ }
+
+ if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
+ /* not initialized yet, I bet chain->tail == chain->head
+ * and the ring is empty */
+ spider_net_refill_rx_chain(card);
+ return 0;
+ }
+
+ /* descriptor definitively used -- move on head */
+ chain->tail = descr->next;
+
+ result = 0;
+ if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
+ (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
+ (status == SPIDER_NET_DESCR_FORCE_END) ) {
+ if (netif_msg_rx_err(card))
+ pr_err("%s: dropping RX descriptor with state %d\n",
+ card->netdev->name, status);
+ card->netdev_stats.rx_dropped++;
+ goto refill;
+ }
+
+ if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
+ (status != SPIDER_NET_DESCR_FRAME_END) ) {
+ if (netif_msg_rx_err(card))
+ pr_err("%s: RX descriptor with state %d\n",
+ card->netdev->name, status);
+ goto refill;
+ }
+
+ /* ok, we've got a packet in descr */
+ result = spider_net_pass_skb_up(descr, card);
+refill:
+ spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ /* change the descriptor state: */
+ spider_net_refill_rx_chain(card);
+
+ return result;
+}
+
+/**
+ * spider_net_poll - NAPI poll function called by the stack to return packets
+ * @netdev: interface device structure
+ * @budget: number of packets we can pass to the stack at most
+ *
+ * returns 0 if no more packets available to the driver/stack. Returns 1,
+ * if the quota is exceeded, but the driver has still packets.
+ *
+ * spider_net_poll returns all packets from the rx descriptors to the stack
+ * (using netif_receive_skb). If all/enough packets are up, the driver
+ * reenables interrupts and returns 0. If not, 1 is returned.
+ */
+static int
+spider_net_poll(struct net_device *netdev, int *budget)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ int packets_to_do, packets_done = 0;
+ int no_more_packets = 0;
+
+ packets_to_do = min(*budget, netdev->quota);
+
+ while (packets_to_do) {
+ if (spider_net_decode_one_descr(card)) {
+ packets_done++;
+ packets_to_do--;
+ } else {
+ /* no more packets for the stack */
+ no_more_packets = 1;
+ break;
+ }
+ }
+
+ netdev->quota -= packets_done;
+ *budget -= packets_done;
+
+ /* if all packets are in the stack, enable interrupts and return 0 */
+ /* if not, return 1 */
+ if (no_more_packets) {
+ netif_rx_complete(netdev);
+ spider_net_rx_irq_on(card);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * spider_net_vlan_rx_reg - initializes VLAN structures in the driver and card
+ * @netdev: interface device structure
+ * @grp: vlan_group structure that is registered (NULL on destroying interface)
+ */
+static void
+spider_net_vlan_rx_reg(struct net_device *netdev, struct vlan_group *grp)
+{
+ /* further enhancement... yet to do */
+ return;
+}
+
+/**
+ * spider_net_vlan_rx_add - adds VLAN id to the card filter
+ * @netdev: interface device structure
+ * @vid: VLAN id to add
+ */
+static void
+spider_net_vlan_rx_add(struct net_device *netdev, uint16_t vid)
+{
+ /* further enhancement... yet to do */
+ /* add vid to card's VLAN filter table */
+ return;
+}
+
+/**
+ * spider_net_vlan_rx_kill - removes VLAN id to the card filter
+ * @netdev: interface device structure
+ * @vid: VLAN id to remove
+ */
+static void
+spider_net_vlan_rx_kill(struct net_device *netdev, uint16_t vid)
+{
+ /* further enhancement... yet to do */
+ /* remove vid from card's VLAN filter table */
+}
+
+/**
+ * spider_net_get_stats - get interface statistics
+ * @netdev: interface device structure
+ *
+ * returns the interface statistics residing in the spider_net_card struct
+ */
+static struct net_device_stats *
+spider_net_get_stats(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ struct net_device_stats *stats = &card->netdev_stats;
+ return stats;
+}
+
+/**
+ * spider_net_change_mtu - changes the MTU of an interface
+ * @netdev: interface device structure
+ * @new_mtu: new MTU value
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ /* no need to re-alloc skbs or so -- the max mtu is about 2.3k
+ * and mtu is outbound only anyway */
+ if ( (new_mtu < SPIDER_NET_MIN_MTU ) ||
+ (new_mtu > SPIDER_NET_MAX_MTU) )
+ return -EINVAL;
+ netdev->mtu = new_mtu;
+ return 0;
+}
+
+/**
+ * spider_net_set_mac - sets the MAC of an interface
+ * @netdev: interface device structure
+ * @ptr: pointer to new MAC address
+ *
+ * Returns 0 on success, <0 on failure. Currently, we don't support this
+ * and will always return EOPNOTSUPP.
+ */
+static int
+spider_net_set_mac(struct net_device *netdev, void *p)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ u32 macl, macu, regvalue;
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ /* switch off GMACTPE and GMACRPE */
+ regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
+ regvalue &= ~((1 << 5) | (1 << 6));
+ spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
+
+ /* write mac */
+ macu = (addr->sa_data[0]<<24) + (addr->sa_data[1]<<16) +
+ (addr->sa_data[2]<<8) + (addr->sa_data[3]);
+ macl = (addr->sa_data[4]<<8) + (addr->sa_data[5]);
+ spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu);
+ spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl);
+
+ /* switch GMACTPE and GMACRPE back on */
+ regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
+ regvalue |= ((1 << 5) | (1 << 6));
+ spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
+
+ spider_net_set_promisc(card);
+
+ /* look up, whether we have been successful */
+ if (spider_net_get_mac_address(netdev))
+ return -EADDRNOTAVAIL;
+ if (memcmp(netdev->dev_addr,addr->sa_data,netdev->addr_len))
+ return -EADDRNOTAVAIL;
+
+ return 0;
+}
+
+/**
+ * spider_net_enable_txdmac - enables a TX DMA controller
+ * @card: card structure
+ *
+ * spider_net_enable_txdmac enables the TX DMA controller by setting the
+ * descriptor chain tail address
+ */
+static void
+spider_net_enable_txdmac(struct spider_net_card *card)
+{
+ /* assume chain is aligned correctly */
+ spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+ card->tx_chain.tail->bus_addr);
+}
+
+/**
+ * spider_net_handle_error_irq - handles errors raised by an interrupt
+ * @card: card structure
+ * @status_reg: interrupt status register 0 (GHIINT0STS)
+ *
+ * spider_net_handle_error_irq treats or ignores all error conditions
+ * found when an interrupt is presented
+ */
+static void
+spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
+{
+ u32 error_reg1, error_reg2;
+ u32 i;
+ int show_error = 1;
+
+ error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
+ error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
+
+ /* check GHIINT0STS ************************************/
+ if (status_reg)
+ for (i = 0; i < 32; i++)
+ if (status_reg & (1<<i))
+ switch (i)
+ {
+ /* let error_reg1 and error_reg2 evaluation decide, what to do
+ case SPIDER_NET_PHYINT:
+ case SPIDER_NET_GMAC2INT:
+ case SPIDER_NET_GMAC1INT:
+ case SPIDER_NET_GIPSINT:
+ case SPIDER_NET_GFIFOINT:
+ case SPIDER_NET_DMACINT:
+ case SPIDER_NET_GSYSINT:
+ break; */
+
+ case SPIDER_NET_GPWOPCMPINT:
+ /* PHY write operation completed */
+ show_error = 0;
+ break;
+ case SPIDER_NET_GPROPCMPINT:
+ /* PHY read operation completed */
+ /* we don't use semaphores, as we poll for the completion
+ * of the read operation in spider_net_read_phy. Should take
+ * about 50 us */
+ show_error = 0;
+ break;
+ case SPIDER_NET_GPWFFINT:
+ /* PHY command queue full */
+ if (netif_msg_intr(card))
+ pr_err("PHY write queue full\n");
+ show_error = 0;
+ break;
+
+ /* case SPIDER_NET_GRMDADRINT: not used. print a message */
+ /* case SPIDER_NET_GRMARPINT: not used. print a message */
+ /* case SPIDER_NET_GRMMPINT: not used. print a message */
+
+ case SPIDER_NET_GDTDEN0INT:
+ /* someone has set TX_DMA_EN to 0 */
+ show_error = 0;
+ break;
+
+ case SPIDER_NET_GDDDEN0INT: /* fallthrough */
+ case SPIDER_NET_GDCDEN0INT: /* fallthrough */
+ case SPIDER_NET_GDBDEN0INT: /* fallthrough */
+ case SPIDER_NET_GDADEN0INT:
+ /* someone has set RX_DMA_EN to 0 */
+ show_error = 0;
+ break;
+
+ /* RX interrupts */
+ case SPIDER_NET_GDDFDCINT:
+ case SPIDER_NET_GDCFDCINT:
+ case SPIDER_NET_GDBFDCINT:
+ case SPIDER_NET_GDAFDCINT:
+ /* case SPIDER_NET_GDNMINT: not used. print a message */
+ /* case SPIDER_NET_GCNMINT: not used. print a message */
+ /* case SPIDER_NET_GBNMINT: not used. print a message */
+ /* case SPIDER_NET_GANMINT: not used. print a message */
+ /* case SPIDER_NET_GRFNMINT: not used. print a message */
+ show_error = 0;
+ break;
+
+ /* TX interrupts */
+ case SPIDER_NET_GDTFDCINT:
+ show_error = 0;
+ break;
+ case SPIDER_NET_GTTEDINT:
+ show_error = 0;
+ break;
+ case SPIDER_NET_GDTDCEINT:
+ /* chain end. If a descriptor should be sent, kick off
+ * tx dma
+ if (card->tx_chain.tail == card->tx_chain.head)
+ spider_net_kick_tx_dma(card);
+ show_error = 0; */
+ break;
+
+ /* case SPIDER_NET_G1TMCNTINT: not used. print a message */
+ /* case SPIDER_NET_GFREECNTINT: not used. print a message */
+ }
+
+ /* check GHIINT1STS ************************************/
+ if (error_reg1)
+ for (i = 0; i < 32; i++)
+ if (error_reg1 & (1<<i))
+ switch (i)
+ {
+ case SPIDER_NET_GTMFLLINT:
+ if (netif_msg_intr(card))
+ pr_err("Spider TX RAM full\n");
+ show_error = 0;
+ break;
+ case SPIDER_NET_GRMFLLINT:
+ if (netif_msg_intr(card))
+ pr_err("Spider RX RAM full, incoming packets "
+ "might be discarded !\n");
+ netif_rx_schedule(card->netdev);
+ spider_net_enable_rxchtails(card);
+ spider_net_enable_rxdmac(card);
+ break;
+
+ /* case SPIDER_NET_GTMSHTINT: problem, print a message */
+ case SPIDER_NET_GDTINVDINT:
+ /* allrighty. tx from previous descr ok */
+ show_error = 0;
+ break;
+ /* case SPIDER_NET_GRFDFLLINT: print a message down there */
+ /* case SPIDER_NET_GRFCFLLINT: print a message down there */
+ /* case SPIDER_NET_GRFBFLLINT: print a message down there */
+ /* case SPIDER_NET_GRFAFLLINT: print a message down there */
+
+ /* chain end */
+ case SPIDER_NET_GDDDCEINT: /* fallthrough */
+ case SPIDER_NET_GDCDCEINT: /* fallthrough */
+ case SPIDER_NET_GDBDCEINT: /* fallthrough */
+ case SPIDER_NET_GDADCEINT:
+ if (netif_msg_intr(card))
+ pr_err("got descriptor chain end interrupt, "
+ "restarting DMAC %c.\n",
+ 'D'+i-SPIDER_NET_GDDDCEINT);
+ spider_net_refill_rx_chain(card);
+ show_error = 0;
+ break;
+
+ /* invalid descriptor */
+ case SPIDER_NET_GDDINVDINT: /* fallthrough */
+ case SPIDER_NET_GDCINVDINT: /* fallthrough */
+ case SPIDER_NET_GDBINVDINT: /* fallthrough */
+ case SPIDER_NET_GDAINVDINT:
+ /* could happen when rx chain is full */
+ spider_net_refill_rx_chain(card);
+ show_error = 0;
+ break;
+
+ /* case SPIDER_NET_GDTRSERINT: problem, print a message */
+ /* case SPIDER_NET_GDDRSERINT: problem, print a message */
+ /* case SPIDER_NET_GDCRSERINT: problem, print a message */
+ /* case SPIDER_NET_GDBRSERINT: problem, print a message */
+ /* case SPIDER_NET_GDARSERINT: problem, print a message */
+ /* case SPIDER_NET_GDSERINT: problem, print a message */
+ /* case SPIDER_NET_GDTPTERINT: problem, print a message */
+ /* case SPIDER_NET_GDDPTERINT: problem, print a message */
+ /* case SPIDER_NET_GDCPTERINT: problem, print a message */
+ /* case SPIDER_NET_GDBPTERINT: problem, print a message */
+ /* case SPIDER_NET_GDAPTERINT: problem, print a message */
+ default:
+ show_error = 1;
+ break;
+ }
+
+ /* check GHIINT2STS ************************************/
+ if (error_reg2)
+ for (i = 0; i < 32; i++)
+ if (error_reg2 & (1<<i))
+ switch (i)
+ {
+ /* there is nothing we can (want to) do at this time. Log a
+ * message, we can switch on and off the specific values later on
+ case SPIDER_NET_GPROPERINT:
+ case SPIDER_NET_GMCTCRSNGINT:
+ case SPIDER_NET_GMCTLCOLINT:
+ case SPIDER_NET_GMCTTMOTINT:
+ case SPIDER_NET_GMCRCAERINT:
+ case SPIDER_NET_GMCRCALERINT:
+ case SPIDER_NET_GMCRALNERINT:
+ case SPIDER_NET_GMCROVRINT:
+ case SPIDER_NET_GMCRRNTINT:
+ case SPIDER_NET_GMCRRXERINT:
+ case SPIDER_NET_GTITCSERINT:
+ case SPIDER_NET_GTIFMTERINT:
+ case SPIDER_NET_GTIPKTRVKINT:
+ case SPIDER_NET_GTISPINGINT:
+ case SPIDER_NET_GTISADNGINT:
+ case SPIDER_NET_GTISPDNGINT:
+ case SPIDER_NET_GRIFMTERINT:
+ case SPIDER_NET_GRIPKTRVKINT:
+ case SPIDER_NET_GRISPINGINT:
+ case SPIDER_NET_GRISADNGINT:
+ case SPIDER_NET_GRISPDNGINT:
+ break;
+ */
+ default:
+ break;
+ }
+
+ if ((show_error) && (netif_msg_intr(card)))
+ pr_err("Got error interrupt, GHIINT0STS = 0x%08x, "
+ "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
+ status_reg, error_reg1, error_reg2);
+
+ /* clear interrupt sources */
+ spider_net_write_reg(card, SPIDER_NET_GHIINT1STS, error_reg1);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT2STS, error_reg2);
+}
+
+/**
+ * spider_net_interrupt - interrupt handler for spider_net
+ * @irq: interupt number
+ * @ptr: pointer to net_device
+ * @regs: PU registers
+ *
+ * returns IRQ_HANDLED, if interrupt was for driver, or IRQ_NONE, if no
+ * interrupt found raised by card.
+ *
+ * This is the interrupt handler, that turns off
+ * interrupts for this device and makes the stack poll the driver
+ */
+static irqreturn_t
+spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+ struct net_device *netdev = ptr;
+ struct spider_net_card *card = netdev_priv(netdev);
+ u32 status_reg;
+
+ status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
+
+ if (!status_reg)
+ return IRQ_NONE;
+
+ if (status_reg & SPIDER_NET_TXINT)
+ spider_net_release_tx_chain(card, 0);
+
+ if (status_reg & SPIDER_NET_RXINT ) {
+ spider_net_rx_irq_off(card);
+ netif_rx_schedule(netdev);
+ }
+
+ /* we do this after rx and tx processing, as we want the tx chain
+ * processed to see, whether we should restart tx dma processing */
+ spider_net_handle_error_irq(card, status_reg);
+
+ /* clear interrupt sources */
+ spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * spider_net_poll_controller - artificial interrupt for netconsole etc.
+ * @netdev: interface device structure
+ *
+ * see Documentation/networking/netconsole.txt
+ */
+static void
+spider_net_poll_controller(struct net_device *netdev)
+{
+ disable_irq(netdev->irq);
+ spider_net_interrupt(netdev->irq, netdev, NULL);
+ enable_irq(netdev->irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/**
+ * spider_net_init_card - initializes the card
+ * @card: card structure
+ *
+ * spider_net_init_card initializes the card so that other registers can
+ * be used
+ */
+static void
+spider_net_init_card(struct spider_net_card *card)
+{
+ spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+ SPIDER_NET_CKRCTRL_STOP_VALUE);
+
+ spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+ SPIDER_NET_CKRCTRL_RUN_VALUE);
+}
+
+/**
+ * spider_net_enable_card - enables the card by setting all kinds of regs
+ * @card: card structure
+ *
+ * spider_net_enable_card sets a lot of SMMIO registers to enable the device
+ */
+static void
+spider_net_enable_card(struct spider_net_card *card)
+{
+ int i;
+ /* the following array consists of (register),(value) pairs
+ * that are set in this function. A register of 0 ends the list */
+ u32 regs[][2] = {
+ { SPIDER_NET_GRESUMINTNUM, 0 },
+ { SPIDER_NET_GREINTNUM, 0 },
+
+ /* set interrupt frame number registers */
+ /* clear the single DMA engine registers first */
+ { SPIDER_NET_GFAFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+ { SPIDER_NET_GFBFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+ { SPIDER_NET_GFCFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+ { SPIDER_NET_GFDFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+ /* then set, what we really need */
+ { SPIDER_NET_GFFRMNUM, SPIDER_NET_FRAMENUM_VALUE },
+
+ /* timer counter registers and stuff */
+ { SPIDER_NET_GFREECNNUM, 0 },
+ { SPIDER_NET_GONETIMENUM, 0 },
+ { SPIDER_NET_GTOUTFRMNUM, 0 },
+
+ /* RX mode setting */
+ { SPIDER_NET_GRXMDSET, SPIDER_NET_RXMODE_VALUE },
+ /* TX mode setting */
+ { SPIDER_NET_GTXMDSET, SPIDER_NET_TXMODE_VALUE },
+ /* IPSEC mode setting */
+ { SPIDER_NET_GIPSECINIT, SPIDER_NET_IPSECINIT_VALUE },
+
+ { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
+
+ { SPIDER_NET_GMRWOLCTRL, 0 },
+ { SPIDER_NET_GTESTMD, 0 },
+
+ { SPIDER_NET_GMACINTEN, 0 },
+
+ /* flow control stuff */
+ { SPIDER_NET_GMACAPAUSE, SPIDER_NET_MACAPAUSE_VALUE },
+ { SPIDER_NET_GMACTXPAUSE, SPIDER_NET_TXPAUSE_VALUE },
+
+ { SPIDER_NET_GMACBSTLMT, SPIDER_NET_BURSTLMT_VALUE },
+ { 0, 0}
+ };
+
+ i = 0;
+ while (regs[i][0]) {
+ spider_net_write_reg(card, regs[i][0], regs[i][1]);
+ i++;
+ }
+
+ /* clear unicast filter table entries 1 to 14 */
+ for (i = 1; i <= 14; i++) {
+ spider_net_write_reg(card,
+ SPIDER_NET_GMRUAFILnR + i * 8,
+ 0x00080000);
+ spider_net_write_reg(card,
+ SPIDER_NET_GMRUAFILnR + i * 8 + 4,
+ 0x00000000);
+ }
+
+ spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R, 0x08080000);
+
+ spider_net_write_reg(card, SPIDER_NET_ECMODE, SPIDER_NET_ECMODE_VALUE);
+
+ /* set chain tail adress for RX chains and
+ * enable DMA */
+ spider_net_enable_rxchtails(card);
+ spider_net_enable_rxdmac(card);
+
+ spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
+
+ /* set chain tail adress for TX chain */
+ spider_net_enable_txdmac(card);
+
+ spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
+ SPIDER_NET_LENLMT_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_GMACMODE,
+ SPIDER_NET_MACMODE_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+ SPIDER_NET_OPMODE_VALUE);
+
+ /* set interrupt mask registers */
+ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
+ SPIDER_NET_INT0_MASK_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
+ SPIDER_NET_INT1_MASK_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
+ SPIDER_NET_INT2_MASK_VALUE);
+}
+
+/**
+ * spider_net_open - called upon ifonfig up
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_open allocates all the descriptors and memory needed for
+ * operation, sets up multicast list and enables interrupts
+ */
+int
+spider_net_open(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ int result;
+
+ result = -ENOMEM;
+ if (spider_net_init_chain(card, &card->tx_chain,
+ card->descr, tx_descriptors))
+ goto alloc_tx_failed;
+ if (spider_net_init_chain(card, &card->rx_chain,
+ card->descr + tx_descriptors, rx_descriptors))
+ goto alloc_rx_failed;
+
+ /* allocate rx skbs */
+ if (spider_net_alloc_rx_skbs(card))
+ goto alloc_skbs_failed;
+
+ spider_net_set_multi(netdev);
+
+ /* further enhancement: setup hw vlan, if needed */
+
+ result = -EBUSY;
+ if (request_irq(netdev->irq, spider_net_interrupt,
+ SA_SHIRQ, netdev->name, netdev))
+ goto register_int_failed;
+
+ spider_net_enable_card(card);
+
+ netif_start_queue(netdev);
+ netif_carrier_on(netdev);
+ netif_poll_enable(netdev);
+
+ return 0;
+
+register_int_failed:
+ spider_net_free_rx_chain_contents(card);
+alloc_skbs_failed:
+ spider_net_free_chain(card, &card->rx_chain);
+alloc_rx_failed:
+ spider_net_free_chain(card, &card->tx_chain);
+alloc_tx_failed:
+ return result;
+}
+
+/**
+ * spider_net_setup_phy - setup PHY
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_setup_phy is used as part of spider_net_probe. Sets
+ * the PHY to 1000 Mbps
+ **/
+static int
+spider_net_setup_phy(struct spider_net_card *card)
+{
+ struct mii_phy *phy = &card->phy;
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
+ SPIDER_NET_DMASEL_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
+ SPIDER_NET_PHY_CTRL_VALUE);
+ phy->mii_id = 1;
+ phy->dev = card->netdev;
+ phy->mdio_read = spider_net_read_phy;
+ phy->mdio_write = spider_net_write_phy;
+
+ mii_phy_probe(phy, phy->mii_id);
+
+ if (phy->def->ops->setup_forced)
+ phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
+
+ /* the following two writes could be moved to sungem_phy.c */
+ /* enable fiber mode */
+ spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020);
+ /* LEDs active in both modes, autosense prio = fiber */
+ spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f);
+
+ phy->def->ops->read_link(phy);
+ pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
+ phy->speed, phy->duplex==1 ? "Full" : "Half");
+
+ return 0;
+}
+
+/**
+ * spider_net_download_firmware - loads firmware into the adapter
+ * @card: card structure
+ * @firmware: firmware pointer
+ *
+ * spider_net_download_firmware loads the firmware opened by
+ * spider_net_init_firmware into the adapter.
+ */
+static void
+spider_net_download_firmware(struct spider_net_card *card,
+ const struct firmware *firmware)
+{
+ int sequencer, i;
+ u32 *fw_ptr = (u32 *)firmware->data;
+
+ /* stop sequencers */
+ spider_net_write_reg(card, SPIDER_NET_GSINIT,
+ SPIDER_NET_STOP_SEQ_VALUE);
+
+ for (sequencer = 0; sequencer < 6; sequencer++) {
+ spider_net_write_reg(card,
+ SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
+ for (i = 0; i < SPIDER_NET_FIRMWARE_LEN; i++) {
+ spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+ sequencer * 8, *fw_ptr);
+ fw_ptr++;
+ }
+ }
+
+ spider_net_write_reg(card, SPIDER_NET_GSINIT,
+ SPIDER_NET_RUN_SEQ_VALUE);
+}
+
+/**
+ * spider_net_init_firmware - reads in firmware parts
+ * @card: card structure
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_init_firmware opens the sequencer firmware and does some basic
+ * checks. This function opens and releases the firmware structure. A call
+ * to download the firmware is performed before the release.
+ *
+ * Firmware format
+ * ===============
+ * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
+ * the program for each sequencer. Use the command
+ * tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt \
+ * Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt \
+ * Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
+ *
+ * to generate spider_fw.bin, if you have sequencer programs with something
+ * like the following contents for each sequencer:
+ * <ONE LINE COMMENT>
+ * <FIRST 4-BYTES-WORD FOR SEQUENCER>
+ * <SECOND 4-BYTES-WORD FOR SEQUENCER>
+ * ...
+ * <1024th 4-BYTES-WORD FOR SEQUENCER>
+ */
+static int
+spider_net_init_firmware(struct spider_net_card *card)
+{
+ const struct firmware *firmware;
+ int err = -EIO;
+
+ if (request_firmware(&firmware,
+ SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) < 0) {
+ if (netif_msg_probe(card))
+ pr_err("Couldn't read in sequencer data file %s.\n",
+ SPIDER_NET_FIRMWARE_NAME);
+ firmware = NULL;
+ goto out;
+ }
+
+ if (firmware->size != 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32)) {
+ if (netif_msg_probe(card))
+ pr_err("Invalid size of sequencer data file %s.\n",
+ SPIDER_NET_FIRMWARE_NAME);
+ goto out;
+ }
+
+ spider_net_download_firmware(card, firmware);
+
+ err = 0;
+out:
+ release_firmware(firmware);
+
+ return err;
+}
+
+/**
+ * spider_net_workaround_rxramfull - work around firmware bug
+ * @card: card structure
+ *
+ * no return value
+ **/
+static void
+spider_net_workaround_rxramfull(struct spider_net_card *card)
+{
+ int i, sequencer = 0;
+
+ /* cancel reset */
+ spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+ SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+ /* empty sequencer data */
+ for (sequencer = 0; sequencer < 6; sequencer++) {
+ spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+ sequencer * 8, 0x0);
+ for (i = 0; i < SPIDER_NET_FIRMWARE_LEN; i++) {
+ spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+ sequencer * 8, 0x0);
+ }
+ }
+
+ /* set sequencer operation */
+ spider_net_write_reg(card, SPIDER_NET_GSINIT, 0x000000fe);
+
+ /* reset */
+ spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+ SPIDER_NET_CKRCTRL_STOP_VALUE);
+}
+
+/**
+ * spider_net_tx_timeout_task - task scheduled by the watchdog timeout
+ * function (to be called not under interrupt status)
+ * @data: data, is interface device structure
+ *
+ * called as task when tx hangs, resets interface (if interface is up)
+ */
+static void
+spider_net_tx_timeout_task(void *data)
+{
+ struct net_device *netdev = data;
+ struct spider_net_card *card = netdev_priv(netdev);
+
+ if (!(netdev->flags & IFF_UP))
+ goto out;
+
+ netif_device_detach(netdev);
+ spider_net_stop(netdev);
+
+ spider_net_workaround_rxramfull(card);
+ spider_net_init_card(card);
+
+ if (spider_net_setup_phy(card))
+ goto out;
+ if (spider_net_init_firmware(card))
+ goto out;
+
+ spider_net_open(netdev);
+ spider_net_kick_tx_dma(card, card->tx_chain.head);
+ netif_device_attach(netdev);
+
+out:
+ atomic_dec(&card->tx_timeout_task_counter);
+}
+
+/**
+ * spider_net_tx_timeout - called when the tx timeout watchdog kicks in.
+ * @netdev: interface device structure
+ *
+ * called, if tx hangs. Schedules a task that resets the interface
+ */
+static void
+spider_net_tx_timeout(struct net_device *netdev)
+{
+ struct spider_net_card *card;
+
+ card = netdev_priv(netdev);
+ atomic_inc(&card->tx_timeout_task_counter);
+ if (netdev->flags & IFF_UP)
+ schedule_work(&card->tx_timeout_task);
+ else
+ atomic_dec(&card->tx_timeout_task_counter);
+}
+
+/**
+ * spider_net_setup_netdev_ops - initialization of net_device operations
+ * @netdev: net_device structure
+ *
+ * fills out function pointers in the net_device structure
+ */
+static void
+spider_net_setup_netdev_ops(struct net_device *netdev)
+{
+ netdev->open = &spider_net_open;
+ netdev->stop = &spider_net_stop;
+ netdev->hard_start_xmit = &spider_net_xmit;
+ netdev->get_stats = &spider_net_get_stats;
+ netdev->set_multicast_list = &spider_net_set_multi;
+ netdev->set_mac_address = &spider_net_set_mac;
+ netdev->change_mtu = &spider_net_change_mtu;
+ netdev->do_ioctl = &spider_net_do_ioctl;
+ /* tx watchdog */
+ netdev->tx_timeout = &spider_net_tx_timeout;
+ netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
+ /* NAPI */
+ netdev->poll = &spider_net_poll;
+ netdev->weight = SPIDER_NET_NAPI_WEIGHT;
+ /* HW VLAN */
+ netdev->vlan_rx_register = &spider_net_vlan_rx_reg;
+ netdev->vlan_rx_add_vid = &spider_net_vlan_rx_add;
+ netdev->vlan_rx_kill_vid = &spider_net_vlan_rx_kill;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ /* poll controller */
+ netdev->poll_controller = &spider_net_poll_controller;
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+ /* ethtool ops */
+ netdev->ethtool_ops = &spider_net_ethtool_ops;
+}
+
+/**
+ * spider_net_setup_netdev - initialization of net_device
+ * @card: card structure
+ *
+ * Returns 0 on success or <0 on failure
+ *
+ * spider_net_setup_netdev initializes the net_device structure
+ **/
+static int
+spider_net_setup_netdev(struct spider_net_card *card)
+{
+ int result;
+ struct net_device *netdev = card->netdev;
+ struct device_node *dn;
+ struct sockaddr addr;
+ u8 *mac;
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &card->pdev->dev);
+
+ pci_set_drvdata(card->pdev, netdev);
+ spin_lock_init(&card->intmask_lock);
+ netdev->irq = card->pdev->irq;
+
+ card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+
+ spider_net_setup_netdev_ops(netdev);
+
+ netdev->features = 0;
+ /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ * NETIF_F_HW_VLAN_FILTER */
+
+ netdev->irq = card->pdev->irq;
+
+ dn = pci_device_to_OF_node(card->pdev);
+ if (!dn)
+ return -EIO;
+
+ mac = (u8 *)get_property(dn, "local-mac-address", NULL);
+ if (!mac)
+ return -EIO;
+ memcpy(addr.sa_data, mac, ETH_ALEN);
+
+ result = spider_net_set_mac(netdev, &addr);
+ if ((result) && (netif_msg_probe(card)))
+ pr_err("Failed to set MAC address: %i\n", result);
+
+ result = register_netdev(netdev);
+ if (result) {
+ if (netif_msg_probe(card))
+ pr_err("Couldn't register net_device: %i\n",
+ result);
+ return result;
+ }
+
+ if (netif_msg_probe(card))
+ pr_info("Initialized device %s.\n", netdev->name);
+
+ return 0;
+}
+
+/**
+ * spider_net_alloc_card - allocates net_device and card structure
+ *
+ * returns the card structure or NULL in case of errors
+ *
+ * the card and net_device structures are linked to each other
+ */
+static struct spider_net_card *
+spider_net_alloc_card(void)
+{
+ struct net_device *netdev;
+ struct spider_net_card *card;
+ size_t alloc_size;
+
+ alloc_size = sizeof (*card) +
+ sizeof (struct spider_net_descr) * rx_descriptors +
+ sizeof (struct spider_net_descr) * tx_descriptors;
+ netdev = alloc_etherdev(alloc_size);
+ if (!netdev)
+ return NULL;
+
+ card = netdev_priv(netdev);
+ card->netdev = netdev;
+ card->msg_enable = SPIDER_NET_DEFAULT_MSG;
+ INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task, netdev);
+ init_waitqueue_head(&card->waitq);
+ atomic_set(&card->tx_timeout_task_counter, 0);
+
+ return card;
+}
+
+/**
+ * spider_net_undo_pci_setup - releases PCI ressources
+ * @card: card structure
+ *
+ * spider_net_undo_pci_setup releases the mapped regions
+ */
+static void
+spider_net_undo_pci_setup(struct spider_net_card *card)
+{
+ iounmap(card->regs);
+ pci_release_regions(card->pdev);
+}
+
+/**
+ * spider_net_setup_pci_dev - sets up the device in terms of PCI operations
+ * @card: card structure
+ * @pdev: PCI device
+ *
+ * Returns the card structure or NULL if any errors occur
+ *
+ * spider_net_setup_pci_dev initializes pdev and together with the
+ * functions called in spider_net_open configures the device so that
+ * data can be transferred over it
+ * The net_device structure is attached to the card structure, if the
+ * function returns without error.
+ **/
+static struct spider_net_card *
+spider_net_setup_pci_dev(struct pci_dev *pdev)
+{
+ struct spider_net_card *card;
+ unsigned long mmio_start, mmio_len;
+
+ if (pci_enable_device(pdev)) {
+ pr_err("Couldn't enable PCI device\n");
+ return NULL;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ pr_err("Couldn't find proper PCI device base address.\n");
+ goto out_disable_dev;
+ }
+
+ if (pci_request_regions(pdev, spider_net_driver_name)) {
+ pr_err("Couldn't obtain PCI resources, aborting.\n");
+ goto out_disable_dev;
+ }
+
+ pci_set_master(pdev);
+
+ card = spider_net_alloc_card();
+ if (!card) {
+ pr_err("Couldn't allocate net_device structure, "
+ "aborting.\n");
+ goto out_release_regions;
+ }
+ card->pdev = pdev;
+
+ /* fetch base address and length of first resource */
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+
+ card->netdev->mem_start = mmio_start;
+ card->netdev->mem_end = mmio_start + mmio_len;
+ card->regs = ioremap(mmio_start, mmio_len);
+
+ if (!card->regs) {
+ pr_err("Couldn't obtain PCI resources, aborting.\n");
+ goto out_release_regions;
+ }
+
+ return card;
+
+out_release_regions:
+ pci_release_regions(pdev);
+out_disable_dev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return NULL;
+}
+
+/**
+ * spider_net_probe - initialization of a device
+ * @pdev: PCI device
+ * @ent: entry in the device id list
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_probe initializes pdev and registers a net_device
+ * structure for it. After that, the device can be ifconfig'ed up
+ **/
+static int __devinit
+spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -EIO;
+ struct spider_net_card *card;
+
+ card = spider_net_setup_pci_dev(pdev);
+ if (!card)
+ goto out;
+
+ spider_net_workaround_rxramfull(card);
+ spider_net_init_card(card);
+
+ err = spider_net_setup_phy(card);
+ if (err)
+ goto out_undo_pci;
+
+ err = spider_net_init_firmware(card);
+ if (err)
+ goto out_undo_pci;
+
+ err = spider_net_setup_netdev(card);
+ if (err)
+ goto out_undo_pci;
+
+ return 0;
+
+out_undo_pci:
+ spider_net_undo_pci_setup(card);
+ free_netdev(card->netdev);
+out:
+ return err;
+}
+
+/**
+ * spider_net_remove - removal of a device
+ * @pdev: PCI device
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_remove is called to remove the device and unregisters the
+ * net_device
+ **/
+static void __devexit
+spider_net_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev;
+ struct spider_net_card *card;
+
+ netdev = pci_get_drvdata(pdev);
+ card = netdev_priv(netdev);
+
+ wait_event(card->waitq,
+ atomic_read(&card->tx_timeout_task_counter) == 0);
+
+ unregister_netdev(netdev);
+
+ /* switch off card */
+ spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+ SPIDER_NET_CKRCTRL_STOP_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+ SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+ spider_net_undo_pci_setup(card);
+ free_netdev(netdev);
+}
+
+static struct pci_driver spider_net_driver = {
+ .owner = THIS_MODULE,
+ .name = spider_net_driver_name,
+ .id_table = spider_net_pci_tbl,
+ .probe = spider_net_probe,
+ .remove = __devexit_p(spider_net_remove)
+};
+
+/**
+ * spider_net_init - init function when the driver is loaded
+ *
+ * spider_net_init registers the device driver
+ */
+static int __init spider_net_init(void)
+{
+ if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
+ rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
+ pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+ }
+ if (rx_descriptors > SPIDER_NET_RX_DESCRIPTORS_MAX) {
+ rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MAX;
+ pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+ }
+ if (tx_descriptors < SPIDER_NET_TX_DESCRIPTORS_MIN) {
+ tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MIN;
+ pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
+ }
+ if (tx_descriptors > SPIDER_NET_TX_DESCRIPTORS_MAX) {
+ tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MAX;
+ pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
+ }
+
+ return pci_register_driver(&spider_net_driver);
+}
+
+/**
+ * spider_net_cleanup - exit function when driver is unloaded
+ *
+ * spider_net_cleanup unregisters the device driver
+ */
+static void __exit spider_net_cleanup(void)
+{
+ pci_unregister_driver(&spider_net_driver);
+}
+
+module_init(spider_net_init);
+module_exit(spider_net_cleanup);
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
new file mode 100644
index 0000000..22b2f23
--- /dev/null
+++ b/drivers/net/spider_net.h
@@ -0,0 +1,469 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ * Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPIDER_NET_H
+#define _SPIDER_NET_H
+
+#include "sungem_phy.h"
+
+extern int spider_net_stop(struct net_device *netdev);
+extern int spider_net_open(struct net_device *netdev);
+
+extern struct ethtool_ops spider_net_ethtool_ops;
+
+extern char spider_net_driver_name[];
+
+#define SPIDER_NET_MAX_MTU 2308
+#define SPIDER_NET_MIN_MTU 64
+
+#define SPIDER_NET_RXBUF_ALIGN 128
+
+#define SPIDER_NET_RX_DESCRIPTORS_DEFAULT 64
+#define SPIDER_NET_RX_DESCRIPTORS_MIN 16
+#define SPIDER_NET_RX_DESCRIPTORS_MAX 256
+
+#define SPIDER_NET_TX_DESCRIPTORS_DEFAULT 64
+#define SPIDER_NET_TX_DESCRIPTORS_MIN 16
+#define SPIDER_NET_TX_DESCRIPTORS_MAX 256
+
+#define SPIDER_NET_RX_CSUM_DEFAULT 1
+
+#define SPIDER_NET_WATCHDOG_TIMEOUT 5*HZ
+#define SPIDER_NET_NAPI_WEIGHT 64
+
+#define SPIDER_NET_FIRMWARE_LEN 1024
+#define SPIDER_NET_FIRMWARE_NAME "spider_fw.bin"
+
+/** spider_net SMMIO registers */
+#define SPIDER_NET_GHIINT0STS 0x00000000
+#define SPIDER_NET_GHIINT1STS 0x00000004
+#define SPIDER_NET_GHIINT2STS 0x00000008
+#define SPIDER_NET_GHIINT0MSK 0x00000010
+#define SPIDER_NET_GHIINT1MSK 0x00000014
+#define SPIDER_NET_GHIINT2MSK 0x00000018
+
+#define SPIDER_NET_GRESUMINTNUM 0x00000020
+#define SPIDER_NET_GREINTNUM 0x00000024
+
+#define SPIDER_NET_GFFRMNUM 0x00000028
+#define SPIDER_NET_GFAFRMNUM 0x0000002c
+#define SPIDER_NET_GFBFRMNUM 0x00000030
+#define SPIDER_NET_GFCFRMNUM 0x00000034
+#define SPIDER_NET_GFDFRMNUM 0x00000038
+
+/* clear them (don't use it) */
+#define SPIDER_NET_GFREECNNUM 0x0000003c
+#define SPIDER_NET_GONETIMENUM 0x00000040
+
+#define SPIDER_NET_GTOUTFRMNUM 0x00000044
+
+#define SPIDER_NET_GTXMDSET 0x00000050
+#define SPIDER_NET_GPCCTRL 0x00000054
+#define SPIDER_NET_GRXMDSET 0x00000058
+#define SPIDER_NET_GIPSECINIT 0x0000005c
+#define SPIDER_NET_GFTRESTRT 0x00000060
+#define SPIDER_NET_GRXDMAEN 0x00000064
+#define SPIDER_NET_GMRWOLCTRL 0x00000068
+#define SPIDER_NET_GPCWOPCMD 0x0000006c
+#define SPIDER_NET_GPCROPCMD 0x00000070
+#define SPIDER_NET_GTTFRMCNT 0x00000078
+#define SPIDER_NET_GTESTMD 0x0000007c
+
+#define SPIDER_NET_GSINIT 0x00000080
+#define SPIDER_NET_GSnPRGADR 0x00000084
+#define SPIDER_NET_GSnPRGDAT 0x00000088
+
+#define SPIDER_NET_GMACOPEMD 0x00000100
+#define SPIDER_NET_GMACLENLMT 0x00000108
+#define SPIDER_NET_GMACINTEN 0x00000118
+#define SPIDER_NET_GMACPHYCTRL 0x00000120
+
+#define SPIDER_NET_GMACAPAUSE 0x00000154
+#define SPIDER_NET_GMACTXPAUSE 0x00000164
+
+#define SPIDER_NET_GMACMODE 0x000001b0
+#define SPIDER_NET_GMACBSTLMT 0x000001b4
+
+#define SPIDER_NET_GMACUNIMACU 0x000001c0
+#define SPIDER_NET_GMACUNIMACL 0x000001c8
+
+#define SPIDER_NET_GMRMHFILnR 0x00000400
+#define SPIDER_NET_MULTICAST_HASHES 256
+
+#define SPIDER_NET_GMRUAFILnR 0x00000500
+#define SPIDER_NET_GMRUA0FIL15R 0x00000578
+
+/* RX DMA controller registers, all 0x00000a.. are for DMA controller A,
+ * 0x00000b.. for DMA controller B, etc. */
+#define SPIDER_NET_GDADCHA 0x00000a00
+#define SPIDER_NET_GDADMACCNTR 0x00000a04
+#define SPIDER_NET_GDACTDPA 0x00000a08
+#define SPIDER_NET_GDACTDCNT 0x00000a0c
+#define SPIDER_NET_GDACDBADDR 0x00000a20
+#define SPIDER_NET_GDACDBSIZE 0x00000a24
+#define SPIDER_NET_GDACNEXTDA 0x00000a28
+#define SPIDER_NET_GDACCOMST 0x00000a2c
+#define SPIDER_NET_GDAWBCOMST 0x00000a30
+#define SPIDER_NET_GDAWBRSIZE 0x00000a34
+#define SPIDER_NET_GDAWBVSIZE 0x00000a38
+#define SPIDER_NET_GDAWBTRST 0x00000a3c
+#define SPIDER_NET_GDAWBTRERR 0x00000a40
+
+/* TX DMA controller registers */
+#define SPIDER_NET_GDTDCHA 0x00000e00
+#define SPIDER_NET_GDTDMACCNTR 0x00000e04
+#define SPIDER_NET_GDTCDPA 0x00000e08
+#define SPIDER_NET_GDTDMASEL 0x00000e14
+
+#define SPIDER_NET_ECMODE 0x00000f00
+/* clock and reset control register */
+#define SPIDER_NET_CKRCTRL 0x00000ff0
+
+/** SCONFIG registers */
+#define SPIDER_NET_SCONFIG_IOACTE 0x00002810
+
+/** hardcoded register values */
+#define SPIDER_NET_INT0_MASK_VALUE 0x3f7fe3ff
+#define SPIDER_NET_INT1_MASK_VALUE 0xffffffff
+/* no MAC aborts -> auto retransmission */
+#define SPIDER_NET_INT2_MASK_VALUE 0xfffffff1
+
+/* clear counter when interrupt sources are cleared
+#define SPIDER_NET_FRAMENUM_VALUE 0x0001f001 */
+/* we rely on flagged descriptor interrupts */
+#define SPIDER_NET_FRAMENUM_VALUE 0x00000000
+/* set this first, then the FRAMENUM_VALUE */
+#define SPIDER_NET_GFXFRAMES_VALUE 0x00000000
+
+#define SPIDER_NET_STOP_SEQ_VALUE 0x00000000
+#define SPIDER_NET_RUN_SEQ_VALUE 0x0000007e
+
+#define SPIDER_NET_PHY_CTRL_VALUE 0x00040040
+/* #define SPIDER_NET_PHY_CTRL_VALUE 0x01070080*/
+#define SPIDER_NET_RXMODE_VALUE 0x00000011
+/* auto retransmission in case of MAC aborts */
+#define SPIDER_NET_TXMODE_VALUE 0x00010000
+#define SPIDER_NET_RESTART_VALUE 0x00000000
+#define SPIDER_NET_WOL_VALUE 0x00001111
+#if 0
+#define SPIDER_NET_WOL_VALUE 0x00000000
+#endif
+#define SPIDER_NET_IPSECINIT_VALUE 0x00f000f8
+
+/* pause frames: automatic, no upper retransmission count */
+/* outside loopback mode: ETOMOD signal dont matter, not connected */
+#define SPIDER_NET_OPMODE_VALUE 0x00000063
+/*#define SPIDER_NET_OPMODE_VALUE 0x001b0062*/
+#define SPIDER_NET_LENLMT_VALUE 0x00000908
+
+#define SPIDER_NET_MACAPAUSE_VALUE 0x00000800 /* about 1 ms */
+#define SPIDER_NET_TXPAUSE_VALUE 0x00000000
+
+#define SPIDER_NET_MACMODE_VALUE 0x00000001
+#define SPIDER_NET_BURSTLMT_VALUE 0x00000200 /* about 16 us */
+
+/* 1(0) enable r/tx dma
+ * 0000000 fixed to 0
+ *
+ * 000000 fixed to 0
+ * 0(1) en/disable descr writeback on force end
+ * 0(1) force end
+ *
+ * 000000 fixed to 0
+ * 00 burst alignment: 128 bytes
+ *
+ * 00000 fixed to 0
+ * 0 descr writeback size 32 bytes
+ * 0(1) descr chain end interrupt enable
+ * 0(1) descr status writeback enable */
+
+/* to set RX_DMA_EN */
+#define SPIDER_NET_DMA_RX_VALUE 0x80000000
+#define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003
+/* to set TX_DMA_EN */
+#define SPIDER_NET_DMA_TX_VALUE 0x80000000
+#define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003
+
+/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
+#define SPIDER_NET_UA_DESCR_VALUE 0x00080000
+#define SPIDER_NET_PROMISC_VALUE 0x00080000
+#define SPIDER_NET_NONPROMISC_VALUE 0x00000000
+
+#define SPIDER_NET_DMASEL_VALUE 0x00000001
+
+#define SPIDER_NET_ECMODE_VALUE 0x00000000
+
+#define SPIDER_NET_CKRCTRL_RUN_VALUE 0x1fff010f
+#define SPIDER_NET_CKRCTRL_STOP_VALUE 0x0000010f
+
+#define SPIDER_NET_SBIMSTATE_VALUE 0x00000000
+#define SPIDER_NET_SBTMSTATE_VALUE 0x00000000
+
+/* SPIDER_NET_GHIINT0STS bits, in reverse order so that they can be used
+ * with 1 << SPIDER_NET_... */
+enum spider_net_int0_status {
+ SPIDER_NET_GPHYINT = 0,
+ SPIDER_NET_GMAC2INT,
+ SPIDER_NET_GMAC1INT,
+ SPIDER_NET_GIPSINT,
+ SPIDER_NET_GFIFOINT,
+ SPIDER_NET_GDMACINT,
+ SPIDER_NET_GSYSINT,
+ SPIDER_NET_GPWOPCMPINT,
+ SPIDER_NET_GPROPCMPINT,
+ SPIDER_NET_GPWFFINT,
+ SPIDER_NET_GRMDADRINT,
+ SPIDER_NET_GRMARPINT,
+ SPIDER_NET_GRMMPINT,
+ SPIDER_NET_GDTDEN0INT,
+ SPIDER_NET_GDDDEN0INT,
+ SPIDER_NET_GDCDEN0INT,
+ SPIDER_NET_GDBDEN0INT,
+ SPIDER_NET_GDADEN0INT,
+ SPIDER_NET_GDTFDCINT,
+ SPIDER_NET_GDDFDCINT,
+ SPIDER_NET_GDCFDCINT,
+ SPIDER_NET_GDBFDCINT,
+ SPIDER_NET_GDAFDCINT,
+ SPIDER_NET_GTTEDINT,
+ SPIDER_NET_GDTDCEINT,
+ SPIDER_NET_GRFDNMINT,
+ SPIDER_NET_GRFCNMINT,
+ SPIDER_NET_GRFBNMINT,
+ SPIDER_NET_GRFANMINT,
+ SPIDER_NET_GRFNMINT,
+ SPIDER_NET_G1TMCNTINT,
+ SPIDER_NET_GFREECNTINT
+};
+/* GHIINT1STS bits */
+enum spider_net_int1_status {
+ SPIDER_NET_GTMFLLINT = 0,
+ SPIDER_NET_GRMFLLINT,
+ SPIDER_NET_GTMSHTINT,
+ SPIDER_NET_GDTINVDINT,
+ SPIDER_NET_GRFDFLLINT,
+ SPIDER_NET_GDDDCEINT,
+ SPIDER_NET_GDDINVDINT,
+ SPIDER_NET_GRFCFLLINT,
+ SPIDER_NET_GDCDCEINT,
+ SPIDER_NET_GDCINVDINT,
+ SPIDER_NET_GRFBFLLINT,
+ SPIDER_NET_GDBDCEINT,
+ SPIDER_NET_GDBINVDINT,
+ SPIDER_NET_GRFAFLLINT,
+ SPIDER_NET_GDADCEINT,
+ SPIDER_NET_GDAINVDINT,
+ SPIDER_NET_GDTRSERINT,
+ SPIDER_NET_GDDRSERINT,
+ SPIDER_NET_GDCRSERINT,
+ SPIDER_NET_GDBRSERINT,
+ SPIDER_NET_GDARSERINT,
+ SPIDER_NET_GDSERINT,
+ SPIDER_NET_GDTPTERINT,
+ SPIDER_NET_GDDPTERINT,
+ SPIDER_NET_GDCPTERINT,
+ SPIDER_NET_GDBPTERINT,
+ SPIDER_NET_GDAPTERINT
+};
+/* GHIINT2STS bits */
+enum spider_net_int2_status {
+ SPIDER_NET_GPROPERINT = 0,
+ SPIDER_NET_GMCTCRSNGINT,
+ SPIDER_NET_GMCTLCOLINT,
+ SPIDER_NET_GMCTTMOTINT,
+ SPIDER_NET_GMCRCAERINT,
+ SPIDER_NET_GMCRCALERINT,
+ SPIDER_NET_GMCRALNERINT,
+ SPIDER_NET_GMCROVRINT,
+ SPIDER_NET_GMCRRNTINT,
+ SPIDER_NET_GMCRRXERINT,
+ SPIDER_NET_GTITCSERINT,
+ SPIDER_NET_GTIFMTERINT,
+ SPIDER_NET_GTIPKTRVKINT,
+ SPIDER_NET_GTISPINGINT,
+ SPIDER_NET_GTISADNGINT,
+ SPIDER_NET_GTISPDNGINT,
+ SPIDER_NET_GRIFMTERINT,
+ SPIDER_NET_GRIPKTRVKINT,
+ SPIDER_NET_GRISPINGINT,
+ SPIDER_NET_GRISADNGINT,
+ SPIDER_NET_GRISPDNGINT
+};
+
+#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \
+ (1 << SPIDER_NET_GDTDCEINT) | \
+ (1 << SPIDER_NET_GDTFDCINT) )
+
+/* we rely on flagged descriptor interrupts*/
+#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \
+ (1 << SPIDER_NET_GRMFLLINT) )
+
+#define SPIDER_NET_GPREXEC 0x80000000
+#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
+
+/* descriptor bits
+ *
+ * 1010 descriptor ready
+ * 0 descr in middle of chain
+ * 000 fixed to 0
+ *
+ * 0 no interrupt on completion
+ * 000 fixed to 0
+ * 1 no ipsec processing
+ * 1 last descriptor for this frame
+ * 00 no checksum
+ * 10 tcp checksum
+ * 11 udp checksum
+ *
+ * 00 fixed to 0
+ * 0 fixed to 0
+ * 0 no interrupt on response errors
+ * 0 no interrupt on invalid descr
+ * 0 no interrupt on dma process termination
+ * 0 no interrupt on descr chain end
+ * 0 no interrupt on descr complete
+ *
+ * 000 fixed to 0
+ * 0 response error interrupt status
+ * 0 invalid descr status
+ * 0 dma termination status
+ * 0 descr chain end status
+ * 0 descr complete status */
+#define SPIDER_NET_DMAC_CMDSTAT_NOCS 0xa00c0000
+#define SPIDER_NET_DMAC_CMDSTAT_TCPCS 0xa00e0000
+#define SPIDER_NET_DMAC_CMDSTAT_UDPCS 0xa00f0000
+#define SPIDER_NET_DESCR_IND_PROC_SHIFT 28
+#define SPIDER_NET_DESCR_IND_PROC_MASKO 0x0fffffff
+
+/* descr ready, descr is in middle of chain, get interrupt on completion */
+#define SPIDER_NET_DMAC_RX_CARDOWNED 0xa0800000
+
+/* multicast is no problem */
+#define SPIDER_NET_DATA_ERROR_MASK 0xffffbfff
+
+enum spider_net_descr_status {
+ SPIDER_NET_DESCR_COMPLETE = 0x00, /* used in rx and tx */
+ SPIDER_NET_DESCR_RESPONSE_ERROR = 0x01, /* used in rx and tx */
+ SPIDER_NET_DESCR_PROTECTION_ERROR = 0x02, /* used in rx and tx */
+ SPIDER_NET_DESCR_FRAME_END = 0x04, /* used in rx */
+ SPIDER_NET_DESCR_FORCE_END = 0x05, /* used in rx and tx */
+ SPIDER_NET_DESCR_CARDOWNED = 0x0a, /* used in rx and tx */
+ SPIDER_NET_DESCR_NOT_IN_USE /* any other value */
+};
+
+struct spider_net_descr {
+ /* as defined by the hardware */
+ dma_addr_t buf_addr;
+ u32 buf_size;
+ dma_addr_t next_descr_addr;
+ u32 dmac_cmd_status;
+ u32 result_size;
+ u32 valid_size; /* all zeroes for tx */
+ u32 data_status;
+ u32 data_error; /* all zeroes for tx */
+
+ /* used in the driver */
+ struct sk_buff *skb;
+ dma_addr_t bus_addr;
+ struct spider_net_descr *next;
+ struct spider_net_descr *prev;
+} __attribute__((aligned(32)));
+
+struct spider_net_descr_chain {
+ /* we walk from tail to head */
+ struct spider_net_descr *head;
+ struct spider_net_descr *tail;
+};
+
+/* descriptor data_status bits */
+#define SPIDER_NET_RXIPCHK 29
+#define SPIDER_NET_TCPUDPIPCHK 28
+#define SPIDER_NET_DATA_STATUS_CHK_MASK (1 << SPIDER_NET_RXIPCHK | \
+ 1 << SPIDER_NET_TCPUDPIPCHK)
+
+#define SPIDER_NET_VLAN_PACKET 21
+
+/* descriptor data_error bits */
+#define SPIDER_NET_RXIPCHKERR 27
+#define SPIDER_NET_RXTCPCHKERR 26
+#define SPIDER_NET_DATA_ERROR_CHK_MASK (1 << SPIDER_NET_RXIPCHKERR | \
+ 1 << SPIDER_NET_RXTCPCHKERR)
+
+/* the cases we don't pass the packet to the stack */
+#define SPIDER_NET_DESTROY_RX_FLAGS 0x70138000
+
+#define SPIDER_NET_DESCR_SIZE 32
+
+/* this will be bigger some time */
+struct spider_net_options {
+ int rx_csum; /* for rx: if 0 ip_summed=NONE,
+ if 1 and hw has verified, ip_summed=UNNECESSARY */
+};
+
+#define SPIDER_NET_DEFAULT_MSG ( NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR | \
+ NETIF_MSG_TX_QUEUED | \
+ NETIF_MSG_INTR | \
+ NETIF_MSG_TX_DONE | \
+ NETIF_MSG_RX_STATUS | \
+ NETIF_MSG_PKTDATA | \
+ NETIF_MSG_HW | \
+ NETIF_MSG_WOL )
+
+struct spider_net_card {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct mii_phy phy;
+
+ void __iomem *regs;
+
+ struct spider_net_descr_chain tx_chain;
+ struct spider_net_descr_chain rx_chain;
+ spinlock_t chain_lock;
+
+ struct net_device_stats netdev_stats;
+
+ struct spider_net_options options;
+
+ spinlock_t intmask_lock;
+
+ struct work_struct tx_timeout_task;
+ atomic_t tx_timeout_task_counter;
+ wait_queue_head_t waitq;
+
+ /* for ethtool */
+ int msg_enable;
+
+ struct spider_net_descr descr[0];
+};
+
+#define pr_err(fmt,arg...) \
+ printk(KERN_ERR fmt ,##arg)
+
+#endif
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
new file mode 100644
index 0000000..d42e60b
--- /dev/null
+++ b/drivers/net/spider_net_ethtool.c
@@ -0,0 +1,126 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ * Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+
+#include "spider_net.h"
+
+static int
+spider_net_ethtool_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct spider_net_card *card;
+ card = netdev_priv(netdev);
+
+ cmd->supported = (SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE);
+ cmd->advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE);
+ cmd->port = PORT_FIBRE;
+ cmd->speed = card->phy.speed;
+ cmd->duplex = DUPLEX_FULL;
+
+ return 0;
+}
+
+static void
+spider_net_ethtool_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct spider_net_card *card;
+ card = netdev_priv(netdev);
+
+ /* clear and fill out info */
+ memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
+ strncpy(drvinfo->driver, spider_net_driver_name, 32);
+ strncpy(drvinfo->version, "0.1", 32);
+ strcpy(drvinfo->fw_version, "no information");
+ strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+}
+
+static void
+spider_net_ethtool_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ /* no support for wol */
+ wolinfo->supported = 0;
+ wolinfo->wolopts = 0;
+}
+
+static u32
+spider_net_ethtool_get_msglevel(struct net_device *netdev)
+{
+ struct spider_net_card *card;
+ card = netdev_priv(netdev);
+ return card->msg_enable;
+}
+
+static void
+spider_net_ethtool_set_msglevel(struct net_device *netdev,
+ u32 level)
+{
+ struct spider_net_card *card;
+ card = netdev_priv(netdev);
+ card->msg_enable = level;
+}
+
+static int
+spider_net_ethtool_nway_reset(struct net_device *netdev)
+{
+ if (netif_running(netdev)) {
+ spider_net_stop(netdev);
+ spider_net_open(netdev);
+ }
+ return 0;
+}
+
+static u32
+spider_net_ethtool_get_rx_csum(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev->priv;
+
+ return card->options.rx_csum;
+}
+
+static int
+spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n)
+{
+ struct spider_net_card *card = netdev->priv;
+
+ card->options.rx_csum = n;
+ return 0;
+}
+
+struct ethtool_ops spider_net_ethtool_ops = {
+ .get_settings = spider_net_ethtool_get_settings,
+ .get_drvinfo = spider_net_ethtool_get_drvinfo,
+ .get_wol = spider_net_ethtool_get_wol,
+ .get_msglevel = spider_net_ethtool_get_msglevel,
+ .set_msglevel = spider_net_ethtool_set_msglevel,
+ .nway_reset = spider_net_ethtool_nway_reset,
+ .get_rx_csum = spider_net_ethtool_get_rx_csum,
+ .set_rx_csum = spider_net_ethtool_set_rx_csum,
+};
+
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 1f43bbf..5c8fcd4 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -162,7 +162,7 @@
#define MEM lp->mem
#define DREG lp->iobase[0]
#define AREG lp->iobase[1]
-#define REGA(a) ( AREG = (a), DREG )
+#define REGA(a) (*( AREG = (a), &DREG ))
/* Definitions for the Lance */
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 2608e7a..3f67a42 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -948,6 +948,7 @@
u32 gem_status = readl(gp->regs + GREG_STAT);
if (gem_status == 0) {
+ netif_poll_enable(dev);
spin_unlock_irqrestore(&gp->lock, flags);
return IRQ_NONE;
}
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 7143fd7..ff8ae5f 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -1020,7 +1020,7 @@
struct gem_init_block *init_block;
struct sk_buff *rx_skbs[RX_RING_SIZE];
- struct sk_buff *tx_skbs[RX_RING_SIZE];
+ struct sk_buff *tx_skbs[TX_RING_SIZE];
dma_addr_t gblock_dvma;
struct pci_dev *pdev;
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index af8263a..dc57352 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -36,6 +36,7 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/workqueue.h>
+#include <linux/prefetch.h>
#include <net/checksum.h>
@@ -66,8 +67,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.37"
-#define DRV_MODULE_RELDATE "August 25, 2005"
+#define DRV_MODULE_VERSION "3.39"
+#define DRV_MODULE_RELDATE "September 5, 2005"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -121,12 +122,9 @@
TG3_RX_RCB_RING_SIZE(tp))
#define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \
TG3_TX_RING_SIZE)
-#define TX_RING_GAP(TP) \
- (TG3_TX_RING_SIZE - (TP)->tx_pending)
#define TX_BUFFS_AVAIL(TP) \
- (((TP)->tx_cons <= (TP)->tx_prod) ? \
- (TP)->tx_cons + (TP)->tx_pending - (TP)->tx_prod : \
- (TP)->tx_cons - (TP)->tx_prod - TX_RING_GAP(TP))
+ ((TP)->tx_pending - \
+ (((TP)->tx_prod - (TP)->tx_cons) & (TG3_TX_RING_SIZE - 1)))
#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
#define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64)
@@ -490,7 +488,8 @@
static inline void tg3_cond_int(struct tg3 *tp)
{
- if (tp->hw_status->status & SD_STATUS_UPDATED)
+ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
+ (tp->hw_status->status & SD_STATUS_UPDATED))
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
}
@@ -2880,9 +2879,13 @@
tp->tx_cons = sw_idx;
- if (netif_queue_stopped(tp->dev) &&
- (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH))
- netif_wake_queue(tp->dev);
+ if (unlikely(netif_queue_stopped(tp->dev))) {
+ spin_lock(&tp->tx_lock);
+ if (netif_queue_stopped(tp->dev) &&
+ (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH))
+ netif_wake_queue(tp->dev);
+ spin_unlock(&tp->tx_lock);
+ }
}
/* Returns size of skb allocated or < 0 on error.
@@ -3198,9 +3201,7 @@
/* run TX completion thread */
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
- spin_lock(&tp->tx_lock);
tg3_tx(tp);
- spin_unlock(&tp->tx_lock);
}
/* run RX thread, within the bounds set by NAPI.
@@ -3220,18 +3221,17 @@
netdev->quota -= work_done;
}
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+ if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
tp->last_tag = sblk->status_tag;
- rmb();
- sblk->status &= ~SD_STATUS_UPDATED;
+ rmb();
+ } else
+ sblk->status &= ~SD_STATUS_UPDATED;
/* if no more work, tell net stack and NIC we're done */
done = !tg3_has_work(tp);
if (done) {
- spin_lock(&tp->lock);
netif_rx_complete(netdev);
tg3_restart_ints(tp);
- spin_unlock(&tp->lock);
}
return (done ? 0 : 1);
@@ -3279,8 +3279,9 @@
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
- struct tg3_hw_status *sblk = tp->hw_status;
+ prefetch(tp->hw_status);
+ prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
/*
* Writing any value to intr-mbox-0 clears PCI INTA# and
* chip-internal interrupt pending events.
@@ -3289,19 +3290,9 @@
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
- tp->last_tag = sblk->status_tag;
- rmb();
- if (tg3_irq_sync(tp))
- goto out;
- sblk->status &= ~SD_STATUS_UPDATED;
- if (likely(tg3_has_work(tp)))
+ if (likely(!tg3_irq_sync(tp)))
netif_rx_schedule(dev); /* schedule NAPI poll */
- else {
- /* No work, re-enable interrupts. */
- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
- tp->last_tag << 24);
- }
-out:
+
return IRQ_RETVAL(1);
}
@@ -3331,9 +3322,10 @@
if (tg3_irq_sync(tp))
goto out;
sblk->status &= ~SD_STATUS_UPDATED;
- if (likely(tg3_has_work(tp)))
+ if (likely(tg3_has_work(tp))) {
+ prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
netif_rx_schedule(dev); /* schedule NAPI poll */
- else {
+ } else {
/* No work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
*/
@@ -3359,7 +3351,7 @@
* Reading the PCI State register will confirm whether the
* interrupt is ours and will flush the status block.
*/
- if ((sblk->status & SD_STATUS_UPDATED) ||
+ if ((sblk->status_tag != tp->last_tag) ||
!(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
/*
* writing any value to intr-mbox-0 clears PCI INTA# and
@@ -3370,19 +3362,17 @@
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
- tp->last_tag = sblk->status_tag;
- rmb();
if (tg3_irq_sync(tp))
goto out;
- sblk->status &= ~SD_STATUS_UPDATED;
- if (likely(tg3_has_work(tp)))
- netif_rx_schedule(dev); /* schedule NAPI poll */
- else {
- /* no work, shared interrupt perhaps? re-enable
- * interrupts, and flush that PCI write
+ if (netif_rx_schedule_prep(dev)) {
+ prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
+ /* Update last_tag to mark that this status has been
+ * seen. Because interrupt may be shared, we may be
+ * racing with tg3_poll(), so only update last_tag
+ * if tg3_poll() is not scheduled.
*/
- tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
- tp->last_tag << 24);
+ tp->last_tag = sblk->status_tag;
+ __netif_rx_schedule(dev);
}
} else { /* shared interrupt */
handled = 0;
@@ -3716,8 +3706,11 @@
tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
tp->tx_prod = entry;
- if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
+ if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) {
netif_stop_queue(dev);
+ if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
+ netif_wake_queue(tp->dev);
+ }
out_unlock:
mmiowb();
@@ -5960,7 +5953,7 @@
tw32(MAC_LED_CTRL, tp->led_ctrl);
tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
udelay(10);
}
@@ -6242,6 +6235,7 @@
if (err)
return err;
+ tp->hw_status->status &= ~SD_STATUS_UPDATED;
tg3_enable_ints(tp);
tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
@@ -7557,6 +7551,38 @@
}
}
+static int tg3_phys_id(struct net_device *dev, u32 data)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ int i;
+
+ if (!netif_running(tp->dev))
+ return -EAGAIN;
+
+ if (data == 0)
+ data = 2;
+
+ for (i = 0; i < (data * 2); i++) {
+ if ((i % 2) == 0)
+ tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_1000MBPS_ON |
+ LED_CTRL_100MBPS_ON |
+ LED_CTRL_10MBPS_ON |
+ LED_CTRL_TRAFFIC_OVERRIDE |
+ LED_CTRL_TRAFFIC_BLINK |
+ LED_CTRL_TRAFFIC_LED);
+
+ else
+ tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_TRAFFIC_OVERRIDE);
+
+ if (msleep_interruptible(500))
+ break;
+ }
+ tw32(MAC_LED_CTRL, tp->led_ctrl);
+ return 0;
+}
+
static void tg3_get_ethtool_stats (struct net_device *dev,
struct ethtool_stats *estats, u64 *tmp_stats)
{
@@ -7616,7 +7642,7 @@
if (!netif_running(tp->dev))
return -ENODEV;
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
max = TG3_SERDES_TIMEOUT_SEC;
else
max = TG3_COPPER_TIMEOUT_SEC;
@@ -7901,9 +7927,12 @@
return err;
}
-static int tg3_test_loopback(struct tg3 *tp)
+#define TG3_MAC_LOOPBACK 0
+#define TG3_PHY_LOOPBACK 1
+
+static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
{
- u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key;
+ u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key;
u32 desc_idx;
struct sk_buff *skb, *rx_skb;
u8 *tx_data;
@@ -7911,18 +7940,26 @@
int num_pkts, tx_len, rx_len, i, err;
struct tg3_rx_buffer_desc *desc;
- if (!netif_running(tp->dev))
- return -ENODEV;
+ if (loopback_mode == TG3_MAC_LOOPBACK) {
+ mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+ MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
+ MAC_MODE_PORT_MODE_GMII;
+ tw32(MAC_MODE, mac_mode);
+ } else if (loopback_mode == TG3_PHY_LOOPBACK) {
+ mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+ MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
+ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
+ mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ tw32(MAC_MODE, mac_mode);
+
+ tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+ BMCR_SPEED1000);
+ }
+ else
+ return -EINVAL;
err = -EIO;
- tg3_reset_hw(tp);
-
- mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
- MAC_MODE_PORT_MODE_GMII;
- tw32(MAC_MODE, mac_mode);
-
tx_len = 1514;
skb = dev_alloc_skb(tx_len);
tx_data = skb_put(skb, tx_len);
@@ -7943,15 +7980,15 @@
rx_start_idx = tp->hw_status->idx[0].rx_producer;
- send_idx = 0;
num_pkts = 0;
- tg3_set_txd(tp, send_idx, map, tx_len, 0, 1);
+ tg3_set_txd(tp, tp->tx_prod, map, tx_len, 0, 1);
- send_idx++;
+ tp->tx_prod++;
num_pkts++;
- tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx);
+ tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW,
+ tp->tx_prod);
tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW);
udelay(10);
@@ -7964,7 +8001,7 @@
tx_idx = tp->hw_status->idx[0].tx_consumer;
rx_idx = tp->hw_status->idx[0].rx_producer;
- if ((tx_idx == send_idx) &&
+ if ((tx_idx == tp->tx_prod) &&
(rx_idx == (rx_start_idx + num_pkts)))
break;
}
@@ -7972,7 +8009,7 @@
pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
- if (tx_idx != send_idx)
+ if (tx_idx != tp->tx_prod)
goto out;
if (rx_idx != rx_start_idx + num_pkts)
@@ -8008,6 +8045,30 @@
return err;
}
+#define TG3_MAC_LOOPBACK_FAILED 1
+#define TG3_PHY_LOOPBACK_FAILED 2
+#define TG3_LOOPBACK_FAILED (TG3_MAC_LOOPBACK_FAILED | \
+ TG3_PHY_LOOPBACK_FAILED)
+
+static int tg3_test_loopback(struct tg3 *tp)
+{
+ int err = 0;
+
+ if (!netif_running(tp->dev))
+ return TG3_LOOPBACK_FAILED;
+
+ tg3_reset_hw(tp);
+
+ if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
+ err |= TG3_MAC_LOOPBACK_FAILED;
+ if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+ if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
+ err |= TG3_PHY_LOOPBACK_FAILED;
+ }
+
+ return err;
+}
+
static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
u64 *data)
{
@@ -8048,10 +8109,8 @@
etest->flags |= ETH_TEST_FL_FAILED;
data[3] = 1;
}
- if (tg3_test_loopback(tp) != 0) {
+ if ((data[4] = tg3_test_loopback(tp)) != 0)
etest->flags |= ETH_TEST_FL_FAILED;
- data[4] = 1;
- }
tg3_full_unlock(tp);
@@ -8239,6 +8298,7 @@
.self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
+ .phys_id = tg3_phys_id,
.get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
.get_coalesce = tg3_get_coalesce,
@@ -8303,7 +8363,8 @@
tw32(NVRAM_CFG1, nvcfg1);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)) {
switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
@@ -8717,8 +8778,9 @@
if (i == (len - 4))
nvram_cmd |= NVRAM_CMD_LAST;
- if ((tp->nvram_jedecnum == JEDEC_ST) &&
- (nvram_cmd & NVRAM_CMD_FIRST)) {
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
+ (tp->nvram_jedecnum == JEDEC_ST) &&
+ (nvram_cmd & NVRAM_CMD_FIRST)) {
if ((ret = tg3_nvram_exec_cmd(tp,
NVRAM_CMD_WREN | NVRAM_CMD_GO |
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index fc353e3..a22d001 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1934,7 +1934,7 @@
struct de_private *de;
int rc;
void __iomem *regs;
- long pciaddr;
+ unsigned long pciaddr;
static int board_idx = -1;
board_idx++;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 05da5be..6266a9a 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -238,6 +238,7 @@
{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
{ 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
+ { 0x1414, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 5ae22b7..1a431633 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
-#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -34,6 +33,7 @@
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
#include <asm/processor.h>
#include <asm/bitops.h>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index effab0b..50b8c67 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -18,6 +18,9 @@
/*
* Changes:
*
+ * Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14
+ * Add TUNSETLINK ioctl to set the link encapsulation
+ *
* Mark Smith <markzzzsmith@yahoo.com.au>
* Use random_ether_addr() for tap MAC address.
*
@@ -612,6 +615,18 @@
DBG(KERN_INFO "%s: owner set to %d\n", tun->dev->name, tun->owner);
break;
+ case TUNSETLINK:
+ /* Only allow setting the type when the interface is down */
+ if (tun->dev->flags & IFF_UP) {
+ DBG(KERN_INFO "%s: Linktype set failed because interface is up\n",
+ tun->dev->name);
+ return -EBUSY;
+ } else {
+ tun->dev->type = (int) arg;
+ DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type);
+ }
+ break;
+
#ifdef TUN_DEBUG
case TUNSETDEBUG:
tun->debug = arg;
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index f58c794..b56a7b5 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -1440,6 +1440,7 @@
* @skb: The buffer to process
* @dev: The device it arrived on
* @p: Unused
+ * @orig_dev: Unused
*
* Protocol glue. This drives the deferred processing mode the poorer
* cards use. This can be called directly by cards that do not have
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ec3f75a..00a07f3 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -137,6 +137,110 @@
comment "Wireless 802.11b ISA/PCI cards support"
depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA)
+config IPW2100
+ tristate "Intel PRO/Wireless 2100 Network Connection"
+ depends on NET_RADIO && PCI && IEEE80211
+ select FW_LOADER
+ ---help---
+ A driver for the Intel PRO/Wireless 2100 Network
+ Connection 802.11b wireless network adapter.
+
+ See <file:Documentation/networking/README.ipw2100> for information on
+ the capabilities currently enabled in this driver and for tips
+ for debugging issues and problems.
+
+ In order to use this driver, you will need a firmware image for it.
+ You can obtain the firmware from
+ <http://ipw2100.sf.net/>. Once you have the firmware image, you
+ will need to place it in /etc/firmware.
+
+ You will also very likely need the Wireless Tools in order to
+ configure your card:
+
+ <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and remvoed from the running kernel whenever you want),
+ say M here and read <file:Documentation/modules.txt>. The module
+ will be called ipw2100.ko.
+
+config IPW2100_MONITOR
+ bool "Enable promiscuous mode"
+ depends on IPW2100
+ ---help---
+ Enables promiscuous/monitor mode support for the ipw2100 driver.
+ With this feature compiled into the driver, you can switch to
+ promiscuous mode via the Wireless Tool's Monitor mode. While in this
+ mode, no packets can be sent.
+
+config IPW_DEBUG
+ bool "Enable full debugging output in IPW2100 module."
+ depends on IPW2100
+ ---help---
+ This option will enable debug tracing output for the IPW2100.
+
+ This will result in the kernel module being ~60k larger. You can
+ control which debug output is sent to the kernel log by setting the
+ value in
+
+ /sys/bus/pci/drivers/ipw2100/debug_level
+
+ This entry will only exist if this option is enabled.
+
+ If you are not trying to debug or develop the IPW2100 driver, you
+ most likely want to say N here.
+
+config IPW2200
+ tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
+ depends on IEEE80211 && PCI
+ select FW_LOADER
+ ---help---
+ A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
+ Connection adapters.
+
+ See <file:Documentation/networking/README.ipw2200> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging issues and problems.
+
+ In order to use this driver, you will need a firmware image for it.
+ You can obtain the firmware from
+ <http://ipw2200.sf.net/>. See the above referenced README.ipw2200
+ for information on where to install the firmare images.
+
+ You will also very likely need the Wireless Tools in order to
+ configure your card:
+
+ <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and remvoed from the running kernel whenever you want),
+ say M here and read <file:Documentation/modules.txt>. The module
+ will be called ipw2200.ko.
+
+config IPW_DEBUG
+ bool "Enable full debugging output in IPW2200 module."
+ depends on IPW2200
+ ---help---
+ This option will enable debug tracing output for the IPW2200.
+
+ This will result in the kernel module being ~100k larger. You can
+ control which debug output is sent to the kernel log by setting the
+ value in
+
+ /sys/bus/pci/drivers/ipw2200/debug_level
+
+ This entry will only exist if this option is enabled.
+
+ To set a value, simply echo an 8-byte hex value to the same file:
+
+ % echo 0x00000FFO > /sys/bus/pci/drivers/ipw2200/debug_level
+
+ You can find the list of debug mask values in
+ drivers/net/wireless/ipw2200.h
+
+ If you are not trying to debug or develop the IPW2200 driver, you
+ most likely want to say N here.
+
config AIRO
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
depends on NET_RADIO && ISA && (PCI || BROKEN)
@@ -185,8 +289,8 @@
a non-standard interface
config PLX_HERMES
- tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)"
- depends on PCI && HERMES && EXPERIMENTAL
+ tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
+ depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in PLX9052 based PCI adaptors. These
@@ -195,12 +299,9 @@
802.11b PCMCIA cards can be used in desktop machines. The Netgear
MA301 is such an adaptor.
- Support for these adaptors is so far still incomplete and buggy.
- You have been warned.
-
config TMD_HERMES
- tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)"
- depends on PCI && HERMES && EXPERIMENTAL
+ tristate "Hermes in TMD7160 based PCI adaptor support"
+ depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in TMD7160 based PCI adaptors. These
@@ -208,12 +309,18 @@
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines.
- Support for these adaptors is so far still incomplete and buggy.
- You have been warned.
+config NORTEL_HERMES
+ tristate "Nortel emobility PCI adaptor support"
+ depends on PCI && HERMES
+ help
+ Enable support for PCMCIA cards supported by the "Hermes" (aka
+ orinoco) driver when used in Nortel emobility PCI adaptors. These
+ adaptors are not full PCMCIA controllers, but act as a more limited
+ PCI <-> PCMCIA bridge.
config PCI_HERMES
- tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)"
- depends on PCI && HERMES && EXPERIMENTAL
+ tristate "Prism 2.5 PCI 802.11b adaptor support"
+ depends on PCI && HERMES
help
Enable support for PCI and mini-PCI 802.11b wireless NICs based on
the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
@@ -268,6 +375,19 @@
configure your card and that /etc/pcmcia/wireless.opts works:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+config PCMCIA_SPECTRUM
+ tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
+ depends on NET_RADIO && PCMCIA && HERMES
+ ---help---
+
+ This is a driver for 802.11b cards using RAM-loadable Symbol
+ firmware, such as Symbol Wireless Networker LA4100, CompactFlash
+ cards by Socket Communications and Intel PRO/Wireless 2011B.
+
+ This driver requires firmware download on startup. Utilities
+ for downloading Symbol firmware are available at
+ <http://sourceforge.net/projects/orinoco/>
+
config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
@@ -355,6 +475,8 @@
say M here and read <file:Documentation/modules.txt>. The module
will be called prism54.ko.
+source "drivers/net/wireless/hostap/Kconfig"
+
# yes, this works even when no drivers are selected
config NET_WIRELESS
bool
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 2b87841..3a6f7ba 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -2,6 +2,10 @@
# Makefile for the Linux Wireless network device drivers.
#
+obj-$(CONFIG_IPW2100) += ipw2100.o
+
+obj-$(CONFIG_IPW2200) += ipw2200.o
+
obj-$(CONFIG_STRIP) += strip.o
obj-$(CONFIG_ARLAN) += arlan.o
@@ -18,6 +22,8 @@
obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
@@ -28,6 +34,8 @@
obj-$(CONFIG_PRISM54) += prism54/
+obj-$(CONFIG_HOSTAP) += hostap/
+
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index df20adc..2be65d3 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1040,7 +1040,7 @@
u16 status;
} WifiCtlHdr;
-WifiCtlHdr wifictlhdr8023 = {
+static WifiCtlHdr wifictlhdr8023 = {
.ctlhdr = {
.ctl = HOST_DONT_RLSE,
}
@@ -1111,13 +1111,13 @@
static void timer_func( struct net_device *dev );
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
#ifdef WIRELESS_EXT
-struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
+static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
static void airo_read_wireless_stats (struct airo_info *local);
#endif /* WIRELESS_EXT */
#ifdef CISCO_EXT
static int readrids(struct net_device *dev, aironet_ioctl *comp);
static int writerids(struct net_device *dev, aironet_ioctl *comp);
-int flashcard(struct net_device *dev, aironet_ioctl *comp);
+static int flashcard(struct net_device *dev, aironet_ioctl *comp);
#endif /* CISCO_EXT */
#ifdef MICSUPPORT
static void micinit(struct airo_info *ai);
@@ -1226,6 +1226,12 @@
static int takedown_proc_entry( struct net_device *dev,
struct airo_info *apriv );
+static int cmdreset(struct airo_info *ai);
+static int setflashmode (struct airo_info *ai);
+static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
+static int flashputbuf(struct airo_info *ai);
+static int flashrestart(struct airo_info *ai,struct net_device *dev);
+
#ifdef MICSUPPORT
/***********************************************************************
* MIC ROUTINES *
@@ -1234,10 +1240,11 @@
static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
static void MoveWindow(miccntx *context, u32 micSeq);
-void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
-void emmh32_init(emmh32_context *context);
-void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
-void emmh32_final(emmh32_context *context, u8 digest[4]);
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
+static void emmh32_init(emmh32_context *context);
+static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
+static void emmh32_final(emmh32_context *context, u8 digest[4]);
+static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
/* micinit - Initialize mic seed */
@@ -1301,7 +1308,7 @@
int i;
if (ai->tfm == NULL)
- ai->tfm = crypto_alloc_tfm("aes", 0);
+ ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
if (ai->tfm == NULL) {
printk(KERN_ERR "airo: failed to load transform for AES\n");
@@ -1315,7 +1322,7 @@
return SUCCESS;
}
-char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
+static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
/*===========================================================================
* Description: Mic a packet
@@ -1570,7 +1577,7 @@
static unsigned char aes_counter[16];
/* expand the key to fill the MMH coefficient array */
-void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
{
/* take the keying material, expand if necessary, truncate at 16-bytes */
/* run through AES counter mode to generate context->coeff[] */
@@ -1602,7 +1609,7 @@
}
/* prepare for calculation of a new mic */
-void emmh32_init(emmh32_context *context)
+static void emmh32_init(emmh32_context *context)
{
/* prepare for new mic calculation */
context->accum = 0;
@@ -1610,7 +1617,7 @@
}
/* add some bytes to the mic calculation */
-void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
+static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
{
int coeff_position, byte_position;
@@ -1652,7 +1659,7 @@
static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
/* calculate the mic */
-void emmh32_final(emmh32_context *context, u8 digest[4])
+static void emmh32_final(emmh32_context *context, u8 digest[4])
{
int coeff_position, byte_position;
u32 val;
@@ -2232,7 +2239,7 @@
u32 *vals = stats_rid.vals;
clear_bit(JOB_STATS, &ai->flags);
- if (ai->power) {
+ if (ai->power.event) {
up(&ai->sem);
return;
}
@@ -2255,7 +2262,7 @@
ai->stats.rx_fifo_errors = vals[0];
}
-struct net_device_stats *airo_get_stats(struct net_device *dev)
+static struct net_device_stats *airo_get_stats(struct net_device *dev)
{
struct airo_info *local = dev->priv;
@@ -2403,8 +2410,7 @@
}
}
#ifdef MICSUPPORT
- if (ai->tfm)
- crypto_free_tfm(ai->tfm);
+ crypto_free_tfm(ai->tfm);
#endif
del_airo_dev( dev );
free_netdev( dev );
@@ -2414,7 +2420,7 @@
static int add_airo_dev( struct net_device *dev );
-int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
{
memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
return ETH_ALEN;
@@ -2681,7 +2687,7 @@
return dev;
}
-int reset_card( struct net_device *dev , int lock) {
+static int reset_card( struct net_device *dev , int lock) {
struct airo_info *ai = dev->priv;
if (lock && down_interruptible(&ai->sem))
@@ -2696,9 +2702,9 @@
return 0;
}
-struct net_device *_init_airo_card( unsigned short irq, int port,
- int is_pcmcia, struct pci_dev *pci,
- struct device *dmdev )
+static struct net_device *_init_airo_card( unsigned short irq, int port,
+ int is_pcmcia, struct pci_dev *pci,
+ struct device *dmdev )
{
struct net_device *dev;
struct airo_info *ai;
@@ -2962,7 +2968,7 @@
break;
}
- if (ai->power || test_bit(FLAG_FLASHING, &ai->flags)) {
+ if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
up(&ai->sem);
continue;
}
@@ -3252,7 +3258,7 @@
wstats.noise = apriv->wstats.qual.noise;
wstats.updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_QUAL_UPDATED
- | IW_QUAL_NOISE_UPDATED;
+ | IW_QUAL_DBM;
/* Update spy records */
wireless_spy_update(dev, sa, &wstats);
}
@@ -3598,7 +3604,7 @@
wstats.noise = ai->wstats.qual.noise;
wstats.updated = IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_UPDATED;
+ | IW_QUAL_DBM;
/* Update spy records */
wireless_spy_update(ai->dev, sa, &wstats);
}
@@ -5514,7 +5520,7 @@
pci_restore_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0);
- if (ai->power > 1) {
+ if (ai->power.event > 1) {
reset_card(dev, 0);
mpi_init_descriptors(ai);
setup_card(ai, dev->dev_addr, 0);
@@ -6483,22 +6489,20 @@
range->max_qual.qual = 100; /* % */
else
range->max_qual.qual = airo_get_max_quality(&cap_rid);
- range->max_qual.level = 0; /* 0 means we use dBm */
- range->max_qual.noise = 0;
- range->max_qual.updated = 0;
+ range->max_qual.level = 0x100 - 120; /* -120 dBm */
+ range->max_qual.noise = 0x100 - 120; /* -120 dBm */
/* Experimental measurements - boundary 11/5.5 Mb/s */
/* Note : with or without the (local->rssi), results
* are somewhat different. - Jean II */
if (local->rssi) {
- range->avg_qual.qual = 50; /* % */
- range->avg_qual.level = 186; /* -70 dBm */
+ range->avg_qual.qual = 50; /* % */
+ range->avg_qual.level = 0x100 - 70; /* -70 dBm */
} else {
range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
- range->avg_qual.level = 176; /* -80 dBm */
+ range->avg_qual.level = 0x100 - 80; /* -80 dBm */
}
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 0;
+ range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
for(i = 0 ; i < 8 ; i++) {
range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
@@ -6721,15 +6725,17 @@
if (local->rssi) {
qual[i].level = 0x100 - BSSList.dBm;
qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
- qual[i].updated = IW_QUAL_QUAL_UPDATED;
+ qual[i].updated = IW_QUAL_QUAL_UPDATED
+ | IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_DBM;
} else {
qual[i].level = (BSSList.dBm + 321) / 2;
qual[i].qual = 0;
- qual[i].updated = IW_QUAL_QUAL_INVALID;
+ qual[i].updated = IW_QUAL_QUAL_INVALID
+ | IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_DBM;
}
qual[i].noise = local->wstats.qual.noise;
- qual[i].updated = IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_UPDATED;
if (BSSList.index == 0xffff)
break;
}
@@ -6855,15 +6861,17 @@
if (ai->rssi) {
iwe.u.qual.level = 0x100 - bss->dBm;
iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED;
+ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
+ | IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_DBM;
} else {
iwe.u.qual.level = (bss->dBm + 321) / 2;
iwe.u.qual.qual = 0;
- iwe.u.qual.updated = IW_QUAL_QUAL_INVALID;
+ iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
+ | IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_DBM;
}
iwe.u.qual.noise = ai->wstats.qual.noise;
- iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_UPDATED;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
/* Add encryption capability */
@@ -7116,7 +7124,7 @@
int rc = 0;
struct airo_info *ai = (struct airo_info *)dev->priv;
- if (ai->power)
+ if (ai->power.event)
return 0;
switch (cmd) {
@@ -7195,7 +7203,7 @@
/* Get stats out of the card */
clear_bit(JOB_WSTATS, &local->flags);
- if (local->power) {
+ if (local->power.event) {
up(&local->sem);
return;
}
@@ -7216,13 +7224,12 @@
local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
}
- local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED;
if (status_rid.len >= 124) {
local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
- local->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED;
+ local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
} else {
local->wstats.qual.noise = 0;
- local->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
+ local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM;
}
/* Packets discarded in the wireless adapter due to wireless
@@ -7235,7 +7242,7 @@
local->wstats.miss.beacon = vals[34];
}
-struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
+static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
{
struct airo_info *local = dev->priv;
@@ -7450,14 +7457,8 @@
* Flash command switch table
*/
-int flashcard(struct net_device *dev, aironet_ioctl *comp) {
+static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
int z;
- int cmdreset(struct airo_info *);
- int setflashmode(struct airo_info *);
- int flashgchar(struct airo_info *,int,int);
- int flashpchar(struct airo_info *,int,int);
- int flashputbuf(struct airo_info *);
- int flashrestart(struct airo_info *,struct net_device *);
/* Only super-user can modify flash */
if (!capable(CAP_NET_ADMIN))
@@ -7515,7 +7516,7 @@
* card.
*/
-int cmdreset(struct airo_info *ai) {
+static int cmdreset(struct airo_info *ai) {
disable_MAC(ai, 1);
if(!waitbusy (ai)){
@@ -7539,7 +7540,7 @@
* mode
*/
-int setflashmode (struct airo_info *ai) {
+static int setflashmode (struct airo_info *ai) {
set_bit (FLAG_FLASHING, &ai->flags);
OUT4500(ai, SWS0, FLASH_COMMAND);
@@ -7566,7 +7567,7 @@
* x 50us for echo .
*/
-int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
+static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
int echo;
int waittime;
@@ -7606,7 +7607,7 @@
* Get a character from the card matching matchbyte
* Step 3)
*/
-int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
+static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
int rchar;
unsigned char rbyte=0;
@@ -7637,7 +7638,7 @@
* send to the card
*/
-int flashputbuf(struct airo_info *ai){
+static int flashputbuf(struct airo_info *ai){
int nwords;
/* Write stuff */
@@ -7659,7 +7660,7 @@
/*
*
*/
-int flashrestart(struct airo_info *ai,struct net_device *dev){
+static int flashrestart(struct airo_info *ai,struct net_device *dev){
int i,status;
ssleep(1); /* Added 12/7/00 */
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 18a7d38..587869d 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -68,7 +68,7 @@
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
-#include "ieee802_11.h"
+#include <net/ieee80211.h>
#include "atmel.h"
#define DRIVER_MAJOR 0
@@ -618,12 +618,12 @@
static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
static void atmel_command_irq(struct atmel_private *priv);
static int atmel_validate_channel(struct atmel_private *priv, int channel);
-static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
u16 frame_len, u8 rssi);
static void atmel_management_timer(u_long a);
static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size);
static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size);
-static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
u8 *body, int body_len);
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -827,7 +827,7 @@
static int start_tx (struct sk_buff *skb, struct net_device *dev)
{
struct atmel_private *priv = netdev_priv(dev);
- struct ieee802_11_hdr header;
+ struct ieee80211_hdr header;
unsigned long flags;
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
@@ -863,17 +863,17 @@
return 1;
}
- frame_ctl = IEEE802_11_FTYPE_DATA;
+ frame_ctl = IEEE80211_FTYPE_DATA;
header.duration_id = 0;
header.seq_ctl = 0;
if (priv->wep_is_on)
- frame_ctl |= IEEE802_11_FCTL_WEP;
+ frame_ctl |= IEEE80211_FCTL_PROTECTED;
if (priv->operating_mode == IW_MODE_ADHOC) {
memcpy(&header.addr1, skb->data, 6);
memcpy(&header.addr2, dev->dev_addr, 6);
memcpy(&header.addr3, priv->BSSID, 6);
} else {
- frame_ctl |= IEEE802_11_FCTL_TODS;
+ frame_ctl |= IEEE80211_FCTL_TODS;
memcpy(&header.addr1, priv->CurrentBSSID, 6);
memcpy(&header.addr2, dev->dev_addr, 6);
memcpy(&header.addr3, skb->data, 6);
@@ -902,7 +902,7 @@
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
- struct ieee802_11_hdr *header,
+ struct ieee80211_hdr *header,
u8 *body, int body_len)
{
u16 buff;
@@ -917,7 +917,7 @@
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
}
-static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header,
u16 msdu_size, u16 rx_packet_loc, u32 crc)
{
/* fast path: unfragmented packet copy directly into skbuf */
@@ -955,7 +955,7 @@
}
memcpy(skbp, header->addr1, 6); /* destination address */
- if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS)
+ if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
memcpy(&skbp[6], header->addr3, 6);
else
memcpy(&skbp[6], header->addr2, 6); /* source address */
@@ -990,14 +990,14 @@
return (crc ^ 0xffffffff) == netcrc;
}
-static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header,
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags)
{
u8 mac4[6];
u8 source[6];
struct sk_buff *skb;
- if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS)
+ if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
memcpy(source, header->addr3, 6);
else
memcpy(source, header->addr2, 6);
@@ -1082,7 +1082,7 @@
static void rx_done_irq(struct atmel_private *priv)
{
int i;
- struct ieee802_11_hdr header;
+ struct ieee80211_hdr header;
for (i = 0;
atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -1117,7 +1117,7 @@
/* probe for CRC use here if needed once five packets have arrived with
the same crc status, we assume we know what's happening and stop probing */
if (priv->probe_crc) {
- if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) {
+ if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) {
priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
} else {
priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24);
@@ -1132,16 +1132,16 @@
}
/* don't CRC header when WEP in use */
- if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) {
+ if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) {
crc = crc32_le(0xffffffff, (unsigned char *)&header, 24);
}
msdu_size -= 24; /* header */
- if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) {
+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
- int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS;
- u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG;
- u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4;
+ int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS;
+ u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG;
+ u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4;
if (!more_fragments && packet_fragment_no == 0 ) {
fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc);
@@ -1151,7 +1151,7 @@
}
}
- if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) {
+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
/* copy rest of packet into buffer */
atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size);
@@ -1593,7 +1593,6 @@
dev->set_mac_address = atmel_set_mac_address;
dev->hard_start_xmit = start_tx;
dev->get_stats = atmel_get_stats;
- dev->get_wireless_stats = atmel_get_wireless_stats;
dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
dev->do_ioctl = atmel_ioctl;
dev->irq = irq;
@@ -2411,7 +2410,8 @@
.num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args),
.standard = (iw_handler *) atmel_handler,
.private = (iw_handler *) atmel_private_handler,
- .private_args = (struct iw_priv_args *) atmel_private_args
+ .private_args = (struct iw_priv_args *) atmel_private_args,
+ .get_wireless_stats = atmel_get_wireless_stats
};
static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -2424,19 +2424,6 @@
char domain[REGDOMAINSZ+1];
switch (cmd) {
- case SIOCGIWPRIV:
- if(wrq->u.data.pointer) {
- /* Set the number of ioctl available */
- wrq->u.data.length = sizeof(atmel_private_args) / sizeof(atmel_private_args[0]);
-
- /* Copy structure to the user buffer */
- if (copy_to_user(wrq->u.data.pointer,
- (u_char *) atmel_private_args,
- sizeof(atmel_private_args)))
- rc = -EFAULT;
- }
- break;
-
case ATMELIDIFC:
wrq->u.param.value = ATMELMAGIC;
break;
@@ -2663,10 +2650,10 @@
static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len)
{
- struct ieee802_11_hdr header;
+ struct ieee80211_hdr header;
struct auth_body auth;
- header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH);
+ header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
header.duration_id = cpu_to_le16(0x8000);
header.seq_ctl = 0;
memcpy(header.addr1, priv->CurrentBSSID, 6);
@@ -2677,7 +2664,7 @@
auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY);
/* no WEP for authentication frames with TrSeqNo 1 */
if (priv->CurrentAuthentTransactionSeqNum != 1)
- header.frame_ctl |= cpu_to_le16(IEEE802_11_FCTL_WEP);
+ header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
} else {
auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM);
}
@@ -2701,7 +2688,7 @@
{
u8 *ssid_el_p;
int bodysize;
- struct ieee802_11_hdr header;
+ struct ieee80211_hdr header;
struct ass_req_format {
u16 capability;
u16 listen_interval;
@@ -2714,8 +2701,8 @@
u8 rates[4];
} body;
- header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT |
- (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ));
+ header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
header.duration_id = cpu_to_le16(0x8000);
header.seq_ctl = 0;
@@ -2751,9 +2738,9 @@
atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
}
-static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header)
+static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header)
{
- if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS)
+ if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
else
return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
@@ -2801,7 +2788,7 @@
}
-static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header,
u16 capability, u16 beacon_period, u8 channel, u8 rssi,
u8 ssid_len, u8 *ssid, int is_beacon)
{
@@ -3085,12 +3072,12 @@
}
/* deals with incoming managment frames. */
-static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header,
+static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
u16 frame_len, u8 rssi)
{
u16 subtype;
- switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) {
+ switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE) {
case C80211_SUBTYPE_MGMT_BEACON :
case C80211_SUBTYPE_MGMT_ProbeResponse:
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
new file mode 100644
index 0000000..56f41c7
--- /dev/null
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -0,0 +1,73 @@
+config HOSTAP
+ tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
+ depends on NET_RADIO
+ select IEEE80211
+ select IEEE80211_CRYPT_WEP
+ ---help---
+ Shared driver code for IEEE 802.11b wireless cards based on
+ Intersil Prism2/2.5/3 chipset. This driver supports so called
+ Host AP mode that allows the card to act as an IEEE 802.11
+ access point.
+
+ See <http://hostap.epitest.fi/> for more information about the
+ Host AP driver configuration and tools. This site includes
+ information and tools (hostapd and wpa_supplicant) for WPA/WPA2
+ support.
+
+ This option includes the base Host AP driver code that is shared by
+ different hardware models. You will also need to enable support for
+ PLX/PCI/CS version of the driver to actually use the driver.
+
+ The driver can be compiled as a module and it will be called
+ "hostap.ko".
+
+config HOSTAP_FIRMWARE
+ bool "Support downloading firmware images with Host AP driver"
+ depends on HOSTAP
+ ---help---
+ Configure Host AP driver to include support for firmware image
+ download. Current version supports only downloading to volatile, i.e.,
+ RAM memory. Flash upgrade is not yet supported.
+
+ Firmware image downloading needs user space tool, prism2_srec. It is
+ available from http://hostap.epitest.fi/.
+
+config HOSTAP_PLX
+ tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
+ depends on PCI && HOSTAP
+ ---help---
+ Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
+ PCI adaptors.
+
+ "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+ driver and its help text includes more information about the Host AP
+ driver.
+
+ The driver can be compiled as a module and will be named
+ "hostap_plx.ko".
+
+config HOSTAP_PCI
+ tristate "Host AP driver for Prism2.5 PCI adaptors"
+ depends on PCI && HOSTAP
+ ---help---
+ Host AP driver's version for Prism2.5 PCI adaptors.
+
+ "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+ driver and its help text includes more information about the Host AP
+ driver.
+
+ The driver can be compiled as a module and will be named
+ "hostap_pci.ko".
+
+config HOSTAP_CS
+ tristate "Host AP driver for Prism2/2.5/3 PC Cards"
+ depends on PCMCIA!=n && HOSTAP
+ ---help---
+ Host AP driver's version for Prism2/2.5/3 PC Cards.
+
+ "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+ driver and its help text includes more information about the Host AP
+ driver.
+
+ The driver can be compiled as a module and will be named
+ "hostap_cs.ko".
diff --git a/drivers/net/wireless/hostap/Makefile b/drivers/net/wireless/hostap/Makefile
new file mode 100644
index 0000000..fc62235
--- /dev/null
+++ b/drivers/net/wireless/hostap/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_HOSTAP) += hostap.o
+
+obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
+obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
+obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c
new file mode 100644
index 0000000..e7f5821
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap.c
@@ -0,0 +1,1198 @@
+/*
+ * Host AP (software wireless LAN access point) driver for
+ * Intersil Prism2/2.5/3 - hostap.o module, common routines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/workqueue.h>
+#include <linux/kmod.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211_crypt.h>
+#include <asm/uaccess.h>
+
+#include "hostap_wlan.h"
+#include "hostap_80211.h"
+#include "hostap_ap.h"
+#include "hostap.h"
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP common routines");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+#define TX_TIMEOUT (2 * HZ)
+
+#define PRISM2_MAX_FRAME_SIZE 2304
+#define PRISM2_MIN_MTU 256
+/* FIX: */
+#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */))
+
+
+/* hostap.c */
+static int prism2_wds_add(local_info_t *local, u8 *remote_addr,
+ int rtnl_locked);
+static int prism2_wds_del(local_info_t *local, u8 *remote_addr,
+ int rtnl_locked, int do_not_remove);
+
+/* hostap_ap.c */
+static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
+ struct iw_quality qual[], int buf_size,
+ int aplist);
+static int prism2_ap_translate_scan(struct net_device *dev, char *buffer);
+static int prism2_hostapd(struct ap_data *ap,
+ struct prism2_hostapd_param *param);
+static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
+ struct ieee80211_crypt_data ***crypt);
+static void ap_control_kickall(struct ap_data *ap);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+static int ap_control_add_mac(struct mac_restrictions *mac_restrictions,
+ u8 *mac);
+static int ap_control_del_mac(struct mac_restrictions *mac_restrictions,
+ u8 *mac);
+static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);
+static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev,
+ u8 *mac);
+#endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484 };
+#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0]))
+
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
+
+/* FIX: these could be compiled separately and linked together to hostap.o */
+#include "hostap_ap.c"
+#include "hostap_info.c"
+#include "hostap_ioctl.c"
+#include "hostap_proc.c"
+#include "hostap_80211_rx.c"
+#include "hostap_80211_tx.c"
+
+
+struct net_device * hostap_add_interface(struct local_info *local,
+ int type, int rtnl_locked,
+ const char *prefix,
+ const char *name)
+{
+ struct net_device *dev, *mdev;
+ struct hostap_interface *iface;
+ int ret;
+
+ dev = alloc_etherdev(sizeof(struct hostap_interface));
+ if (dev == NULL)
+ return NULL;
+
+ iface = netdev_priv(dev);
+ iface->dev = dev;
+ iface->local = local;
+ iface->type = type;
+ list_add(&iface->list, &local->hostap_interfaces);
+
+ mdev = local->dev;
+ memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN);
+ dev->base_addr = mdev->base_addr;
+ dev->irq = mdev->irq;
+ dev->mem_start = mdev->mem_start;
+ dev->mem_end = mdev->mem_end;
+
+ hostap_setup_dev(dev, local, 0);
+ dev->destructor = free_netdev;
+
+ sprintf(dev->name, "%s%s", prefix, name);
+ if (!rtnl_locked)
+ rtnl_lock();
+
+ ret = 0;
+ if (strchr(dev->name, '%'))
+ ret = dev_alloc_name(dev, dev->name);
+
+ SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+ if (ret >= 0)
+ ret = register_netdevice(dev);
+
+ if (!rtnl_locked)
+ rtnl_unlock();
+
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: failed to add new netdevice!\n",
+ dev->name);
+ free_netdev(dev);
+ return NULL;
+ }
+
+ printk(KERN_DEBUG "%s: registered netdevice %s\n",
+ mdev->name, dev->name);
+
+ return dev;
+}
+
+
+void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
+ int remove_from_list)
+{
+ struct hostap_interface *iface;
+
+ if (!dev)
+ return;
+
+ iface = netdev_priv(dev);
+
+ if (remove_from_list) {
+ list_del(&iface->list);
+ }
+
+ if (dev == iface->local->ddev)
+ iface->local->ddev = NULL;
+ else if (dev == iface->local->apdev)
+ iface->local->apdev = NULL;
+ else if (dev == iface->local->stadev)
+ iface->local->stadev = NULL;
+
+ if (rtnl_locked)
+ unregister_netdevice(dev);
+ else
+ unregister_netdev(dev);
+
+ /* dev->destructor = free_netdev() will free the device data, including
+ * private data, when removing the device */
+}
+
+
+static inline int prism2_wds_special_addr(u8 *addr)
+{
+ if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5])
+ return 0;
+
+ return 1;
+}
+
+
+static int prism2_wds_add(local_info_t *local, u8 *remote_addr,
+ int rtnl_locked)
+{
+ struct net_device *dev;
+ struct list_head *ptr;
+ struct hostap_interface *iface, *empty, *match;
+
+ empty = match = NULL;
+ read_lock_bh(&local->iface_lock);
+ list_for_each(ptr, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type != HOSTAP_INTERFACE_WDS)
+ continue;
+
+ if (prism2_wds_special_addr(iface->u.wds.remote_addr))
+ empty = iface;
+ else if (memcmp(iface->u.wds.remote_addr, remote_addr,
+ ETH_ALEN) == 0) {
+ match = iface;
+ break;
+ }
+ }
+ if (!match && empty && !prism2_wds_special_addr(remote_addr)) {
+ /* take pre-allocated entry into use */
+ memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN);
+ read_unlock_bh(&local->iface_lock);
+ printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n",
+ local->dev->name, empty->dev->name);
+ return 0;
+ }
+ read_unlock_bh(&local->iface_lock);
+
+ if (!prism2_wds_special_addr(remote_addr)) {
+ if (match)
+ return -EEXIST;
+ hostap_add_sta(local->ap, remote_addr);
+ }
+
+ if (local->wds_connections >= local->wds_max_connections)
+ return -ENOBUFS;
+
+ /* verify that there is room for wds# postfix in the interface name */
+ if (strlen(local->dev->name) > IFNAMSIZ - 5) {
+ printk(KERN_DEBUG "'%s' too long base device name\n",
+ local->dev->name);
+ return -EINVAL;
+ }
+
+ dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked,
+ local->ddev->name, "wds%d");
+ if (dev == NULL)
+ return -ENOMEM;
+
+ iface = netdev_priv(dev);
+ memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN);
+
+ local->wds_connections++;
+
+ return 0;
+}
+
+
+static int prism2_wds_del(local_info_t *local, u8 *remote_addr,
+ int rtnl_locked, int do_not_remove)
+{
+ unsigned long flags;
+ struct list_head *ptr;
+ struct hostap_interface *iface, *selected = NULL;
+
+ write_lock_irqsave(&local->iface_lock, flags);
+ list_for_each(ptr, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type != HOSTAP_INTERFACE_WDS)
+ continue;
+
+ if (memcmp(iface->u.wds.remote_addr, remote_addr,
+ ETH_ALEN) == 0) {
+ selected = iface;
+ break;
+ }
+ }
+ if (selected && !do_not_remove)
+ list_del(&selected->list);
+ write_unlock_irqrestore(&local->iface_lock, flags);
+
+ if (selected) {
+ if (do_not_remove)
+ memset(selected->u.wds.remote_addr, 0, ETH_ALEN);
+ else {
+ hostap_remove_interface(selected->dev, rtnl_locked, 0);
+ local->wds_connections--;
+ }
+ }
+
+ return selected ? 0 : -ENODEV;
+}
+
+
+u16 hostap_tx_callback_register(local_info_t *local,
+ void (*func)(struct sk_buff *, int ok, void *),
+ void *data)
+{
+ unsigned long flags;
+ struct hostap_tx_callback_info *entry;
+
+ entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry),
+ GFP_ATOMIC);
+ if (entry == NULL)
+ return 0;
+
+ entry->func = func;
+ entry->data = data;
+
+ spin_lock_irqsave(&local->lock, flags);
+ entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1;
+ entry->next = local->tx_callback;
+ local->tx_callback = entry;
+ spin_unlock_irqrestore(&local->lock, flags);
+
+ return entry->idx;
+}
+
+
+int hostap_tx_callback_unregister(local_info_t *local, u16 idx)
+{
+ unsigned long flags;
+ struct hostap_tx_callback_info *cb, *prev = NULL;
+
+ spin_lock_irqsave(&local->lock, flags);
+ cb = local->tx_callback;
+ while (cb != NULL && cb->idx != idx) {
+ prev = cb;
+ cb = cb->next;
+ }
+ if (cb) {
+ if (prev == NULL)
+ local->tx_callback = cb->next;
+ else
+ prev->next = cb->next;
+ kfree(cb);
+ }
+ spin_unlock_irqrestore(&local->lock, flags);
+
+ return cb ? 0 : -1;
+}
+
+
+/* val is in host byte order */
+int hostap_set_word(struct net_device *dev, int rid, u16 val)
+{
+ struct hostap_interface *iface;
+ u16 tmp = cpu_to_le16(val);
+ iface = netdev_priv(dev);
+ return iface->local->func->set_rid(dev, rid, &tmp, 2);
+}
+
+
+int hostap_set_string(struct net_device *dev, int rid, const char *val)
+{
+ struct hostap_interface *iface;
+ char buf[MAX_SSID_LEN + 2];
+ int len;
+
+ iface = netdev_priv(dev);
+ len = strlen(val);
+ if (len > MAX_SSID_LEN)
+ return -1;
+ memset(buf, 0, sizeof(buf));
+ buf[0] = len; /* little endian 16 bit word */
+ memcpy(buf + 2, val, len);
+
+ return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2);
+}
+
+
+u16 hostap_get_porttype(local_info_t *local)
+{
+ if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc)
+ return HFA384X_PORTTYPE_PSEUDO_IBSS;
+ if (local->iw_mode == IW_MODE_ADHOC)
+ return HFA384X_PORTTYPE_IBSS;
+ if (local->iw_mode == IW_MODE_INFRA)
+ return HFA384X_PORTTYPE_BSS;
+ if (local->iw_mode == IW_MODE_REPEAT)
+ return HFA384X_PORTTYPE_WDS;
+ if (local->iw_mode == IW_MODE_MONITOR)
+ return HFA384X_PORTTYPE_PSEUDO_IBSS;
+ return HFA384X_PORTTYPE_HOSTAP;
+}
+
+
+int hostap_set_encryption(local_info_t *local)
+{
+ u16 val, old_val;
+ int i, keylen, len, idx;
+ char keybuf[WEP_KEY_LEN + 1];
+ enum { NONE, WEP, OTHER } encrypt_type;
+
+ idx = local->tx_keyidx;
+ if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL)
+ encrypt_type = NONE;
+ else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0)
+ encrypt_type = WEP;
+ else
+ encrypt_type = OTHER;
+
+ if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2,
+ 1) < 0) {
+ printk(KERN_DEBUG "Could not read current WEP flags.\n");
+ goto fail;
+ }
+ le16_to_cpus(&val);
+ old_val = val;
+
+ if (encrypt_type != NONE || local->privacy_invoked)
+ val |= HFA384X_WEPFLAGS_PRIVACYINVOKED;
+ else
+ val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED;
+
+ if (local->open_wep || encrypt_type == NONE ||
+ ((local->ieee_802_1x || local->wpa) && local->host_decrypt))
+ val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
+ else
+ val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
+
+ if ((encrypt_type != NONE || local->privacy_invoked) &&
+ (encrypt_type == OTHER || local->host_encrypt))
+ val |= HFA384X_WEPFLAGS_HOSTENCRYPT;
+ else
+ val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT;
+ if ((encrypt_type != NONE || local->privacy_invoked) &&
+ (encrypt_type == OTHER || local->host_decrypt))
+ val |= HFA384X_WEPFLAGS_HOSTDECRYPT;
+ else
+ val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT;
+
+ if (val != old_val &&
+ hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) {
+ printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n",
+ val);
+ goto fail;
+ }
+
+ if (encrypt_type != WEP)
+ return 0;
+
+ /* 104-bit support seems to require that all the keys are set to the
+ * same keylen */
+ keylen = 6; /* first 5 octets */
+ len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf),
+ NULL, local->crypt[idx]->priv);
+ if (idx >= 0 && idx < WEP_KEYS && len > 5)
+ keylen = WEP_KEY_LEN + 1; /* first 13 octets */
+
+ for (i = 0; i < WEP_KEYS; i++) {
+ memset(keybuf, 0, sizeof(keybuf));
+ if (local->crypt[i]) {
+ (void) local->crypt[i]->ops->get_key(
+ keybuf, sizeof(keybuf),
+ NULL, local->crypt[i]->priv);
+ }
+ if (local->func->set_rid(local->dev,
+ HFA384X_RID_CNFDEFAULTKEY0 + i,
+ keybuf, keylen)) {
+ printk(KERN_DEBUG "Could not set key %d (len=%d)\n",
+ i, keylen);
+ goto fail;
+ }
+ }
+ if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) {
+ printk(KERN_DEBUG "Could not set default keyid %d\n", idx);
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name);
+ return -1;
+}
+
+
+int hostap_set_antsel(local_info_t *local)
+{
+ u16 val;
+ int ret = 0;
+
+ if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
+ local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
+ HFA386X_CR_TX_CONFIGURE,
+ NULL, &val) == 0) {
+ val &= ~(BIT(2) | BIT(1));
+ switch (local->antsel_tx) {
+ case HOSTAP_ANTSEL_DIVERSITY:
+ val |= BIT(1);
+ break;
+ case HOSTAP_ANTSEL_LOW:
+ break;
+ case HOSTAP_ANTSEL_HIGH:
+ val |= BIT(2);
+ break;
+ }
+
+ if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_TX_CONFIGURE, &val, NULL)) {
+ printk(KERN_INFO "%s: setting TX AntSel failed\n",
+ local->dev->name);
+ ret = -1;
+ }
+ }
+
+ if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
+ local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
+ HFA386X_CR_RX_CONFIGURE,
+ NULL, &val) == 0) {
+ val &= ~(BIT(1) | BIT(0));
+ switch (local->antsel_rx) {
+ case HOSTAP_ANTSEL_DIVERSITY:
+ break;
+ case HOSTAP_ANTSEL_LOW:
+ val |= BIT(0);
+ break;
+ case HOSTAP_ANTSEL_HIGH:
+ val |= BIT(0) | BIT(1);
+ break;
+ }
+
+ if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_RX_CONFIGURE, &val, NULL)) {
+ printk(KERN_INFO "%s: setting RX AntSel failed\n",
+ local->dev->name);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+int hostap_set_roaming(local_info_t *local)
+{
+ u16 val;
+
+ switch (local->host_roaming) {
+ case 1:
+ val = HFA384X_ROAMING_HOST;
+ break;
+ case 2:
+ val = HFA384X_ROAMING_DISABLED;
+ break;
+ case 0:
+ default:
+ val = HFA384X_ROAMING_FIRMWARE;
+ break;
+ }
+
+ return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val);
+}
+
+
+int hostap_set_auth_algs(local_info_t *local)
+{
+ int val = local->auth_algs;
+ /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication
+ * set to include both Open and Shared Key flags. It tries to use
+ * Shared Key authentication in that case even if WEP keys are not
+ * configured.. STA f/w v0.7.6 is able to handle such configuration,
+ * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */
+ if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) &&
+ val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY)
+ val = PRISM2_AUTH_OPEN;
+
+ if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) {
+ printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x "
+ "failed\n", local->dev->name, local->auth_algs);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
+{
+ u16 status, fc;
+
+ status = __le16_to_cpu(rx->status);
+
+ printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, "
+ "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; "
+ "jiffies=%ld\n",
+ name, status, (status >> 8) & 0x07, status >> 13, status & 1,
+ rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies);
+
+ fc = __le16_to_cpu(rx->frame_control);
+ printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
+ "data_len=%d%s%s\n",
+ fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+ __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl),
+ __le16_to_cpu(rx->data_len),
+ fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+ fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+ printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
+ MACSTR "\n",
+ MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3),
+ MAC2STR(rx->addr4));
+
+ printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n",
+ MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr),
+ __be16_to_cpu(rx->len));
+}
+
+
+void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
+{
+ u16 fc;
+
+ printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
+ "tx_control=0x%04x; jiffies=%ld\n",
+ name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate,
+ __le16_to_cpu(tx->tx_control), jiffies);
+
+ fc = __le16_to_cpu(tx->frame_control);
+ printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
+ "data_len=%d%s%s\n",
+ fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+ __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl),
+ __le16_to_cpu(tx->data_len),
+ fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+ fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+ printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
+ MACSTR "\n",
+ MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3),
+ MAC2STR(tx->addr4));
+
+ printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n",
+ MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr),
+ __be16_to_cpu(tx->len));
+}
+
+
+int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+ memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */
+ return ETH_ALEN;
+}
+
+
+int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+ if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) {
+ memcpy(haddr, skb->mac.raw +
+ sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+ ETH_ALEN); /* addr2 */
+ } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */
+ memcpy(haddr, skb->mac.raw +
+ sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+ ETH_ALEN); /* addr2 */
+ }
+ return ETH_ALEN;
+}
+
+
+int hostap_80211_get_hdrlen(u16 fc)
+{
+ int hdrlen = 24;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+ hdrlen = 30; /* Addr4 */
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (WLAN_FC_GET_STYPE(fc)) {
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ default:
+ hdrlen = 16;
+ break;
+ }
+ break;
+ }
+
+ return hdrlen;
+}
+
+
+struct net_device_stats *hostap_get_stats(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ iface = netdev_priv(dev);
+ return &iface->stats;
+}
+
+
+static int prism2_close(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name);
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (dev == local->ddev) {
+ prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
+ }
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (!local->hostapd && dev == local->dev &&
+ (!local->func->card_present || local->func->card_present(local)) &&
+ local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER)
+ hostap_deauth_all_stas(dev, local->ap, 1);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ if (local->func->dev_close && local->func->dev_close(local))
+ return 0;
+
+ if (dev == local->dev) {
+ local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL);
+ }
+
+ if (netif_running(dev)) {
+ netif_stop_queue(dev);
+ netif_device_detach(dev);
+ }
+
+ flush_scheduled_work();
+
+ module_put(local->hw_module);
+
+ local->num_dev_open--;
+
+ if (dev != local->dev && local->dev->flags & IFF_UP &&
+ local->master_dev_auto_open && local->num_dev_open == 1) {
+ /* Close master radio interface automatically if it was also
+ * opened automatically and we are now closing the last
+ * remaining non-master device. */
+ dev_close(local->dev);
+ }
+
+ return 0;
+}
+
+
+static int prism2_open(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name);
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->no_pri) {
+ printk(KERN_DEBUG "%s: could not set interface UP - no PRI "
+ "f/w\n", dev->name);
+ return 1;
+ }
+
+ if ((local->func->card_present && !local->func->card_present(local)) ||
+ local->hw_downloading)
+ return -ENODEV;
+
+ if (local->func->dev_open && local->func->dev_open(local))
+ return 1;
+
+ if (!try_module_get(local->hw_module))
+ return -ENODEV;
+ local->num_dev_open++;
+
+ if (!local->dev_enabled && local->func->hw_enable(dev, 1)) {
+ printk(KERN_WARNING "%s: could not enable MAC port\n",
+ dev->name);
+ prism2_close(dev);
+ return 1;
+ }
+ if (!local->dev_enabled)
+ prism2_callback(local, PRISM2_CALLBACK_ENABLE);
+ local->dev_enabled = 1;
+
+ if (dev != local->dev && !(local->dev->flags & IFF_UP)) {
+ /* Master radio interface is needed for all operation, so open
+ * it automatically when any virtual net_device is opened. */
+ local->master_dev_auto_open = 1;
+ dev_open(local->dev);
+ }
+
+ netif_device_attach(dev);
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+
+static int prism2_set_mac_address(struct net_device *dev, void *p)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct list_head *ptr;
+ struct sockaddr *addr = p;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data,
+ ETH_ALEN) < 0 || local->func->reset_port(dev))
+ return -EINVAL;
+
+ read_lock_bh(&local->iface_lock);
+ list_for_each(ptr, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ memcpy(iface->dev->dev_addr, addr->sa_data, ETH_ALEN);
+ }
+ memcpy(local->dev->dev_addr, addr->sa_data, ETH_ALEN);
+ read_unlock_bh(&local->iface_lock);
+
+ return 0;
+}
+
+
+/* TODO: to be further implemented as soon as Prism2 fully supports
+ * GroupAddresses and correct documentation is available */
+void hostap_set_multicast_list_queue(void *data)
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
+ local->is_promisc)) {
+ printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
+ dev->name, local->is_promisc ? "en" : "dis");
+ }
+}
+
+
+static void hostap_set_multicast_list(struct net_device *dev)
+{
+#if 0
+ /* FIX: promiscuous mode seems to be causing a lot of problems with
+ * some station firmware versions (FCSErr frames, invalid MACPort, etc.
+ * corrupted incoming frames). This code is now commented out while the
+ * problems are investigated. */
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) {
+ local->is_promisc = 1;
+ } else {
+ local->is_promisc = 0;
+ }
+
+ schedule_work(&local->set_multicast_list_queue);
+#endif
+}
+
+
+static int prism2_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < PRISM2_MIN_MTU || new_mtu > PRISM2_MAX_MTU)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+static void prism2_tx_timeout(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hfa384x_regs regs;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name);
+ netif_stop_queue(local->dev);
+
+ local->func->read_regs(dev, ®s);
+ printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x "
+ "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n",
+ dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1,
+ regs.swsupport0);
+
+ local->func->schedule_reset(local);
+}
+
+
+void hostap_setup_dev(struct net_device *dev, local_info_t *local,
+ int main_dev)
+{
+ struct hostap_interface *iface;
+
+ iface = netdev_priv(dev);
+ ether_setup(dev);
+
+ /* kernel callbacks */
+ dev->get_stats = hostap_get_stats;
+ if (iface) {
+ /* Currently, we point to the proper spy_data only on
+ * the main_dev. This could be fixed. Jean II */
+ iface->wireless_data.spy_data = &iface->spy_data;
+ dev->wireless_data = &iface->wireless_data;
+ }
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &hostap_iw_handler_def;
+ dev->do_ioctl = hostap_ioctl;
+ dev->open = prism2_open;
+ dev->stop = prism2_close;
+ dev->hard_start_xmit = hostap_data_start_xmit;
+ dev->set_mac_address = prism2_set_mac_address;
+ dev->set_multicast_list = hostap_set_multicast_list;
+ dev->change_mtu = prism2_change_mtu;
+ dev->tx_timeout = prism2_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ dev->mtu = local->mtu;
+ if (!main_dev) {
+ /* use main radio device queue */
+ dev->tx_queue_len = 0;
+ }
+
+ SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops);
+
+ netif_stop_queue(dev);
+}
+
+
+static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
+{
+ struct net_device *dev = local->dev;
+
+ if (local->apdev)
+ return -EEXIST;
+
+ printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name);
+
+ local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP,
+ rtnl_locked, local->ddev->name,
+ "ap");
+ if (local->apdev == NULL)
+ return -ENOMEM;
+
+ local->apdev->hard_start_xmit = hostap_mgmt_start_xmit;
+ local->apdev->type = ARPHRD_IEEE80211;
+ local->apdev->hard_header_parse = hostap_80211_header_parse;
+
+ return 0;
+}
+
+
+static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked)
+{
+ struct net_device *dev = local->dev;
+
+ printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
+
+ hostap_remove_interface(local->apdev, rtnl_locked, 1);
+ local->apdev = NULL;
+
+ return 0;
+}
+
+
+static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked)
+{
+ struct net_device *dev = local->dev;
+
+ if (local->stadev)
+ return -EEXIST;
+
+ printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name);
+
+ local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA,
+ rtnl_locked, local->ddev->name,
+ "sta");
+ if (local->stadev == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+
+static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked)
+{
+ struct net_device *dev = local->dev;
+
+ printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
+
+ hostap_remove_interface(local->stadev, rtnl_locked, 1);
+ local->stadev = NULL;
+
+ return 0;
+}
+
+
+int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked)
+{
+ int ret;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ if (local->hostapd == val)
+ return 0;
+
+ if (val) {
+ ret = hostap_enable_hostapd(local, rtnl_locked);
+ if (ret == 0)
+ local->hostapd = 1;
+ } else {
+ local->hostapd = 0;
+ ret = hostap_disable_hostapd(local, rtnl_locked);
+ if (ret != 0)
+ local->hostapd = 1;
+ }
+
+ return ret;
+}
+
+
+int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked)
+{
+ int ret;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ if (local->hostapd_sta == val)
+ return 0;
+
+ if (val) {
+ ret = hostap_enable_hostapd_sta(local, rtnl_locked);
+ if (ret == 0)
+ local->hostapd_sta = 1;
+ } else {
+ local->hostapd_sta = 0;
+ ret = hostap_disable_hostapd_sta(local, rtnl_locked);
+ if (ret != 0)
+ local->hostapd_sta = 1;
+ }
+
+
+ return ret;
+}
+
+
+int prism2_update_comms_qual(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret = 0;
+ struct hfa384x_comms_quality sq;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ if (!local->sta_fw_ver)
+ ret = -1;
+ else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
+ if (local->func->get_rid(local->dev,
+ HFA384X_RID_DBMCOMMSQUALITY,
+ &sq, sizeof(sq), 1) >= 0) {
+ local->comms_qual = (s16) le16_to_cpu(sq.comm_qual);
+ local->avg_signal = (s16) le16_to_cpu(sq.signal_level);
+ local->avg_noise = (s16) le16_to_cpu(sq.noise_level);
+ local->last_comms_qual_update = jiffies;
+ } else
+ ret = -1;
+ } else {
+ if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY,
+ &sq, sizeof(sq), 1) >= 0) {
+ local->comms_qual = le16_to_cpu(sq.comm_qual);
+ local->avg_signal = HFA384X_LEVEL_TO_dBm(
+ le16_to_cpu(sq.signal_level));
+ local->avg_noise = HFA384X_LEVEL_TO_dBm(
+ le16_to_cpu(sq.noise_level));
+ local->last_comms_qual_update = jiffies;
+ } else
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
+ u8 *body, size_t bodylen)
+{
+ struct sk_buff *skb;
+ struct hostap_ieee80211_mgmt *mgmt;
+ struct hostap_skb_tx_data *meta;
+ struct net_device *dev = local->dev;
+
+ skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ mgmt = (struct hostap_ieee80211_mgmt *)
+ skb_put(skb, IEEE80211_MGMT_HDR_LEN);
+ memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
+ memcpy(mgmt->da, dst, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, dst, ETH_ALEN);
+ if (body)
+ memcpy(skb_put(skb, bodylen), body, bodylen);
+
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ memset(meta, 0, sizeof(*meta));
+ meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+ meta->iface = netdev_priv(dev);
+
+ skb->dev = dev;
+ skb->mac.raw = skb->nh.raw = skb->data;
+ dev_queue_xmit(skb);
+
+ return 0;
+}
+
+
+int prism2_sta_deauth(local_info_t *local, u16 reason)
+{
+ union iwreq_data wrqu;
+ int ret;
+
+ if (local->iw_mode != IW_MODE_INFRA ||
+ memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 ||
+ memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0)
+ return 0;
+
+ reason = cpu_to_le16(reason);
+ ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH,
+ (u8 *) &reason, 2);
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
+ return ret;
+}
+
+
+struct proc_dir_entry *hostap_proc;
+
+static int __init hostap_init(void)
+{
+ if (proc_net != NULL) {
+ hostap_proc = proc_mkdir("hostap", proc_net);
+ if (!hostap_proc)
+ printk(KERN_WARNING "Failed to mkdir "
+ "/proc/net/hostap\n");
+ } else
+ hostap_proc = NULL;
+
+ return 0;
+}
+
+
+static void __exit hostap_exit(void)
+{
+ if (hostap_proc != NULL) {
+ hostap_proc = NULL;
+ remove_proc_entry("hostap", proc_net);
+ }
+}
+
+
+EXPORT_SYMBOL(hostap_set_word);
+EXPORT_SYMBOL(hostap_set_string);
+EXPORT_SYMBOL(hostap_get_porttype);
+EXPORT_SYMBOL(hostap_set_encryption);
+EXPORT_SYMBOL(hostap_set_antsel);
+EXPORT_SYMBOL(hostap_set_roaming);
+EXPORT_SYMBOL(hostap_set_auth_algs);
+EXPORT_SYMBOL(hostap_dump_rx_header);
+EXPORT_SYMBOL(hostap_dump_tx_header);
+EXPORT_SYMBOL(hostap_80211_header_parse);
+EXPORT_SYMBOL(hostap_80211_prism_header_parse);
+EXPORT_SYMBOL(hostap_80211_get_hdrlen);
+EXPORT_SYMBOL(hostap_get_stats);
+EXPORT_SYMBOL(hostap_setup_dev);
+EXPORT_SYMBOL(hostap_proc);
+EXPORT_SYMBOL(hostap_set_multicast_list_queue);
+EXPORT_SYMBOL(hostap_set_hostapd);
+EXPORT_SYMBOL(hostap_set_hostapd_sta);
+EXPORT_SYMBOL(hostap_add_interface);
+EXPORT_SYMBOL(hostap_remove_interface);
+EXPORT_SYMBOL(prism2_update_comms_qual);
+
+module_init(hostap_init);
+module_exit(hostap_exit);
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
new file mode 100644
index 0000000..5fac89b
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -0,0 +1,57 @@
+#ifndef HOSTAP_H
+#define HOSTAP_H
+
+/* hostap.c */
+
+extern struct proc_dir_entry *hostap_proc;
+
+u16 hostap_tx_callback_register(local_info_t *local,
+ void (*func)(struct sk_buff *, int ok, void *),
+ void *data);
+int hostap_tx_callback_unregister(local_info_t *local, u16 idx);
+int hostap_set_word(struct net_device *dev, int rid, u16 val);
+int hostap_set_string(struct net_device *dev, int rid, const char *val);
+u16 hostap_get_porttype(local_info_t *local);
+int hostap_set_encryption(local_info_t *local);
+int hostap_set_antsel(local_info_t *local);
+int hostap_set_roaming(local_info_t *local);
+int hostap_set_auth_algs(local_info_t *local);
+void hostap_dump_rx_header(const char *name,
+ const struct hfa384x_rx_frame *rx);
+void hostap_dump_tx_header(const char *name,
+ const struct hfa384x_tx_frame *tx);
+int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
+int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
+int hostap_80211_get_hdrlen(u16 fc);
+struct net_device_stats *hostap_get_stats(struct net_device *dev);
+void hostap_setup_dev(struct net_device *dev, local_info_t *local,
+ int main_dev);
+void hostap_set_multicast_list_queue(void *data);
+int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
+int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
+void hostap_cleanup(local_info_t *local);
+void hostap_cleanup_handler(void *data);
+struct net_device * hostap_add_interface(struct local_info *local,
+ int type, int rtnl_locked,
+ const char *prefix, const char *name);
+void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
+ int remove_from_list);
+int prism2_update_comms_qual(struct net_device *dev);
+int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
+ u8 *body, size_t bodylen);
+int prism2_sta_deauth(local_info_t *local, u16 reason);
+
+
+/* hostap_proc.c */
+
+void hostap_init_proc(local_info_t *local);
+void hostap_remove_proc(local_info_t *local);
+
+
+/* hostap_info.c */
+
+void hostap_info_init(local_info_t *local);
+void hostap_info_process(local_info_t *local, struct sk_buff *skb);
+
+
+#endif /* HOSTAP_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
new file mode 100644
index 0000000..bf506f5
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -0,0 +1,96 @@
+#ifndef HOSTAP_80211_H
+#define HOSTAP_80211_H
+
+struct hostap_ieee80211_mgmt {
+ u16 frame_control;
+ u16 duration;
+ u8 da[6];
+ u8 sa[6];
+ u8 bssid[6];
+ u16 seq_ctrl;
+ union {
+ struct {
+ u16 auth_alg;
+ u16 auth_transaction;
+ u16 status_code;
+ /* possibly followed by Challenge text */
+ u8 variable[0];
+ } __attribute__ ((packed)) auth;
+ struct {
+ u16 reason_code;
+ } __attribute__ ((packed)) deauth;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) assoc_req;
+ struct {
+ u16 capab_info;
+ u16 status_code;
+ u16 aid;
+ /* followed by Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ u8 current_ap[6];
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) reassoc_req;
+ struct {
+ u16 reason_code;
+ } __attribute__ ((packed)) disassoc;
+ struct {
+ } __attribute__ ((packed)) probe_req;
+ struct {
+ u8 timestamp[8];
+ u16 beacon_int;
+ u16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params, TIM */
+ u8 variable[0];
+ } __attribute__ ((packed)) beacon, probe_resp;
+ } u;
+} __attribute__ ((packed));
+
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+struct hostap_80211_rx_status {
+ u32 mac_time;
+ u8 signal;
+ u8 noise;
+ u16 rate; /* in 100 kbps */
+};
+
+
+void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats);
+
+
+/* prism2_rx_80211 'type' argument */
+enum {
+ PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
+ PRISM2_RX_NULLFUNC_ACK
+};
+
+int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats, int type);
+void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats);
+void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats);
+
+void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
+int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
+struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
+ struct ieee80211_crypt_data *crypt);
+int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+#endif /* HOSTAP_80211_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
new file mode 100644
index 0000000..b050124
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -0,0 +1,1091 @@
+#include <linux/etherdevice.h>
+
+#include "hostap_80211.h"
+#include "hostap.h"
+
+void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d "
+ "jiffies=%ld\n",
+ name, rx_stats->signal, rx_stats->noise, rx_stats->rate,
+ skb->len, jiffies);
+
+ if (skb->len < 2)
+ return;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
+ fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+ fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+ fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+ if (skb->len < IEEE80211_DATA_HDR3_LEN) {
+ printk("\n");
+ return;
+ }
+
+ printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
+ le16_to_cpu(hdr->seq_ctl));
+
+ printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
+ MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+ if (skb->len >= 30)
+ printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+ printk("\n");
+}
+
+
+/* Send RX frame to netif with 802.11 (and possible prism) header.
+ * Called from hardware or software IRQ context. */
+int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats, int type)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int hdrlen, phdrlen, head_need, tail_need;
+ u16 fc;
+ int prism_header, ret;
+ struct ieee80211_hdr *hdr;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ dev->last_rx = jiffies;
+
+ if (dev->type == ARPHRD_IEEE80211_PRISM) {
+ if (local->monitor_type == PRISM2_MONITOR_PRISM) {
+ prism_header = 1;
+ phdrlen = sizeof(struct linux_wlan_ng_prism_hdr);
+ } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */
+ prism_header = 2;
+ phdrlen = sizeof(struct linux_wlan_ng_cap_hdr);
+ }
+ } else {
+ prism_header = 0;
+ phdrlen = 0;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
+ printk(KERN_DEBUG "%s: dropped management frame with header "
+ "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS);
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ hdrlen = hostap_80211_get_hdrlen(fc);
+
+ /* check if there is enough room for extra data; if not, expand skb
+ * buffer to be large enough for the changes */
+ head_need = phdrlen;
+ tail_need = 0;
+#ifdef PRISM2_ADD_BOGUS_CRC
+ tail_need += 4;
+#endif /* PRISM2_ADD_BOGUS_CRC */
+
+ head_need -= skb_headroom(skb);
+ tail_need -= skb_tailroom(skb);
+
+ if (head_need > 0 || tail_need > 0) {
+ if (pskb_expand_head(skb, head_need > 0 ? head_need : 0,
+ tail_need > 0 ? tail_need : 0,
+ GFP_ATOMIC)) {
+ printk(KERN_DEBUG "%s: prism2_rx_80211 failed to "
+ "reallocate skb buffer\n", dev->name);
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+ }
+
+ /* We now have an skb with enough head and tail room, so just insert
+ * the extra data */
+
+#ifdef PRISM2_ADD_BOGUS_CRC
+ memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */
+#endif /* PRISM2_ADD_BOGUS_CRC */
+
+ if (prism_header == 1) {
+ struct linux_wlan_ng_prism_hdr *hdr;
+ hdr = (struct linux_wlan_ng_prism_hdr *)
+ skb_push(skb, phdrlen);
+ memset(hdr, 0, phdrlen);
+ hdr->msgcode = LWNG_CAP_DID_BASE;
+ hdr->msglen = sizeof(*hdr);
+ memcpy(hdr->devname, dev->name, sizeof(hdr->devname));
+#define LWNG_SETVAL(f,i,s,l,d) \
+hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \
+hdr->f.status = s; hdr->f.len = l; hdr->f.data = d
+ LWNG_SETVAL(hosttime, 1, 0, 4, jiffies);
+ LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time);
+ LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0);
+ LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0);
+ LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0);
+ LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal);
+ LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise);
+ LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5);
+ LWNG_SETVAL(istx, 9, 0, 4, 0);
+ LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen);
+#undef LWNG_SETVAL
+ } else if (prism_header == 2) {
+ struct linux_wlan_ng_cap_hdr *hdr;
+ hdr = (struct linux_wlan_ng_cap_hdr *)
+ skb_push(skb, phdrlen);
+ memset(hdr, 0, phdrlen);
+ hdr->version = htonl(LWNG_CAPHDR_VERSION);
+ hdr->length = htonl(phdrlen);
+ hdr->mactime = __cpu_to_be64(rx_stats->mac_time);
+ hdr->hosttime = __cpu_to_be64(jiffies);
+ hdr->phytype = htonl(4); /* dss_dot11_b */
+ hdr->channel = htonl(local->channel);
+ hdr->datarate = htonl(rx_stats->rate);
+ hdr->antenna = htonl(0); /* unknown */
+ hdr->priority = htonl(0); /* unknown */
+ hdr->ssi_type = htonl(3); /* raw */
+ hdr->ssi_signal = htonl(rx_stats->signal);
+ hdr->ssi_noise = htonl(rx_stats->noise);
+ hdr->preamble = htonl(0); /* unknown */
+ hdr->encoding = htonl(1); /* cck */
+ }
+
+ ret = skb->len - phdrlen;
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ skb_pull(skb, hdrlen);
+ if (prism_header)
+ skb_pull(skb, phdrlen);
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+
+ return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void monitor_rx(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct net_device_stats *stats;
+ int len;
+
+ len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR);
+ stats = hostap_get_stats(dev);
+ stats->rx_packets++;
+ stats->rx_bytes += len;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static struct prism2_frag_entry *
+prism2_frag_cache_find(local_info_t *local, unsigned int seq,
+ unsigned int frag, u8 *src, u8 *dst)
+{
+ struct prism2_frag_entry *entry;
+ int i;
+
+ for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
+ entry = &local->frag_cache[i];
+ if (entry->skb != NULL &&
+ time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
+ printk(KERN_DEBUG "%s: expiring fragment cache entry "
+ "seq=%u last_frag=%u\n",
+ local->dev->name, entry->seq, entry->last_frag);
+ dev_kfree_skb(entry->skb);
+ entry->skb = NULL;
+ }
+
+ if (entry->skb != NULL && entry->seq == seq &&
+ (entry->last_frag + 1 == frag || frag == -1) &&
+ memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
+ memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static struct sk_buff *
+prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
+{
+ struct sk_buff *skb = NULL;
+ u16 sc;
+ unsigned int frag, seq;
+ struct prism2_frag_entry *entry;
+
+ sc = le16_to_cpu(hdr->seq_ctl);
+ frag = WLAN_GET_SEQ_FRAG(sc);
+ seq = WLAN_GET_SEQ_SEQ(sc) >> 4;
+
+ if (frag == 0) {
+ /* Reserve enough space to fit maximum frame length */
+ skb = dev_alloc_skb(local->dev->mtu +
+ sizeof(struct ieee80211_hdr) +
+ 8 /* LLC */ +
+ 2 /* alignment */ +
+ 8 /* WEP */ + ETH_ALEN /* WDS */);
+ if (skb == NULL)
+ return NULL;
+
+ entry = &local->frag_cache[local->frag_next_idx];
+ local->frag_next_idx++;
+ if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN)
+ local->frag_next_idx = 0;
+
+ if (entry->skb != NULL)
+ dev_kfree_skb(entry->skb);
+
+ entry->first_frag_time = jiffies;
+ entry->seq = seq;
+ entry->last_frag = frag;
+ entry->skb = skb;
+ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
+ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
+ } else {
+ /* received a fragment of a frame for which the head fragment
+ * should have already been received */
+ entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2,
+ hdr->addr1);
+ if (entry != NULL) {
+ entry->last_frag = frag;
+ skb = entry->skb;
+ }
+ }
+
+ return skb;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static int prism2_frag_cache_invalidate(local_info_t *local,
+ struct ieee80211_hdr *hdr)
+{
+ u16 sc;
+ unsigned int seq;
+ struct prism2_frag_entry *entry;
+
+ sc = le16_to_cpu(hdr->seq_ctl);
+ seq = WLAN_GET_SEQ_SEQ(sc) >> 4;
+
+ entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1);
+
+ if (entry == NULL) {
+ printk(KERN_DEBUG "%s: could not invalidate fragment cache "
+ "entry (seq=%u)\n",
+ local->dev->name, seq);
+ return -1;
+ }
+
+ entry->skb = NULL;
+ return 0;
+}
+
+
+static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid,
+ u8 *ssid, size_t ssid_len)
+{
+ struct list_head *ptr;
+ struct hostap_bss_info *bss;
+
+ list_for_each(ptr, &local->bss_list) {
+ bss = list_entry(ptr, struct hostap_bss_info, list);
+ if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+ (ssid == NULL ||
+ (ssid_len == bss->ssid_len &&
+ memcmp(ssid, bss->ssid, ssid_len) == 0))) {
+ list_move(&bss->list, &local->bss_list);
+ return bss;
+ }
+ }
+
+ return NULL;
+}
+
+
+static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid,
+ u8 *ssid, size_t ssid_len)
+{
+ struct hostap_bss_info *bss;
+
+ if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) {
+ bss = list_entry(local->bss_list.prev,
+ struct hostap_bss_info, list);
+ list_del(&bss->list);
+ local->num_bss_info--;
+ } else {
+ bss = (struct hostap_bss_info *)
+ kmalloc(sizeof(*bss), GFP_ATOMIC);
+ if (bss == NULL)
+ return NULL;
+ }
+
+ memset(bss, 0, sizeof(*bss));
+ memcpy(bss->bssid, bssid, ETH_ALEN);
+ memcpy(bss->ssid, ssid, ssid_len);
+ bss->ssid_len = ssid_len;
+ local->num_bss_info++;
+ list_add(&bss->list, &local->bss_list);
+ return bss;
+}
+
+
+static void __hostap_expire_bss(local_info_t *local)
+{
+ struct hostap_bss_info *bss;
+
+ while (local->num_bss_info > 0) {
+ bss = list_entry(local->bss_list.prev,
+ struct hostap_bss_info, list);
+ if (!time_after(jiffies, bss->last_update + 60 * HZ))
+ break;
+
+ list_del(&bss->list);
+ local->num_bss_info--;
+ kfree(bss);
+ }
+}
+
+
+/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so
+ * the same routine can be used to parse both of them. */
+static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
+ int stype)
+{
+ struct hostap_ieee80211_mgmt *mgmt;
+ int left, chan = 0;
+ u8 *pos;
+ u8 *ssid = NULL, *wpa = NULL, *rsn = NULL;
+ size_t ssid_len = 0, wpa_len = 0, rsn_len = 0;
+ struct hostap_bss_info *bss;
+
+ if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon))
+ return;
+
+ mgmt = (struct hostap_ieee80211_mgmt *) skb->data;
+ pos = mgmt->u.beacon.variable;
+ left = skb->len - (pos - skb->data);
+
+ while (left >= 2) {
+ if (2 + pos[1] > left)
+ return; /* parse failed */
+ switch (*pos) {
+ case WLAN_EID_SSID:
+ ssid = pos + 2;
+ ssid_len = pos[1];
+ break;
+ case WLAN_EID_GENERIC:
+ if (pos[1] >= 4 &&
+ pos[2] == 0x00 && pos[3] == 0x50 &&
+ pos[4] == 0xf2 && pos[5] == 1) {
+ wpa = pos;
+ wpa_len = pos[1] + 2;
+ }
+ break;
+ case WLAN_EID_RSN:
+ rsn = pos;
+ rsn_len = pos[1] + 2;
+ break;
+ case WLAN_EID_DS_PARAMS:
+ if (pos[1] >= 1)
+ chan = pos[2];
+ break;
+ }
+ left -= 2 + pos[1];
+ pos += 2 + pos[1];
+ }
+
+ if (wpa_len > MAX_WPA_IE_LEN)
+ wpa_len = MAX_WPA_IE_LEN;
+ if (rsn_len > MAX_WPA_IE_LEN)
+ rsn_len = MAX_WPA_IE_LEN;
+ if (ssid_len > sizeof(bss->ssid))
+ ssid_len = sizeof(bss->ssid);
+
+ spin_lock(&local->lock);
+ bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len);
+ if (bss == NULL)
+ bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len);
+ if (bss) {
+ bss->last_update = jiffies;
+ bss->count++;
+ bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info);
+ if (wpa) {
+ memcpy(bss->wpa_ie, wpa, wpa_len);
+ bss->wpa_ie_len = wpa_len;
+ } else
+ bss->wpa_ie_len = 0;
+ if (rsn) {
+ memcpy(bss->rsn_ie, rsn, rsn_len);
+ bss->rsn_ie_len = rsn_len;
+ } else
+ bss->rsn_ie_len = 0;
+ bss->chan = chan;
+ }
+ __hostap_expire_bss(local);
+ spin_unlock(&local->lock);
+}
+
+
+static inline int
+hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats, u16 type,
+ u16 stype)
+{
+ if (local->iw_mode == IW_MODE_MASTER) {
+ hostap_update_sta_ps(local, (struct ieee80211_hdr *)
+ skb->data);
+ }
+
+ if (local->hostapd && type == IEEE80211_FTYPE_MGMT) {
+ if (stype == IEEE80211_STYPE_BEACON &&
+ local->iw_mode == IW_MODE_MASTER) {
+ struct sk_buff *skb2;
+ /* Process beacon frames also in kernel driver to
+ * update STA(AP) table statistics */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2)
+ hostap_rx(skb2->dev, skb2, rx_stats);
+ }
+
+ /* send management frames to the user space daemon for
+ * processing */
+ local->apdevstats.rx_packets++;
+ local->apdevstats.rx_bytes += skb->len;
+ if (local->apdev == NULL)
+ return -1;
+ prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT);
+ return 0;
+ }
+
+ if (local->iw_mode == IW_MODE_MASTER) {
+ if (type != IEEE80211_FTYPE_MGMT &&
+ type != IEEE80211_FTYPE_CTL) {
+ printk(KERN_DEBUG "%s: unknown management frame "
+ "(type=0x%02x, stype=0x%02x) dropped\n",
+ skb->dev->name, type >> 2, stype >> 4);
+ return -1;
+ }
+
+ hostap_rx(skb->dev, skb, rx_stats);
+ return 0;
+ } else if (type == IEEE80211_FTYPE_MGMT &&
+ (stype == IEEE80211_STYPE_BEACON ||
+ stype == IEEE80211_STYPE_PROBE_RESP)) {
+ hostap_rx_sta_beacon(local, skb, stype);
+ return -1;
+ } else if (type == IEEE80211_FTYPE_MGMT &&
+ (stype == IEEE80211_STYPE_ASSOC_RESP ||
+ stype == IEEE80211_STYPE_REASSOC_RESP)) {
+ /* Ignore (Re)AssocResp silently since these are not currently
+ * needed but are still received when WPA/RSN mode is enabled.
+ */
+ return -1;
+ } else {
+ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled"
+ " management frame in non-Host AP mode (type=%d:%d)\n",
+ skb->dev->name, type >> 2, stype >> 4);
+ return -1;
+ }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static inline struct net_device *prism2_rx_get_wds(local_info_t *local,
+ u8 *addr)
+{
+ struct hostap_interface *iface = NULL;
+ struct list_head *ptr;
+
+ read_lock_bh(&local->iface_lock);
+ list_for_each(ptr, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type == HOSTAP_INTERFACE_WDS &&
+ memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0)
+ break;
+ iface = NULL;
+ }
+ read_unlock_bh(&local->iface_lock);
+
+ return iface ? iface->dev : NULL;
+}
+
+
+static inline int
+hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr,
+ u16 fc, struct net_device **wds)
+{
+ /* FIX: is this really supposed to accept WDS frames only in Master
+ * mode? What about Repeater or Managed with WDS frames? */
+ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
+ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) &&
+ (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS)))
+ return 0; /* not a WDS frame */
+
+ /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS)
+ * or own non-standard frame with 4th address after payload */
+ if (memcmp(hdr->addr1, local->dev->dev_addr, ETH_ALEN) != 0 &&
+ (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff ||
+ hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
+ hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
+ /* RA (or BSSID) is not ours - drop */
+ PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
+ "not own or broadcast %s=" MACSTR "\n",
+ local->dev->name,
+ fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
+ MAC2STR(hdr->addr1));
+ return -1;
+ }
+
+ /* check if the frame came from a registered WDS connection */
+ *wds = prism2_rx_get_wds(local, hdr->addr2);
+ if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS &&
+ (local->iw_mode != IW_MODE_INFRA ||
+ !(local->wds_type & HOSTAP_WDS_AP_CLIENT) ||
+ memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) {
+ /* require that WDS link has been registered with TA or the
+ * frame is from current AP when using 'AP client mode' */
+ PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
+ "from unknown TA=" MACSTR "\n",
+ local->dev->name, MAC2STR(hdr->addr2));
+ if (local->ap && local->ap->autom_ap_wds)
+ hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
+ return -1;
+ }
+
+ if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap &&
+ hostap_is_sta_assoc(local->ap, hdr->addr2)) {
+ /* STA is actually associated with us even though it has a
+ * registered WDS link. Assume it is in 'AP client' mode.
+ * Since this is a 3-addr frame, assume it is not (bogus) WDS
+ * frame and process it like any normal ToDS frame from
+ * associated STA. */
+ *wds = NULL;
+ }
+
+ return 0;
+}
+
+
+static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
+{
+ struct net_device *dev = local->dev;
+ u16 fc, ethertype;
+ struct ieee80211_hdr *hdr;
+ u8 *pos;
+
+ if (skb->len < 24)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ /* check that the frame is unicast frame to us */
+ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 &&
+ memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+ /* ToDS frame with own addr BSSID and DA */
+ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+ /* FromDS frame with own addr as DA */
+ } else
+ return 0;
+
+ if (skb->len < 24 + 8)
+ return 0;
+
+ /* check for port access entity Ethernet type */
+ pos = skb->data + 24;
+ ethertype = (pos[6] << 8) | pos[7];
+ if (ethertype == ETH_P_PAE)
+ return 1;
+
+ return 0;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static inline int
+hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
+ struct ieee80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ if (local->tkip_countermeasures &&
+ strcmp(crypt->ops->name, "TKIP") == 0) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+ "received packet from " MACSTR "\n",
+ local->dev->name, MAC2STR(hdr->addr2));
+ }
+ return -1;
+ }
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR
+ ") res=%d\n",
+ local->dev->name, MAC2STR(hdr->addr2), res);
+ local->comm_tallies.rx_discards_wep_undecryptable++;
+ return -1;
+ }
+
+ return res;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static inline int
+hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
+ int keyidx, struct ieee80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
+ " (SA=" MACSTR " keyidx=%d)\n",
+ local->dev->name, MAC2STR(hdr->addr2), keyidx);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* All received frames are sent to this function. @skb contains the frame in
+ * IEEE 802.11 format, i.e., in the format it was sent over air.
+ * This function is called only as a tasklet (software IRQ). */
+void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct ieee80211_hdr *hdr;
+ size_t hdrlen;
+ u16 fc, type, stype, sc;
+ struct net_device *wds = NULL;
+ struct net_device_stats *stats;
+ unsigned int frag;
+ u8 *payload;
+ struct sk_buff *skb2 = NULL;
+ u16 ethertype;
+ int frame_authorized = 0;
+ int from_assoc_ap = 0;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ struct ieee80211_crypt_data *crypt = NULL;
+ void *sta = NULL;
+ int keyidx = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ iface->stats.rx_packets++;
+ iface->stats.rx_bytes += skb->len;
+
+ /* dev is the master radio device; change this to be the default
+ * virtual interface (this may be changed to WDS device below) */
+ dev = local->ddev;
+ iface = netdev_priv(dev);
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ stats = hostap_get_stats(dev);
+
+ if (skb->len < 10)
+ goto rx_dropped;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+ sc = le16_to_cpu(hdr->seq_ctl);
+ frag = WLAN_GET_SEQ_FRAG(sc);
+ hdrlen = hostap_80211_get_hdrlen(fc);
+
+ /* Put this code here so that we avoid duplicating it in all
+ * Rx paths. - Jean II */
+#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
+ /* If spy monitoring on */
+ if (iface->spy_data.spy_number > 0) {
+ struct iw_quality wstats;
+ wstats.level = rx_stats->signal;
+ wstats.noise = rx_stats->noise;
+ wstats.updated = 6; /* No qual value */
+ /* Update spy records */
+ wireless_spy_update(dev, hdr->addr2, &wstats);
+ }
+#endif /* IW_WIRELESS_SPY */
+ hostap_update_rx_stats(local->ap, hdr, rx_stats);
+
+ if (local->iw_mode == IW_MODE_MONITOR) {
+ monitor_rx(dev, skb, rx_stats);
+ return;
+ }
+
+ if (local->host_decrypt) {
+ int idx = 0;
+ if (skb->len >= hdrlen + 3)
+ idx = skb->data[hdrlen + 3] >> 6;
+ crypt = local->crypt[idx];
+ sta = NULL;
+
+ /* Use station specific key to override default keys if the
+ * receiver address is a unicast address ("individual RA"). If
+ * bcrx_sta_key parameter is set, station specific key is used
+ * even with broad/multicast targets (this is against IEEE
+ * 802.11, but makes it easier to use different keys with
+ * stations that do not support WEP key mapping). */
+
+ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
+ (void) hostap_handle_sta_crypto(local, hdr, &crypt,
+ &sta);
+
+ /* allow NULL decrypt to indicate an station specific override
+ * for default encryption */
+ if (crypt && (crypt->ops == NULL ||
+ crypt->ops->decrypt_mpdu == NULL))
+ crypt = NULL;
+
+ if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
+#if 0
+ /* This seems to be triggered by some (multicast?)
+ * frames from other than current BSS, so just drop the
+ * frames silently instead of filling system log with
+ * these reports. */
+ printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
+ " (SA=" MACSTR ")\n",
+ local->dev->name, MAC2STR(hdr->addr2));
+#endif
+ local->comm_tallies.rx_discards_wep_undecryptable++;
+ goto rx_dropped;
+ }
+ }
+
+ if (type != IEEE80211_FTYPE_DATA) {
+ if (type == IEEE80211_FTYPE_MGMT &&
+ stype == IEEE80211_STYPE_AUTH &&
+ fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt &&
+ (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
+ {
+ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
+ "from " MACSTR "\n", dev->name,
+ MAC2STR(hdr->addr2));
+ /* TODO: could inform hostapd about this so that it
+ * could send auth failure report */
+ goto rx_dropped;
+ }
+
+ if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype))
+ goto rx_dropped;
+ else
+ goto rx_exit;
+ }
+
+ /* Data frame - extract src/dst addresses */
+ if (skb->len < IEEE80211_DATA_HDR3_LEN)
+ goto rx_dropped;
+
+ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr3, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_TODS:
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ if (skb->len < IEEE80211_DATA_HDR4_LEN)
+ goto rx_dropped;
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr4, ETH_ALEN);
+ break;
+ case 0:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ break;
+ }
+
+ if (hostap_rx_frame_wds(local, hdr, fc, &wds))
+ goto rx_dropped;
+ if (wds) {
+ skb->dev = dev = wds;
+ stats = hostap_get_stats(dev);
+ }
+
+ if (local->iw_mode == IW_MODE_MASTER && !wds &&
+ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS &&
+ local->stadev &&
+ memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) {
+ /* Frame from BSSID of the AP for which we are a client */
+ skb->dev = dev = local->stadev;
+ stats = hostap_get_stats(dev);
+ from_assoc_ap = 1;
+ }
+
+ dev->last_rx = jiffies;
+
+ if ((local->iw_mode == IW_MODE_MASTER ||
+ local->iw_mode == IW_MODE_REPEAT) &&
+ !from_assoc_ap) {
+ switch (hostap_handle_sta_rx(local, dev, skb, rx_stats,
+ wds != NULL)) {
+ case AP_RX_CONTINUE_NOT_AUTHORIZED:
+ frame_authorized = 0;
+ break;
+ case AP_RX_CONTINUE:
+ frame_authorized = 1;
+ break;
+ case AP_RX_DROP:
+ goto rx_dropped;
+ case AP_RX_EXIT:
+ goto rx_exit;
+ }
+ }
+
+ /* Nullfunc frames may have PS-bit set, so they must be passed to
+ * hostap_handle_sta_rx() before being dropped here. */
+ if (stype != IEEE80211_STYPE_DATA &&
+ stype != IEEE80211_STYPE_DATA_CFACK &&
+ stype != IEEE80211_STYPE_DATA_CFPOLL &&
+ stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
+ if (stype != IEEE80211_STYPE_NULLFUNC)
+ printk(KERN_DEBUG "%s: RX: dropped data frame "
+ "with no data (type=0x%02x, subtype=0x%02x)\n",
+ dev->name, type >> 2, stype >> 4);
+ goto rx_dropped;
+ }
+
+ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
+
+ if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
+ goto rx_dropped;
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ /* skb: hdr + (possibly fragmented) plaintext payload */
+
+ if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+ int flen;
+ struct sk_buff *frag_skb =
+ prism2_frag_cache_get(local, hdr);
+ if (!frag_skb) {
+ printk(KERN_DEBUG "%s: Rx cannot get skb from "
+ "fragment cache (morefrag=%d seq=%u frag=%u)\n",
+ dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
+ WLAN_GET_SEQ_SEQ(sc) >> 4, frag);
+ goto rx_dropped;
+ }
+
+ flen = skb->len;
+ if (frag != 0)
+ flen -= hdrlen;
+
+ if (frag_skb->tail + flen > frag_skb->end) {
+ printk(KERN_WARNING "%s: host decrypted and "
+ "reassembled frame did not fit skb\n",
+ dev->name);
+ prism2_frag_cache_invalidate(local, hdr);
+ goto rx_dropped;
+ }
+
+ if (frag == 0) {
+ /* copy first fragment (including full headers) into
+ * beginning of the fragment cache skb */
+ memcpy(skb_put(frag_skb, flen), skb->data, flen);
+ } else {
+ /* append frame payload to the end of the fragment
+ * cache skb */
+ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
+ flen);
+ }
+ dev_kfree_skb(skb);
+ skb = NULL;
+
+ if (fc & IEEE80211_FCTL_MOREFRAGS) {
+ /* more fragments expected - leave the skb in fragment
+ * cache for now; it will be delivered to upper layers
+ * after all fragments have been received */
+ goto rx_exit;
+ }
+
+ /* this was the last fragment and the frame will be
+ * delivered, so remove skb from fragment cache */
+ skb = frag_skb;
+ hdr = (struct ieee80211_hdr *) skb->data;
+ prism2_frag_cache_invalidate(local, hdr);
+ }
+
+ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
+ * encrypted/authenticated */
+
+ if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt))
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) {
+ if (local->ieee_802_1x &&
+ hostap_is_eapol_frame(local, skb)) {
+ /* pass unencrypted EAPOL frames even if encryption is
+ * configured */
+ PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing "
+ "unencrypted EAPOL frame\n", local->dev->name);
+ } else {
+ printk(KERN_DEBUG "%s: encryption configured, but RX "
+ "frame not encrypted (SA=" MACSTR ")\n",
+ local->dev->name, MAC2STR(hdr->addr2));
+ goto rx_dropped;
+ }
+ }
+
+ if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) &&
+ !hostap_is_eapol_frame(local, skb)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: dropped unencrypted RX data "
+ "frame from " MACSTR " (drop_unencrypted=1)\n",
+ dev->name, MAC2STR(hdr->addr2));
+ }
+ goto rx_dropped;
+ }
+
+ /* skb: hdr + (possible reassembled) full plaintext payload */
+
+ payload = skb->data + hdrlen;
+ ethertype = (payload[6] << 8) | payload[7];
+
+ /* If IEEE 802.1X is used, check whether the port is authorized to send
+ * the received frame. */
+ if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) {
+ if (ethertype == ETH_P_PAE) {
+ PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n",
+ dev->name);
+ if (local->hostapd && local->apdev) {
+ /* Send IEEE 802.1X frames to the user
+ * space daemon for processing */
+ prism2_rx_80211(local->apdev, skb, rx_stats,
+ PRISM2_RX_MGMT);
+ local->apdevstats.rx_packets++;
+ local->apdevstats.rx_bytes += skb->len;
+ goto rx_exit;
+ }
+ } else if (!frame_authorized) {
+ printk(KERN_DEBUG "%s: dropped frame from "
+ "unauthorized port (IEEE 802.1X): "
+ "ethertype=0x%04x\n",
+ dev->name, ethertype);
+ goto rx_dropped;
+ }
+ }
+
+ /* convert hdr + possible LLC headers into Ethernet header */
+ if (skb->len - hdrlen >= 8 &&
+ ((memcmp(payload, rfc1042_header, 6) == 0 &&
+ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+ memcmp(payload, bridge_tunnel_header, 6) == 0)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and
+ * replace EtherType */
+ skb_pull(skb, hdrlen + 6);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ } else {
+ u16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ skb_pull(skb, hdrlen);
+ len = htons(skb->len);
+ memcpy(skb_push(skb, 2), &len, 2);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ }
+
+ if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS) &&
+ skb->len >= ETH_HLEN + ETH_ALEN) {
+ /* Non-standard frame: get addr4 from its bogus location after
+ * the payload */
+ memcpy(skb->data + ETH_ALEN,
+ skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+ skb_trim(skb, skb->len - ETH_ALEN);
+ }
+
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+ if (local->iw_mode == IW_MODE_MASTER && !wds &&
+ local->ap->bridge_packets) {
+ if (dst[0] & 0x01) {
+ /* copy multicast frame both to the higher layers and
+ * to the wireless media */
+ local->ap->bridged_multicast++;
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ printk(KERN_DEBUG "%s: skb_clone failed for "
+ "multicast frame\n", dev->name);
+ } else if (hostap_is_sta_authorized(local->ap, dst)) {
+ /* send frame directly to the associated STA using
+ * wireless media and not passing to higher layers */
+ local->ap->bridged_unicast++;
+ skb2 = skb;
+ skb = NULL;
+ }
+ }
+
+ if (skb2 != NULL) {
+ /* send to wireless media */
+ skb2->protocol = __constant_htons(ETH_P_802_3);
+ skb2->mac.raw = skb2->nh.raw = skb2->data;
+ /* skb2->nh.raw = skb2->data + ETH_HLEN; */
+ skb2->dev = dev;
+ dev_queue_xmit(skb2);
+ }
+
+ if (skb) {
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ skb->dev = dev;
+ netif_rx(skb);
+ }
+
+ rx_exit:
+ if (sta)
+ hostap_handle_sta_release(sta);
+ return;
+
+ rx_dropped:
+ dev_kfree_skb(skb);
+
+ stats->rx_dropped++;
+ goto rx_exit;
+}
+
+
+EXPORT_SYMBOL(hostap_80211_rx);
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
new file mode 100644
index 0000000..6358015
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -0,0 +1,524 @@
+void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
+ name, skb->len, jiffies);
+
+ if (skb->len < 2)
+ return;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
+ fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+ fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
+ fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
+
+ if (skb->len < IEEE80211_DATA_HDR3_LEN) {
+ printk("\n");
+ return;
+ }
+
+ printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
+ le16_to_cpu(hdr->seq_ctl));
+
+ printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
+ MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+ if (skb->len >= 30)
+ printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+ printk("\n");
+}
+
+
+/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
+ * Convert Ethernet header into a suitable IEEE 802.11 header depending on
+ * device configuration. */
+int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int need_headroom, need_tailroom = 0;
+ struct ieee80211_hdr hdr;
+ u16 fc, ethertype = 0;
+ enum {
+ WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
+ } use_wds = WDS_NO;
+ u8 *encaps_data;
+ int hdr_len, encaps_len, skip_header_bytes;
+ int to_assoc_ap = 0;
+ struct hostap_skb_tx_data *meta;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (skb->len < ETH_HLEN) {
+ printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
+ "(len=%d)\n", dev->name, skb->len);
+ kfree_skb(skb);
+ return 0;
+ }
+
+ if (local->ddev != dev) {
+ use_wds = (local->iw_mode == IW_MODE_MASTER &&
+ !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?
+ WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;
+ if (dev == local->stadev) {
+ to_assoc_ap = 1;
+ use_wds = WDS_NO;
+ } else if (dev == local->apdev) {
+ printk(KERN_DEBUG "%s: prism2_tx: trying to use "
+ "AP device with Ethernet net dev\n", dev->name);
+ kfree_skb(skb);
+ return 0;
+ }
+ } else {
+ if (local->iw_mode == IW_MODE_REPEAT) {
+ printk(KERN_DEBUG "%s: prism2_tx: trying to use "
+ "non-WDS link in Repeater mode\n", dev->name);
+ kfree_skb(skb);
+ return 0;
+ } else if (local->iw_mode == IW_MODE_INFRA &&
+ (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
+ memcmp(skb->data + ETH_ALEN, dev->dev_addr,
+ ETH_ALEN) != 0) {
+ /* AP client mode: send frames with foreign src addr
+ * using 4-addr WDS frames */
+ use_wds = WDS_COMPLIANT_FRAME;
+ }
+ }
+
+ /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
+ * ==>
+ * Prism2 TX frame with 802.11 header:
+ * txdesc (address order depending on used mode; includes dst_addr and
+ * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;
+ * proto[2], payload {, possible addr4[6]} */
+
+ ethertype = (skb->data[12] << 8) | skb->data[13];
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ /* Length of data after IEEE 802.11 header */
+ encaps_data = NULL;
+ encaps_len = 0;
+ skip_header_bytes = ETH_HLEN;
+ if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
+ encaps_data = bridge_tunnel_header;
+ encaps_len = sizeof(bridge_tunnel_header);
+ skip_header_bytes -= 2;
+ } else if (ethertype >= 0x600) {
+ encaps_data = rfc1042_header;
+ encaps_len = sizeof(rfc1042_header);
+ skip_header_bytes -= 2;
+ }
+
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+ hdr_len = IEEE80211_DATA_HDR3_LEN;
+
+ if (use_wds != WDS_NO) {
+ /* Note! Prism2 station firmware has problems with sending real
+ * 802.11 frames with four addresses; until these problems can
+ * be fixed or worked around, 4-addr frames needed for WDS are
+ * using incompatible format: FromDS flag is not set and the
+ * fourth address is added after the frame payload; it is
+ * assumed, that the receiving station knows how to handle this
+ * frame format */
+
+ if (use_wds == WDS_COMPLIANT_FRAME) {
+ fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+ /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
+ * Addr4 = SA */
+ memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+ hdr_len += ETH_ALEN;
+ } else {
+ /* bogus 4-addr format to workaround Prism2 station
+ * f/w bug */
+ fc |= IEEE80211_FCTL_TODS;
+ /* From DS: Addr1 = DA (used as RA),
+ * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
+ */
+
+ /* SA from skb->data + ETH_ALEN will be added after
+ * frame payload; use hdr.addr4 as a temporary buffer
+ */
+ memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+ need_tailroom += ETH_ALEN;
+ }
+
+ /* send broadcast and multicast frames to broadcast RA, if
+ * configured; otherwise, use unicast RA of the WDS link */
+ if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&
+ skb->data[0] & 0x01)
+ memset(&hdr.addr1, 0xff, ETH_ALEN);
+ else if (iface->type == HOSTAP_INTERFACE_WDS)
+ memcpy(&hdr.addr1, iface->u.wds.remote_addr,
+ ETH_ALEN);
+ else
+ memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
+ memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+ } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
+ fc |= IEEE80211_FCTL_FROMDS;
+ /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
+ memcpy(&hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+ } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
+ fc |= IEEE80211_FCTL_TODS;
+ /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
+ memcpy(&hdr.addr1, to_assoc_ap ?
+ local->assoc_ap_addr : local->bssid, ETH_ALEN);
+ memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+ } else if (local->iw_mode == IW_MODE_ADHOC) {
+ /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
+ memcpy(&hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
+ }
+
+ hdr.frame_ctl = cpu_to_le16(fc);
+
+ skb_pull(skb, skip_header_bytes);
+ need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
+ if (skb_tailroom(skb) < need_tailroom) {
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (skb == NULL) {
+ iface->stats.tx_dropped++;
+ return 0;
+ }
+ if (pskb_expand_head(skb, need_headroom, need_tailroom,
+ GFP_ATOMIC)) {
+ kfree_skb(skb);
+ iface->stats.tx_dropped++;
+ return 0;
+ }
+ } else if (skb_headroom(skb) < need_headroom) {
+ struct sk_buff *tmp = skb;
+ skb = skb_realloc_headroom(skb, need_headroom);
+ kfree_skb(tmp);
+ if (skb == NULL) {
+ iface->stats.tx_dropped++;
+ return 0;
+ }
+ } else {
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (skb == NULL) {
+ iface->stats.tx_dropped++;
+ return 0;
+ }
+ }
+
+ if (encaps_data)
+ memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+ memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);
+ if (use_wds == WDS_OWN_FRAME) {
+ memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN);
+ }
+
+ iface->stats.tx_packets++;
+ iface->stats.tx_bytes += skb->len;
+
+ skb->mac.raw = skb->data;
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ memset(meta, 0, sizeof(*meta));
+ meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+ if (use_wds)
+ meta->flags |= HOSTAP_TX_FLAGS_WDS;
+ meta->ethertype = ethertype;
+ meta->iface = iface;
+
+ /* Send IEEE 802.11 encapsulated frame using the master radio device */
+ skb->dev = local->dev;
+ dev_queue_xmit(skb);
+ return 0;
+}
+
+
+/* hard_start_xmit function for hostapd wlan#ap interfaces */
+int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hostap_skb_tx_data *meta;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (skb->len < 10) {
+ printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
+ "(len=%d)\n", dev->name, skb->len);
+ kfree_skb(skb);
+ return 0;
+ }
+
+ iface->stats.tx_packets++;
+ iface->stats.tx_bytes += skb->len;
+
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ memset(meta, 0, sizeof(*meta));
+ meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+ meta->iface = iface;
+
+ if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+ WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) {
+ u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
+ sizeof(rfc1042_header)];
+ meta->ethertype = (pos[0] << 8) | pos[1];
+ }
+ }
+
+ /* Send IEEE 802.11 encapsulated frame using the master radio device */
+ skb->dev = local->dev;
+ dev_queue_xmit(skb);
+ return 0;
+}
+
+
+/* Called only from software IRQ */
+struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
+ struct ieee80211_crypt_data *crypt)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ int hdr_len, res;
+
+ iface = netdev_priv(skb->dev);
+ local = iface->local;
+
+ if (skb->len < IEEE80211_DATA_HDR3_LEN) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ if (local->tkip_countermeasures &&
+ crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+ "TX packet to " MACSTR "\n",
+ local->dev->name, MAC2STR(hdr->addr1));
+ }
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (skb == NULL)
+ return NULL;
+
+ if ((skb_headroom(skb) < crypt->ops->extra_prefix_len ||
+ skb_tailroom(skb) < crypt->ops->extra_postfix_len) &&
+ pskb_expand_head(skb, crypt->ops->extra_prefix_len,
+ crypt->ops->extra_postfix_len, GFP_ATOMIC)) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ hdr_len = hostap_80211_get_hdrlen(fc);
+
+ /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
+ * call both MSDU and MPDU encryption functions from here. */
+ atomic_inc(&crypt->refcnt);
+ res = 0;
+ if (crypt->ops->encrypt_msdu)
+ res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);
+ if (res == 0 && crypt->ops->encrypt_mpdu)
+ res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ return skb;
+}
+
+
+/* hard_start_xmit function for master radio interface wifi#.
+ * AP processing (TX rate control, power save buffering, etc.).
+ * Use hardware TX function to send the frame. */
+int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret = 1;
+ u16 fc;
+ struct hostap_tx_data tx;
+ ap_tx_ret tx_ret;
+ struct hostap_skb_tx_data *meta;
+ int no_encrypt = 0;
+ struct ieee80211_hdr *hdr;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ tx.skb = skb;
+ tx.sta_ptr = NULL;
+
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
+ printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
+ "expected 0x%08x)\n",
+ dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
+ ret = 0;
+ iface->stats.tx_dropped++;
+ goto fail;
+ }
+
+ if (local->host_encrypt) {
+ /* Set crypt to default algorithm and key; will be replaced in
+ * AP code if STA has own alg/key */
+ tx.crypt = local->crypt[local->tx_keyidx];
+ tx.host_encrypt = 1;
+ } else {
+ tx.crypt = NULL;
+ tx.host_encrypt = 0;
+ }
+
+ if (skb->len < 24) {
+ printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
+ "(len=%d)\n", dev->name, skb->len);
+ ret = 0;
+ iface->stats.tx_dropped++;
+ goto fail;
+ }
+
+ /* FIX (?):
+ * Wi-Fi 802.11b test plan suggests that AP should ignore power save
+ * bit in authentication and (re)association frames and assume tha
+ * STA remains awake for the response. */
+ tx_ret = hostap_handle_sta_tx(local, &tx);
+ skb = tx.skb;
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ switch (tx_ret) {
+ case AP_TX_CONTINUE:
+ break;
+ case AP_TX_CONTINUE_NOT_AUTHORIZED:
+ if (local->ieee_802_1x &&
+ WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+ meta->ethertype != ETH_P_PAE &&
+ !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
+ printk(KERN_DEBUG "%s: dropped frame to unauthorized "
+ "port (IEEE 802.1X): ethertype=0x%04x\n",
+ dev->name, meta->ethertype);
+ hostap_dump_tx_80211(dev->name, skb);
+
+ ret = 0; /* drop packet */
+ iface->stats.tx_dropped++;
+ goto fail;
+ }
+ break;
+ case AP_TX_DROP:
+ ret = 0; /* drop packet */
+ iface->stats.tx_dropped++;
+ goto fail;
+ case AP_TX_RETRY:
+ goto fail;
+ case AP_TX_BUFFERED:
+ /* do not free skb here, it will be freed when the
+ * buffered frame is sent/timed out */
+ ret = 0;
+ goto tx_exit;
+ }
+
+ /* Request TX callback if protocol version is 2 in 802.11 header;
+ * this version 2 is a special case used between hostapd and kernel
+ * driver */
+ if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
+ local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
+ meta->tx_cb_idx = local->ap->tx_callback_idx;
+
+ /* remove special version from the frame header */
+ fc &= ~IEEE80211_FCTL_VERS;
+ hdr->frame_ctl = cpu_to_le16(fc);
+ }
+
+ if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) {
+ no_encrypt = 1;
+ tx.crypt = NULL;
+ }
+
+ if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
+ !(fc & IEEE80211_FCTL_VERS)) {
+ no_encrypt = 1;
+ PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
+ "unencrypted EAPOL frame\n", dev->name);
+ tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */
+ }
+
+ if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
+ tx.crypt = NULL;
+ else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) {
+ /* Add ISWEP flag both for firmware and host based encryption
+ */
+ fc |= IEEE80211_FCTL_PROTECTED;
+ hdr->frame_ctl = cpu_to_le16(fc);
+ } else if (local->drop_unencrypted &&
+ WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+ meta->ethertype != ETH_P_PAE) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: dropped unencrypted TX data "
+ "frame (drop_unencrypted=1)\n", dev->name);
+ }
+ iface->stats.tx_dropped++;
+ ret = 0;
+ goto fail;
+ }
+
+ if (tx.crypt) {
+ skb = hostap_tx_encrypt(skb, tx.crypt);
+ if (skb == NULL) {
+ printk(KERN_DEBUG "%s: TX - encryption failed\n",
+ dev->name);
+ ret = 0;
+ goto fail;
+ }
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
+ printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
+ "expected 0x%08x) after hostap_tx_encrypt\n",
+ dev->name, meta->magic,
+ HOSTAP_SKB_TX_DATA_MAGIC);
+ ret = 0;
+ iface->stats.tx_dropped++;
+ goto fail;
+ }
+ }
+
+ if (local->func->tx == NULL || local->func->tx(skb, dev)) {
+ ret = 0;
+ iface->stats.tx_dropped++;
+ } else {
+ ret = 0;
+ iface->stats.tx_packets++;
+ iface->stats.tx_bytes += skb->len;
+ }
+
+ fail:
+ if (!ret && skb)
+ dev_kfree_skb(skb);
+ tx_exit:
+ if (tx.sta_ptr)
+ hostap_handle_sta_release(tx.sta_ptr);
+ return ret;
+}
+
+
+EXPORT_SYMBOL(hostap_dump_tx_80211);
+EXPORT_SYMBOL(hostap_tx_encrypt);
+EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
new file mode 100644
index 0000000..930cef8
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -0,0 +1,3288 @@
+/*
+ * Intersil Prism2 driver with Host AP (software access point) support
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This file is to be included into hostap.c when S/W AP functionality is
+ * compiled.
+ *
+ * AP: FIX:
+ * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from
+ * unauthenticated STA, send deauth. frame (8802.11: 5.5)
+ * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received
+ * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5)
+ * - if unicast Class 3 received from unauthenticated STA, send deauth. frame
+ * (8802.11: 5.5)
+ */
+
+static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL,
+ DEF_INTS };
+module_param_array(other_ap_policy, int, NULL, 0444);
+MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)");
+
+static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC,
+ DEF_INTS };
+module_param_array(ap_max_inactivity, int, NULL, 0444);
+MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station "
+ "inactivity");
+
+static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS };
+module_param_array(ap_bridge_packets, int, NULL, 0444);
+MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between "
+ "stations");
+
+static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS };
+module_param_array(autom_ap_wds, int, NULL, 0444);
+MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs "
+ "automatically");
+
+
+static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);
+static void hostap_event_expired_sta(struct net_device *dev,
+ struct sta_info *sta);
+static void handle_add_proc_queue(void *data);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+static void handle_wds_oper_queue(void *data);
+static void prism2_send_mgmt(struct net_device *dev,
+ u16 type_subtype, char *body,
+ int body_len, u8 *addr, u16 tx_cb_idx);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+static int ap_debug_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ap_data *ap = (struct ap_data *) data;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
+ p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
+ p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ);
+ p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets);
+ p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack);
+ p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds);
+ p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs);
+ p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
+
+ return (p - page);
+}
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+
+static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
+{
+ sta->hnext = ap->sta_hash[STA_HASH(sta->addr)];
+ ap->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
+{
+ struct sta_info *s;
+
+ s = ap->sta_hash[STA_HASH(sta->addr)];
+ if (s == NULL) return;
+ if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
+ ap->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+ return;
+ }
+
+ while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN)
+ != 0)
+ s = s->hnext;
+ if (s->hnext != NULL)
+ s->hnext = s->hnext->hnext;
+ else
+ printk("AP: could not remove STA " MACSTR " from hash table\n",
+ MAC2STR(sta->addr));
+}
+
+static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
+{
+ if (sta->ap && sta->local)
+ hostap_event_expired_sta(sta->local->dev, sta);
+
+ if (ap->proc != NULL) {
+ char name[20];
+ sprintf(name, MACSTR, MAC2STR(sta->addr));
+ remove_proc_entry(name, ap->proc);
+ }
+
+ if (sta->crypt) {
+ sta->crypt->ops->deinit(sta->crypt->priv);
+ kfree(sta->crypt);
+ sta->crypt = NULL;
+ }
+
+ skb_queue_purge(&sta->tx_buf);
+
+ ap->num_sta--;
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (sta->aid > 0)
+ ap->sta_aid[sta->aid - 1] = NULL;
+
+ if (!sta->ap && sta->u.sta.challenge)
+ kfree(sta->u.sta.challenge);
+ del_timer(&sta->timer);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ kfree(sta);
+}
+
+
+static void hostap_set_tim(local_info_t *local, int aid, int set)
+{
+ if (local->func->set_tim)
+ local->func->set_tim(local->dev, aid, set);
+}
+
+
+static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta)
+{
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL);
+}
+
+
+static void hostap_event_expired_sta(struct net_device *dev,
+ struct sta_info *sta)
+{
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+static void ap_handle_timer(unsigned long data)
+{
+ struct sta_info *sta = (struct sta_info *) data;
+ local_info_t *local;
+ struct ap_data *ap;
+ unsigned long next_time = 0;
+ int was_assoc;
+
+ if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
+ PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
+ return;
+ }
+
+ local = sta->local;
+ ap = local->ap;
+ was_assoc = sta->flags & WLAN_STA_ASSOC;
+
+ if (atomic_read(&sta->users) != 0)
+ next_time = jiffies + HZ;
+ else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH))
+ next_time = jiffies + ap->max_inactivity;
+
+ if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) {
+ /* station activity detected; reset timeout state */
+ sta->timeout_next = STA_NULLFUNC;
+ next_time = sta->last_rx + ap->max_inactivity;
+ } else if (sta->timeout_next == STA_DISASSOC &&
+ !(sta->flags & WLAN_STA_PENDING_POLL)) {
+ /* STA ACKed data nullfunc frame poll */
+ sta->timeout_next = STA_NULLFUNC;
+ next_time = jiffies + ap->max_inactivity;
+ }
+
+ if (next_time) {
+ sta->timer.expires = next_time;
+ add_timer(&sta->timer);
+ return;
+ }
+
+ if (sta->ap)
+ sta->timeout_next = STA_DEAUTH;
+
+ if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) {
+ spin_lock(&ap->sta_table_lock);
+ ap_sta_hash_del(ap, sta);
+ list_del(&sta->list);
+ spin_unlock(&ap->sta_table_lock);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ } else if (sta->timeout_next == STA_DISASSOC)
+ sta->flags &= ~WLAN_STA_ASSOC;
+
+ if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+ hostap_event_expired_sta(local->dev, sta);
+
+ if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 &&
+ !skb_queue_empty(&sta->tx_buf)) {
+ hostap_set_tim(local, sta->aid, 0);
+ sta->flags &= ~WLAN_STA_TIM;
+ }
+
+ if (sta->ap) {
+ if (ap->autom_ap_wds) {
+ PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
+ "connection to AP " MACSTR "\n",
+ local->dev->name, MAC2STR(sta->addr));
+ hostap_wds_link_oper(local, sta->addr, WDS_DEL);
+ }
+ } else if (sta->timeout_next == STA_NULLFUNC) {
+ /* send data frame to poll STA and check whether this frame
+ * is ACKed */
+ /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but
+ * it is apparently not retried so TX Exc events are not
+ * received for it */
+ sta->flags |= WLAN_STA_PENDING_POLL;
+ prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_DATA, NULL, 0,
+ sta->addr, ap->tx_callback_poll);
+ } else {
+ int deauth = sta->timeout_next == STA_DEAUTH;
+ u16 resp;
+ PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR
+ "(last=%lu, jiffies=%lu)\n",
+ local->dev->name,
+ deauth ? "deauthentication" : "disassociation",
+ MAC2STR(sta->addr), sta->last_rx, jiffies);
+
+ resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+ prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT |
+ (deauth ? IEEE80211_STYPE_DEAUTH :
+ IEEE80211_STYPE_DISASSOC),
+ (char *) &resp, 2, sta->addr, 0);
+ }
+
+ if (sta->timeout_next == STA_DEAUTH) {
+ if (sta->flags & WLAN_STA_PERM) {
+ PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been "
+ "removed, but it has 'perm' flag\n",
+ local->dev->name, MAC2STR(sta->addr));
+ } else
+ ap_free_sta(ap, sta);
+ return;
+ }
+
+ if (sta->timeout_next == STA_NULLFUNC) {
+ sta->timeout_next = STA_DISASSOC;
+ sta->timer.expires = jiffies + AP_DISASSOC_DELAY;
+ } else {
+ sta->timeout_next = STA_DEAUTH;
+ sta->timer.expires = jiffies + AP_DEAUTH_DELAY;
+ }
+
+ add_timer(&sta->timer);
+}
+
+
+void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
+ int resend)
+{
+ u8 addr[ETH_ALEN];
+ u16 resp;
+ int i;
+
+ PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);
+ memset(addr, 0xff, ETH_ALEN);
+
+ resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+ /* deauth message sent; try to resend it few times; the message is
+ * broadcast, so it may be delayed until next DTIM; there is not much
+ * else we can do at this point since the driver is going to be shut
+ * down */
+ for (i = 0; i < 5; i++) {
+ prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_DEAUTH,
+ (char *) &resp, 2, addr, 0);
+
+ if (!resend || ap->num_sta <= 0)
+ return;
+
+ mdelay(50);
+ }
+}
+
+
+static int ap_control_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ap_data *ap = (struct ap_data *) data;
+ char *policy_txt;
+ struct list_head *ptr;
+ struct mac_entry *entry;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ switch (ap->mac_restrictions.policy) {
+ case MAC_POLICY_OPEN:
+ policy_txt = "open";
+ break;
+ case MAC_POLICY_ALLOW:
+ policy_txt = "allow";
+ break;
+ case MAC_POLICY_DENY:
+ policy_txt = "deny";
+ break;
+ default:
+ policy_txt = "unknown";
+ break;
+ };
+ p += sprintf(p, "MAC policy: %s\n", policy_txt);
+ p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
+ p += sprintf(p, "MAC list:\n");
+ spin_lock_bh(&ap->mac_restrictions.lock);
+ for (ptr = ap->mac_restrictions.mac_list.next;
+ ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) {
+ if (p - page > PAGE_SIZE - 80) {
+ p += sprintf(p, "All entries did not fit one page.\n");
+ break;
+ }
+
+ entry = list_entry(ptr, struct mac_entry, list);
+ p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
+ }
+ spin_unlock_bh(&ap->mac_restrictions.lock);
+
+ return (p - page);
+}
+
+
+static int ap_control_add_mac(struct mac_restrictions *mac_restrictions,
+ u8 *mac)
+{
+ struct mac_entry *entry;
+
+ entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
+ if (entry == NULL)
+ return -1;
+
+ memcpy(entry->addr, mac, ETH_ALEN);
+
+ spin_lock_bh(&mac_restrictions->lock);
+ list_add_tail(&entry->list, &mac_restrictions->mac_list);
+ mac_restrictions->entries++;
+ spin_unlock_bh(&mac_restrictions->lock);
+
+ return 0;
+}
+
+
+static int ap_control_del_mac(struct mac_restrictions *mac_restrictions,
+ u8 *mac)
+{
+ struct list_head *ptr;
+ struct mac_entry *entry;
+
+ spin_lock_bh(&mac_restrictions->lock);
+ for (ptr = mac_restrictions->mac_list.next;
+ ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
+ entry = list_entry(ptr, struct mac_entry, list);
+
+ if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
+ list_del(ptr);
+ kfree(entry);
+ mac_restrictions->entries--;
+ spin_unlock_bh(&mac_restrictions->lock);
+ return 0;
+ }
+ }
+ spin_unlock_bh(&mac_restrictions->lock);
+ return -1;
+}
+
+
+static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
+ u8 *mac)
+{
+ struct list_head *ptr;
+ struct mac_entry *entry;
+ int found = 0;
+
+ if (mac_restrictions->policy == MAC_POLICY_OPEN)
+ return 0;
+
+ spin_lock_bh(&mac_restrictions->lock);
+ for (ptr = mac_restrictions->mac_list.next;
+ ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
+ entry = list_entry(ptr, struct mac_entry, list);
+
+ if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&mac_restrictions->lock);
+
+ if (mac_restrictions->policy == MAC_POLICY_ALLOW)
+ return !found;
+ else
+ return found;
+}
+
+
+static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions)
+{
+ struct list_head *ptr, *n;
+ struct mac_entry *entry;
+
+ if (mac_restrictions->entries == 0)
+ return;
+
+ spin_lock_bh(&mac_restrictions->lock);
+ for (ptr = mac_restrictions->mac_list.next, n = ptr->next;
+ ptr != &mac_restrictions->mac_list;
+ ptr = n, n = ptr->next) {
+ entry = list_entry(ptr, struct mac_entry, list);
+ list_del(ptr);
+ kfree(entry);
+ }
+ mac_restrictions->entries = 0;
+ spin_unlock_bh(&mac_restrictions->lock);
+}
+
+
+static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev,
+ u8 *mac)
+{
+ struct sta_info *sta;
+ u16 resp;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, mac);
+ if (sta) {
+ ap_sta_hash_del(ap, sta);
+ list_del(&sta->list);
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (!sta)
+ return -EINVAL;
+
+ resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH,
+ (char *) &resp, 2, sta->addr, 0);
+
+ if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+ hostap_event_expired_sta(dev, sta);
+
+ ap_free_sta(ap, sta);
+
+ return 0;
+}
+
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+static void ap_control_kickall(struct ap_data *ap)
+{
+ struct list_head *ptr, *n;
+ struct sta_info *sta;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list;
+ ptr = n, n = ptr->next) {
+ sta = list_entry(ptr, struct sta_info, list);
+ ap_sta_hash_del(ap, sta);
+ list_del(&sta->list);
+ if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+ hostap_event_expired_sta(sta->local->dev, sta);
+ ap_free_sta(ap, sta);
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+#define PROC_LIMIT (PAGE_SIZE - 80)
+
+static int prism2_ap_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct ap_data *ap = (struct ap_data *) data;
+ struct list_head *ptr;
+ int i;
+
+ if (off > PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
+ spin_lock_bh(&ap->sta_table_lock);
+ for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
+ struct sta_info *sta = (struct sta_info *) ptr;
+
+ if (!sta->ap)
+ continue;
+
+ p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr),
+ sta->u.ap.channel, sta->last_rx_signal,
+ sta->last_rx_silence, sta->last_rx_rate);
+ for (i = 0; i < sta->u.ap.ssid_len; i++)
+ p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
+ sta->u.ap.ssid[i] < 127) ?
+ "%c" : "<%02x>"),
+ sta->u.ap.ssid[i]);
+ p += sprintf(p, "'");
+ if (sta->capability & WLAN_CAPABILITY_ESS)
+ p += sprintf(p, " [ESS]");
+ if (sta->capability & WLAN_CAPABILITY_IBSS)
+ p += sprintf(p, " [IBSS]");
+ if (sta->capability & WLAN_CAPABILITY_PRIVACY)
+ p += sprintf(p, " [WEP]");
+ p += sprintf(p, "\n");
+
+ if ((p - page) > PROC_LIMIT) {
+ printk(KERN_DEBUG "hostap: ap proc did not fit\n");
+ break;
+ }
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if ((p - page) <= off) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = page + off;
+
+ return (p - page - off);
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver)
+{
+ if (!ap)
+ return;
+
+ if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) {
+ PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - "
+ "firmware upgrade recommended\n");
+ ap->nullfunc_ack = 1;
+ } else
+ ap->nullfunc_ack = 0;
+
+ if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) {
+ printk(KERN_WARNING "%s: Warning: secondary station firmware "
+ "version 1.4.2 does not seem to work in Host AP mode\n",
+ ap->local->dev->name);
+ }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
+{
+ struct ap_data *ap = data;
+ u16 fc;
+ struct ieee80211_hdr *hdr;
+
+ if (!ap->local->hostapd || !ap->local->apdev) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ /* Pass the TX callback frame to the hostapd; use 802.11 header version
+ * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */
+
+ fc &= ~IEEE80211_FCTL_VERS;
+ fc |= ok ? BIT(1) : BIT(0);
+ hdr->frame_ctl = cpu_to_le16(fc);
+
+ skb->dev = ap->local->apdev;
+ skb_pull(skb, hostap_80211_get_hdrlen(fc));
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+/* Called only as a tasklet (software IRQ) */
+static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
+{
+ struct ap_data *ap = data;
+ struct net_device *dev = ap->local->dev;
+ struct ieee80211_hdr *hdr;
+ u16 fc, *pos, auth_alg, auth_transaction, status;
+ struct sta_info *sta = NULL;
+ char *txt = NULL;
+
+ if (ap->local->hostapd) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH ||
+ skb->len < IEEE80211_MGMT_HDR_LEN + 6) {
+ printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid "
+ "frame\n", dev->name);
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+ auth_alg = le16_to_cpu(*pos++);
+ auth_transaction = le16_to_cpu(*pos++);
+ status = le16_to_cpu(*pos++);
+
+ if (!ok) {
+ txt = "frame was not ACKed";
+ goto done;
+ }
+
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, hdr->addr1);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock(&ap->sta_table_lock);
+
+ if (!sta) {
+ txt = "STA not found";
+ goto done;
+ }
+
+ if (status == WLAN_STATUS_SUCCESS &&
+ ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
+ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
+ txt = "STA authenticated";
+ sta->flags |= WLAN_STA_AUTH;
+ sta->last_auth = jiffies;
+ } else if (status != WLAN_STATUS_SUCCESS)
+ txt = "authentication failed";
+
+ done:
+ if (sta)
+ atomic_dec(&sta->users);
+ if (txt) {
+ PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d "
+ "status=%d - %s\n",
+ dev->name, MAC2STR(hdr->addr1), auth_alg,
+ auth_transaction, status, txt);
+ }
+ dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
+{
+ struct ap_data *ap = data;
+ struct net_device *dev = ap->local->dev;
+ struct ieee80211_hdr *hdr;
+ u16 fc, *pos, status;
+ struct sta_info *sta = NULL;
+ char *txt = NULL;
+
+ if (ap->local->hostapd) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
+ (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP &&
+ WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) ||
+ skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
+ printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid "
+ "frame\n", dev->name);
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ if (!ok) {
+ txt = "frame was not ACKed";
+ goto done;
+ }
+
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, hdr->addr1);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock(&ap->sta_table_lock);
+
+ if (!sta) {
+ txt = "STA not found";
+ goto done;
+ }
+
+ pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+ pos++;
+ status = le16_to_cpu(*pos++);
+ if (status == WLAN_STATUS_SUCCESS) {
+ if (!(sta->flags & WLAN_STA_ASSOC))
+ hostap_event_new_sta(dev, sta);
+ txt = "STA associated";
+ sta->flags |= WLAN_STA_ASSOC;
+ sta->last_assoc = jiffies;
+ } else
+ txt = "association failed";
+
+ done:
+ if (sta)
+ atomic_dec(&sta->users);
+ if (txt) {
+ PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n",
+ dev->name, MAC2STR(hdr->addr1), txt);
+ }
+ dev_kfree_skb(skb);
+}
+
+/* Called only as a tasklet (software IRQ); TX callback for poll frames used
+ * in verifying whether the STA is still present. */
+static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
+{
+ struct ap_data *ap = data;
+ struct ieee80211_hdr *hdr;
+ struct sta_info *sta;
+
+ if (skb->len < 24)
+ goto fail;
+ hdr = (struct ieee80211_hdr *) skb->data;
+ if (ok) {
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, hdr->addr1);
+ if (sta)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ spin_unlock(&ap->sta_table_lock);
+ } else {
+ PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity "
+ "poll frame\n", ap->local->dev->name,
+ MAC2STR(hdr->addr1));
+ }
+
+ fail:
+ dev_kfree_skb(skb);
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+void hostap_init_data(local_info_t *local)
+{
+ struct ap_data *ap = local->ap;
+
+ if (ap == NULL) {
+ printk(KERN_WARNING "hostap_init_data: ap == NULL\n");
+ return;
+ }
+ memset(ap, 0, sizeof(struct ap_data));
+ ap->local = local;
+
+ ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx);
+ ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx);
+ ap->max_inactivity =
+ GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ;
+ ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx);
+
+ spin_lock_init(&ap->sta_table_lock);
+ INIT_LIST_HEAD(&ap->sta_list);
+
+ /* Initialize task queue structure for AP management */
+ INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap);
+
+ ap->tx_callback_idx =
+ hostap_tx_callback_register(local, hostap_ap_tx_cb, ap);
+ if (ap->tx_callback_idx == 0)
+ printk(KERN_WARNING "%s: failed to register TX callback for "
+ "AP\n", local->dev->name);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local);
+
+ ap->tx_callback_auth =
+ hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
+ ap->tx_callback_assoc =
+ hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap);
+ ap->tx_callback_poll =
+ hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap);
+ if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 ||
+ ap->tx_callback_poll == 0)
+ printk(KERN_WARNING "%s: failed to register TX callback for "
+ "AP\n", local->dev->name);
+
+ spin_lock_init(&ap->mac_restrictions.lock);
+ INIT_LIST_HEAD(&ap->mac_restrictions.mac_list);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ ap->initialized = 1;
+}
+
+
+void hostap_init_ap_proc(local_info_t *local)
+{
+ struct ap_data *ap = local->ap;
+
+ ap->proc = local->proc;
+ if (ap->proc == NULL)
+ return;
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ create_proc_read_entry("ap_debug", 0, ap->proc,
+ ap_debug_proc_read, ap);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ create_proc_read_entry("ap_control", 0, ap->proc,
+ ap_control_proc_read, ap);
+ create_proc_read_entry("ap", 0, ap->proc,
+ prism2_ap_proc_read, ap);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+}
+
+
+void hostap_free_data(struct ap_data *ap)
+{
+ struct list_head *n, *ptr;
+
+ if (ap == NULL || !ap->initialized) {
+ printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
+ "initialized - skip resource freeing\n");
+ return;
+ }
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (ap->crypt)
+ ap->crypt->deinit(ap->crypt_priv);
+ ap->crypt = ap->crypt_priv = NULL;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ list_for_each_safe(ptr, n, &ap->sta_list) {
+ struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+ ap_sta_hash_del(ap, sta);
+ list_del(&sta->list);
+ if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+ hostap_event_expired_sta(sta->local->dev, sta);
+ ap_free_sta(ap, sta);
+ }
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ if (ap->proc != NULL) {
+ remove_proc_entry("ap_debug", ap->proc);
+ }
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (ap->proc != NULL) {
+ remove_proc_entry("ap", ap->proc);
+ remove_proc_entry("ap_control", ap->proc);
+ }
+ ap_control_flush_macs(&ap->mac_restrictions);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ ap->initialized = 0;
+}
+
+
+/* caller should have mutex for AP STA list handling */
+static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta)
+{
+ struct sta_info *s;
+
+ s = ap->sta_hash[STA_HASH(sta)];
+ while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0)
+ s = s->hnext;
+ return s;
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+/* Called from timer handler and from scheduled AP queue handlers */
+static void prism2_send_mgmt(struct net_device *dev,
+ u16 type_subtype, char *body,
+ int body_len, u8 *addr, u16 tx_cb_idx)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ struct sk_buff *skb;
+ struct hostap_skb_tx_data *meta;
+ int hdrlen;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ dev = local->dev; /* always use master radio device */
+ iface = netdev_priv(dev);
+
+ if (!(dev->flags & IFF_UP)) {
+ PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - "
+ "cannot send frame\n", dev->name);
+ return;
+ }
+
+ skb = dev_alloc_skb(sizeof(*hdr) + body_len);
+ if (skb == NULL) {
+ PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate "
+ "skb\n", dev->name);
+ return;
+ }
+
+ fc = type_subtype;
+ hdrlen = hostap_80211_get_hdrlen(fc);
+ hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen);
+ if (body)
+ memcpy(skb_put(skb, body_len), body, body_len);
+
+ memset(hdr, 0, hdrlen);
+
+ /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11
+ * tx_control instead of using local->tx_control */
+
+
+ memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */
+ if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) {
+ fc |= IEEE80211_FCTL_FROMDS;
+ memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */
+ memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */
+ } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) {
+ /* control:ACK does not have addr2 or addr3 */
+ memset(hdr->addr2, 0, ETH_ALEN);
+ memset(hdr->addr3, 0, ETH_ALEN);
+ } else {
+ memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */
+ memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */
+ }
+
+ hdr->frame_ctl = cpu_to_le16(fc);
+
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ memset(meta, 0, sizeof(*meta));
+ meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
+ meta->iface = iface;
+ meta->tx_cb_idx = tx_cb_idx;
+
+ skb->dev = dev;
+ skb->mac.raw = skb->nh.raw = skb->data;
+ dev_queue_xmit(skb);
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+static int prism2_sta_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct sta_info *sta = (struct sta_info *) data;
+ int i;
+
+ /* FIX: possible race condition.. the STA data could have just expired,
+ * but proc entry was still here so that the read could have started;
+ * some locking should be done here.. */
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n"
+ "flags=0x%04x%s%s%s%s%s%s%s\n"
+ "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
+ sta->ap ? "AP" : "STA",
+ MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid,
+ sta->flags,
+ sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
+ sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
+ sta->flags & WLAN_STA_PS ? " PS" : "",
+ sta->flags & WLAN_STA_TIM ? " TIM" : "",
+ sta->flags & WLAN_STA_PERM ? " PERM" : "",
+ sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
+ sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
+ sta->capability, sta->listen_interval);
+ /* supported_rates: 500 kbit/s units with msb ignored */
+ for (i = 0; i < sizeof(sta->supported_rates); i++)
+ if (sta->supported_rates[i] != 0)
+ p += sprintf(p, "%d%sMbps ",
+ (sta->supported_rates[i] & 0x7f) / 2,
+ sta->supported_rates[i] & 1 ? ".5" : "");
+ p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
+ "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
+ "tx_packets=%lu\n"
+ "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
+ "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
+ "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
+ "tx[11M]=%d\n"
+ "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
+ jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
+ sta->last_tx,
+ sta->rx_packets, sta->tx_packets, sta->rx_bytes,
+ sta->tx_bytes, skb_queue_len(&sta->tx_buf),
+ sta->last_rx_silence,
+ sta->last_rx_signal, sta->last_rx_rate / 10,
+ sta->last_rx_rate % 10 ? ".5" : "",
+ sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
+ sta->tx_count[2], sta->tx_count[3], sta->rx_count[0],
+ sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
+ if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats)
+ p = sta->crypt->ops->print_stats(p, sta->crypt->priv);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (sta->ap) {
+ if (sta->u.ap.channel >= 0)
+ p += sprintf(p, "channel=%d\n", sta->u.ap.channel);
+ p += sprintf(p, "ssid=");
+ for (i = 0; i < sta->u.ap.ssid_len; i++)
+ p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
+ sta->u.ap.ssid[i] < 127) ?
+ "%c" : "<%02x>"),
+ sta->u.ap.ssid[i]);
+ p += sprintf(p, "\n");
+ }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ return (p - page);
+}
+
+
+static void handle_add_proc_queue(void *data)
+{
+ struct ap_data *ap = (struct ap_data *) data;
+ struct sta_info *sta;
+ char name[20];
+ struct add_sta_proc_data *entry, *prev;
+
+ entry = ap->add_sta_proc_entries;
+ ap->add_sta_proc_entries = NULL;
+
+ while (entry) {
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, entry->addr);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (sta) {
+ sprintf(name, MACSTR, MAC2STR(sta->addr));
+ sta->proc = create_proc_read_entry(
+ name, 0, ap->proc,
+ prism2_sta_proc_read, sta);
+
+ atomic_dec(&sta->users);
+ }
+
+ prev = entry;
+ entry = entry->next;
+ kfree(prev);
+ }
+}
+
+
+static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr)
+{
+ struct sta_info *sta;
+
+ sta = (struct sta_info *)
+ kmalloc(sizeof(struct sta_info), GFP_ATOMIC);
+ if (sta == NULL) {
+ PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
+ return NULL;
+ }
+
+ /* initialize STA info data */
+ memset(sta, 0, sizeof(struct sta_info));
+ sta->local = ap->local;
+ skb_queue_head_init(&sta->tx_buf);
+ memcpy(sta->addr, addr, ETH_ALEN);
+
+ atomic_inc(&sta->users);
+ spin_lock_bh(&ap->sta_table_lock);
+ list_add(&sta->list, &ap->sta_list);
+ ap->num_sta++;
+ ap_sta_hash_add(ap, sta);
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (ap->proc) {
+ struct add_sta_proc_data *entry;
+ /* schedule a non-interrupt context process to add a procfs
+ * entry for the STA since procfs code use GFP_KERNEL */
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry) {
+ memcpy(entry->addr, sta->addr, ETH_ALEN);
+ entry->next = ap->add_sta_proc_entries;
+ ap->add_sta_proc_entries = entry;
+ schedule_work(&ap->add_sta_proc_queue);
+ } else
+ printk(KERN_DEBUG "Failed to add STA proc data\n");
+ }
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ init_timer(&sta->timer);
+ sta->timer.expires = jiffies + ap->max_inactivity;
+ sta->timer.data = (unsigned long) sta;
+ sta->timer.function = ap_handle_timer;
+ if (!ap->local->hostapd)
+ add_timer(&sta->timer);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ return sta;
+}
+
+
+static int ap_tx_rate_ok(int rateidx, struct sta_info *sta,
+ local_info_t *local)
+{
+ if (rateidx > sta->tx_max_rate ||
+ !(sta->tx_supp_rates & (1 << rateidx)))
+ return 0;
+
+ if (local->tx_rate_control != 0 &&
+ !(local->tx_rate_control & (1 << rateidx)))
+ return 0;
+
+ return 1;
+}
+
+
+static void prism2_check_tx_rates(struct sta_info *sta)
+{
+ int i;
+
+ sta->tx_supp_rates = 0;
+ for (i = 0; i < sizeof(sta->supported_rates); i++) {
+ if ((sta->supported_rates[i] & 0x7f) == 2)
+ sta->tx_supp_rates |= WLAN_RATE_1M;
+ if ((sta->supported_rates[i] & 0x7f) == 4)
+ sta->tx_supp_rates |= WLAN_RATE_2M;
+ if ((sta->supported_rates[i] & 0x7f) == 11)
+ sta->tx_supp_rates |= WLAN_RATE_5M5;
+ if ((sta->supported_rates[i] & 0x7f) == 22)
+ sta->tx_supp_rates |= WLAN_RATE_11M;
+ }
+ sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0;
+ if (sta->tx_supp_rates & WLAN_RATE_1M) {
+ sta->tx_max_rate = 0;
+ if (ap_tx_rate_ok(0, sta, sta->local)) {
+ sta->tx_rate = 10;
+ sta->tx_rate_idx = 0;
+ }
+ }
+ if (sta->tx_supp_rates & WLAN_RATE_2M) {
+ sta->tx_max_rate = 1;
+ if (ap_tx_rate_ok(1, sta, sta->local)) {
+ sta->tx_rate = 20;
+ sta->tx_rate_idx = 1;
+ }
+ }
+ if (sta->tx_supp_rates & WLAN_RATE_5M5) {
+ sta->tx_max_rate = 2;
+ if (ap_tx_rate_ok(2, sta, sta->local)) {
+ sta->tx_rate = 55;
+ sta->tx_rate_idx = 2;
+ }
+ }
+ if (sta->tx_supp_rates & WLAN_RATE_11M) {
+ sta->tx_max_rate = 3;
+ if (ap_tx_rate_ok(3, sta, sta->local)) {
+ sta->tx_rate = 110;
+ sta->tx_rate_idx = 3;
+ }
+ }
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+static void ap_crypt_init(struct ap_data *ap)
+{
+ ap->crypt = ieee80211_get_crypto_ops("WEP");
+
+ if (ap->crypt) {
+ if (ap->crypt->init) {
+ ap->crypt_priv = ap->crypt->init(0);
+ if (ap->crypt_priv == NULL)
+ ap->crypt = NULL;
+ else {
+ u8 key[WEP_KEY_LEN];
+ get_random_bytes(key, WEP_KEY_LEN);
+ ap->crypt->set_key(key, WEP_KEY_LEN, NULL,
+ ap->crypt_priv);
+ }
+ }
+ }
+
+ if (ap->crypt == NULL) {
+ printk(KERN_WARNING "AP could not initialize WEP: load module "
+ "ieee80211_crypt_wep.ko\n");
+ }
+}
+
+
+/* Generate challenge data for shared key authentication. IEEE 802.11 specifies
+ * that WEP algorithm is used for generating challange. This should be unique,
+ * but otherwise there is not really need for randomness etc. Initialize WEP
+ * with pseudo random key and then use increasing IV to get unique challenge
+ * streams.
+ *
+ * Called only as a scheduled task for pending AP frames.
+ */
+static char * ap_auth_make_challenge(struct ap_data *ap)
+{
+ char *tmpbuf;
+ struct sk_buff *skb;
+
+ if (ap->crypt == NULL) {
+ ap_crypt_init(ap);
+ if (ap->crypt == NULL)
+ return NULL;
+ }
+
+ tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
+ if (tmpbuf == NULL) {
+ PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n");
+ return NULL;
+ }
+
+ skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN +
+ ap->crypt->extra_prefix_len +
+ ap->crypt->extra_postfix_len);
+ if (skb == NULL) {
+ kfree(tmpbuf);
+ return NULL;
+ }
+
+ skb_reserve(skb, ap->crypt->extra_prefix_len);
+ memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0,
+ WLAN_AUTH_CHALLENGE_LEN);
+ if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) {
+ dev_kfree_skb(skb);
+ kfree(tmpbuf);
+ return NULL;
+ }
+
+ memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len,
+ WLAN_AUTH_CHALLENGE_LEN);
+ dev_kfree_skb(skb);
+
+ return tmpbuf;
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_authen(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct net_device *dev = local->dev;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ size_t hdrlen;
+ struct ap_data *ap = local->ap;
+ char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
+ int len, olen;
+ u16 auth_alg, auth_transaction, status_code, *pos;
+ u16 resp = WLAN_STATUS_SUCCESS, fc;
+ struct sta_info *sta = NULL;
+ struct ieee80211_crypt_data *crypt;
+ char *txt = "";
+
+ len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ hdrlen = hostap_80211_get_hdrlen(fc);
+
+ if (len < 6) {
+ PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
+ "(len=%d) from " MACSTR "\n", dev->name, len,
+ MAC2STR(hdr->addr2));
+ return;
+ }
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&local->ap->sta_table_lock);
+
+ if (sta && sta->crypt)
+ crypt = sta->crypt;
+ else {
+ int idx = 0;
+ if (skb->len >= hdrlen + 3)
+ idx = skb->data[hdrlen + 3] >> 6;
+ crypt = local->crypt[idx];
+ }
+
+ pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+ auth_alg = __le16_to_cpu(*pos);
+ pos++;
+ auth_transaction = __le16_to_cpu(*pos);
+ pos++;
+ status_code = __le16_to_cpu(*pos);
+ pos++;
+
+ if (memcmp(dev->dev_addr, hdr->addr2, ETH_ALEN) == 0 ||
+ ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) {
+ txt = "authentication denied";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (((local->auth_algs & PRISM2_AUTH_OPEN) &&
+ auth_alg == WLAN_AUTH_OPEN) ||
+ ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) &&
+ crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) {
+ } else {
+ txt = "unsupported algorithm";
+ resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+ goto fail;
+ }
+
+ if (len >= 8) {
+ u8 *u = (u8 *) pos;
+ if (*u == WLAN_EID_CHALLENGE) {
+ if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) {
+ txt = "invalid challenge len";
+ resp = WLAN_STATUS_CHALLENGE_FAIL;
+ goto fail;
+ }
+ if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) {
+ txt = "challenge underflow";
+ resp = WLAN_STATUS_CHALLENGE_FAIL;
+ goto fail;
+ }
+ challenge = (char *) (u + 2);
+ }
+ }
+
+ if (sta && sta->ap) {
+ if (time_after(jiffies, sta->u.ap.last_beacon +
+ (10 * sta->listen_interval * HZ) / 1024)) {
+ PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
+ " assuming AP " MACSTR " is now STA\n",
+ dev->name, MAC2STR(sta->addr));
+ sta->ap = 0;
+ sta->flags = 0;
+ sta->u.sta.challenge = NULL;
+ } else {
+ txt = "AP trying to authenticate?";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+
+ if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ||
+ (auth_alg == WLAN_AUTH_SHARED_KEY &&
+ (auth_transaction == 1 ||
+ (auth_transaction == 3 && sta != NULL &&
+ sta->u.sta.challenge != NULL)))) {
+ } else {
+ txt = "unknown authentication transaction number";
+ resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ goto fail;
+ }
+
+ if (sta == NULL) {
+ txt = "new STA";
+
+ if (local->ap->num_sta >= MAX_STA_COUNT) {
+ /* FIX: might try to remove some old STAs first? */
+ txt = "no more room for new STAs";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ sta = ap_add_sta(local->ap, hdr->addr2);
+ if (sta == NULL) {
+ txt = "ap_add_sta failed";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+
+ switch (auth_alg) {
+ case WLAN_AUTH_OPEN:
+ txt = "authOK";
+ /* IEEE 802.11 standard is not completely clear about
+ * whether STA is considered authenticated after
+ * authentication OK frame has been send or after it
+ * has been ACKed. In order to reduce interoperability
+ * issues, mark the STA authenticated before ACK. */
+ sta->flags |= WLAN_STA_AUTH;
+ break;
+
+ case WLAN_AUTH_SHARED_KEY:
+ if (auth_transaction == 1) {
+ if (sta->u.sta.challenge == NULL) {
+ sta->u.sta.challenge =
+ ap_auth_make_challenge(local->ap);
+ if (sta->u.sta.challenge == NULL) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+ } else {
+ if (sta->u.sta.challenge == NULL ||
+ challenge == NULL ||
+ memcmp(sta->u.sta.challenge, challenge,
+ WLAN_AUTH_CHALLENGE_LEN) != 0 ||
+ !(fc & IEEE80211_FCTL_PROTECTED)) {
+ txt = "challenge response incorrect";
+ resp = WLAN_STATUS_CHALLENGE_FAIL;
+ goto fail;
+ }
+
+ txt = "challenge OK - authOK";
+ /* IEEE 802.11 standard is not completely clear about
+ * whether STA is considered authenticated after
+ * authentication OK frame has been send or after it
+ * has been ACKed. In order to reduce interoperability
+ * issues, mark the STA authenticated before ACK. */
+ sta->flags |= WLAN_STA_AUTH;
+ kfree(sta->u.sta.challenge);
+ sta->u.sta.challenge = NULL;
+ }
+ break;
+ }
+
+ fail:
+ pos = (u16 *) body;
+ *pos = cpu_to_le16(auth_alg);
+ pos++;
+ *pos = cpu_to_le16(auth_transaction + 1);
+ pos++;
+ *pos = cpu_to_le16(resp); /* status_code */
+ pos++;
+ olen = 6;
+
+ if (resp == WLAN_STATUS_SUCCESS && sta != NULL &&
+ sta->u.sta.challenge != NULL &&
+ auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) {
+ u8 *tmp = (u8 *) pos;
+ *tmp++ = WLAN_EID_CHALLENGE;
+ *tmp++ = WLAN_AUTH_CHALLENGE_LEN;
+ pos++;
+ memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN);
+ olen += 2 + WLAN_AUTH_CHALLENGE_LEN;
+ }
+
+ prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH,
+ body, olen, hdr->addr2, ap->tx_callback_auth);
+
+ if (sta) {
+ sta->last_rx = jiffies;
+ atomic_dec(&sta->users);
+ }
+
+ if (resp) {
+ PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d "
+ "stat=%d len=%d fc=%04x) ==> %d (%s)\n",
+ dev->name, MAC2STR(hdr->addr2), auth_alg,
+ auth_transaction, status_code, len, fc, resp, txt);
+ }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_assoc(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats, int reassoc)
+{
+ struct net_device *dev = local->dev;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ char body[12], *p, *lpos;
+ int len, left;
+ u16 *pos;
+ u16 resp = WLAN_STATUS_SUCCESS;
+ struct sta_info *sta = NULL;
+ int send_deauth = 0;
+ char *txt = "";
+ u8 prev_ap[ETH_ALEN];
+
+ left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+ if (len < (reassoc ? 10 : 4)) {
+ PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
+ "(len=%d, reassoc=%d) from " MACSTR "\n",
+ dev->name, len, reassoc, MAC2STR(hdr->addr2));
+ return;
+ }
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
+ spin_unlock_bh(&local->ap->sta_table_lock);
+ txt = "trying to associate before authentication";
+ send_deauth = 1;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ sta = NULL; /* do not decrement sta->users */
+ goto fail;
+ }
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&local->ap->sta_table_lock);
+
+ pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+ sta->capability = __le16_to_cpu(*pos);
+ pos++; left -= 2;
+ sta->listen_interval = __le16_to_cpu(*pos);
+ pos++; left -= 2;
+
+ if (reassoc) {
+ memcpy(prev_ap, pos, ETH_ALEN);
+ pos++; pos++; pos++; left -= 6;
+ } else
+ memset(prev_ap, 0, ETH_ALEN);
+
+ if (left >= 2) {
+ unsigned int ileft;
+ unsigned char *u = (unsigned char *) pos;
+
+ if (*u == WLAN_EID_SSID) {
+ u++; left--;
+ ileft = *u;
+ u++; left--;
+
+ if (ileft > left || ileft > MAX_SSID_LEN) {
+ txt = "SSID overflow";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (ileft != strlen(local->essid) ||
+ memcmp(local->essid, u, ileft) != 0) {
+ txt = "not our SSID";
+ resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ goto fail;
+ }
+
+ u += ileft;
+ left -= ileft;
+ }
+
+ if (left >= 2 && *u == WLAN_EID_SUPP_RATES) {
+ u++; left--;
+ ileft = *u;
+ u++; left--;
+
+ if (ileft > left || ileft == 0 ||
+ ileft > WLAN_SUPP_RATES_MAX) {
+ txt = "SUPP_RATES len error";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ memset(sta->supported_rates, 0,
+ sizeof(sta->supported_rates));
+ memcpy(sta->supported_rates, u, ileft);
+ prism2_check_tx_rates(sta);
+
+ u += ileft;
+ left -= ileft;
+ }
+
+ if (left > 0) {
+ PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra"
+ " data (%d bytes) [",
+ dev->name, MAC2STR(hdr->addr2), left);
+ while (left > 0) {
+ PDEBUG2(DEBUG_AP, "<%02x>", *u);
+ u++; left--;
+ }
+ PDEBUG2(DEBUG_AP, "]\n");
+ }
+ } else {
+ txt = "frame underflow";
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ /* get a unique AID */
+ if (sta->aid > 0)
+ txt = "OK, old AID";
+ else {
+ spin_lock_bh(&local->ap->sta_table_lock);
+ for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
+ if (local->ap->sta_aid[sta->aid - 1] == NULL)
+ break;
+ if (sta->aid > MAX_AID_TABLE_SIZE) {
+ sta->aid = 0;
+ spin_unlock_bh(&local->ap->sta_table_lock);
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ txt = "no room for more AIDs";
+ } else {
+ local->ap->sta_aid[sta->aid - 1] = sta;
+ spin_unlock_bh(&local->ap->sta_table_lock);
+ txt = "OK, new AID";
+ }
+ }
+
+ fail:
+ pos = (u16 *) body;
+
+ if (send_deauth) {
+ *pos = __constant_cpu_to_le16(
+ WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
+ pos++;
+ } else {
+ /* FIX: CF-Pollable and CF-PollReq should be set to match the
+ * values in beacons/probe responses */
+ /* FIX: how about privacy and WEP? */
+ /* capability */
+ *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS);
+ pos++;
+
+ /* status_code */
+ *pos = __cpu_to_le16(resp);
+ pos++;
+
+ *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
+ BIT(14) | BIT(15)); /* AID */
+ pos++;
+
+ /* Supported rates (Information element) */
+ p = (char *) pos;
+ *p++ = WLAN_EID_SUPP_RATES;
+ lpos = p;
+ *p++ = 0; /* len */
+ if (local->tx_rate_control & WLAN_RATE_1M) {
+ *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02;
+ (*lpos)++;
+ }
+ if (local->tx_rate_control & WLAN_RATE_2M) {
+ *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04;
+ (*lpos)++;
+ }
+ if (local->tx_rate_control & WLAN_RATE_5M5) {
+ *p++ = local->basic_rates & WLAN_RATE_5M5 ?
+ 0x8b : 0x0b;
+ (*lpos)++;
+ }
+ if (local->tx_rate_control & WLAN_RATE_11M) {
+ *p++ = local->basic_rates & WLAN_RATE_11M ?
+ 0x96 : 0x16;
+ (*lpos)++;
+ }
+ pos = (u16 *) p;
+ }
+
+ prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
+ (send_deauth ? IEEE80211_STYPE_DEAUTH :
+ (reassoc ? IEEE80211_STYPE_REASSOC_RESP :
+ IEEE80211_STYPE_ASSOC_RESP)),
+ body, (u8 *) pos - (u8 *) body,
+ hdr->addr2,
+ send_deauth ? 0 : local->ap->tx_callback_assoc);
+
+ if (sta) {
+ if (resp == WLAN_STATUS_SUCCESS) {
+ sta->last_rx = jiffies;
+ /* STA will be marked associated from TX callback, if
+ * AssocResp is ACKed */
+ }
+ atomic_dec(&sta->users);
+ }
+
+#if 0
+ PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR
+ ") => %d(%d) (%s)\n",
+ dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len,
+ MAC2STR(prev_ap), resp, send_deauth, txt);
+#endif
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_deauth(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct net_device *dev = local->dev;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+ int len;
+ u16 reason_code, *pos;
+ struct sta_info *sta = NULL;
+
+ len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+ if (len < 2) {
+ printk("handle_deauth - too short payload (len=%d)\n", len);
+ return;
+ }
+
+ pos = (u16 *) body;
+ reason_code = __le16_to_cpu(*pos);
+
+ PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, "
+ "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+ reason_code);
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta != NULL) {
+ if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+ hostap_event_expired_sta(local->dev, sta);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ }
+ spin_unlock_bh(&local->ap->sta_table_lock);
+ if (sta == NULL) {
+ printk("%s: deauthentication from " MACSTR ", "
+ "reason_code=%d, but STA not authenticated\n", dev->name,
+ MAC2STR(hdr->addr2), reason_code);
+ }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct net_device *dev = local->dev;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
+ int len;
+ u16 reason_code, *pos;
+ struct sta_info *sta = NULL;
+
+ len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+ if (len < 2) {
+ printk("handle_disassoc - too short payload (len=%d)\n", len);
+ return;
+ }
+
+ pos = (u16 *) body;
+ reason_code = __le16_to_cpu(*pos);
+
+ PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, "
+ "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+ reason_code);
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta != NULL) {
+ if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+ hostap_event_expired_sta(local->dev, sta);
+ sta->flags &= ~WLAN_STA_ASSOC;
+ }
+ spin_unlock_bh(&local->ap->sta_table_lock);
+ if (sta == NULL) {
+ printk("%s: disassociation from " MACSTR ", "
+ "reason_code=%d, but STA not authenticated\n",
+ dev->name, MAC2STR(hdr->addr2), reason_code);
+ }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void ap_handle_data_nullfunc(local_info_t *local,
+ struct ieee80211_hdr *hdr)
+{
+ struct net_device *dev = local->dev;
+
+ /* some STA f/w's seem to require control::ACK frame for
+ * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does
+ * not send this..
+ * send control::ACK for the data::nullfunc */
+
+ printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n");
+ prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK,
+ NULL, 0, hdr->addr2, 0);
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void ap_handle_dropped_data(local_info_t *local,
+ struct ieee80211_hdr *hdr)
+{
+ struct net_device *dev = local->dev;
+ struct sta_info *sta;
+ u16 reason;
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&local->ap->sta_table_lock);
+
+ if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) {
+ PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n");
+ atomic_dec(&sta->users);
+ return;
+ }
+
+ reason = __constant_cpu_to_le16(
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
+ ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ?
+ IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC),
+ (char *) &reason, sizeof(reason), hdr->addr2, 0);
+
+ if (sta)
+ atomic_dec(&sta->users);
+}
+
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
+ struct sk_buff *skb)
+{
+ struct hostap_skb_tx_data *meta;
+
+ if (!(sta->flags & WLAN_STA_PS)) {
+ /* Station has moved to non-PS mode, so send all buffered
+ * frames using normal device queue. */
+ dev_queue_xmit(skb);
+ return;
+ }
+
+ /* add a flag for hostap_handle_sta_tx() to know that this skb should
+ * be passed through even though STA is using PS */
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME;
+ if (!skb_queue_empty(&sta->tx_buf)) {
+ /* indicate to STA that more frames follow */
+ meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA;
+ }
+ dev_queue_xmit(skb);
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_pspoll(local_info_t *local,
+ struct ieee80211_hdr *hdr,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct net_device *dev = local->dev;
+ struct sta_info *sta;
+ u16 aid;
+ struct sk_buff *skb;
+
+ PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR
+ " PWRMGT=%d\n",
+ MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+ !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
+
+ if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
+ PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR
+ " not own MAC\n", MAC2STR(hdr->addr1));
+ return;
+ }
+
+ aid = __le16_to_cpu(hdr->duration_id);
+ if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) {
+ PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n");
+ return;
+ }
+ aid &= ~BIT(15) & ~BIT(14);
+ if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
+ PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid);
+ return;
+ }
+ PDEBUG(DEBUG_PS2, " aid=%d\n", aid);
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&local->ap->sta_table_lock);
+
+ if (sta == NULL) {
+ PDEBUG(DEBUG_PS, " STA not found\n");
+ return;
+ }
+ if (sta->aid != aid) {
+ PDEBUG(DEBUG_PS, " received aid=%i does not match with "
+ "assoc.aid=%d\n", aid, sta->aid);
+ return;
+ }
+
+ /* FIX: todo:
+ * - add timeout for buffering (clear aid in TIM vector if buffer timed
+ * out (expiry time must be longer than ListenInterval for
+ * the corresponding STA; "8802-11: 11.2.1.9 AP aging function"
+ * - what to do, if buffered, pspolled, and sent frame is not ACKed by
+ * sta; store buffer for later use and leave TIM aid bit set? use
+ * TX event to check whether frame was ACKed?
+ */
+
+ while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) {
+ /* send buffered frame .. */
+ PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL"
+ " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf));
+
+ pspoll_send_buffered(local, sta, skb);
+
+ if (sta->flags & WLAN_STA_PS) {
+ /* send only one buffered packet per PS Poll */
+ /* FIX: should ignore further PS Polls until the
+ * buffered packet that was just sent is acknowledged
+ * (Tx or TxExc event) */
+ break;
+ }
+ }
+
+ if (skb_queue_empty(&sta->tx_buf)) {
+ /* try to clear aid from TIM */
+ if (!(sta->flags & WLAN_STA_TIM))
+ PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n",
+ aid);
+ hostap_set_tim(local, aid, 0);
+ sta->flags &= ~WLAN_STA_TIM;
+ }
+
+ atomic_dec(&sta->users);
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+
+static void handle_wds_oper_queue(void *data)
+{
+ local_info_t *local = data;
+ struct wds_oper_data *entry, *prev;
+
+ spin_lock_bh(&local->lock);
+ entry = local->ap->wds_oper_entries;
+ local->ap->wds_oper_entries = NULL;
+ spin_unlock_bh(&local->lock);
+
+ while (entry) {
+ PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
+ "to AP " MACSTR "\n",
+ local->dev->name,
+ entry->type == WDS_ADD ? "adding" : "removing",
+ MAC2STR(entry->addr));
+ if (entry->type == WDS_ADD)
+ prism2_wds_add(local, entry->addr, 0);
+ else if (entry->type == WDS_DEL)
+ prism2_wds_del(local, entry->addr, 0, 1);
+
+ prev = entry;
+ entry = entry->next;
+ kfree(prev);
+ }
+}
+
+
+/* Called only as a scheduled task for pending AP frames. */
+static void handle_beacon(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
+ int len, left;
+ u16 *pos, beacon_int, capability;
+ char *ssid = NULL;
+ unsigned char *supp_rates = NULL;
+ int ssid_len = 0, supp_rates_len = 0;
+ struct sta_info *sta = NULL;
+ int new_sta = 0, channel = -1;
+
+ len = skb->len - IEEE80211_MGMT_HDR_LEN;
+
+ if (len < 8 + 2 + 2) {
+ printk(KERN_DEBUG "handle_beacon - too short payload "
+ "(len=%d)\n", len);
+ return;
+ }
+
+ pos = (u16 *) body;
+ left = len;
+
+ /* Timestamp (8 octets) */
+ pos += 4; left -= 8;
+ /* Beacon interval (2 octets) */
+ beacon_int = __le16_to_cpu(*pos);
+ pos++; left -= 2;
+ /* Capability information (2 octets) */
+ capability = __le16_to_cpu(*pos);
+ pos++; left -= 2;
+
+ if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS &&
+ capability & WLAN_CAPABILITY_IBSS)
+ return;
+
+ if (left >= 2) {
+ unsigned int ileft;
+ unsigned char *u = (unsigned char *) pos;
+
+ if (*u == WLAN_EID_SSID) {
+ u++; left--;
+ ileft = *u;
+ u++; left--;
+
+ if (ileft > left || ileft > MAX_SSID_LEN) {
+ PDEBUG(DEBUG_AP, "SSID: overflow\n");
+ return;
+ }
+
+ if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID &&
+ (ileft != strlen(local->essid) ||
+ memcmp(local->essid, u, ileft) != 0)) {
+ /* not our SSID */
+ return;
+ }
+
+ ssid = u;
+ ssid_len = ileft;
+
+ u += ileft;
+ left -= ileft;
+ }
+
+ if (*u == WLAN_EID_SUPP_RATES) {
+ u++; left--;
+ ileft = *u;
+ u++; left--;
+
+ if (ileft > left || ileft == 0 || ileft > 8) {
+ PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n");
+ return;
+ }
+
+ supp_rates = u;
+ supp_rates_len = ileft;
+
+ u += ileft;
+ left -= ileft;
+ }
+
+ if (*u == WLAN_EID_DS_PARAMS) {
+ u++; left--;
+ ileft = *u;
+ u++; left--;
+
+ if (ileft > left || ileft != 1) {
+ PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n");
+ return;
+ }
+
+ channel = *u;
+
+ u += ileft;
+ left -= ileft;
+ }
+ }
+
+ spin_lock_bh(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta != NULL)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&local->ap->sta_table_lock);
+
+ if (sta == NULL) {
+ /* add new AP */
+ new_sta = 1;
+ sta = ap_add_sta(local->ap, hdr->addr2);
+ if (sta == NULL) {
+ printk(KERN_INFO "prism2: kmalloc failed for AP "
+ "data structure\n");
+ return;
+ }
+ hostap_event_new_sta(local->dev, sta);
+
+ /* mark APs authentication and associated for pseudo ad-hoc
+ * style communication */
+ sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+ if (local->ap->autom_ap_wds) {
+ hostap_wds_link_oper(local, sta->addr, WDS_ADD);
+ }
+ }
+
+ sta->ap = 1;
+ if (ssid) {
+ sta->u.ap.ssid_len = ssid_len;
+ memcpy(sta->u.ap.ssid, ssid, ssid_len);
+ sta->u.ap.ssid[ssid_len] = '\0';
+ } else {
+ sta->u.ap.ssid_len = 0;
+ sta->u.ap.ssid[0] = '\0';
+ }
+ sta->u.ap.channel = channel;
+ sta->rx_packets++;
+ sta->rx_bytes += len;
+ sta->u.ap.last_beacon = sta->last_rx = jiffies;
+ sta->capability = capability;
+ sta->listen_interval = beacon_int;
+
+ atomic_dec(&sta->users);
+
+ if (new_sta) {
+ memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
+ memcpy(sta->supported_rates, supp_rates, supp_rates_len);
+ prism2_check_tx_rates(sta);
+ }
+}
+
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+/* Called only as a tasklet. */
+static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ struct net_device *dev = local->dev;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+ u16 fc, type, stype;
+ struct ieee80211_hdr *hdr;
+
+ /* FIX: should give skb->len to handler functions and check that the
+ * buffer is long enough */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (!local->hostapd && type == IEEE80211_FTYPE_DATA) {
+ PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n");
+
+ if (!(fc & IEEE80211_FCTL_TODS) ||
+ (fc & IEEE80211_FCTL_FROMDS)) {
+ if (stype == IEEE80211_STYPE_NULLFUNC) {
+ /* no ToDS nullfunc seems to be used to check
+ * AP association; so send reject message to
+ * speed up re-association */
+ ap_handle_dropped_data(local, hdr);
+ goto done;
+ }
+ PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n",
+ fc);
+ goto done;
+ }
+
+ if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
+ MACSTR " not own MAC\n",
+ MAC2STR(hdr->addr1));
+ goto done;
+ }
+
+ if (local->ap->nullfunc_ack &&
+ stype == IEEE80211_STYPE_NULLFUNC)
+ ap_handle_data_nullfunc(local, hdr);
+ else
+ ap_handle_dropped_data(local, hdr);
+ goto done;
+ }
+
+ if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) {
+ handle_beacon(local, skb, rx_stats);
+ goto done;
+ }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) {
+ handle_pspoll(local, hdr, rx_stats);
+ goto done;
+ }
+
+ if (local->hostapd) {
+ PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x "
+ "subtype=0x%02x\n", type, stype);
+ goto done;
+ }
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (type != IEEE80211_FTYPE_MGMT) {
+ PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n");
+ goto done;
+ }
+
+ if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR
+ " not own MAC\n", MAC2STR(hdr->addr1));
+ goto done;
+ }
+
+ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR
+ " not own MAC\n", MAC2STR(hdr->addr3));
+ goto done;
+ }
+
+ switch (stype) {
+ case IEEE80211_STYPE_ASSOC_REQ:
+ handle_assoc(local, skb, rx_stats, 0);
+ break;
+ case IEEE80211_STYPE_ASSOC_RESP:
+ PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n");
+ break;
+ case IEEE80211_STYPE_REASSOC_REQ:
+ handle_assoc(local, skb, rx_stats, 1);
+ break;
+ case IEEE80211_STYPE_REASSOC_RESP:
+ PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n");
+ break;
+ case IEEE80211_STYPE_ATIM:
+ PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n");
+ break;
+ case IEEE80211_STYPE_DISASSOC:
+ handle_disassoc(local, skb, rx_stats);
+ break;
+ case IEEE80211_STYPE_AUTH:
+ handle_authen(local, skb, rx_stats);
+ break;
+ case IEEE80211_STYPE_DEAUTH:
+ handle_deauth(local, skb, rx_stats);
+ break;
+ default:
+ PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n",
+ stype >> 4);
+ break;
+ }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ done:
+ dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+void hostap_rx(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 fc;
+ struct ieee80211_hdr *hdr;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (skb->len < 16)
+ goto drop;
+
+ local->stats.rx_packets++;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
+ WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON)
+ goto drop;
+
+ skb->protocol = __constant_htons(ETH_P_HOSTAP);
+ handle_ap_item(local, skb, rx_stats);
+ return;
+
+ drop:
+ dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ struct hostap_80211_rx_status rx_stats;
+
+ if (skb_queue_empty(&sta->tx_buf))
+ return;
+
+ skb = dev_alloc_skb(16);
+ if (skb == NULL) {
+ printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc "
+ "failed\n", local->dev->name);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) skb_put(skb, 16);
+
+ /* Generate a fake pspoll frame to start packet delivery */
+ hdr->frame_ctl = __constant_cpu_to_le16(
+ IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
+ memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN);
+ memcpy(hdr->addr2, sta->addr, ETH_ALEN);
+ hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
+
+ PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for "
+ "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr));
+
+ skb->dev = local->dev;
+
+ memset(&rx_stats, 0, sizeof(rx_stats));
+ hostap_rx(local->dev, skb, &rx_stats);
+}
+
+
+static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
+ struct iw_quality qual[], int buf_size,
+ int aplist)
+{
+ struct ap_data *ap = local->ap;
+ struct list_head *ptr;
+ int count = 0;
+
+ spin_lock_bh(&ap->sta_table_lock);
+
+ for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
+ ptr = ptr->next) {
+ struct sta_info *sta = (struct sta_info *) ptr;
+
+ if (aplist && !sta->ap)
+ continue;
+ addr[count].sa_family = ARPHRD_ETHER;
+ memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
+ if (sta->last_rx_silence == 0)
+ qual[count].qual = sta->last_rx_signal < 27 ?
+ 0 : (sta->last_rx_signal - 27) * 92 / 127;
+ else
+ qual[count].qual = sta->last_rx_signal -
+ sta->last_rx_silence - 35;
+ qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
+ qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+ qual[count].updated = sta->last_rx_updated;
+
+ sta->last_rx_updated = 0;
+
+ count++;
+ if (count >= buf_size)
+ break;
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ return count;
+}
+
+
+/* Translate our list of Access Points & Stations to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct ap_data *ap;
+ struct list_head *ptr;
+ struct iw_event iwe;
+ char *current_ev = buffer;
+ char *end_buf = buffer + IW_SCAN_MAX_DATA;
+#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT)
+ char buf[64];
+#endif
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ ap = local->ap;
+
+ spin_lock_bh(&ap->sta_table_lock);
+
+ for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
+ ptr = ptr->next) {
+ struct sta_info *sta = (struct sta_info *) ptr;
+
+ /* First entry *MUST* be the AP MAC address */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_ADDR_LEN);
+
+ /* Use the mode to indicate if it's a station or
+ * an Access Point */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWMODE;
+ if (sta->ap)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_INFRA;
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_UINT_LEN);
+
+ /* Some quality */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ if (sta->last_rx_silence == 0)
+ iwe.u.qual.qual = sta->last_rx_signal < 27 ?
+ 0 : (sta->last_rx_signal - 27) * 92 / 127;
+ else
+ iwe.u.qual.qual = sta->last_rx_signal -
+ sta->last_rx_silence - 35;
+ iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
+ iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+ iwe.u.qual.updated = sta->last_rx_updated;
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_QUAL_LEN);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ if (sta->ap) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = sta->u.ap.ssid_len;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe,
+ sta->u.ap.ssid);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWENCODE;
+ if (sta->capability & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags =
+ IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe,
+ sta->u.ap.ssid
+ /* 0 byte memcpy */);
+
+ if (sta->u.ap.channel > 0 &&
+ sta->u.ap.channel <= FREQ_COUNT) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = freq_list[sta->u.ap.channel - 1]
+ * 100000;
+ iwe.u.freq.e = 1;
+ current_ev = iwe_stream_add_event(
+ current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "beacon_interval=%d",
+ sta->listen_interval);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ }
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+ sta->last_rx_updated = 0;
+
+ /* To be continued, we should make good use of IWEVCUSTOM */
+ }
+
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ return current_ev - buffer;
+}
+
+
+static int prism2_hostapd_add_sta(struct ap_data *ap,
+ struct prism2_hostapd_param *param)
+{
+ struct sta_info *sta;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, param->sta_addr);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (sta == NULL) {
+ sta = ap_add_sta(ap, param->sta_addr);
+ if (sta == NULL)
+ return -1;
+ }
+
+ if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+ hostap_event_new_sta(sta->local->dev, sta);
+
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ sta->last_rx = jiffies;
+ sta->aid = param->u.add_sta.aid;
+ sta->capability = param->u.add_sta.capability;
+ sta->tx_supp_rates = param->u.add_sta.tx_supp_rates;
+ if (sta->tx_supp_rates & WLAN_RATE_1M)
+ sta->supported_rates[0] = 2;
+ if (sta->tx_supp_rates & WLAN_RATE_2M)
+ sta->supported_rates[1] = 4;
+ if (sta->tx_supp_rates & WLAN_RATE_5M5)
+ sta->supported_rates[2] = 11;
+ if (sta->tx_supp_rates & WLAN_RATE_11M)
+ sta->supported_rates[3] = 22;
+ prism2_check_tx_rates(sta);
+ atomic_dec(&sta->users);
+ return 0;
+}
+
+
+static int prism2_hostapd_remove_sta(struct ap_data *ap,
+ struct prism2_hostapd_param *param)
+{
+ struct sta_info *sta;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, param->sta_addr);
+ if (sta) {
+ ap_sta_hash_del(ap, sta);
+ list_del(&sta->list);
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (!sta)
+ return -ENOENT;
+
+ if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
+ hostap_event_expired_sta(sta->local->dev, sta);
+ ap_free_sta(ap, sta);
+
+ return 0;
+}
+
+
+static int prism2_hostapd_get_info_sta(struct ap_data *ap,
+ struct prism2_hostapd_param *param)
+{
+ struct sta_info *sta;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, param->sta_addr);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (!sta)
+ return -ENOENT;
+
+ param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ;
+
+ atomic_dec(&sta->users);
+
+ return 1;
+}
+
+
+static int prism2_hostapd_set_flags_sta(struct ap_data *ap,
+ struct prism2_hostapd_param *param)
+{
+ struct sta_info *sta;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, param->sta_addr);
+ if (sta) {
+ sta->flags |= param->u.set_flags_sta.flags_or;
+ sta->flags &= param->u.set_flags_sta.flags_and;
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (!sta)
+ return -ENOENT;
+
+ return 0;
+}
+
+
+static int prism2_hostapd_sta_clear_stats(struct ap_data *ap,
+ struct prism2_hostapd_param *param)
+{
+ struct sta_info *sta;
+ int rate;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, param->sta_addr);
+ if (sta) {
+ sta->rx_packets = sta->tx_packets = 0;
+ sta->rx_bytes = sta->tx_bytes = 0;
+ for (rate = 0; rate < WLAN_RATE_COUNT; rate++) {
+ sta->tx_count[rate] = 0;
+ sta->rx_count[rate] = 0;
+ }
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (!sta)
+ return -ENOENT;
+
+ return 0;
+}
+
+
+static int prism2_hostapd(struct ap_data *ap,
+ struct prism2_hostapd_param *param)
+{
+ switch (param->cmd) {
+ case PRISM2_HOSTAPD_FLUSH:
+ ap_control_kickall(ap);
+ return 0;
+ case PRISM2_HOSTAPD_ADD_STA:
+ return prism2_hostapd_add_sta(ap, param);
+ case PRISM2_HOSTAPD_REMOVE_STA:
+ return prism2_hostapd_remove_sta(ap, param);
+ case PRISM2_HOSTAPD_GET_INFO_STA:
+ return prism2_hostapd_get_info_sta(ap, param);
+ case PRISM2_HOSTAPD_SET_FLAGS_STA:
+ return prism2_hostapd_set_flags_sta(ap, param);
+ case PRISM2_HOSTAPD_STA_CLEAR_STATS:
+ return prism2_hostapd_sta_clear_stats(ap, param);
+ default:
+ printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n",
+ param->cmd);
+ return -EOPNOTSUPP;
+ }
+}
+
+
+/* Update station info for host-based TX rate control and return current
+ * TX rate */
+static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
+{
+ int ret = sta->tx_rate;
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ sta->tx_count[sta->tx_rate_idx]++;
+ sta->tx_since_last_failure++;
+ sta->tx_consecutive_exc = 0;
+ if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT &&
+ sta->tx_rate_idx < sta->tx_max_rate) {
+ /* use next higher rate */
+ int old_rate, new_rate;
+ old_rate = new_rate = sta->tx_rate_idx;
+ while (new_rate < sta->tx_max_rate) {
+ new_rate++;
+ if (ap_tx_rate_ok(new_rate, sta, local)) {
+ sta->tx_rate_idx = new_rate;
+ break;
+ }
+ }
+ if (old_rate != sta->tx_rate_idx) {
+ switch (sta->tx_rate_idx) {
+ case 0: sta->tx_rate = 10; break;
+ case 1: sta->tx_rate = 20; break;
+ case 2: sta->tx_rate = 55; break;
+ case 3: sta->tx_rate = 110; break;
+ default: sta->tx_rate = 0; break;
+ }
+ PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to"
+ " %d\n", dev->name, MAC2STR(sta->addr),
+ sta->tx_rate);
+ }
+ sta->tx_since_last_failure = 0;
+ }
+
+ return ret;
+}
+
+
+/* Called only from software IRQ. Called for each TX frame prior possible
+ * encryption and transmit. */
+ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
+{
+ struct sta_info *sta = NULL;
+ struct sk_buff *skb = tx->skb;
+ int set_tim, ret;
+ struct ieee80211_hdr *hdr;
+ struct hostap_skb_tx_data *meta;
+
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+ ret = AP_TX_CONTINUE;
+ if (local->ap == NULL || skb->len < 10 ||
+ meta->iface->type == HOSTAP_INTERFACE_STA)
+ goto out;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (hdr->addr1[0] & 0x01) {
+ /* broadcast/multicast frame - no AP related processing */
+ goto out;
+ }
+
+ /* unicast packet - check whether destination STA is associated */
+ spin_lock(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr1);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock(&local->ap->sta_table_lock);
+
+ if (local->iw_mode == IW_MODE_MASTER && sta == NULL &&
+ !(meta->flags & HOSTAP_TX_FLAGS_WDS) &&
+ meta->iface->type != HOSTAP_INTERFACE_MASTER &&
+ meta->iface->type != HOSTAP_INTERFACE_AP) {
+#if 0
+ /* This can happen, e.g., when wlan0 is added to a bridge and
+ * bridging code does not know which port is the correct target
+ * for a unicast frame. In this case, the packet is send to all
+ * ports of the bridge. Since this is a valid scenario, do not
+ * print out any errors here. */
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "AP: drop packet to non-associated "
+ "STA " MACSTR "\n", MAC2STR(hdr->addr1));
+ }
+#endif
+ local->ap->tx_drop_nonassoc++;
+ ret = AP_TX_DROP;
+ goto out;
+ }
+
+ if (sta == NULL)
+ goto out;
+
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ ret = AP_TX_CONTINUE_NOT_AUTHORIZED;
+
+ /* Set tx_rate if using host-based TX rate control */
+ if (!local->fw_tx_rate_control)
+ local->ap->last_tx_rate = meta->rate =
+ ap_update_sta_tx_rate(sta, local->dev);
+
+ if (local->iw_mode != IW_MODE_MASTER)
+ goto out;
+
+ if (!(sta->flags & WLAN_STA_PS))
+ goto out;
+
+ if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) {
+ /* indicate to STA that more frames follow */
+ hdr->frame_ctl |=
+ __constant_cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ }
+
+ if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) {
+ /* packet was already buffered and now send due to
+ * PS poll, so do not rebuffer it */
+ goto out;
+ }
+
+ if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
+ PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS "
+ "mode buffer\n", local->dev->name, MAC2STR(sta->addr));
+ /* Make sure that TIM is set for the station (it might not be
+ * after AP wlan hw reset). */
+ /* FIX: should fix hw reset to restore bits based on STA
+ * buffer state.. */
+ hostap_set_tim(local, sta->aid, 1);
+ sta->flags |= WLAN_STA_TIM;
+ ret = AP_TX_DROP;
+ goto out;
+ }
+
+ /* STA in PS mode, buffer frame for later delivery */
+ set_tim = skb_queue_empty(&sta->tx_buf);
+ skb_queue_tail(&sta->tx_buf, skb);
+ /* FIX: could save RX time to skb and expire buffered frames after
+ * some time if STA does not poll for them */
+
+ if (set_tim) {
+ if (sta->flags & WLAN_STA_TIM)
+ PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n",
+ sta->aid);
+ hostap_set_tim(local, sta->aid, 1);
+ sta->flags |= WLAN_STA_TIM;
+ }
+
+ ret = AP_TX_BUFFERED;
+
+ out:
+ if (sta != NULL) {
+ if (ret == AP_TX_CONTINUE ||
+ ret == AP_TX_CONTINUE_NOT_AUTHORIZED) {
+ sta->tx_packets++;
+ sta->tx_bytes += skb->len;
+ sta->last_tx = jiffies;
+ }
+
+ if ((ret == AP_TX_CONTINUE ||
+ ret == AP_TX_CONTINUE_NOT_AUTHORIZED) &&
+ sta->crypt && tx->host_encrypt) {
+ tx->crypt = sta->crypt;
+ tx->sta_ptr = sta; /* hostap_handle_sta_release() will
+ * be called to release sta info
+ * later */
+ } else
+ atomic_dec(&sta->users);
+ }
+
+ return ret;
+}
+
+
+void hostap_handle_sta_release(void *ptr)
+{
+ struct sta_info *sta = ptr;
+ atomic_dec(&sta->users);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
+{
+ struct sta_info *sta;
+ struct ieee80211_hdr *hdr;
+ struct hostap_skb_tx_data *meta;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+
+ spin_lock(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr1);
+ if (!sta) {
+ spin_unlock(&local->ap->sta_table_lock);
+ PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this "
+ "TX error (@%lu)\n",
+ local->dev->name, MAC2STR(hdr->addr1), jiffies);
+ return;
+ }
+
+ sta->tx_since_last_failure = 0;
+ sta->tx_consecutive_exc++;
+
+ if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD &&
+ sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) {
+ /* use next lower rate */
+ int old, rate;
+ old = rate = sta->tx_rate_idx;
+ while (rate > 0) {
+ rate--;
+ if (ap_tx_rate_ok(rate, sta, local)) {
+ sta->tx_rate_idx = rate;
+ break;
+ }
+ }
+ if (old != sta->tx_rate_idx) {
+ switch (sta->tx_rate_idx) {
+ case 0: sta->tx_rate = 10; break;
+ case 1: sta->tx_rate = 20; break;
+ case 2: sta->tx_rate = 55; break;
+ case 3: sta->tx_rate = 110; break;
+ default: sta->tx_rate = 0; break;
+ }
+ PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered "
+ "to %d\n", local->dev->name, MAC2STR(sta->addr),
+ sta->tx_rate);
+ }
+ sta->tx_consecutive_exc = 0;
+ }
+ spin_unlock(&local->ap->sta_table_lock);
+}
+
+
+static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
+ int pwrmgt, int type, int stype)
+{
+ if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
+ sta->flags |= WLAN_STA_PS;
+ PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS "
+ "mode (type=0x%02X, stype=0x%02X)\n",
+ MAC2STR(sta->addr), type >> 2, stype >> 4);
+ } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
+ sta->flags &= ~WLAN_STA_PS;
+ PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use "
+ "PS mode (type=0x%02X, stype=0x%02X)\n",
+ MAC2STR(sta->addr), type >> 2, stype >> 4);
+ if (type != IEEE80211_FTYPE_CTL ||
+ stype != IEEE80211_STYPE_PSPOLL)
+ schedule_packet_send(local, sta);
+ }
+}
+
+
+/* Called only as a tasklet (software IRQ). Called for each RX frame to update
+ * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr)
+{
+ struct sta_info *sta;
+ u16 fc;
+
+ spin_lock(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock(&local->ap->sta_table_lock);
+
+ if (!sta)
+ return -1;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
+ WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc));
+
+ atomic_dec(&sta->users);
+ return 0;
+}
+
+
+/* Called only as a tasklet (software IRQ). Called for each RX frame after
+ * getting RX header and payload from hardware. */
+ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
+ struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats,
+ int wds)
+{
+ int ret;
+ struct sta_info *sta;
+ u16 fc, type, stype;
+ struct ieee80211_hdr *hdr;
+
+ if (local->ap == NULL)
+ return AP_RX_CONTINUE;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ spin_lock(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock(&local->ap->sta_table_lock);
+
+ if (sta && !(sta->flags & WLAN_STA_AUTHORIZED))
+ ret = AP_RX_CONTINUE_NOT_AUTHORIZED;
+ else
+ ret = AP_RX_CONTINUE;
+
+
+ if (fc & IEEE80211_FCTL_TODS) {
+ if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
+ if (local->hostapd) {
+ prism2_rx_80211(local->apdev, skb, rx_stats,
+ PRISM2_RX_NON_ASSOC);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ } else {
+ printk(KERN_DEBUG "%s: dropped received packet"
+ " from non-associated STA " MACSTR
+ " (type=0x%02x, subtype=0x%02x)\n",
+ dev->name, MAC2STR(hdr->addr2),
+ type >> 2, stype >> 4);
+ hostap_rx(dev, skb, rx_stats);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+ }
+ ret = AP_RX_EXIT;
+ goto out;
+ }
+ } else if (fc & IEEE80211_FCTL_FROMDS) {
+ if (!wds) {
+ /* FromDS frame - not for us; probably
+ * broadcast/multicast in another BSS - drop */
+ if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+ printk(KERN_DEBUG "Odd.. FromDS packet "
+ "received with own BSSID\n");
+ hostap_dump_rx_80211(dev->name, skb, rx_stats);
+ }
+ ret = AP_RX_DROP;
+ goto out;
+ }
+ } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+
+ if (local->hostapd) {
+ prism2_rx_80211(local->apdev, skb, rx_stats,
+ PRISM2_RX_NON_ASSOC);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ } else {
+ /* At least Lucent f/w seems to send data::nullfunc
+ * frames with no ToDS flag when the current AP returns
+ * after being unavailable for some time. Speed up
+ * re-association by informing the station about it not
+ * being associated. */
+ printk(KERN_DEBUG "%s: rejected received nullfunc "
+ "frame without ToDS from not associated STA "
+ MACSTR "\n",
+ dev->name, MAC2STR(hdr->addr2));
+ hostap_rx(dev, skb, rx_stats);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+ }
+ ret = AP_RX_EXIT;
+ goto out;
+ } else if (stype == IEEE80211_STYPE_NULLFUNC) {
+ /* At least Lucent cards seem to send periodic nullfunc
+ * frames with ToDS. Let these through to update SQ
+ * stats and PS state. Nullfunc frames do not contain
+ * any data and they will be dropped below. */
+ } else {
+ /* If BSSID (Addr3) is foreign, this frame is a normal
+ * broadcast frame from an IBSS network. Drop it silently.
+ * If BSSID is own, report the dropping of this frame. */
+ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+ printk(KERN_DEBUG "%s: dropped received packet from "
+ MACSTR " with no ToDS flag (type=0x%02x, "
+ "subtype=0x%02x)\n", dev->name,
+ MAC2STR(hdr->addr2), type >> 2, stype >> 4);
+ hostap_dump_rx_80211(dev->name, skb, rx_stats);
+ }
+ ret = AP_RX_DROP;
+ goto out;
+ }
+
+ if (sta) {
+ hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
+ type, stype);
+
+ sta->rx_packets++;
+ sta->rx_bytes += skb->len;
+ sta->last_rx = jiffies;
+ }
+
+ if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC &&
+ fc & IEEE80211_FCTL_TODS) {
+ if (local->hostapd) {
+ prism2_rx_80211(local->apdev, skb, rx_stats,
+ PRISM2_RX_NULLFUNC_ACK);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ } else {
+ /* some STA f/w's seem to require control::ACK frame
+ * for data::nullfunc, but Prism2 f/w 0.8.0 (at least
+ * from Compaq) does not send this.. Try to generate
+ * ACK for these frames from the host driver to make
+ * power saving work with, e.g., Lucent WaveLAN f/w */
+ hostap_rx(dev, skb, rx_stats);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+ }
+ ret = AP_RX_EXIT;
+ goto out;
+ }
+
+ out:
+ if (sta)
+ atomic_dec(&sta->users);
+
+ return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_handle_sta_crypto(local_info_t *local,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_crypt_data **crypt,
+ void **sta_ptr)
+{
+ struct sta_info *sta;
+
+ spin_lock(&local->ap->sta_table_lock);
+ sta = ap_get_sta(local->ap, hdr->addr2);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock(&local->ap->sta_table_lock);
+
+ if (!sta)
+ return -1;
+
+ if (sta->crypt) {
+ *crypt = sta->crypt;
+ *sta_ptr = sta;
+ /* hostap_handle_sta_release() will be called to release STA
+ * info */
+ } else
+ atomic_dec(&sta->users);
+
+ return 0;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr)
+{
+ struct sta_info *sta;
+ int ret = 0;
+
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, sta_addr);
+ if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap)
+ ret = 1;
+ spin_unlock(&ap->sta_table_lock);
+
+ return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr)
+{
+ struct sta_info *sta;
+ int ret = 0;
+
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, sta_addr);
+ if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap &&
+ ((sta->flags & WLAN_STA_AUTHORIZED) ||
+ ap->local->ieee_802_1x == 0))
+ ret = 1;
+ spin_unlock(&ap->sta_table_lock);
+
+ return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
+{
+ struct sta_info *sta;
+ int ret = 1;
+
+ if (!ap)
+ return -1;
+
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, sta_addr);
+ if (sta)
+ ret = 0;
+ spin_unlock(&ap->sta_table_lock);
+
+ if (ret == 1) {
+ sta = ap_add_sta(ap, sta_addr);
+ if (!sta)
+ ret = -1;
+ sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ sta->ap = 1;
+ memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
+ /* No way of knowing which rates are supported since we did not
+ * get supported rates element from beacon/assoc req. Assume
+ * that remote end supports all 802.11b rates. */
+ sta->supported_rates[0] = 0x82;
+ sta->supported_rates[1] = 0x84;
+ sta->supported_rates[2] = 0x0b;
+ sta->supported_rates[3] = 0x16;
+ sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M |
+ WLAN_RATE_5M5 | WLAN_RATE_11M;
+ sta->tx_rate = 110;
+ sta->tx_max_rate = sta->tx_rate_idx = 3;
+ }
+
+ return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+int hostap_update_rx_stats(struct ap_data *ap,
+ struct ieee80211_hdr *hdr,
+ struct hostap_80211_rx_status *rx_stats)
+{
+ struct sta_info *sta;
+
+ if (!ap)
+ return -1;
+
+ spin_lock(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, hdr->addr2);
+ if (sta) {
+ sta->last_rx_silence = rx_stats->noise;
+ sta->last_rx_signal = rx_stats->signal;
+ sta->last_rx_rate = rx_stats->rate;
+ sta->last_rx_updated = 7;
+ if (rx_stats->rate == 10)
+ sta->rx_count[0]++;
+ else if (rx_stats->rate == 20)
+ sta->rx_count[1]++;
+ else if (rx_stats->rate == 55)
+ sta->rx_count[2]++;
+ else if (rx_stats->rate == 110)
+ sta->rx_count[3]++;
+ }
+ spin_unlock(&ap->sta_table_lock);
+
+ return sta ? 0 : -1;
+}
+
+
+void hostap_update_rates(local_info_t *local)
+{
+ struct list_head *ptr;
+ struct ap_data *ap = local->ap;
+
+ if (!ap)
+ return;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
+ struct sta_info *sta = (struct sta_info *) ptr;
+ prism2_check_tx_rates(sta);
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+}
+
+
+static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
+ struct ieee80211_crypt_data ***crypt)
+{
+ struct sta_info *sta;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ sta = ap_get_sta(ap, addr);
+ if (sta)
+ atomic_inc(&sta->users);
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ if (!sta && permanent)
+ sta = ap_add_sta(ap, addr);
+
+ if (!sta)
+ return NULL;
+
+ if (permanent)
+ sta->flags |= WLAN_STA_PERM;
+
+ *crypt = &sta->crypt;
+
+ return sta;
+}
+
+
+void hostap_add_wds_links(local_info_t *local)
+{
+ struct ap_data *ap = local->ap;
+ struct list_head *ptr;
+
+ spin_lock_bh(&ap->sta_table_lock);
+ list_for_each(ptr, &ap->sta_list) {
+ struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+ if (sta->ap)
+ hostap_wds_link_oper(local, sta->addr, WDS_ADD);
+ }
+ spin_unlock_bh(&ap->sta_table_lock);
+
+ schedule_work(&local->ap->wds_oper_queue);
+}
+
+
+void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type)
+{
+ struct wds_oper_data *entry;
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return;
+ memcpy(entry->addr, addr, ETH_ALEN);
+ entry->type = type;
+ spin_lock_bh(&local->lock);
+ entry->next = local->ap->wds_oper_entries;
+ local->ap->wds_oper_entries = entry;
+ spin_unlock_bh(&local->lock);
+
+ schedule_work(&local->ap->wds_oper_queue);
+}
+
+
+EXPORT_SYMBOL(hostap_init_data);
+EXPORT_SYMBOL(hostap_init_ap_proc);
+EXPORT_SYMBOL(hostap_free_data);
+EXPORT_SYMBOL(hostap_check_sta_fw_version);
+EXPORT_SYMBOL(hostap_handle_sta_tx);
+EXPORT_SYMBOL(hostap_handle_sta_release);
+EXPORT_SYMBOL(hostap_handle_sta_tx_exc);
+EXPORT_SYMBOL(hostap_update_sta_ps);
+EXPORT_SYMBOL(hostap_handle_sta_rx);
+EXPORT_SYMBOL(hostap_is_sta_assoc);
+EXPORT_SYMBOL(hostap_is_sta_authorized);
+EXPORT_SYMBOL(hostap_add_sta);
+EXPORT_SYMBOL(hostap_update_rates);
+EXPORT_SYMBOL(hostap_add_wds_links);
+EXPORT_SYMBOL(hostap_wds_link_oper);
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+EXPORT_SYMBOL(hostap_deauth_all_stas);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h
new file mode 100644
index 0000000..816a52b
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_ap.h
@@ -0,0 +1,261 @@
+#ifndef HOSTAP_AP_H
+#define HOSTAP_AP_H
+
+/* AP data structures for STAs */
+
+/* maximum number of frames to buffer per STA */
+#define STA_MAX_TX_BUFFER 32
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
+#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
+#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
+ * controlling whether STA is authorized to
+ * send and receive non-IEEE 802.1X frames
+ */
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+#define WLAN_RATE_COUNT 4
+
+/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
+ * but some pre-standard IEEE 802.11g products use longer elements. */
+#define WLAN_SUPP_RATES_MAX 32
+
+/* Try to increase TX rate after # successfully sent consecutive packets */
+#define WLAN_RATE_UPDATE_COUNT 50
+
+/* Decrease TX rate after # consecutive dropped packets */
+#define WLAN_RATE_DECREASE_THRESHOLD 2
+
+struct sta_info {
+ struct list_head list;
+ struct sta_info *hnext; /* next entry in hash table list */
+ atomic_t users; /* number of users (do not remove if > 0) */
+ struct proc_dir_entry *proc;
+
+ u8 addr[6];
+ u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+ u32 flags;
+ u16 capability;
+ u16 listen_interval; /* or beacon_int for APs */
+ u8 supported_rates[WLAN_SUPP_RATES_MAX];
+
+ unsigned long last_auth;
+ unsigned long last_assoc;
+ unsigned long last_rx;
+ unsigned long last_tx;
+ unsigned long rx_packets, tx_packets;
+ unsigned long rx_bytes, tx_bytes;
+ struct sk_buff_head tx_buf;
+ /* FIX: timeout buffers with an expiry time somehow derived from
+ * listen_interval */
+
+ s8 last_rx_silence; /* Noise in dBm */
+ s8 last_rx_signal; /* Signal strength in dBm */
+ u8 last_rx_rate; /* TX rate in 0.1 Mbps */
+ u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */
+
+ u8 tx_supp_rates; /* bit field of supported TX rates */
+ u8 tx_rate; /* current TX rate (in 0.1 Mbps) */
+ u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */
+ u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */
+ u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */
+ u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
+ */
+ u32 tx_since_last_failure;
+ u32 tx_consecutive_exc;
+
+ struct ieee80211_crypt_data *crypt;
+
+ int ap; /* whether this station is an AP */
+
+ local_info_t *local;
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ union {
+ struct {
+ char *challenge; /* shared key authentication
+ * challenge */
+ } sta;
+ struct {
+ int ssid_len;
+ unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */
+ int channel;
+ unsigned long last_beacon; /* last RX beacon time */
+ } ap;
+ } u;
+
+ struct timer_list timer;
+ enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+};
+
+
+#define MAX_STA_COUNT 1024
+
+/* Maximum number of AIDs to use for STAs; must be 2007 or lower
+ * (8802.11 limitation) */
+#define MAX_AID_TABLE_SIZE 128
+
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC
+ * has passed since last received frame from the station, a nullfunc data
+ * frame is sent to the station. If this frame is not acknowledged and no other
+ * frames have been received, the station will be disassociated after
+ * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after
+ * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
+ * max inactivity timer. */
+#define AP_MAX_INACTIVITY_SEC (5 * 60)
+#define AP_DISASSOC_DELAY (HZ)
+#define AP_DEAUTH_DELAY (HZ)
+
+/* ap_policy: whether to accept frames to/from other APs/IBSS */
+typedef enum {
+ AP_OTHER_AP_SKIP_ALL = 0,
+ AP_OTHER_AP_SAME_SSID = 1,
+ AP_OTHER_AP_ALL = 2,
+ AP_OTHER_AP_EVEN_IBSS = 3
+} ap_policy_enum;
+
+#define PRISM2_AUTH_OPEN BIT(0)
+#define PRISM2_AUTH_SHARED_KEY BIT(1)
+
+
+/* MAC address-based restrictions */
+struct mac_entry {
+ struct list_head list;
+ u8 addr[6];
+};
+
+struct mac_restrictions {
+ enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy;
+ unsigned int entries;
+ struct list_head mac_list;
+ spinlock_t lock;
+};
+
+
+struct add_sta_proc_data {
+ u8 addr[ETH_ALEN];
+ struct add_sta_proc_data *next;
+};
+
+
+typedef enum { WDS_ADD, WDS_DEL } wds_oper_type;
+struct wds_oper_data {
+ wds_oper_type type;
+ u8 addr[ETH_ALEN];
+ struct wds_oper_data *next;
+};
+
+
+struct ap_data {
+ int initialized; /* whether ap_data has been initialized */
+ local_info_t *local;
+ int bridge_packets; /* send packet to associated STAs directly to the
+ * wireless media instead of higher layers in the
+ * kernel */
+ unsigned int bridged_unicast; /* number of unicast frames bridged on
+ * wireless media */
+ unsigned int bridged_multicast; /* number of non-unicast frames
+ * bridged on wireless media */
+ unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped
+ * because they were to an address that
+ * was not associated */
+ int nullfunc_ack; /* use workaround for nullfunc frame ACKs */
+
+ spinlock_t sta_table_lock;
+ int num_sta; /* number of entries in sta_list */
+ struct list_head sta_list; /* STA info list head */
+ struct sta_info *sta_hash[STA_HASH_SIZE];
+
+ struct proc_dir_entry *proc;
+
+ ap_policy_enum ap_policy;
+ unsigned int max_inactivity;
+ int autom_ap_wds;
+
+ struct mac_restrictions mac_restrictions; /* MAC-based auth */
+ int last_tx_rate;
+
+ struct work_struct add_sta_proc_queue;
+ struct add_sta_proc_data *add_sta_proc_entries;
+
+ struct work_struct wds_oper_queue;
+ struct wds_oper_data *wds_oper_entries;
+
+ u16 tx_callback_idx;
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ /* pointers to STA info; based on allocated AID or NULL if AID free
+ * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+ * and so on
+ */
+ struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
+
+ u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
+
+ /* WEP operations for generating challenges to be used with shared key
+ * authentication */
+ struct ieee80211_crypto_ops *crypt;
+ void *crypt_priv;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+};
+
+
+void hostap_rx(struct net_device *dev, struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats);
+void hostap_init_data(local_info_t *local);
+void hostap_init_ap_proc(local_info_t *local);
+void hostap_free_data(struct ap_data *ap);
+void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver);
+
+typedef enum {
+ AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED,
+ AP_TX_CONTINUE_NOT_AUTHORIZED
+} ap_tx_ret;
+struct hostap_tx_data {
+ struct sk_buff *skb;
+ int host_encrypt;
+ struct ieee80211_crypt_data *crypt;
+ void *sta_ptr;
+};
+ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
+void hostap_handle_sta_release(void *ptr);
+void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
+typedef enum {
+ AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
+} ap_rx_ret;
+ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
+ struct sk_buff *skb,
+ struct hostap_80211_rx_status *rx_stats,
+ int wds);
+int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
+ struct ieee80211_crypt_data **crypt,
+ void **sta_ptr);
+int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
+int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
+int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
+int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
+ struct hostap_80211_rx_status *rx_stats);
+void hostap_update_rates(local_info_t *local);
+void hostap_add_wds_links(local_info_t *local);
+void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type);
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
+ int resend);
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+#endif /* HOSTAP_AP_H */
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
new file mode 100644
index 0000000..6f4fa9d
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -0,0 +1,435 @@
+#ifndef HOSTAP_COMMON_H
+#define HOSTAP_COMMON_H
+
+#define BIT(x) (1 << (x))
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+
+/* IEEE 802.11 defines */
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+#define WLAN_EID_RSN 48
+#define WLAN_EID_GENERIC 221
+
+
+/* HFA384X Configuration RIDs */
+#define HFA384X_RID_CNFPORTTYPE 0xFC00
+#define HFA384X_RID_CNFOWNMACADDR 0xFC01
+#define HFA384X_RID_CNFDESIREDSSID 0xFC02
+#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
+#define HFA384X_RID_CNFOWNSSID 0xFC04
+#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
+#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
+#define HFA384X_RID_CNFMAXDATALEN 0xFC07
+#define HFA384X_RID_CNFWDSADDRESS 0xFC08
+#define HFA384X_RID_CNFPMENABLED 0xFC09
+#define HFA384X_RID_CNFPMEPS 0xFC0A
+#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
+#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
+#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
+#define HFA384X_RID_CNFOWNNAME 0xFC0E
+#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
+#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
+#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
+#define HFA384X_RID_UNKNOWN1 0xFC20
+#define HFA384X_RID_UNKNOWN2 0xFC21
+#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
+#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
+#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
+#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
+#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
+#define HFA384X_RID_CNFWEPFLAGS 0xFC28
+#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
+#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
+#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
+#define HFA384X_RID_CNFTXCONTROL 0xFC2C
+#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
+#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
+#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
+#define HFA384X_RID_CNFMMLIFE 0xFC31
+#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
+#define HFA384X_RID_CNFBEACONINT 0xFC33
+#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
+#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
+#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
+#define HFA384X_RID_CNFTIMCTRL 0xFC40
+#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
+#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
+#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
+#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
+ * write only */
+#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_GROUPADDRESSES 0xFC80
+#define HFA384X_RID_CREATEIBSS 0xFC81
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
+#define HFA384X_RID_RTSTHRESHOLD 0xFC83
+#define HFA384X_RID_TXRATECONTROL 0xFC84
+#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
+#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
+#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
+#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
+#define HFA384X_RID_CNFBASICRATES 0xFCB3
+#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
+#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
+#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
+#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
+#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
+#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
+#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
+#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
+#define HFA384X_RID_TICKTIME 0xFCE0
+#define HFA384X_RID_SCANREQUEST 0xFCE1
+#define HFA384X_RID_JOINREQUEST 0xFCE2
+#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
+#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
+#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
+
+/* HFA384X Information RIDs */
+#define HFA384X_RID_MAXLOADTIME 0xFD00
+#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
+#define HFA384X_RID_PRIID 0xFD02
+#define HFA384X_RID_PRISUPRANGE 0xFD03
+#define HFA384X_RID_CFIACTRANGES 0xFD04
+#define HFA384X_RID_NICSERNUM 0xFD0A
+#define HFA384X_RID_NICID 0xFD0B
+#define HFA384X_RID_MFISUPRANGE 0xFD0C
+#define HFA384X_RID_CFISUPRANGE 0xFD0D
+#define HFA384X_RID_CHANNELLIST 0xFD10
+#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
+#define HFA384X_RID_TEMPTYPE 0xFD12
+#define HFA384X_RID_CIS 0xFD13
+#define HFA384X_RID_STAID 0xFD20
+#define HFA384X_RID_STASUPRANGE 0xFD21
+#define HFA384X_RID_MFIACTRANGES 0xFD22
+#define HFA384X_RID_CFIACTRANGES2 0xFD23
+#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
+ * only Prism2.5(?) */
+#define HFA384X_RID_PORTSTATUS 0xFD40
+#define HFA384X_RID_CURRENTSSID 0xFD41
+#define HFA384X_RID_CURRENTBSSID 0xFD42
+#define HFA384X_RID_COMMSQUALITY 0xFD43
+#define HFA384X_RID_CURRENTTXRATE 0xFD44
+#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
+#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
+#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
+#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
+#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
+#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
+#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
+#define HFA384X_RID_CFPOLLABLE 0xFD4C
+#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
+#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
+#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
+#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
+#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
+#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
+#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
+#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
+#define HFA384X_RID_PHYTYPE 0xFDC0
+#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
+#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
+#define HFA384X_RID_CCAMODE 0xFDC3
+#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
+#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
+#define HFA384X_RID_BUILDSEQ 0xFFFE
+#define HFA384X_RID_FWID 0xFFFF
+
+
+struct hfa384x_comp_ident
+{
+ u16 id;
+ u16 variant;
+ u16 major;
+ u16 minor;
+} __attribute__ ((packed));
+
+#define HFA384X_COMP_ID_PRI 0x15
+#define HFA384X_COMP_ID_STA 0x1f
+#define HFA384X_COMP_ID_FW_AP 0x14b
+
+struct hfa384x_sup_range
+{
+ u16 role;
+ u16 id;
+ u16 variant;
+ u16 bottom;
+ u16 top;
+} __attribute__ ((packed));
+
+
+struct hfa384x_build_id
+{
+ u16 pri_seq;
+ u16 sec_seq;
+} __attribute__ ((packed));
+
+/* FD01 - Download Buffer */
+struct hfa384x_rid_download_buffer
+{
+ u16 page;
+ u16 offset;
+ u16 length;
+} __attribute__ ((packed));
+
+/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
+struct hfa384x_comms_quality {
+ u16 comm_qual; /* 0 .. 92 */
+ u16 signal_level; /* 27 .. 154 */
+ u16 noise_level; /* 27 .. 154 */
+} __attribute__ ((packed));
+
+
+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
+
+/* New wireless extensions API - SET/GET convention (even ioctl numbers are
+ * root only)
+ */
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
+
+/* following are not in SIOCGIWPRIV list; check permission in the driver code
+ */
+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_TXRATECTRL = 2,
+ PRISM2_PARAM_BEACON_INT = 3,
+ PRISM2_PARAM_PSEUDO_IBSS = 4,
+ PRISM2_PARAM_ALC = 5,
+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_DUMP = 7,
+ PRISM2_PARAM_OTHER_AP_POLICY = 8,
+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_DTIM_PERIOD = 11,
+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+ PRISM2_PARAM_MAX_WDS = 13,
+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+ PRISM2_PARAM_AP_AUTH_ALGS = 15,
+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+ PRISM2_PARAM_HOST_ENCRYPT = 17,
+ PRISM2_PARAM_HOST_DECRYPT = 18,
+ /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */
+ /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */
+ PRISM2_PARAM_HOST_ROAMING = 21,
+ PRISM2_PARAM_BCRX_STA_KEY = 22,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+ PRISM2_PARAM_MONITOR_TYPE = 26,
+ PRISM2_PARAM_WDS_TYPE = 27,
+ PRISM2_PARAM_HOSTSCAN = 28,
+ PRISM2_PARAM_AP_SCAN = 29,
+ PRISM2_PARAM_ENH_SEC = 30,
+ PRISM2_PARAM_IO_DEBUG = 31,
+ PRISM2_PARAM_BASIC_RATES = 32,
+ PRISM2_PARAM_OPER_RATES = 33,
+ PRISM2_PARAM_HOSTAPD = 34,
+ PRISM2_PARAM_HOSTAPD_STA = 35,
+ PRISM2_PARAM_WPA = 36,
+ PRISM2_PARAM_PRIVACY_INVOKED = 37,
+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
+ HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
+
+
+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
+ AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
+ AP_MAC_CMD_KICKALL = 4 };
+
+
+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
+enum {
+ PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
+ /* Note! Old versions of prism2_srec have a fatal error in CRC-16
+ * calculation, which will corrupt all non-volatile downloads.
+ * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
+ * prevent use of old versions of prism2_srec for non-volatile
+ * download. */
+ PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
+ /* Persistent versions of volatile download commands (keep firmware
+ * data in memory and automatically re-download after hw_reset */
+ PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
+};
+
+struct prism2_download_param {
+ u32 dl_cmd;
+ u32 start_addr;
+ u32 num_areas;
+ struct prism2_download_area {
+ u32 addr; /* wlan card address */
+ u32 len;
+ void __user *ptr; /* pointer to data in user space */
+ } data[0];
+};
+
+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
+#define PRISM2_MAX_DOWNLOAD_LEN 262144
+
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+ PRISM2_HOSTAPD_ADD_STA = 2,
+ PRISM2_HOSTAPD_REMOVE_STA = 3,
+ PRISM2_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_GET_ENCRYPTION = 7,
+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+ PRISM2_HOSTAPD_GET_RID = 9,
+ PRISM2_HOSTAPD_SET_RID = 10,
+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+
+#endif /* HOSTAP_COMMON_H */
diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h
new file mode 100644
index 0000000..7ed3425
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_config.h
@@ -0,0 +1,55 @@
+#ifndef HOSTAP_CONFIG_H
+#define HOSTAP_CONFIG_H
+
+#define PRISM2_VERSION "0.4.4-kernel"
+
+/* In the previous versions of Host AP driver, support for user space version
+ * of IEEE 802.11 management (hostapd) used to be disabled in the default
+ * configuration. From now on, support for hostapd is always included and it is
+ * possible to disable kernel driver version of IEEE 802.11 management with a
+ * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */
+/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+/* Maximum number of events handler per one interrupt */
+#define PRISM2_MAX_INTERRUPT_EVENTS 20
+
+/* Include code for downloading firmware images into volatile RAM. */
+#define PRISM2_DOWNLOAD_SUPPORT
+
+/* Allow kernel configuration to enable download support. */
+#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE)
+#define PRISM2_DOWNLOAD_SUPPORT
+#endif
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+/* Allow writing firmware images into flash, i.e., to non-volatile storage.
+ * Before you enable this option, you should make absolutely sure that you are
+ * using prism2_srec utility that comes with THIS version of the driver!
+ * In addition, please note that it is possible to kill your card with
+ * non-volatile download if you are using incorrect image. This feature has not
+ * been fully tested, so please be careful with it. */
+/* #define PRISM2_NON_VOLATILE_DOWNLOAD */
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+/* Save low-level I/O for debugging. This should not be enabled in normal use.
+ */
+/* #define PRISM2_IO_DEBUG */
+
+/* Following defines can be used to remove unneeded parts of the driver, e.g.,
+ * to limit the size of the kernel module. Definitions can be added here in
+ * hostap_config.h or they can be added to make command with EXTRA_CFLAGS,
+ * e.g.,
+ * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
+ */
+
+/* Do not include debug messages into the driver */
+/* #define PRISM2_NO_DEBUG */
+
+/* Do not include /proc/net/prism2/wlan#/{registers,debug} */
+/* #define PRISM2_NO_PROCFS_DEBUG */
+
+/* Do not include station functionality (i.e., allow only Master (Host AP) mode
+ */
+/* #define PRISM2_NO_STATION_MODES */
+
+#endif /* HOSTAP_CONFIG_H */
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
new file mode 100644
index 0000000..faa83ba
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -0,0 +1,1030 @@
+#define PRISM2_PCCARD
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <asm/io.h>
+
+#include "hostap_wlan.h"
+
+
+static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static dev_info_t dev_info = "hostap_cs";
+static dev_link_t *dev_list = NULL;
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
+ "cards (PC Card).");
+MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+
+static int ignore_cis_vcc;
+module_param(ignore_cis_vcc, int, 0444);
+MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
+
+
+/* struct local_info::hw_priv */
+struct hostap_cs_priv {
+ dev_node_t node;
+ dev_link_t *link;
+ int sandisk_connectplus;
+};
+
+
+#ifdef PRISM2_IO_DEBUG
+
+static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
+ outb(v, dev->base_addr + a);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+ u8 v;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ spin_lock_irqsave(&local->lock, flags);
+ v = inb(dev->base_addr + a);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
+ spin_unlock_irqrestore(&local->lock, flags);
+ return v;
+}
+
+static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
+ outw(v, dev->base_addr + a);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+ u16 v;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ spin_lock_irqsave(&local->lock, flags);
+ v = inw(dev->base_addr + a);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
+ spin_unlock_irqrestore(&local->lock, flags);
+ return v;
+}
+
+static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
+ u8 *buf, int wc)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
+ outsw(dev->base_addr + a, buf, wc);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline void hfa384x_insw_debug(struct net_device *dev, int a,
+ u8 *buf, int wc)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
+ insw(dev->base_addr + a, buf, wc);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
+#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
+#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
+
+#else /* PRISM2_IO_DEBUG */
+
+#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
+#define HFA384X_INB(a) inb(dev->base_addr + (a))
+#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
+#define HFA384X_INW(a) inw(dev->base_addr + (a))
+#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
+#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
+ int len)
+{
+ u16 d_off;
+ u16 *pos;
+
+ d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+ pos = (u16 *) buf;
+
+ if (len / 2)
+ HFA384X_INSW(d_off, buf, len / 2);
+ pos += len / 2;
+
+ if (len & 1)
+ *((char *) pos) = HFA384X_INB(d_off);
+
+ return 0;
+}
+
+
+static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
+{
+ u16 d_off;
+ u16 *pos;
+
+ d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+ pos = (u16 *) buf;
+
+ if (len / 2)
+ HFA384X_OUTSW(d_off, buf, len / 2);
+ pos += len / 2;
+
+ if (len & 1)
+ HFA384X_OUTB(*((char *) pos), d_off);
+
+ return 0;
+}
+
+
+/* FIX: This might change at some point.. */
+#include "hostap_hw.c"
+
+
+
+static void prism2_detach(dev_link_t *link);
+static void prism2_release(u_long arg);
+static int prism2_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+
+static int prism2_pccard_card_present(local_info_t *local)
+{
+ struct hostap_cs_priv *hw_priv = local->hw_priv;
+ if (hw_priv != NULL && hw_priv->link != NULL &&
+ ((hw_priv->link->state & (DEV_PRESENT | DEV_CONFIG)) ==
+ (DEV_PRESENT | DEV_CONFIG)))
+ return 1;
+ return 0;
+}
+
+
+/*
+ * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
+ * Document No. 20-10-00058, January 2004
+ * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
+ */
+#define SANDISK_WLAN_ACTIVATION_OFF 0x40
+#define SANDISK_HCR_OFF 0x42
+
+
+static void sandisk_set_iobase(local_info_t *local)
+{
+ int res;
+ conf_reg_t reg;
+ struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+ reg.Function = 0;
+ reg.Action = CS_WRITE;
+ reg.Offset = 0x10; /* 0x3f0 IO base 1 */
+ reg.Value = hw_priv->link->io.BasePort1 & 0x00ff;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
+ " res=%d\n", res);
+ }
+ udelay(10);
+
+ reg.Function = 0;
+ reg.Action = CS_WRITE;
+ reg.Offset = 0x12; /* 0x3f2 IO base 2 */
+ reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
+ " res=%d\n", res);
+ }
+}
+
+
+static void sandisk_write_hcr(local_info_t *local, int hcr)
+{
+ struct net_device *dev = local->dev;
+ int i;
+
+ HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
+ udelay(50);
+ for (i = 0; i < 10; i++) {
+ HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
+ }
+ udelay(55);
+ HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
+}
+
+
+static int sandisk_enable_wireless(struct net_device *dev)
+{
+ int res, ret = 0;
+ conf_reg_t reg;
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+ tuple_t tuple;
+ cisparse_t *parse = NULL;
+ u_char buf[64];
+ struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+ if (hw_priv->link->io.NumPorts1 < 0x42) {
+ /* Not enough ports to be SanDisk multi-function card */
+ ret = -ENODEV;
+ goto done;
+ }
+
+ parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
+ if (parse == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ tuple.DesiredTuple = CISTPL_MANFID;
+ tuple.Attributes = TUPLE_RETURN_COMMON;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) ||
+ pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) ||
+ pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) ||
+ parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) {
+ /* No SanDisk manfid found */
+ ret = -ENODEV;
+ goto done;
+ }
+
+ tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+ if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) ||
+ pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) ||
+ pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) ||
+ parse->longlink_mfc.nfn < 2) {
+ /* No multi-function links found */
+ ret = -ENODEV;
+ goto done;
+ }
+
+ printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
+ " - using vendor-specific initialization\n", dev->name);
+ hw_priv->sandisk_connectplus = 1;
+
+ reg.Function = 0;
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ reg.Value = COR_SOFT_RESET;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
+ dev->name, res);
+ goto done;
+ }
+ mdelay(5);
+
+ reg.Function = 0;
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ /*
+ * Do not enable interrupts here to avoid some bogus events. Interrupts
+ * will be enabled during the first cor_sreset call.
+ */
+ reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
+ dev->name, res);
+ goto done;
+ }
+ mdelay(5);
+
+ sandisk_set_iobase(local);
+
+ HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
+ udelay(10);
+ HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
+ udelay(10);
+
+done:
+ kfree(parse);
+ return ret;
+}
+
+
+static void prism2_pccard_cor_sreset(local_info_t *local)
+{
+ int res;
+ conf_reg_t reg;
+ struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+ if (!prism2_pccard_card_present(local))
+ return;
+
+ reg.Function = 0;
+ reg.Action = CS_READ;
+ reg.Offset = CISREG_COR;
+ reg.Value = 0;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
+ res);
+ return;
+ }
+ printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
+ reg.Value);
+
+ reg.Action = CS_WRITE;
+ reg.Value |= COR_SOFT_RESET;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
+ res);
+ return;
+ }
+
+ mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
+
+ reg.Value &= ~COR_SOFT_RESET;
+ if (hw_priv->sandisk_connectplus)
+ reg.Value |= COR_IREQ_ENA;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
+ res);
+ return;
+ }
+
+ mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
+
+ if (hw_priv->sandisk_connectplus)
+ sandisk_set_iobase(local);
+}
+
+
+static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
+{
+ int res;
+ conf_reg_t reg;
+ int old_cor;
+ struct hostap_cs_priv *hw_priv = local->hw_priv;
+
+ if (!prism2_pccard_card_present(local))
+ return;
+
+ if (hw_priv->sandisk_connectplus) {
+ sandisk_write_hcr(local, hcr);
+ return;
+ }
+
+ reg.Function = 0;
+ reg.Action = CS_READ;
+ reg.Offset = CISREG_COR;
+ reg.Value = 0;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
+ "(%d)\n", res);
+ return;
+ }
+ printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n",
+ reg.Value);
+ old_cor = reg.Value;
+
+ reg.Action = CS_WRITE;
+ reg.Value |= COR_SOFT_RESET;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
+ "(%d)\n", res);
+ return;
+ }
+
+ mdelay(10);
+
+ /* Setup Genesis mode */
+ reg.Action = CS_WRITE;
+ reg.Value = hcr;
+ reg.Offset = CISREG_CCSR;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
+ "(%d)\n", res);
+ return;
+ }
+ mdelay(10);
+
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ reg.Value = old_cor & ~COR_SOFT_RESET;
+ res = pcmcia_access_configuration_register(hw_priv->link->handle,
+ ®);
+ if (res != CS_SUCCESS) {
+ printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
+ "(%d)\n", res);
+ return;
+ }
+
+ mdelay(10);
+}
+
+
+static int prism2_pccard_dev_open(local_info_t *local)
+{
+ struct hostap_cs_priv *hw_priv = local->hw_priv;
+ hw_priv->link->open++;
+ return 0;
+}
+
+
+static int prism2_pccard_dev_close(local_info_t *local)
+{
+ struct hostap_cs_priv *hw_priv;
+
+ if (local == NULL || local->hw_priv == NULL)
+ return 1;
+ hw_priv = local->hw_priv;
+ if (hw_priv->link == NULL)
+ return 1;
+
+ if (!hw_priv->link->open) {
+ printk(KERN_WARNING "%s: prism2_pccard_dev_close(): "
+ "link not open?!\n", local->dev->name);
+ return 1;
+ }
+
+ hw_priv->link->open--;
+
+ return 0;
+}
+
+
+static struct prism2_helper_functions prism2_pccard_funcs =
+{
+ .card_present = prism2_pccard_card_present,
+ .cor_sreset = prism2_pccard_cor_sreset,
+ .dev_open = prism2_pccard_dev_open,
+ .dev_close = prism2_pccard_dev_close,
+ .genesis_reset = prism2_pccard_genesis_reset,
+ .hw_type = HOSTAP_HW_PCCARD,
+};
+
+
+/* allocate local data and register with CardServices
+ * initialize dev_link structure, but do not configure the card yet */
+static dev_link_t *prism2_attach(void)
+{
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret;
+
+ link = kmalloc(sizeof(dev_link_t), GFP_KERNEL);
+ if (link == NULL)
+ return NULL;
+
+ memset(link, 0, sizeof(dev_link_t));
+
+ PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
+ link->conf.Vcc = 33;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* register with CardServices */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ prism2_detach(link);
+ return NULL;
+ }
+ return link;
+}
+
+
+static void prism2_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ PDEBUG(DEBUG_FLOW, "prism2_detach\n");
+
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link)
+ break;
+ if (*linkp == NULL) {
+ printk(KERN_WARNING "%s: Attempt to detach non-existing "
+ "PCMCIA client\n", dev_info);
+ return;
+ }
+
+ if (link->state & DEV_CONFIG) {
+ prism2_release((u_long)link);
+ }
+
+ if (link->handle) {
+ int res = pcmcia_deregister_client(link->handle);
+ if (res) {
+ printk("CardService(DeregisterClient) => %d\n", res);
+ cs_error(link->handle, DeregisterClient, res);
+ }
+ }
+
+ *linkp = link->next;
+ /* release net devices */
+ if (link->priv) {
+ struct net_device *dev;
+ struct hostap_interface *iface;
+ dev = link->priv;
+ iface = netdev_priv(dev);
+ kfree(iface->local->hw_priv);
+ iface->local->hw_priv = NULL;
+ prism2_free_local_data(dev);
+ }
+ kfree(link);
+}
+
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+#define CFG_CHECK2(fn, retf) \
+do { int ret = (retf); \
+if (ret != 0) { \
+ PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
+ cs_error(link->handle, fn, ret); \
+ goto next_entry; \
+} \
+} while (0)
+
+
+/* run after a CARD_INSERTION event is received to configure the PCMCIA
+ * socket and make the device available to the system */
+static int prism2_config(dev_link_t *link)
+{
+ struct net_device *dev;
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret = 1;
+ tuple_t tuple;
+ cisparse_t *parse;
+ int last_fn, last_ret;
+ u_char buf[64];
+ config_info_t conf;
+ cistpl_cftable_entry_t dflt = { 0 };
+ struct hostap_cs_priv *hw_priv;
+
+ PDEBUG(DEBUG_FLOW, "prism2_config()\n");
+
+ parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
+ hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+ if (parse == NULL || hw_priv == NULL) {
+ kfree(parse);
+ kfree(hw_priv);
+ ret = -ENOMEM;
+ goto failed;
+ }
+ memset(hw_priv, 0, sizeof(*hw_priv));
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse));
+ link->conf.ConfigBase = parse->config.base;
+ link->conf.Present = parse->config.rmask[0];
+
+ CS_CHECK(GetConfigurationInfo,
+ pcmcia_get_configuration_info(link->handle, &conf));
+ PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info,
+ ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc);
+ link->conf.Vcc = conf.Vcc;
+
+ /* Look for an appropriate configuration table entry in the CIS */
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
+ for (;;) {
+ cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
+ CFG_CHECK2(GetTupleData,
+ pcmcia_get_tuple_data(link->handle, &tuple));
+ CFG_CHECK2(ParseTuple,
+ pcmcia_parse_tuple(link->handle, &tuple, parse));
+
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ dflt = *cfg;
+ if (cfg->index == 0)
+ goto next_entry;
+ link->conf.ConfigIndex = cfg->index;
+ PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
+ "(default 0x%02X)\n", cfg->index, dflt.index);
+
+ /* Does this card need audio output? */
+ if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+ link->conf.Attributes |= CONF_ENABLE_SPKR;
+ link->conf.Status = CCSR_AUDIO_ENA;
+ }
+
+ /* Use power settings for Vcc and Vpp if present */
+ /* Note that the CIS values need to be rescaled */
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
+ 10000 && !ignore_cis_vcc) {
+ PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping"
+ " this entry\n");
+ goto next_entry;
+ }
+ } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
+ 10000 && !ignore_cis_vcc) {
+ PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch "
+ "- skipping this entry\n");
+ goto next_entry;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ /* Do we need to allocate an interrupt? */
+ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+ else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) {
+ /* At least Compaq WL200 does not have IRQInfo1 set,
+ * but it does not work without interrupts.. */
+ printk("Config has no IRQ info, but trying to enable "
+ "IRQ anyway..\n");
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+ }
+
+ /* IO window settings */
+ PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
+ "dflt.io.nwin=%d\n",
+ cfg->io.nwin, dflt.io.nwin);
+ link->io.NumPorts1 = link->io.NumPorts2 = 0;
+ if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
+ "io.base=0x%04x, len=%d\n", io->flags,
+ io->win[0].base, io->win[0].len);
+ if (!(io->flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = io->flags &
+ CISTPL_IO_LINES_MASK;
+ link->io.BasePort1 = io->win[0].base;
+ link->io.NumPorts1 = io->win[0].len;
+ if (io->nwin > 1) {
+ link->io.Attributes2 = link->io.Attributes1;
+ link->io.BasePort2 = io->win[1].base;
+ link->io.NumPorts2 = io->win[1].len;
+ }
+ }
+
+ /* This reserves IO space but doesn't actually enable it */
+ CFG_CHECK2(RequestIO,
+ pcmcia_request_io(link->handle, &link->io));
+
+ /* This configuration table entry is OK */
+ break;
+
+ next_entry:
+ CS_CHECK(GetNextTuple,
+ pcmcia_get_next_tuple(link->handle, &tuple));
+ }
+
+ /* Need to allocate net_device before requesting IRQ handler */
+ dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
+ &handle_to_dev(link->handle));
+ if (dev == NULL)
+ goto failed;
+ link->priv = dev;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ local->hw_priv = hw_priv;
+ hw_priv->link = link;
+ strcpy(hw_priv->node.dev_name, dev->name);
+ link->dev = &hw_priv->node;
+
+ /*
+ * Allocate an interrupt line. Note that this does not assign a
+ * handler to the interrupt, unless the 'Handler' member of the
+ * irq structure is initialized.
+ */
+ if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Handler = prism2_interrupt;
+ link->irq.Instance = dev;
+ CS_CHECK(RequestIRQ,
+ pcmcia_request_irq(link->handle, &link->irq));
+ }
+
+ /*
+ * This actually configures the PCMCIA socket -- setting up
+ * the I/O windows and the interrupt mapping, and putting the
+ * card and host interface into "Memory and IO" mode.
+ */
+ CS_CHECK(RequestConfiguration,
+ pcmcia_request_configuration(link->handle, &link->conf));
+
+ dev->irq = link->irq.AssignedIRQ;
+ dev->base_addr = link->io.BasePort1;
+
+ /* Finally, report what we've done */
+ printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+ dev_info, link->conf.ConfigIndex,
+ link->conf.Vcc / 10, link->conf.Vcc % 10);
+ if (link->conf.Vpp1)
+ printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+ link->conf.Vpp1 % 10);
+ if (link->conf.Attributes & CONF_ENABLE_IRQ)
+ printk(", irq %d", link->irq.AssignedIRQ);
+ if (link->io.NumPorts1)
+ printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ link->io.BasePort1+link->io.NumPorts1-1);
+ if (link->io.NumPorts2)
+ printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ link->io.BasePort2+link->io.NumPorts2-1);
+ printk("\n");
+
+ link->state |= DEV_CONFIG;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ local->shutdown = 0;
+
+ sandisk_enable_wireless(dev);
+
+ ret = prism2_hw_config(dev, 1);
+ if (!ret) {
+ ret = hostap_hw_ready(dev);
+ if (ret == 0 && local->ddev)
+ strcpy(hw_priv->node.dev_name, local->ddev->name);
+ }
+ kfree(parse);
+ return ret;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+
+ failed:
+ kfree(parse);
+ kfree(hw_priv);
+ prism2_release((u_long)link);
+ return ret;
+}
+
+
+static void prism2_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ PDEBUG(DEBUG_FLOW, "prism2_release\n");
+
+ if (link->priv) {
+ struct net_device *dev = link->priv;
+ struct hostap_interface *iface;
+
+ iface = netdev_priv(dev);
+ if (link->state & DEV_CONFIG)
+ prism2_hw_shutdown(dev, 0);
+ iface->local->shutdown = 1;
+ }
+
+ if (link->win)
+ pcmcia_release_window(link->win);
+ pcmcia_release_configuration(link->handle);
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ if (link->irq.AssignedIRQ)
+ pcmcia_release_irq(link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+
+ PDEBUG(DEBUG_FLOW, "release - done\n");
+}
+
+
+static int prism2_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ struct net_device *dev = (struct net_device *) link->priv;
+
+ switch (event) {
+ case CS_EVENT_CARD_INSERTION:
+ PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info);
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ if (prism2_config(link)) {
+ PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
+ }
+ break;
+
+ case CS_EVENT_CARD_REMOVAL:
+ PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info);
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ netif_stop_queue(dev);
+ netif_device_detach(dev);
+ prism2_release((u_long) link);
+ }
+ break;
+
+ case CS_EVENT_PM_SUSPEND:
+ PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
+ link->state |= DEV_SUSPEND;
+ /* fall through */
+
+ case CS_EVENT_RESET_PHYSICAL:
+ PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info);
+ if (link->state & DEV_CONFIG) {
+ if (link->open) {
+ netif_stop_queue(dev);
+ netif_device_detach(dev);
+ }
+ prism2_suspend(dev);
+ pcmcia_release_configuration(link->handle);
+ }
+ break;
+
+ case CS_EVENT_PM_RESUME:
+ PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
+ link->state &= ~DEV_SUSPEND;
+ /* fall through */
+
+ case CS_EVENT_CARD_RESET:
+ PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info);
+ if (link->state & DEV_CONFIG) {
+ pcmcia_request_configuration(link->handle,
+ &link->conf);
+ prism2_hw_shutdown(dev, 1);
+ prism2_hw_config(dev, link->open ? 0 : 1);
+ if (link->open) {
+ netif_device_attach(dev);
+ netif_start_queue(dev);
+ }
+ }
+ break;
+
+ default:
+ PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n",
+ dev_info, event);
+ break;
+ }
+ return 0;
+}
+
+
+static struct pcmcia_device_id hostap_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
+ PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
+ PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
+ PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
+ PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
+ PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
+ 0x7a954bd9, 0x74be00c6),
+ PCMCIA_DEVICE_PROD_ID1234(
+ "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
+ "Eval-RevA",
+ 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+ PCMCIA_DEVICE_PROD_ID123(
+ "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
+ 0xe6ec52ce, 0x08649af2, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID123(
+ "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
+ 0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID123(
+ "Instant Wireless ", " Network PC CARD", "Version 01.02",
+ 0x11d901af, 0x6e9bd926, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID123(
+ "SMC", "SMC2632W", "Version 01.02",
+ 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G",
+ 0x2decece3, 0x82067c18),
+ PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
+ 0x54f7c49c, 0x15a75e5b),
+ PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
+ 0x74c5e40d, 0xdb472a18),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
+ 0x0733cc81, 0x0c52f395),
+ PCMCIA_DEVICE_PROD_ID12(
+ "ZoomAir 11Mbps High", "Rate wireless Networking",
+ 0x273fe3db, 0x32a1eaee),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
+
+
+static struct pcmcia_driver hostap_driver = {
+ .drv = {
+ .name = "hostap_cs",
+ },
+ .attach = prism2_attach,
+ .detach = prism2_detach,
+ .owner = THIS_MODULE,
+ .event = prism2_event,
+ .id_table = hostap_cs_ids,
+};
+
+static int __init init_prism2_pccard(void)
+{
+ printk(KERN_INFO "%s: %s\n", dev_info, version);
+ return pcmcia_register_driver(&hostap_driver);
+}
+
+static void __exit exit_prism2_pccard(void)
+{
+ pcmcia_unregister_driver(&hostap_driver);
+ printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+
+
+module_init(init_prism2_pccard);
+module_exit(exit_prism2_pccard);
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c
new file mode 100644
index 0000000..ab26b52
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_download.c
@@ -0,0 +1,766 @@
+static int prism2_enable_aux_port(struct net_device *dev, int enable)
+{
+ u16 val, reg;
+ int i, tries;
+ unsigned long flags;
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->no_pri) {
+ if (enable) {
+ PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
+ "port is already enabled\n", dev->name);
+ }
+ return 0;
+ }
+
+ spin_lock_irqsave(&local->cmdlock, flags);
+
+ /* wait until busy bit is clear */
+ tries = HFA384X_CMD_BUSY_TIMEOUT;
+ while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
+ tries--;
+ udelay(1);
+ }
+ if (tries == 0) {
+ reg = HFA384X_INW(HFA384X_CMD_OFF);
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+ printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
+ dev->name, reg);
+ return -ETIMEDOUT;
+ }
+
+ val = HFA384X_INW(HFA384X_CONTROL_OFF);
+
+ if (enable) {
+ HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
+ HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
+ HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
+
+ if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
+ printk("prism2_enable_aux_port: was not disabled!?\n");
+ val &= ~HFA384X_AUX_PORT_MASK;
+ val |= HFA384X_AUX_PORT_ENABLE;
+ } else {
+ HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
+ HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
+ HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+
+ if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
+ printk("prism2_enable_aux_port: was not enabled!?\n");
+ val &= ~HFA384X_AUX_PORT_MASK;
+ val |= HFA384X_AUX_PORT_DISABLE;
+ }
+ HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
+
+ udelay(5);
+
+ i = 10000;
+ while (i > 0) {
+ val = HFA384X_INW(HFA384X_CONTROL_OFF);
+ val &= HFA384X_AUX_PORT_MASK;
+
+ if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
+ (!enable && val == HFA384X_AUX_PORT_DISABLED))
+ break;
+
+ udelay(10);
+ i--;
+ }
+
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+
+ if (i == 0) {
+ printk("prism2_enable_aux_port(%d) timed out\n",
+ enable);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+
+static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
+ void *buf)
+{
+ u16 page, offset;
+ if (addr & 1 || len & 1)
+ return -1;
+
+ page = addr >> 7;
+ offset = addr & 0x7f;
+
+ HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
+ HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
+
+ udelay(5);
+
+#ifdef PRISM2_PCI
+ {
+ u16 *pos = (u16 *) buf;
+ while (len > 0) {
+ *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
+ len -= 2;
+ }
+ }
+#else /* PRISM2_PCI */
+ HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
+#endif /* PRISM2_PCI */
+
+ return 0;
+}
+
+
+static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
+ void *buf)
+{
+ u16 page, offset;
+ if (addr & 1 || len & 1)
+ return -1;
+
+ page = addr >> 7;
+ offset = addr & 0x7f;
+
+ HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
+ HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
+
+ udelay(5);
+
+#ifdef PRISM2_PCI
+ {
+ u16 *pos = (u16 *) buf;
+ while (len > 0) {
+ HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
+ len -= 2;
+ }
+ }
+#else /* PRISM2_PCI */
+ HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
+#endif /* PRISM2_PCI */
+
+ return 0;
+}
+
+
+static int prism2_pda_ok(u8 *buf)
+{
+ u16 *pda = (u16 *) buf;
+ int pos;
+ u16 len, pdr;
+
+ if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
+ buf[3] == 0x00)
+ return 0;
+
+ pos = 0;
+ while (pos + 1 < PRISM2_PDA_SIZE / 2) {
+ len = le16_to_cpu(pda[pos]);
+ pdr = le16_to_cpu(pda[pos + 1]);
+ if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
+ return 0;
+
+ if (pdr == 0x0000 && len == 2) {
+ /* PDA end found */
+ return 1;
+ }
+
+ pos += len + 1;
+ }
+
+ return 0;
+}
+
+
+static int prism2_download_aux_dump(struct net_device *dev,
+ unsigned int addr, int len, u8 *buf)
+{
+ int res;
+
+ prism2_enable_aux_port(dev, 1);
+ res = hfa384x_from_aux(dev, addr, len, buf);
+ prism2_enable_aux_port(dev, 0);
+ if (res)
+ return -1;
+
+ return 0;
+}
+
+
+static u8 * prism2_read_pda(struct net_device *dev)
+{
+ u8 *buf;
+ int res, i, found = 0;
+#define NUM_PDA_ADDRS 4
+ unsigned int pda_addr[NUM_PDA_ADDRS] = {
+ 0x7f0000 /* others than HFA3841 */,
+ 0x3f0000 /* HFA3841 */,
+ 0x390000 /* apparently used in older cards */,
+ 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
+ };
+
+ buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
+ if (buf == NULL)
+ return NULL;
+
+ /* Note: wlan card should be in initial state (just after init cmd)
+ * and no other operations should be performed concurrently. */
+
+ prism2_enable_aux_port(dev, 1);
+
+ for (i = 0; i < NUM_PDA_ADDRS; i++) {
+ PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
+ dev->name, pda_addr[i]);
+ res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
+ if (res)
+ continue;
+ if (res == 0 && prism2_pda_ok(buf)) {
+ PDEBUG2(DEBUG_EXTRA2, ": OK\n");
+ found = 1;
+ break;
+ } else {
+ PDEBUG2(DEBUG_EXTRA2, ": failed\n");
+ }
+ }
+
+ prism2_enable_aux_port(dev, 0);
+
+ if (!found) {
+ printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
+ kfree(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+
+static int prism2_download_volatile(local_info_t *local,
+ struct prism2_download_data *param)
+{
+ struct net_device *dev = local->dev;
+ int ret = 0, i;
+ u16 param0, param1;
+
+ if (local->hw_downloading) {
+ printk(KERN_WARNING "%s: Already downloading - aborting new "
+ "request\n", dev->name);
+ return -1;
+ }
+
+ local->hw_downloading = 1;
+ if (local->pri_only) {
+ hfa384x_disable_interrupts(dev);
+ } else {
+ prism2_hw_shutdown(dev, 0);
+
+ if (prism2_hw_init(dev, 0)) {
+ printk(KERN_WARNING "%s: Could not initialize card for"
+ " download\n", dev->name);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ if (prism2_enable_aux_port(dev, 1)) {
+ printk(KERN_WARNING "%s: Could not enable AUX port\n",
+ dev->name);
+ ret = -1;
+ goto out;
+ }
+
+ param0 = param->start_addr & 0xffff;
+ param1 = param->start_addr >> 16;
+
+ HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+ HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
+ if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+ (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
+ param0)) {
+ printk(KERN_WARNING "%s: Download command execution failed\n",
+ dev->name);
+ ret = -1;
+ goto out;
+ }
+
+ for (i = 0; i < param->num_areas; i++) {
+ PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
+ dev->name, param->data[i].len, param->data[i].addr);
+ if (hfa384x_to_aux(dev, param->data[i].addr,
+ param->data[i].len, param->data[i].data)) {
+ printk(KERN_WARNING "%s: RAM download at 0x%08x "
+ "(len=%d) failed\n", dev->name,
+ param->data[i].addr, param->data[i].len);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
+ HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+ if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+ (HFA384X_PROGMODE_DISABLE << 8), param0)) {
+ printk(KERN_WARNING "%s: Download command execution failed\n",
+ dev->name);
+ ret = -1;
+ goto out;
+ }
+ /* ProgMode disable causes the hardware to restart itself from the
+ * given starting address. Give hw some time and ACK command just in
+ * case restart did not happen. */
+ mdelay(5);
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+
+ if (prism2_enable_aux_port(dev, 0)) {
+ printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
+ dev->name);
+ /* continue anyway.. restart should have taken care of this */
+ }
+
+ mdelay(5);
+ local->hw_downloading = 0;
+ if (prism2_hw_config(dev, 2)) {
+ printk(KERN_WARNING "%s: Card configuration after RAM "
+ "download failed\n", dev->name);
+ ret = -1;
+ goto out;
+ }
+
+ out:
+ local->hw_downloading = 0;
+ return ret;
+}
+
+
+static int prism2_enable_genesis(local_info_t *local, int hcr)
+{
+ struct net_device *dev = local->dev;
+ u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
+ u8 readbuf[4];
+
+ printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
+ dev->name, hcr);
+ local->func->cor_sreset(local);
+ hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
+ local->func->genesis_reset(local, hcr);
+
+ /* Readback test */
+ hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
+ hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
+ hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
+
+ if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
+ printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
+ hcr);
+ return 0;
+ } else {
+ printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
+ "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
+ hcr, initseq[0], initseq[1], initseq[2], initseq[3],
+ readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
+ return 1;
+ }
+}
+
+
+static int prism2_get_ram_size(local_info_t *local)
+{
+ int ret;
+
+ /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
+ if (prism2_enable_genesis(local, 0x1f) == 0)
+ ret = 8;
+ else if (prism2_enable_genesis(local, 0x0f) == 0)
+ ret = 16;
+ else
+ ret = -1;
+
+ /* Disable genesis mode */
+ local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
+
+ return ret;
+}
+
+
+static int prism2_download_genesis(local_info_t *local,
+ struct prism2_download_data *param)
+{
+ struct net_device *dev = local->dev;
+ int ram16 = 0, i;
+ int ret = 0;
+
+ if (local->hw_downloading) {
+ printk(KERN_WARNING "%s: Already downloading - aborting new "
+ "request\n", dev->name);
+ return -EBUSY;
+ }
+
+ if (!local->func->genesis_reset || !local->func->cor_sreset) {
+ printk(KERN_INFO "%s: Genesis mode downloading not supported "
+ "with this hwmodel\n", dev->name);
+ return -EOPNOTSUPP;
+ }
+
+ local->hw_downloading = 1;
+
+ if (prism2_enable_aux_port(dev, 1)) {
+ printk(KERN_DEBUG "%s: failed to enable AUX port\n",
+ dev->name);
+ ret = -EIO;
+ goto out;
+ }
+
+ if (local->sram_type == -1) {
+ /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
+ if (prism2_enable_genesis(local, 0x1f) == 0) {
+ ram16 = 0;
+ PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
+ "SRAM\n", dev->name);
+ } else if (prism2_enable_genesis(local, 0x0f) == 0) {
+ ram16 = 1;
+ PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
+ "SRAM\n", dev->name);
+ } else {
+ printk(KERN_DEBUG "%s: Could not initiate genesis "
+ "mode\n", dev->name);
+ ret = -EIO;
+ goto out;
+ }
+ } else {
+ if (prism2_enable_genesis(local, local->sram_type == 8 ?
+ 0x1f : 0x0f)) {
+ printk(KERN_DEBUG "%s: Failed to set Genesis "
+ "mode (sram_type=%d)\n", dev->name,
+ local->sram_type);
+ ret = -EIO;
+ goto out;
+ }
+ ram16 = local->sram_type != 8;
+ }
+
+ for (i = 0; i < param->num_areas; i++) {
+ PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
+ dev->name, param->data[i].len, param->data[i].addr);
+ if (hfa384x_to_aux(dev, param->data[i].addr,
+ param->data[i].len, param->data[i].data)) {
+ printk(KERN_WARNING "%s: RAM download at 0x%08x "
+ "(len=%d) failed\n", dev->name,
+ param->data[i].addr, param->data[i].len);
+ ret = -EIO;
+ goto out;
+ }
+ }
+
+ PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
+ local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
+ if (prism2_enable_aux_port(dev, 0)) {
+ printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
+ dev->name);
+ }
+
+ mdelay(5);
+ local->hw_downloading = 0;
+
+ PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
+ /*
+ * Make sure the INIT command does not generate a command completion
+ * event by disabling interrupts.
+ */
+ hfa384x_disable_interrupts(dev);
+ if (prism2_hw_init(dev, 1)) {
+ printk(KERN_DEBUG "%s: Initialization after genesis mode "
+ "download failed\n", dev->name);
+ ret = -EIO;
+ goto out;
+ }
+
+ PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
+ if (prism2_hw_init2(dev, 1)) {
+ printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
+ "download failed\n", dev->name);
+ ret = -EIO;
+ goto out;
+ }
+
+ out:
+ local->hw_downloading = 0;
+ return ret;
+}
+
+
+#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
+/* Note! Non-volatile downloading functionality has not yet been tested
+ * thoroughly and it may corrupt flash image and effectively kill the card that
+ * is being updated. You have been warned. */
+
+static inline int prism2_download_block(struct net_device *dev,
+ u32 addr, u8 *data,
+ u32 bufaddr, int rest_len)
+{
+ u16 param0, param1;
+ int block_len;
+
+ block_len = rest_len < 4096 ? rest_len : 4096;
+
+ param0 = addr & 0xffff;
+ param1 = addr >> 16;
+
+ HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
+ HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
+
+ if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+ (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
+ param0)) {
+ printk(KERN_WARNING "%s: Flash download command execution "
+ "failed\n", dev->name);
+ return -1;
+ }
+
+ if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
+ printk(KERN_WARNING "%s: flash download at 0x%08x "
+ "(len=%d) failed\n", dev->name, addr, block_len);
+ return -1;
+ }
+
+ HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+ HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
+ if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+ (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
+ 0)) {
+ printk(KERN_WARNING "%s: Flash write command execution "
+ "failed\n", dev->name);
+ return -1;
+ }
+
+ return block_len;
+}
+
+
+static int prism2_download_nonvolatile(local_info_t *local,
+ struct prism2_download_data *dl)
+{
+ struct net_device *dev = local->dev;
+ int ret = 0, i;
+ struct {
+ u16 page;
+ u16 offset;
+ u16 len;
+ } dlbuffer;
+ u32 bufaddr;
+
+ if (local->hw_downloading) {
+ printk(KERN_WARNING "%s: Already downloading - aborting new "
+ "request\n", dev->name);
+ return -1;
+ }
+
+ ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
+ &dlbuffer, 6, 0);
+
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: Could not read download buffer "
+ "parameters\n", dev->name);
+ goto out;
+ }
+
+ dlbuffer.page = le16_to_cpu(dlbuffer.page);
+ dlbuffer.offset = le16_to_cpu(dlbuffer.offset);
+ dlbuffer.len = le16_to_cpu(dlbuffer.len);
+
+ printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
+ dlbuffer.len, dlbuffer.page, dlbuffer.offset);
+
+ bufaddr = (dlbuffer.page << 7) + dlbuffer.offset;
+
+ local->hw_downloading = 1;
+
+ if (!local->pri_only) {
+ prism2_hw_shutdown(dev, 0);
+
+ if (prism2_hw_init(dev, 0)) {
+ printk(KERN_WARNING "%s: Could not initialize card for"
+ " download\n", dev->name);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ hfa384x_disable_interrupts(dev);
+
+ if (prism2_enable_aux_port(dev, 1)) {
+ printk(KERN_WARNING "%s: Could not enable AUX port\n",
+ dev->name);
+ ret = -1;
+ goto out;
+ }
+
+ printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
+ for (i = 0; i < dl->num_areas; i++) {
+ int rest_len = dl->data[i].len;
+ int data_off = 0;
+
+ while (rest_len > 0) {
+ int block_len;
+
+ block_len = prism2_download_block(
+ dev, dl->data[i].addr + data_off,
+ dl->data[i].data + data_off, bufaddr,
+ rest_len);
+
+ if (block_len < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ rest_len -= block_len;
+ data_off += block_len;
+ }
+ }
+
+ HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
+ HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
+ if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
+ (HFA384X_PROGMODE_DISABLE << 8), 0)) {
+ printk(KERN_WARNING "%s: Download command execution failed\n",
+ dev->name);
+ ret = -1;
+ goto out;
+ }
+
+ if (prism2_enable_aux_port(dev, 0)) {
+ printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
+ dev->name);
+ /* continue anyway.. restart should have taken care of this */
+ }
+
+ mdelay(5);
+
+ local->func->hw_reset(dev);
+ local->hw_downloading = 0;
+ if (prism2_hw_config(dev, 2)) {
+ printk(KERN_WARNING "%s: Card configuration after flash "
+ "download failed\n", dev->name);
+ ret = -1;
+ } else {
+ printk(KERN_INFO "%s: Card initialized successfully after "
+ "flash download\n", dev->name);
+ }
+
+ out:
+ local->hw_downloading = 0;
+ return ret;
+}
+#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
+
+
+static void prism2_download_free_data(struct prism2_download_data *dl)
+{
+ int i;
+
+ if (dl == NULL)
+ return;
+
+ for (i = 0; i < dl->num_areas; i++)
+ kfree(dl->data[i].data);
+ kfree(dl);
+}
+
+
+static int prism2_download(local_info_t *local,
+ struct prism2_download_param *param)
+{
+ int ret = 0;
+ int i;
+ u32 total_len = 0;
+ struct prism2_download_data *dl = NULL;
+
+ printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
+ "num_areas=%d\n",
+ param->dl_cmd, param->start_addr, param->num_areas);
+
+ if (param->num_areas > 100) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dl = kmalloc(sizeof(*dl) + param->num_areas *
+ sizeof(struct prism2_download_data_area), GFP_KERNEL);
+ if (dl == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ memset(dl, 0, sizeof(*dl) + param->num_areas *
+ sizeof(struct prism2_download_data_area));
+ dl->dl_cmd = param->dl_cmd;
+ dl->start_addr = param->start_addr;
+ dl->num_areas = param->num_areas;
+ for (i = 0; i < param->num_areas; i++) {
+ PDEBUG(DEBUG_EXTRA2,
+ " area %d: addr=0x%08x len=%d ptr=0x%p\n",
+ i, param->data[i].addr, param->data[i].len,
+ param->data[i].ptr);
+
+ dl->data[i].addr = param->data[i].addr;
+ dl->data[i].len = param->data[i].len;
+
+ total_len += param->data[i].len;
+ if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
+ total_len > PRISM2_MAX_DOWNLOAD_LEN) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
+ if (dl->data[i].data == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(dl->data[i].data, param->data[i].ptr,
+ param->data[i].len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ switch (param->dl_cmd) {
+ case PRISM2_DOWNLOAD_VOLATILE:
+ case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
+ ret = prism2_download_volatile(local, dl);
+ break;
+ case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
+ case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
+ ret = prism2_download_genesis(local, dl);
+ break;
+ case PRISM2_DOWNLOAD_NON_VOLATILE:
+#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
+ ret = prism2_download_nonvolatile(local, dl);
+#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
+ printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
+ local->dev->name);
+ ret = -EOPNOTSUPP;
+#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
+ break;
+ default:
+ printk(KERN_DEBUG "%s: unsupported download command %d\n",
+ local->dev->name, param->dl_cmd);
+ ret = -EINVAL;
+ break;
+ };
+
+ out:
+ if (ret == 0 && dl &&
+ param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
+ prism2_download_free_data(local->dl_pri);
+ local->dl_pri = dl;
+ } else if (ret == 0 && dl &&
+ param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
+ prism2_download_free_data(local->dl_sec);
+ local->dl_sec = dl;
+ } else
+ prism2_download_free_data(dl);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
new file mode 100644
index 0000000..e533a66
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -0,0 +1,3445 @@
+/*
+ * Host AP (software wireless LAN access point) driver for
+ * Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ *
+ * FIX:
+ * - there is currently no way of associating TX packets to correct wds device
+ * when TX Exc/OK event occurs, so all tx_packets and some
+ * tx_errors/tx_dropped are added to the main netdevice; using sw_support
+ * field in txdesc might be used to fix this (using Alloc event to increment
+ * tx_packets would need some further info in txfid table)
+ *
+ * Buffer Access Path (BAP) usage:
+ * Prism2 cards have two separate BAPs for accessing the card memory. These
+ * should allow concurrent access to two different frames and the driver
+ * previously used BAP0 for sending data and BAP1 for receiving data.
+ * However, there seems to be number of issues with concurrent access and at
+ * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI
+ * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between
+ * host and card memories. BAP0 accesses are protected with local->baplock
+ * (spin_lock_bh) to prevent concurrent use.
+ */
+
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211_crypt.h>
+#include <asm/irq.h>
+
+#include "hostap_80211.h"
+#include "hostap.h"
+#include "hostap_ap.h"
+
+
+/* #define final_version */
+
+static int mtu = 1500;
+module_param(mtu, int, 0444);
+MODULE_PARM_DESC(mtu, "Maximum transfer unit");
+
+static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS };
+module_param_array(channel, int, NULL, 0444);
+MODULE_PARM_DESC(channel, "Initial channel");
+
+static char essid[33] = "test";
+module_param_string(essid, essid, sizeof(essid), 0444);
+MODULE_PARM_DESC(essid, "Host AP's ESSID");
+
+static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS };
+module_param_array(iw_mode, int, NULL, 0444);
+MODULE_PARM_DESC(iw_mode, "Initial operation mode");
+
+static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS };
+module_param_array(beacon_int, int, NULL, 0444);
+MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)");
+
+static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS };
+module_param_array(dtim_period, int, NULL, 0444);
+MODULE_PARM_DESC(dtim_period, "DTIM period");
+
+static char dev_template[16] = "wlan%d";
+module_param_string(dev_template, dev_template, sizeof(dev_template), 0444);
+MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: "
+ "wlan%d)");
+
+#ifdef final_version
+#define EXTRA_EVENTS_WTERR 0
+#else
+/* check WTERR events (Wait Time-out) in development versions */
+#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR
+#endif
+
+/* Events that will be using BAP0 */
+#define HFA384X_BAP0_EVENTS \
+ (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX)
+
+/* event mask, i.e., events that will result in an interrupt */
+#define HFA384X_EVENT_MASK \
+ (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \
+ HFA384X_EV_CMD | HFA384X_EV_TICK | \
+ EXTRA_EVENTS_WTERR)
+
+/* Default TX control flags: use 802.11 headers and request interrupt for
+ * failed transmits. Frames that request ACK callback, will add
+ * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy.
+ */
+#define HFA384X_TX_CTRL_FLAGS \
+ (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX)
+
+
+/* ca. 1 usec */
+#define HFA384X_CMD_BUSY_TIMEOUT 5000
+#define HFA384X_BAP_BUSY_TIMEOUT 50000
+
+/* ca. 10 usec */
+#define HFA384X_CMD_COMPL_TIMEOUT 20000
+#define HFA384X_DL_COMPL_TIMEOUT 1000000
+
+/* Wait times for initialization; yield to other processes to avoid busy
+ * waiting for long time. */
+#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */
+#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */
+
+
+static void prism2_hw_reset(struct net_device *dev);
+static void prism2_check_sta_fw_version(local_info_t *local);
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+/* hostap_download.c */
+static int prism2_download_aux_dump(struct net_device *dev,
+ unsigned int addr, int len, u8 *buf);
+static u8 * prism2_read_pda(struct net_device *dev);
+static int prism2_download(local_info_t *local,
+ struct prism2_download_param *param);
+static void prism2_download_free_data(struct prism2_download_data *dl);
+static int prism2_download_volatile(local_info_t *local,
+ struct prism2_download_data *param);
+static int prism2_download_genesis(local_info_t *local,
+ struct prism2_download_data *param);
+static int prism2_get_ram_size(local_info_t *local);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+
+
+
+#ifndef final_version
+/* magic value written to SWSUPPORT0 reg. for detecting whether card is still
+ * present */
+#define HFA384X_MAGIC 0x8A32
+#endif
+
+
+static u16 hfa384x_read_reg(struct net_device *dev, u16 reg)
+{
+ return HFA384X_INW(reg);
+}
+
+
+static void hfa384x_read_regs(struct net_device *dev,
+ struct hfa384x_regs *regs)
+{
+ regs->cmd = HFA384X_INW(HFA384X_CMD_OFF);
+ regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF);
+ regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF);
+ regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF);
+}
+
+
+/**
+ * __hostap_cmd_queue_free - Free Prism2 command queue entry (private)
+ * @local: pointer to private Host AP driver data
+ * @entry: Prism2 command queue entry to be freed
+ * @del_req: request the entry to be removed
+ *
+ * Internal helper function for freeing Prism2 command queue entries.
+ * Caller must have acquired local->cmdlock before calling this function.
+ */
+static inline void __hostap_cmd_queue_free(local_info_t *local,
+ struct hostap_cmd_queue *entry,
+ int del_req)
+{
+ if (del_req) {
+ entry->del_req = 1;
+ if (!list_empty(&entry->list)) {
+ list_del_init(&entry->list);
+ local->cmd_queue_len--;
+ }
+ }
+
+ if (atomic_dec_and_test(&entry->usecnt) && entry->del_req)
+ kfree(entry);
+}
+
+
+/**
+ * hostap_cmd_queue_free - Free Prism2 command queue entry
+ * @local: pointer to private Host AP driver data
+ * @entry: Prism2 command queue entry to be freed
+ * @del_req: request the entry to be removed
+ *
+ * Free a Prism2 command queue entry.
+ */
+static inline void hostap_cmd_queue_free(local_info_t *local,
+ struct hostap_cmd_queue *entry,
+ int del_req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->cmdlock, flags);
+ __hostap_cmd_queue_free(local, entry, del_req);
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+}
+
+
+/**
+ * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries
+ * @local: pointer to private Host AP driver data
+ */
+static void prism2_clear_cmd_queue(local_info_t *local)
+{
+ struct list_head *ptr, *n;
+ unsigned long flags;
+ struct hostap_cmd_queue *entry;
+
+ spin_lock_irqsave(&local->cmdlock, flags);
+ list_for_each_safe(ptr, n, &local->cmd_queue) {
+ entry = list_entry(ptr, struct hostap_cmd_queue, list);
+ atomic_inc(&entry->usecnt);
+ printk(KERN_DEBUG "%s: removed pending cmd_queue entry "
+ "(type=%d, cmd=0x%04x, param0=0x%04x)\n",
+ local->dev->name, entry->type, entry->cmd,
+ entry->param0);
+ __hostap_cmd_queue_free(local, entry, 1);
+ }
+ if (local->cmd_queue_len) {
+ /* This should not happen; print debug message and clear
+ * queue length. */
+ printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after "
+ "flush\n", local->dev->name, local->cmd_queue_len);
+ local->cmd_queue_len = 0;
+ }
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+}
+
+
+/**
+ * hfa384x_cmd_issue - Issue a Prism2 command to the hardware
+ * @dev: pointer to net_device
+ * @entry: Prism2 command queue entry to be issued
+ */
+static inline int hfa384x_cmd_issue(struct net_device *dev,
+ struct hostap_cmd_queue *entry)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int tries;
+ u16 reg;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->card_present && !local->func->card_present(local))
+ return -ENODEV;
+
+ if (entry->issued) {
+ printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n",
+ dev->name, entry);
+ }
+
+ /* wait until busy bit is clear; this should always be clear since the
+ * commands are serialized */
+ tries = HFA384X_CMD_BUSY_TIMEOUT;
+ while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
+ tries--;
+ udelay(1);
+ }
+#ifndef final_version
+ if (tries != HFA384X_CMD_BUSY_TIMEOUT) {
+ prism2_io_debug_error(dev, 1);
+ printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy "
+ "for %d usec\n", dev->name,
+ HFA384X_CMD_BUSY_TIMEOUT - tries);
+ }
+#endif
+ if (tries == 0) {
+ reg = HFA384X_INW(HFA384X_CMD_OFF);
+ prism2_io_debug_error(dev, 2);
+ printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - "
+ "reg=0x%04x\n", dev->name, reg);
+ return -ETIMEDOUT;
+ }
+
+ /* write command */
+ spin_lock_irqsave(&local->cmdlock, flags);
+ HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF);
+ HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF);
+ HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF);
+ entry->issued = 1;
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+
+ return 0;
+}
+
+
+/**
+ * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ * @param1: value for Param1 register (pointer; %NULL if not used)
+ * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed
+ *
+ * Issue given command (possibly after waiting in command queue) and sleep
+ * until the command is completed (or timed out or interrupted). This can be
+ * called only from user process context.
+ */
+static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0,
+ u16 *param1, u16 *resp0)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int err, res, issue, issued = 0;
+ unsigned long flags;
+ struct hostap_cmd_queue *entry;
+ DECLARE_WAITQUEUE(wait, current);
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (in_interrupt()) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt "
+ "context\n", dev->name);
+ return -1;
+ }
+
+ if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
+ dev->name);
+ return -1;
+ }
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ entry = (struct hostap_cmd_queue *)
+ kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry == NULL) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n",
+ dev->name);
+ return -ENOMEM;
+ }
+ memset(entry, 0, sizeof(*entry));
+ atomic_set(&entry->usecnt, 1);
+ entry->type = CMD_SLEEP;
+ entry->cmd = cmd;
+ entry->param0 = param0;
+ if (param1)
+ entry->param1 = *param1;
+ init_waitqueue_head(&entry->compl);
+
+ /* prepare to wait for command completion event, but do not sleep yet
+ */
+ add_wait_queue(&entry->compl, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&local->cmdlock, flags);
+ issue = list_empty(&local->cmd_queue);
+ if (issue)
+ entry->issuing = 1;
+ list_add_tail(&entry->list, &local->cmd_queue);
+ local->cmd_queue_len++;
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+
+ err = 0;
+ if (!issue)
+ goto wait_completion;
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ if (!err) {
+ if (hfa384x_cmd_issue(dev, entry))
+ err = -ETIMEDOUT;
+ else
+ issued = 1;
+ }
+
+ wait_completion:
+ if (!err && entry->type != CMD_COMPLETED) {
+ /* sleep until command is completed or timed out */
+ res = schedule_timeout(2 * HZ);
+ } else
+ res = -1;
+
+ if (!err && signal_pending(current))
+ err = -EINTR;
+
+ if (err && issued) {
+ /* the command was issued, so a CmdCompl event should occur
+ * soon; however, there's a pending signal and
+ * schedule_timeout() would be interrupted; wait a short period
+ * of time to avoid removing entry from the list before
+ * CmdCompl event */
+ udelay(300);
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&entry->compl, &wait);
+
+ /* If entry->list is still in the list, it must be removed
+ * first and in this case prism2_cmd_ev() does not yet have
+ * local reference to it, and the data can be kfree()'d
+ * here. If the command completion event is still generated,
+ * it will be assigned to next (possibly) pending command, but
+ * the driver will reset the card anyway due to timeout
+ *
+ * If the entry is not in the list prism2_cmd_ev() has a local
+ * reference to it, but keeps cmdlock as long as the data is
+ * needed, so the data can be kfree()'d here. */
+
+ /* FIX: if the entry->list is in the list, it has not been completed
+ * yet, so removing it here is somewhat wrong.. this could cause
+ * references to freed memory and next list_del() causing NULL pointer
+ * dereference.. it would probably be better to leave the entry in the
+ * list and the list should be emptied during hw reset */
+
+ spin_lock_irqsave(&local->cmdlock, flags);
+ if (!list_empty(&entry->list)) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? "
+ "(entry=%p, type=%d, res=%d)\n", dev->name, entry,
+ entry->type, res);
+ list_del_init(&entry->list);
+ local->cmd_queue_len--;
+ }
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+
+ if (err) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n",
+ dev->name, err);
+ res = err;
+ goto done;
+ }
+
+ if (entry->type != CMD_COMPLETED) {
+ u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ printk(KERN_DEBUG "%s: hfa384x_cmd: command was not "
+ "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, "
+ "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name,
+ res, entry, entry->type, entry->cmd, entry->param0, reg,
+ HFA384X_INW(HFA384X_INTEN_OFF));
+ if (reg & HFA384X_EV_CMD) {
+ /* Command completion event is pending, but the
+ * interrupt was not delivered - probably an issue
+ * with pcmcia-cs configuration. */
+ printk(KERN_WARNING "%s: interrupt delivery does not "
+ "seem to work\n", dev->name);
+ }
+ prism2_io_debug_error(dev, 3);
+ res = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (resp0 != NULL)
+ *resp0 = entry->resp0;
+#ifndef final_version
+ if (entry->res) {
+ printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, "
+ "resp0=0x%04x\n",
+ dev->name, cmd, entry->res, entry->resp0);
+ }
+#endif /* final_version */
+
+ res = entry->res;
+ done:
+ hostap_cmd_queue_free(local, entry, 1);
+ return res;
+}
+
+
+/**
+ * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ * @callback: command completion callback function (%NULL = no callback)
+ * @context: context data to be given to the callback function
+ *
+ * Issue given command (possibly after waiting in command queue) and use
+ * callback function to indicate command completion. This can be called both
+ * from user and interrupt context. The callback function will be called in
+ * hardware IRQ context. It can be %NULL, when no function is called when
+ * command is completed.
+ */
+static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0,
+ void (*callback)(struct net_device *dev,
+ long context, u16 resp0,
+ u16 status),
+ long context)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int issue, ret;
+ unsigned long flags;
+ struct hostap_cmd_queue *entry;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
+ dev->name);
+ return -1;
+ }
+
+ entry = (struct hostap_cmd_queue *)
+ kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry == NULL) {
+ printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc "
+ "failed\n", dev->name);
+ return -ENOMEM;
+ }
+ memset(entry, 0, sizeof(*entry));
+ atomic_set(&entry->usecnt, 1);
+ entry->type = CMD_CALLBACK;
+ entry->cmd = cmd;
+ entry->param0 = param0;
+ entry->callback = callback;
+ entry->context = context;
+
+ spin_lock_irqsave(&local->cmdlock, flags);
+ issue = list_empty(&local->cmd_queue);
+ if (issue)
+ entry->issuing = 1;
+ list_add_tail(&entry->list, &local->cmd_queue);
+ local->cmd_queue_len++;
+ spin_unlock_irqrestore(&local->cmdlock, flags);
+
+ if (issue && hfa384x_cmd_issue(dev, entry))
+ ret = -ETIMEDOUT;
+ else
+ ret = 0;
+
+ hostap_cmd_queue_free(local, entry, ret);
+
+ return ret;
+}
+
+
+/**
+ * __hfa384x_cmd_no_wait - Issue a Prism2 command (private)
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ * @io_debug_num: I/O debug error number
+ *
+ * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait().
+ */
+static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0,
+ int io_debug_num)
+{
+ int tries;
+ u16 reg;
+
+ /* wait until busy bit is clear; this should always be clear since the
+ * commands are serialized */
+ tries = HFA384X_CMD_BUSY_TIMEOUT;
+ while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
+ tries--;
+ udelay(1);
+ }
+ if (tries == 0) {
+ reg = HFA384X_INW(HFA384X_CMD_OFF);
+ prism2_io_debug_error(dev, io_debug_num);
+ printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - "
+ "reg=0x%04x\n", dev->name, io_debug_num, reg);
+ return -ETIMEDOUT;
+ }
+
+ /* write command */
+ HFA384X_OUTW(param0, HFA384X_PARAM0_OFF);
+ HFA384X_OUTW(cmd, HFA384X_CMD_OFF);
+
+ return 0;
+}
+
+
+/**
+ * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ */
+static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0)
+{
+ int res, tries;
+ u16 reg;
+
+ res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4);
+ if (res)
+ return res;
+
+ /* wait for command completion */
+ if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD)
+ tries = HFA384X_DL_COMPL_TIMEOUT;
+ else
+ tries = HFA384X_CMD_COMPL_TIMEOUT;
+
+ while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
+ tries > 0) {
+ tries--;
+ udelay(10);
+ }
+ if (tries == 0) {
+ reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ prism2_io_debug_error(dev, 5);
+ printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - "
+ "reg=0x%04x\n", dev->name, reg);
+ return -ETIMEDOUT;
+ }
+
+ res = (HFA384X_INW(HFA384X_STATUS_OFF) &
+ (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) |
+ BIT(8))) >> 8;
+#ifndef final_version
+ if (res) {
+ printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n",
+ dev->name, cmd, res);
+ }
+#endif
+
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+
+ return res;
+}
+
+
+/**
+ * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion
+ * @dev: pointer to net_device
+ * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
+ * @param0: value for Param0 register
+ */
+static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd,
+ u16 param0)
+{
+ return __hfa384x_cmd_no_wait(dev, cmd, param0, 6);
+}
+
+
+/**
+ * prism2_cmd_ev - Prism2 command completion event handler
+ * @dev: pointer to net_device
+ *
+ * Interrupt handler for command completion events. Called by the main
+ * interrupt handler in hardware IRQ context. Read Resp0 and status registers
+ * from the hardware and ACK the event. Depending on the issued command type
+ * either wake up the sleeping process that is waiting for command completion
+ * or call the callback function. Issue the next command, if one is pending.
+ */
+static void prism2_cmd_ev(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hostap_cmd_queue *entry = NULL;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock(&local->cmdlock);
+ if (!list_empty(&local->cmd_queue)) {
+ entry = list_entry(local->cmd_queue.next,
+ struct hostap_cmd_queue, list);
+ atomic_inc(&entry->usecnt);
+ list_del_init(&entry->list);
+ local->cmd_queue_len--;
+
+ if (!entry->issued) {
+ printk(KERN_DEBUG "%s: Command completion event, but "
+ "cmd not issued\n", dev->name);
+ __hostap_cmd_queue_free(local, entry, 1);
+ entry = NULL;
+ }
+ }
+ spin_unlock(&local->cmdlock);
+
+ if (!entry) {
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+ printk(KERN_DEBUG "%s: Command completion event, but no "
+ "pending commands\n", dev->name);
+ return;
+ }
+
+ entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF);
+ entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) &
+ (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) |
+ BIT(9) | BIT(8))) >> 8;
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+
+ /* TODO: rest of the CmdEv handling could be moved to tasklet */
+ if (entry->type == CMD_SLEEP) {
+ entry->type = CMD_COMPLETED;
+ wake_up_interruptible(&entry->compl);
+ } else if (entry->type == CMD_CALLBACK) {
+ if (entry->callback)
+ entry->callback(dev, entry->context, entry->resp0,
+ entry->res);
+ } else {
+ printk(KERN_DEBUG "%s: Invalid command completion type %d\n",
+ dev->name, entry->type);
+ }
+ hostap_cmd_queue_free(local, entry, 1);
+
+ /* issue next command, if pending */
+ entry = NULL;
+ spin_lock(&local->cmdlock);
+ if (!list_empty(&local->cmd_queue)) {
+ entry = list_entry(local->cmd_queue.next,
+ struct hostap_cmd_queue, list);
+ if (entry->issuing) {
+ /* hfa384x_cmd() has already started issuing this
+ * command, so do not start here */
+ entry = NULL;
+ }
+ if (entry)
+ atomic_inc(&entry->usecnt);
+ }
+ spin_unlock(&local->cmdlock);
+
+ if (entry) {
+ /* issue next command; if command issuing fails, remove the
+ * entry from cmd_queue */
+ int res = hfa384x_cmd_issue(dev, entry);
+ spin_lock(&local->cmdlock);
+ __hostap_cmd_queue_free(local, entry, res);
+ spin_unlock(&local->cmdlock);
+ }
+}
+
+
+static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
+{
+ int tries = HFA384X_BAP_BUSY_TIMEOUT;
+ int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
+
+ while (res && tries > 0) {
+ tries--;
+ udelay(1);
+ res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
+ }
+ return res;
+}
+
+
+/* Offset must be even */
+static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id,
+ int offset)
+{
+ u16 o_off, s_off;
+ int ret = 0;
+
+ if (offset % 2 || bap > 1)
+ return -EINVAL;
+
+ if (bap == BAP1) {
+ o_off = HFA384X_OFFSET1_OFF;
+ s_off = HFA384X_SELECT1_OFF;
+ } else {
+ o_off = HFA384X_OFFSET0_OFF;
+ s_off = HFA384X_SELECT0_OFF;
+ }
+
+ if (hfa384x_wait_offset(dev, o_off)) {
+ prism2_io_debug_error(dev, 7);
+ printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n",
+ dev->name);
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ HFA384X_OUTW(id, s_off);
+ HFA384X_OUTW(offset, o_off);
+
+ if (hfa384x_wait_offset(dev, o_off)) {
+ prism2_io_debug_error(dev, 8);
+ printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n",
+ dev->name);
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+#ifndef final_version
+ if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) {
+ prism2_io_debug_error(dev, 9);
+ printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error "
+ "(%d,0x04%x,%d); reg=0x%04x\n",
+ dev->name, bap, id, offset, HFA384X_INW(o_off));
+ ret = -EINVAL;
+ }
+#endif
+
+ out:
+ return ret;
+}
+
+
+static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
+ int exact_len)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int res, rlen = 0;
+ struct hfa384x_rid_hdr rec;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->no_pri) {
+ printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI "
+ "f/w\n", dev->name, rid, len);
+ return -ENOTTY; /* Well.. not really correct, but return
+ * something unique enough.. */
+ }
+
+ if ((local->func->card_present && !local->func->card_present(local)) ||
+ local->hw_downloading)
+ return -ENODEV;
+
+ res = down_interruptible(&local->rid_bap_sem);
+ if (res)
+ return res;
+
+ res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL);
+ if (res) {
+ printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
+ "(res=%d, rid=%04x, len=%d)\n",
+ dev->name, res, rid, len);
+ up(&local->rid_bap_sem);
+ return res;
+ }
+
+ spin_lock_bh(&local->baplock);
+
+ res = hfa384x_setup_bap(dev, BAP0, rid, 0);
+ if (!res)
+ res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+
+ if (le16_to_cpu(rec.len) == 0) {
+ /* RID not available */
+ res = -ENODATA;
+ }
+
+ rlen = (le16_to_cpu(rec.len) - 1) * 2;
+ if (!res && exact_len && rlen != len) {
+ printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
+ "rid=0x%04x, len=%d (expected %d)\n",
+ dev->name, rid, rlen, len);
+ res = -ENODATA;
+ }
+
+ if (!res)
+ res = hfa384x_from_bap(dev, BAP0, buf, len);
+
+ spin_unlock_bh(&local->baplock);
+ up(&local->rid_bap_sem);
+
+ if (res) {
+ if (res != -ENODATA)
+ printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, "
+ "len=%d) - failed - res=%d\n", dev->name, rid,
+ len, res);
+ if (res == -ETIMEDOUT)
+ prism2_hw_reset(dev);
+ return res;
+ }
+
+ return rlen;
+}
+
+
+static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hfa384x_rid_hdr rec;
+ int res;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->no_pri) {
+ printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI "
+ "f/w\n", dev->name, rid, len);
+ return -ENOTTY; /* Well.. not really correct, but return
+ * something unique enough.. */
+ }
+
+ if ((local->func->card_present && !local->func->card_present(local)) ||
+ local->hw_downloading)
+ return -ENODEV;
+
+ rec.rid = cpu_to_le16(rid);
+ /* RID len in words and +1 for rec.rid */
+ rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
+
+ res = down_interruptible(&local->rid_bap_sem);
+ if (res)
+ return res;
+
+ spin_lock_bh(&local->baplock);
+ res = hfa384x_setup_bap(dev, BAP0, rid, 0);
+ if (!res)
+ res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec));
+ if (!res)
+ res = hfa384x_to_bap(dev, BAP0, buf, len);
+ spin_unlock_bh(&local->baplock);
+
+ if (res) {
+ printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
+ "failed - res=%d\n", dev->name, rid, len, res);
+ up(&local->rid_bap_sem);
+ return res;
+ }
+
+ res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
+ up(&local->rid_bap_sem);
+ if (res) {
+ printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
+ "failed (res=%d, rid=%04x, len=%d)\n",
+ dev->name, res, rid, len);
+ return res;
+ }
+
+ if (res == -ETIMEDOUT)
+ prism2_hw_reset(dev);
+
+ return res;
+}
+
+
+static void hfa384x_disable_interrupts(struct net_device *dev)
+{
+ /* disable interrupts and clear event status */
+ HFA384X_OUTW(0, HFA384X_INTEN_OFF);
+ HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+}
+
+
+static void hfa384x_enable_interrupts(struct net_device *dev)
+{
+ /* ack pending events and enable interrupts from selected events */
+ HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+ HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
+}
+
+
+static void hfa384x_events_no_bap0(struct net_device *dev)
+{
+ HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS,
+ HFA384X_INTEN_OFF);
+}
+
+
+static void hfa384x_events_all(struct net_device *dev)
+{
+ HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
+}
+
+
+static void hfa384x_events_only_cmd(struct net_device *dev)
+{
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF);
+}
+
+
+static u16 hfa384x_allocate_fid(struct net_device *dev, int len)
+{
+ u16 fid;
+ unsigned long delay;
+
+ /* FIX: this could be replace with hfa384x_cmd() if the Alloc event
+ * below would be handled like CmdCompl event (sleep here, wake up from
+ * interrupt handler */
+ if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) {
+ printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n",
+ dev->name, len);
+ return 0xffff;
+ }
+
+ delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT;
+ while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) &&
+ time_before(jiffies, delay))
+ yield();
+ if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) {
+ printk("%s: fid allocate, len=%d - timeout\n", dev->name, len);
+ return 0xffff;
+ }
+
+ fid = HFA384X_INW(HFA384X_ALLOCFID_OFF);
+ HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
+
+ return fid;
+}
+
+
+static int prism2_reset_port(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int res;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (!local->dev_enabled)
+ return 0;
+
+ res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0,
+ NULL, NULL);
+ if (res)
+ printk(KERN_DEBUG "%s: reset port failed to disable port\n",
+ dev->name);
+ else {
+ res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0,
+ NULL, NULL);
+ if (res)
+ printk(KERN_DEBUG "%s: reset port failed to enable "
+ "port\n", dev->name);
+ }
+
+ /* It looks like at least some STA firmware versions reset
+ * fragmentation threshold back to 2346 after enable command. Restore
+ * the configured value, if it differs from this default. */
+ if (local->fragm_threshold != 2346 &&
+ hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
+ local->fragm_threshold)) {
+ printk(KERN_DEBUG "%s: failed to restore fragmentation "
+ "threshold (%d) after Port0 enable\n",
+ dev->name, local->fragm_threshold);
+ }
+
+ return res;
+}
+
+
+static int prism2_get_version_info(struct net_device *dev, u16 rid,
+ const char *txt)
+{
+ struct hfa384x_comp_ident comp;
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->no_pri) {
+ /* PRI f/w not yet available - cannot read RIDs */
+ return -1;
+ }
+ if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) {
+ printk(KERN_DEBUG "Could not get RID for component %s\n", txt);
+ return -1;
+ }
+
+ printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt,
+ __le16_to_cpu(comp.id), __le16_to_cpu(comp.major),
+ __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant));
+ return 0;
+}
+
+
+static int prism2_setup_rids(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 tmp;
+ int ret = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000);
+
+ if (!local->fw_ap) {
+ tmp = hostap_get_porttype(local);
+ ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp);
+ if (ret) {
+ printk("%s: Port type setting to %d failed\n",
+ dev->name, tmp);
+ goto fail;
+ }
+ }
+
+ /* Setting SSID to empty string seems to kill the card in Host AP mode
+ */
+ if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') {
+ ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID,
+ local->essid);
+ if (ret) {
+ printk("%s: AP own SSID setting failed\n", dev->name);
+ goto fail;
+ }
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN,
+ PRISM2_DATA_MAXLEN);
+ if (ret) {
+ printk("%s: MAC data length setting to %d failed\n",
+ dev->name, PRISM2_DATA_MAXLEN);
+ goto fail;
+ }
+
+ if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) {
+ printk("%s: Channel list read failed\n", dev->name);
+ ret = -EINVAL;
+ goto fail;
+ }
+ local->channel_mask = __le16_to_cpu(tmp);
+
+ if (local->channel < 1 || local->channel > 14 ||
+ !(local->channel_mask & (1 << (local->channel - 1)))) {
+ printk(KERN_WARNING "%s: Channel setting out of range "
+ "(%d)!\n", dev->name, local->channel);
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel);
+ if (ret) {
+ printk("%s: Channel setting to %d failed\n",
+ dev->name, local->channel);
+ goto fail;
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT,
+ local->beacon_int);
+ if (ret) {
+ printk("%s: Beacon interval setting to %d failed\n",
+ dev->name, local->beacon_int);
+ /* this may fail with Symbol/Lucent firmware */
+ if (ret == -ETIMEDOUT)
+ goto fail;
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD,
+ local->dtim_period);
+ if (ret) {
+ printk("%s: DTIM period setting to %d failed\n",
+ dev->name, local->dtim_period);
+ /* this may fail with Symbol/Lucent firmware */
+ if (ret == -ETIMEDOUT)
+ goto fail;
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
+ local->is_promisc);
+ if (ret)
+ printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n",
+ dev->name, local->is_promisc);
+
+ if (!local->fw_ap) {
+ ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID,
+ local->essid);
+ if (ret) {
+ printk("%s: Desired SSID setting failed\n", dev->name);
+ goto fail;
+ }
+ }
+
+ /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and
+ * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic
+ * rates */
+ if (local->tx_rate_control == 0) {
+ local->tx_rate_control =
+ HFA384X_RATES_1MBPS |
+ HFA384X_RATES_2MBPS |
+ HFA384X_RATES_5MBPS |
+ HFA384X_RATES_11MBPS;
+ }
+ if (local->basic_rates == 0)
+ local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS;
+
+ if (!local->fw_ap) {
+ ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
+ local->tx_rate_control);
+ if (ret) {
+ printk("%s: TXRateControl setting to %d failed\n",
+ dev->name, local->tx_rate_control);
+ goto fail;
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
+ local->tx_rate_control);
+ if (ret) {
+ printk("%s: cnfSupportedRates setting to %d failed\n",
+ dev->name, local->tx_rate_control);
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
+ local->basic_rates);
+ if (ret) {
+ printk("%s: cnfBasicRates setting to %d failed\n",
+ dev->name, local->basic_rates);
+ }
+
+ ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1);
+ if (ret) {
+ printk("%s: Create IBSS setting to 1 failed\n",
+ dev->name);
+ }
+ }
+
+ if (local->name_set)
+ (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME,
+ local->name);
+
+ if (hostap_set_encryption(local)) {
+ printk(KERN_INFO "%s: could not configure encryption\n",
+ dev->name);
+ }
+
+ (void) hostap_set_antsel(local);
+
+ if (hostap_set_roaming(local)) {
+ printk(KERN_INFO "%s: could not set host roaming\n",
+ dev->name);
+ }
+
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) &&
+ hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec))
+ printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n",
+ dev->name, local->enh_sec);
+
+ /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently
+ * not working correctly (last seven counters report bogus values).
+ * This has been fixed in 0.8.2, so enable 32-bit tallies only
+ * beginning with that firmware version. Another bug fix for 32-bit
+ * tallies in 1.4.0; should 16-bit tallies be used for some other
+ * versions, too? */
+ if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) {
+ if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) {
+ printk(KERN_INFO "%s: cnfThirty2Tally setting "
+ "failed\n", dev->name);
+ local->tallies32 = 0;
+ } else
+ local->tallies32 = 1;
+ } else
+ local->tallies32 = 0;
+
+ hostap_set_auth_algs(local);
+
+ if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
+ local->fragm_threshold)) {
+ printk(KERN_INFO "%s: setting FragmentationThreshold to %d "
+ "failed\n", dev->name, local->fragm_threshold);
+ }
+
+ if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD,
+ local->rts_threshold)) {
+ printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n",
+ dev->name, local->rts_threshold);
+ }
+
+ if (local->manual_retry_count >= 0 &&
+ hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
+ local->manual_retry_count)) {
+ printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n",
+ dev->name, local->manual_retry_count);
+ }
+
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) &&
+ hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) {
+ local->rssi_to_dBm = le16_to_cpu(tmp);
+ }
+
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa &&
+ hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) {
+ printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n",
+ dev->name);
+ }
+
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem &&
+ hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT,
+ local->generic_elem, local->generic_elem_len)) {
+ printk(KERN_INFO "%s: setting genericElement failed\n",
+ dev->name);
+ }
+
+ fail:
+ return ret;
+}
+
+
+static int prism2_hw_init(struct net_device *dev, int initial)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret, first = 1;
+ unsigned long start, delay;
+
+ PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n");
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits);
+
+ init:
+ /* initialize HFA 384x */
+ ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0);
+ if (ret) {
+ printk(KERN_INFO "%s: first command failed - assuming card "
+ "does not have primary firmware\n", dev_info);
+ }
+
+ if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
+ /* EvStat has Cmd bit set in some cases, so retry once if no
+ * wait was needed */
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+ printk(KERN_DEBUG "%s: init command completed too quickly - "
+ "retrying\n", dev->name);
+ first = 0;
+ goto init;
+ }
+
+ start = jiffies;
+ delay = jiffies + HFA384X_INIT_TIMEOUT;
+ while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
+ time_before(jiffies, delay))
+ yield();
+ if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
+ printk(KERN_DEBUG "%s: assuming no Primary image in "
+ "flash - card initialization not completed\n",
+ dev_info);
+ local->no_pri = 1;
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ if (local->sram_type == -1)
+ local->sram_type = prism2_get_ram_size(local);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+ return 1;
+ }
+ local->no_pri = 0;
+ printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n",
+ (jiffies - start) * 1000 / HZ);
+ HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
+ return 0;
+}
+
+
+static int prism2_hw_init2(struct net_device *dev, int initial)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int i;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ kfree(local->pda);
+ if (local->no_pri)
+ local->pda = NULL;
+ else
+ local->pda = prism2_read_pda(dev);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+ hfa384x_disable_interrupts(dev);
+
+#ifndef final_version
+ HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF);
+ if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
+ printk("SWSUPPORT0 write/read failed: %04X != %04X\n",
+ HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC);
+ goto failed;
+ }
+#endif
+
+ if (initial || local->pri_only) {
+ hfa384x_events_only_cmd(dev);
+ /* get card version information */
+ if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") ||
+ prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) {
+ hfa384x_disable_interrupts(dev);
+ goto failed;
+ }
+
+ if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) {
+ printk(KERN_DEBUG "%s: Failed to read STA f/w version "
+ "- only Primary f/w present\n", dev->name);
+ local->pri_only = 1;
+ return 0;
+ }
+ local->pri_only = 0;
+ hfa384x_disable_interrupts(dev);
+ }
+
+ /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and
+ * enable interrupts before this. This would also require some sort of
+ * sleeping AllocEv waiting */
+
+ /* allocate TX FIDs */
+ local->txfid_len = PRISM2_TXFID_LEN;
+ for (i = 0; i < PRISM2_TXFID_COUNT; i++) {
+ local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len);
+ if (local->txfid[i] == 0xffff && local->txfid_len > 1600) {
+ local->txfid[i] = hfa384x_allocate_fid(dev, 1600);
+ if (local->txfid[i] != 0xffff) {
+ printk(KERN_DEBUG "%s: Using shorter TX FID "
+ "(1600 bytes)\n", dev->name);
+ local->txfid_len = 1600;
+ }
+ }
+ if (local->txfid[i] == 0xffff)
+ goto failed;
+ local->intransmitfid[i] = PRISM2_TXFID_EMPTY;
+ }
+
+ hfa384x_events_only_cmd(dev);
+
+ if (initial) {
+ struct list_head *ptr;
+ prism2_check_sta_fw_version(local);
+
+ if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR,
+ &dev->dev_addr, 6, 1) < 0) {
+ printk("%s: could not get own MAC address\n",
+ dev->name);
+ }
+ list_for_each(ptr, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN);
+ }
+ } else if (local->fw_ap)
+ prism2_check_sta_fw_version(local);
+
+ prism2_setup_rids(dev);
+
+ /* MAC is now configured, but port 0 is not yet enabled */
+ return 0;
+
+ failed:
+ if (!local->no_pri)
+ printk(KERN_WARNING "%s: Initialization failed\n", dev_info);
+ return 1;
+}
+
+
+static int prism2_hw_enable(struct net_device *dev, int initial)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int was_resetting;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ was_resetting = local->hw_resetting;
+
+ if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) {
+ printk("%s: MAC port 0 enabling failed\n", dev->name);
+ return 1;
+ }
+
+ local->hw_ready = 1;
+ local->hw_reset_tries = 0;
+ local->hw_resetting = 0;
+ hfa384x_enable_interrupts(dev);
+
+ /* at least D-Link DWL-650 seems to require additional port reset
+ * before it starts acting as an AP, so reset port automatically
+ * here just in case */
+ if (initial && prism2_reset_port(dev)) {
+ printk("%s: MAC port 0 reseting failed\n", dev->name);
+ return 1;
+ }
+
+ if (was_resetting && netif_queue_stopped(dev)) {
+ /* If hw_reset() was called during pending transmit, netif
+ * queue was stopped. Wake it up now since the wlan card has
+ * been resetted. */
+ netif_wake_queue(dev);
+ }
+
+ return 0;
+}
+
+
+static int prism2_hw_config(struct net_device *dev, int initial)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->hw_downloading)
+ return 1;
+
+ if (prism2_hw_init(dev, initial)) {
+ return local->no_pri ? 0 : 1;
+ }
+
+ if (prism2_hw_init2(dev, initial))
+ return 1;
+
+ /* Enable firmware if secondary image is loaded and at least one of the
+ * netdevices is up. */
+ if (!local->pri_only &&
+ (initial == 0 || (initial == 2 && local->num_dev_open > 0))) {
+ if (!local->dev_enabled)
+ prism2_callback(local, PRISM2_CALLBACK_ENABLE);
+ local->dev_enabled = 1;
+ return prism2_hw_enable(dev, initial);
+ }
+
+ return 0;
+}
+
+
+static void prism2_hw_shutdown(struct net_device *dev, int no_disable)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* Allow only command completion events during disable */
+ hfa384x_events_only_cmd(dev);
+
+ local->hw_ready = 0;
+ if (local->dev_enabled)
+ prism2_callback(local, PRISM2_CALLBACK_DISABLE);
+ local->dev_enabled = 0;
+
+ if (local->func->card_present && !local->func->card_present(local)) {
+ printk(KERN_DEBUG "%s: card already removed or not configured "
+ "during shutdown\n", dev->name);
+ return;
+ }
+
+ if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 &&
+ hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL))
+ printk(KERN_WARNING "%s: Shutdown failed\n", dev_info);
+
+ hfa384x_disable_interrupts(dev);
+
+ if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL)
+ hfa384x_events_only_cmd(dev);
+ else
+ prism2_clear_cmd_queue(local);
+}
+
+
+static void prism2_hw_reset(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+#if 0
+ static long last_reset = 0;
+
+ /* do not reset card more than once per second to avoid ending up in a
+ * busy loop reseting the card */
+ if (time_before_eq(jiffies, last_reset + HZ))
+ return;
+ last_reset = jiffies;
+#endif
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (in_interrupt()) {
+ printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called "
+ "in interrupt context\n", dev->name);
+ return;
+ }
+
+ if (local->hw_downloading)
+ return;
+
+ if (local->hw_resetting) {
+ printk(KERN_WARNING "%s: %s: already resetting card - "
+ "ignoring reset request\n", dev_info, dev->name);
+ return;
+ }
+
+ local->hw_reset_tries++;
+ if (local->hw_reset_tries > 10) {
+ printk(KERN_WARNING "%s: too many reset tries, skipping\n",
+ dev->name);
+ return;
+ }
+
+ printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name);
+ hfa384x_disable_interrupts(dev);
+ local->hw_resetting = 1;
+ if (local->func->cor_sreset) {
+ /* Host system seems to hang in some cases with high traffic
+ * load or shared interrupts during COR sreset. Disable shared
+ * interrupts during reset to avoid these crashes. COS sreset
+ * takes quite a long time, so it is unfortunate that this
+ * seems to be needed. Anyway, I do not know of any better way
+ * of avoiding the crash. */
+ disable_irq(dev->irq);
+ local->func->cor_sreset(local);
+ enable_irq(dev->irq);
+ }
+ prism2_hw_shutdown(dev, 1);
+ prism2_hw_config(dev, 0);
+ local->hw_resetting = 0;
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ if (local->dl_pri) {
+ printk(KERN_DEBUG "%s: persistent download of primary "
+ "firmware\n", dev->name);
+ if (prism2_download_genesis(local, local->dl_pri) < 0)
+ printk(KERN_WARNING "%s: download (PRI) failed\n",
+ dev->name);
+ }
+
+ if (local->dl_sec) {
+ printk(KERN_DEBUG "%s: persistent download of secondary "
+ "firmware\n", dev->name);
+ if (prism2_download_volatile(local, local->dl_sec) < 0)
+ printk(KERN_WARNING "%s: download (SEC) failed\n",
+ dev->name);
+ }
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+ /* TODO: restore beacon TIM bits for STAs that have buffered frames */
+}
+
+
+static void prism2_schedule_reset(local_info_t *local)
+{
+ schedule_work(&local->reset_queue);
+}
+
+
+/* Called only as scheduled task after noticing card timeout in interrupt
+ * context */
+static void handle_reset_queue(void *data)
+{
+ local_info_t *local = (local_info_t *) data;
+
+ printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);
+ prism2_hw_reset(local->dev);
+
+ if (netif_queue_stopped(local->dev)) {
+ int i;
+
+ for (i = 0; i < PRISM2_TXFID_COUNT; i++)
+ if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) {
+ PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: "
+ "wake up queue\n");
+ netif_wake_queue(local->dev);
+ break;
+ }
+ }
+}
+
+
+static int prism2_get_txfid_idx(local_info_t *local)
+{
+ int idx, end;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->txfidlock, flags);
+ end = idx = local->next_txfid;
+ do {
+ if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
+ local->intransmitfid[idx] = PRISM2_TXFID_RESERVED;
+ spin_unlock_irqrestore(&local->txfidlock, flags);
+ return idx;
+ }
+ idx++;
+ if (idx >= PRISM2_TXFID_COUNT)
+ idx = 0;
+ } while (idx != end);
+ spin_unlock_irqrestore(&local->txfidlock, flags);
+
+ PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "
+ "packet dropped\n");
+ local->stats.tx_dropped++;
+
+ return -1;
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_transmit_cb(struct net_device *dev, long context,
+ u16 resp0, u16 res)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int idx = (int) context;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (res) {
+ printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n",
+ dev->name, res);
+ return;
+ }
+
+ if (idx < 0 || idx >= PRISM2_TXFID_COUNT) {
+ printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid "
+ "idx=%d\n", dev->name, idx);
+ return;
+ }
+
+ if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
+ printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called "
+ "with no pending transmit\n", dev->name);
+ }
+
+ if (netif_queue_stopped(dev)) {
+ /* ready for next TX, so wake up queue that was stopped in
+ * prism2_transmit() */
+ netif_wake_queue(dev);
+ }
+
+ spin_lock(&local->txfidlock);
+
+ /* With reclaim, Resp0 contains new txfid for transmit; the old txfid
+ * will be automatically allocated for the next TX frame */
+ local->intransmitfid[idx] = resp0;
+
+ PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, "
+ "resp0=0x%04x, transmit_txfid=0x%04x\n",
+ dev->name, idx, local->txfid[idx],
+ resp0, local->intransmitfid[local->next_txfid]);
+
+ idx++;
+ if (idx >= PRISM2_TXFID_COUNT)
+ idx = 0;
+ local->next_txfid = idx;
+
+ /* check if all TX buffers are occupied */
+ do {
+ if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
+ spin_unlock(&local->txfidlock);
+ return;
+ }
+ idx++;
+ if (idx >= PRISM2_TXFID_COUNT)
+ idx = 0;
+ } while (idx != local->next_txfid);
+ spin_unlock(&local->txfidlock);
+
+ /* no empty TX buffers, stop queue */
+ netif_stop_queue(dev);
+}
+
+
+/* Called only from software IRQ if PCI bus master is not used (with bus master
+ * this can be called both from software and hardware IRQ) */
+static int prism2_transmit(struct net_device *dev, int idx)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int res;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* The driver tries to stop netif queue so that there would not be
+ * more than one attempt to transmit frames going on; check that this
+ * is really the case */
+
+ if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
+ printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called "
+ "when previous TX was pending\n", dev->name);
+ return -1;
+ }
+
+ /* stop the queue for the time that transmit is pending */
+ netif_stop_queue(dev);
+
+ /* transmit packet */
+ res = hfa384x_cmd_callback(
+ dev,
+ HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM,
+ local->txfid[idx],
+ prism2_transmit_cb, (long) idx);
+
+ if (res) {
+ struct net_device_stats *stats;
+ printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "
+ "failed (res=%d)\n", dev->name, res);
+ stats = hostap_get_stats(dev);
+ stats->tx_dropped++;
+ netif_wake_queue(dev);
+ return -1;
+ }
+ dev->trans_start = jiffies;
+
+ /* Since we did not wait for command completion, the card continues
+ * to process on the background and we will finish handling when
+ * command completion event is handled (prism2_cmd_ev() function) */
+
+ return 0;
+}
+
+
+/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and
+ * send the payload with this descriptor) */
+/* Called only from software IRQ */
+static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hfa384x_tx_frame txdesc;
+ struct hostap_skb_tx_data *meta;
+ int hdr_len, data_len, idx, res, ret = -1;
+ u16 tx_control, fc;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ meta = (struct hostap_skb_tx_data *) skb->cb;
+
+ prism2_callback(local, PRISM2_CALLBACK_TX_START);
+
+ if ((local->func->card_present && !local->func->card_present(local)) ||
+ !local->hw_ready || local->hw_downloading || local->pri_only) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -"
+ " skipping\n", dev->name);
+ }
+ goto fail;
+ }
+
+ memset(&txdesc, 0, sizeof(txdesc));
+
+ /* skb->data starts with txdesc->frame_control */
+ hdr_len = 24;
+ memcpy(&txdesc.frame_control, skb->data, hdr_len);
+ fc = le16_to_cpu(txdesc.frame_control);
+ if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+ (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) &&
+ skb->len >= 30) {
+ /* Addr4 */
+ memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN);
+ hdr_len += ETH_ALEN;
+ }
+
+ tx_control = local->tx_control;
+ if (meta->tx_cb_idx) {
+ tx_control |= HFA384X_TX_CTRL_TX_OK;
+ txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx);
+ }
+ txdesc.tx_control = cpu_to_le16(tx_control);
+ txdesc.tx_rate = meta->rate;
+
+ data_len = skb->len - hdr_len;
+ txdesc.data_len = cpu_to_le16(data_len);
+ txdesc.len = cpu_to_be16(data_len);
+
+ idx = prism2_get_txfid_idx(local);
+ if (idx < 0)
+ goto fail;
+
+ if (local->frame_dump & PRISM2_DUMP_TX_HDR)
+ hostap_dump_tx_header(dev->name, &txdesc);
+
+ spin_lock(&local->baplock);
+ res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0);
+
+ if (!res)
+ res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc));
+ if (!res)
+ res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len,
+ skb->len - hdr_len);
+ spin_unlock(&local->baplock);
+
+ if (!res)
+ res = prism2_transmit(dev, idx);
+ if (res) {
+ printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n",
+ dev->name);
+ local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
+ schedule_work(&local->reset_queue);
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ prism2_callback(local, PRISM2_CALLBACK_TX_END);
+ return ret;
+}
+
+
+/* Some SMP systems have reported number of odd errors with hostap_pci. fid
+ * register has changed values between consecutive reads for an unknown reason.
+ * This should really not happen, so more debugging is needed. This test
+ * version is a big slower, but it will detect most of such register changes
+ * and will try to get the correct fid eventually. */
+#define EXTRA_FID_READ_TESTS
+
+static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
+{
+#ifdef EXTRA_FID_READ_TESTS
+ u16 val, val2, val3;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ val = HFA384X_INW(reg);
+ val2 = HFA384X_INW(reg);
+ val3 = HFA384X_INW(reg);
+
+ if (val == val2 && val == val3)
+ return val;
+
+ printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):"
+ " %04x %04x %04x\n",
+ dev->name, i, reg, val, val2, val3);
+ if ((val == val2 || val == val3) && val != 0)
+ return val;
+ if (val2 == val3 && val2 != 0)
+ return val2;
+ }
+ printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg "
+ "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3);
+ return val;
+#else /* EXTRA_FID_READ_TESTS */
+ return HFA384X_INW(reg);
+#endif /* EXTRA_FID_READ_TESTS */
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_rx(local_info_t *local)
+{
+ struct net_device *dev = local->dev;
+ int res, rx_pending = 0;
+ u16 len, hdr_len, rxfid, status, macport;
+ struct net_device_stats *stats;
+ struct hfa384x_rx_frame rxdesc;
+ struct sk_buff *skb = NULL;
+
+ prism2_callback(local, PRISM2_CALLBACK_RX_START);
+ stats = hostap_get_stats(dev);
+
+ rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);
+#ifndef final_version
+ if (rxfid == 0) {
+ rxfid = HFA384X_INW(HFA384X_RXFID_OFF);
+ printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n",
+ rxfid);
+ if (rxfid == 0) {
+ schedule_work(&local->reset_queue);
+ goto rx_dropped;
+ }
+ /* try to continue with the new rxfid value */
+ }
+#endif
+
+ spin_lock(&local->baplock);
+ res = hfa384x_setup_bap(dev, BAP0, rxfid, 0);
+ if (!res)
+ res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc));
+
+ if (res) {
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name,
+ res);
+ if (res == -ETIMEDOUT) {
+ schedule_work(&local->reset_queue);
+ }
+ goto rx_dropped;
+ }
+
+ len = le16_to_cpu(rxdesc.data_len);
+ hdr_len = sizeof(rxdesc);
+ status = le16_to_cpu(rxdesc.status);
+ macport = (status >> 8) & 0x07;
+
+ /* Drop frames with too large reported payload length. Monitor mode
+ * seems to sometimes pass frames (e.g., ctrl::ack) with signed and
+ * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for
+ * macport 7 */
+ if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {
+ if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {
+ if (len >= (u16) -14) {
+ hdr_len -= 65535 - len;
+ hdr_len--;
+ }
+ len = 0;
+ } else {
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "%s: Received frame with invalid "
+ "length 0x%04x\n", dev->name, len);
+ hostap_dump_rx_header(dev->name, &rxdesc);
+ goto rx_dropped;
+ }
+ }
+
+ skb = dev_alloc_skb(len + hdr_len);
+ if (!skb) {
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "%s: RX failed to allocate skb\n",
+ dev->name);
+ goto rx_dropped;
+ }
+ skb->dev = dev;
+ memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len);
+
+ if (len > 0)
+ res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len);
+ spin_unlock(&local->baplock);
+ if (res) {
+ printk(KERN_DEBUG "%s: RX failed to read "
+ "frame data\n", dev->name);
+ goto rx_dropped;
+ }
+
+ skb_queue_tail(&local->rx_list, skb);
+ tasklet_schedule(&local->rx_tasklet);
+
+ rx_exit:
+ prism2_callback(local, PRISM2_CALLBACK_RX_END);
+ if (!rx_pending) {
+ HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF);
+ }
+
+ return;
+
+ rx_dropped:
+ stats->rx_dropped++;
+ if (skb)
+ dev_kfree_skb(skb);
+ goto rx_exit;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
+{
+ struct hfa384x_rx_frame *rxdesc;
+ struct net_device *dev = skb->dev;
+ struct hostap_80211_rx_status stats;
+ int hdrlen, rx_hdrlen;
+
+ rx_hdrlen = sizeof(*rxdesc);
+ if (skb->len < sizeof(*rxdesc)) {
+ /* Allow monitor mode to receive shorter frames */
+ if (local->iw_mode == IW_MODE_MONITOR &&
+ skb->len >= sizeof(*rxdesc) - 30) {
+ rx_hdrlen = skb->len;
+ } else {
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
+ rxdesc = (struct hfa384x_rx_frame *) skb->data;
+
+ if (local->frame_dump & PRISM2_DUMP_RX_HDR &&
+ skb->len >= sizeof(*rxdesc))
+ hostap_dump_rx_header(dev->name, rxdesc);
+
+ if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&
+ (!local->monitor_allow_fcserr ||
+ local->iw_mode != IW_MODE_MONITOR))
+ goto drop;
+
+ if (skb->len > PRISM2_DATA_MAXLEN) {
+ printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n",
+ dev->name, skb->len, PRISM2_DATA_MAXLEN);
+ goto drop;
+ }
+
+ stats.mac_time = le32_to_cpu(rxdesc->time);
+ stats.signal = rxdesc->signal - local->rssi_to_dBm;
+ stats.noise = rxdesc->silence - local->rssi_to_dBm;
+ stats.rate = rxdesc->rate;
+
+ /* Convert Prism2 RX structure into IEEE 802.11 header */
+ hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control));
+ if (hdrlen > rx_hdrlen)
+ hdrlen = rx_hdrlen;
+
+ memmove(skb_pull(skb, rx_hdrlen - hdrlen),
+ &rxdesc->frame_control, hdrlen);
+
+ hostap_80211_rx(dev, skb, &stats);
+ return;
+
+ drop:
+ dev_kfree_skb(skb);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_rx_tasklet(unsigned long data)
+{
+ local_info_t *local = (local_info_t *) data;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&local->rx_list)) != NULL)
+ hostap_rx_skb(local, skb);
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_alloc_ev(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int idx;
+ u16 fid;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF);
+
+ PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid);
+
+ spin_lock(&local->txfidlock);
+ idx = local->next_alloc;
+
+ do {
+ if (local->txfid[idx] == fid) {
+ PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n",
+ idx);
+
+#ifndef final_version
+ if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY)
+ printk("Already released txfid found at idx "
+ "%d\n", idx);
+ if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED)
+ printk("Already reserved txfid found at idx "
+ "%d\n", idx);
+#endif
+ local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
+ idx++;
+ local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 :
+ idx;
+
+ if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) &&
+ netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+
+ spin_unlock(&local->txfidlock);
+ return;
+ }
+
+ idx++;
+ if (idx >= PRISM2_TXFID_COUNT)
+ idx = 0;
+ } while (idx != local->next_alloc);
+
+ printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new "
+ "read 0x%04x) for alloc event\n", dev->name, fid,
+ HFA384X_INW(HFA384X_ALLOCFID_OFF));
+ printk(KERN_DEBUG "TXFIDs:");
+ for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++)
+ printk(" %04x[%04x]", local->txfid[idx],
+ local->intransmitfid[idx]);
+ printk("\n");
+ spin_unlock(&local->txfidlock);
+
+ /* FIX: should probably schedule reset; reference to one txfid was lost
+ * completely.. Bad things will happen if we run out of txfids
+ * Actually, this will cause netdev watchdog to notice TX timeout and
+ * then card reset after all txfids have been leaked. */
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_tx_callback(local_info_t *local,
+ struct hfa384x_tx_frame *txdesc, int ok,
+ char *payload)
+{
+ u16 sw_support, hdrlen, len;
+ struct sk_buff *skb;
+ struct hostap_tx_callback_info *cb;
+
+ /* Make sure that frame was from us. */
+ if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) {
+ printk(KERN_DEBUG "%s: TX callback - foreign frame\n",
+ local->dev->name);
+ return;
+ }
+
+ sw_support = le16_to_cpu(txdesc->sw_support);
+
+ spin_lock(&local->lock);
+ cb = local->tx_callback;
+ while (cb != NULL && cb->idx != sw_support)
+ cb = cb->next;
+ spin_unlock(&local->lock);
+
+ if (cb == NULL) {
+ printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n",
+ local->dev->name, sw_support);
+ return;
+ }
+
+ hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control));
+ len = le16_to_cpu(txdesc->data_len);
+ skb = dev_alloc_skb(hdrlen + len);
+ if (skb == NULL) {
+ printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate "
+ "skb\n", local->dev->name);
+ return;
+ }
+
+ memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen);
+ if (payload)
+ memcpy(skb_put(skb, len), payload, len);
+
+ skb->dev = local->dev;
+ skb->mac.raw = skb->data;
+
+ cb->func(skb, ok, cb->data);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static int hostap_tx_compl_read(local_info_t *local, int error,
+ struct hfa384x_tx_frame *txdesc,
+ char **payload)
+{
+ u16 fid, len;
+ int res, ret = 0;
+ struct net_device *dev = local->dev;
+
+ fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF);
+
+ PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error);
+
+ spin_lock(&local->baplock);
+ res = hfa384x_setup_bap(dev, BAP0, fid, 0);
+ if (!res)
+ res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc));
+ if (res) {
+ PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not "
+ "read txdesc\n", dev->name, error, fid);
+ if (res == -ETIMEDOUT) {
+ schedule_work(&local->reset_queue);
+ }
+ ret = -1;
+ goto fail;
+ }
+ if (txdesc->sw_support) {
+ len = le16_to_cpu(txdesc->data_len);
+ if (len < PRISM2_DATA_MAXLEN) {
+ *payload = (char *) kmalloc(len, GFP_ATOMIC);
+ if (*payload == NULL ||
+ hfa384x_from_bap(dev, BAP0, *payload, len)) {
+ PDEBUG(DEBUG_EXTRA, "%s: could not read TX "
+ "frame payload\n", dev->name);
+ kfree(*payload);
+ *payload = NULL;
+ ret = -1;
+ goto fail;
+ }
+ }
+ }
+
+ fail:
+ spin_unlock(&local->baplock);
+
+ return ret;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_tx_ev(local_info_t *local)
+{
+ struct net_device *dev = local->dev;
+ char *payload = NULL;
+ struct hfa384x_tx_frame txdesc;
+
+ if (hostap_tx_compl_read(local, 0, &txdesc, &payload))
+ goto fail;
+
+ if (local->frame_dump & PRISM2_DUMP_TX_HDR) {
+ PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x "
+ "retry_count=%d tx_rate=%d seq_ctrl=%d "
+ "duration_id=%d\n",
+ dev->name, le16_to_cpu(txdesc.status),
+ txdesc.retry_count, txdesc.tx_rate,
+ le16_to_cpu(txdesc.seq_ctrl),
+ le16_to_cpu(txdesc.duration_id));
+ }
+
+ if (txdesc.sw_support)
+ hostap_tx_callback(local, &txdesc, 1, payload);
+ kfree(payload);
+
+ fail:
+ HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_sta_tx_exc_tasklet(unsigned long data)
+{
+ local_info_t *local = (local_info_t *) data;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) {
+ struct hfa384x_tx_frame *txdesc =
+ (struct hfa384x_tx_frame *) skb->data;
+
+ if (skb->len >= sizeof(*txdesc)) {
+ /* Convert Prism2 RX structure into IEEE 802.11 header
+ */
+ u16 fc = le16_to_cpu(txdesc->frame_control);
+ int hdrlen = hostap_80211_get_hdrlen(fc);
+ memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen),
+ &txdesc->frame_control, hdrlen);
+
+ hostap_handle_sta_tx_exc(local, skb);
+ }
+ dev_kfree_skb(skb);
+ }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_txexc(local_info_t *local)
+{
+ struct net_device *dev = local->dev;
+ u16 status, fc;
+ int show_dump, res;
+ char *payload = NULL;
+ struct hfa384x_tx_frame txdesc;
+
+ show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
+ local->stats.tx_errors++;
+
+ res = hostap_tx_compl_read(local, 1, &txdesc, &payload);
+ HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF);
+ if (res)
+ return;
+
+ status = le16_to_cpu(txdesc.status);
+
+ /* We produce a TXDROP event only for retry or lifetime
+ * exceeded, because that's the only status that really mean
+ * that this particular node went away.
+ * Other errors means that *we* screwed up. - Jean II */
+ if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR))
+ {
+ union iwreq_data wrqu;
+
+ /* Copy 802.11 dest address. */
+ memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+ } else
+ show_dump = 1;
+
+ if (local->iw_mode == IW_MODE_MASTER ||
+ local->iw_mode == IW_MODE_REPEAT ||
+ local->wds_type & HOSTAP_WDS_AP_CLIENT) {
+ struct sk_buff *skb;
+ skb = dev_alloc_skb(sizeof(txdesc));
+ if (skb) {
+ memcpy(skb_put(skb, sizeof(txdesc)), &txdesc,
+ sizeof(txdesc));
+ skb_queue_tail(&local->sta_tx_exc_list, skb);
+ tasklet_schedule(&local->sta_tx_exc_tasklet);
+ }
+ }
+
+ if (txdesc.sw_support)
+ hostap_tx_callback(local, &txdesc, 0, payload);
+ kfree(payload);
+
+ if (!show_dump)
+ return;
+
+ PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)"
+ " tx_control=%04x\n",
+ dev->name, status,
+ status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "",
+ status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "",
+ status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "",
+ status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "",
+ le16_to_cpu(txdesc.tx_control));
+
+ fc = le16_to_cpu(txdesc.frame_control);
+ PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x "
+ "(%s%s%s::%d%s%s)\n",
+ txdesc.retry_count, txdesc.tx_rate, fc,
+ WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT ? "Mgmt" : "",
+ WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL ? "Ctrl" : "",
+ WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA ? "Data" : "",
+ WLAN_FC_GET_STYPE(fc) >> 4,
+ fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
+ fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
+ PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3="
+ MACSTR " A4=" MACSTR "\n",
+ MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2),
+ MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4));
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_info_tasklet(unsigned long data)
+{
+ local_info_t *local = (local_info_t *) data;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&local->info_list)) != NULL) {
+ hostap_info_process(local, skb);
+ dev_kfree_skb(skb);
+ }
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info(local_info_t *local)
+{
+ struct net_device *dev = local->dev;
+ u16 fid;
+ int res, left;
+ struct hfa384x_info_frame info;
+ struct sk_buff *skb;
+
+ fid = HFA384X_INW(HFA384X_INFOFID_OFF);
+
+ spin_lock(&local->baplock);
+ res = hfa384x_setup_bap(dev, BAP0, fid, 0);
+ if (!res)
+ res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info));
+ if (res) {
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n",
+ fid);
+ if (res == -ETIMEDOUT) {
+ schedule_work(&local->reset_queue);
+ }
+ goto out;
+ }
+
+ le16_to_cpus(&info.len);
+ le16_to_cpus(&info.type);
+ left = (info.len - 1) * 2;
+
+ if (info.len & 0x8000 || info.len == 0 || left > 2060) {
+ /* data register seems to give 0x8000 in some error cases even
+ * though busy bit is not set in offset register;
+ * in addition, length must be at least 1 due to type field */
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "%s: Received info frame with invalid "
+ "length 0x%04x (type 0x%04x)\n", dev->name, info.len,
+ info.type);
+ goto out;
+ }
+
+ skb = dev_alloc_skb(sizeof(info) + left);
+ if (skb == NULL) {
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "%s: Could not allocate skb for info "
+ "frame\n", dev->name);
+ goto out;
+ }
+
+ memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info));
+ if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left))
+ {
+ spin_unlock(&local->baplock);
+ printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, "
+ "len=0x%04x, type=0x%04x\n",
+ dev->name, fid, info.len, info.type);
+ dev_kfree_skb(skb);
+ goto out;
+ }
+ spin_unlock(&local->baplock);
+
+ skb_queue_tail(&local->info_list, skb);
+ tasklet_schedule(&local->info_tasklet);
+
+ out:
+ HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void hostap_bap_tasklet(unsigned long data)
+{
+ local_info_t *local = (local_info_t *) data;
+ struct net_device *dev = local->dev;
+ u16 ev;
+ int frames = 30;
+
+ if (local->func->card_present && !local->func->card_present(local))
+ return;
+
+ set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
+
+ /* Process all pending BAP events without generating new interrupts
+ * for them */
+ while (frames-- > 0) {
+ ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS))
+ break;
+ if (ev & HFA384X_EV_RX)
+ prism2_rx(local);
+ if (ev & HFA384X_EV_INFO)
+ prism2_info(local);
+ if (ev & HFA384X_EV_TX)
+ prism2_tx_ev(local);
+ if (ev & HFA384X_EV_TXEXC)
+ prism2_txexc(local);
+ }
+
+ set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
+ clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
+
+ /* Enable interrupts for new BAP events */
+ hfa384x_events_all(dev);
+ clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_infdrop(struct net_device *dev)
+{
+ static unsigned long last_inquire = 0;
+
+ PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name);
+
+ /* some firmware versions seem to get stuck with
+ * full CommTallies in high traffic load cases; every
+ * packet will then cause INFDROP event and CommTallies
+ * info frame will not be sent automatically. Try to
+ * get out of this state by inquiring CommTallies. */
+ if (!last_inquire || time_after(jiffies, last_inquire + HZ)) {
+ hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE,
+ HFA384X_INFO_COMMTALLIES, NULL, 0);
+ last_inquire = jiffies;
+ }
+}
+
+
+/* Called only from hardware IRQ */
+static void prism2_ev_tick(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 evstat, inten;
+ static int prev_stuck = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (time_after(jiffies, local->last_tick_timer + 5 * HZ) &&
+ local->last_tick_timer) {
+ evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ inten = HFA384X_INW(HFA384X_INTEN_OFF);
+ if (!prev_stuck) {
+ printk(KERN_INFO "%s: SW TICK stuck? "
+ "bits=0x%lx EvStat=%04x IntEn=%04x\n",
+ dev->name, local->bits, evstat, inten);
+ }
+ local->sw_tick_stuck++;
+ if ((evstat & HFA384X_BAP0_EVENTS) &&
+ (inten & HFA384X_BAP0_EVENTS)) {
+ printk(KERN_INFO "%s: trying to recover from IRQ "
+ "hang\n", dev->name);
+ hfa384x_events_no_bap0(dev);
+ }
+ prev_stuck = 1;
+ } else
+ prev_stuck = 0;
+}
+
+
+/* Called only from hardware IRQ */
+static inline void prism2_check_magic(local_info_t *local)
+{
+ /* at least PCI Prism2.5 with bus mastering seems to sometimes
+ * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the
+ * register once or twice seems to get the correct value.. PCI cards
+ * cannot anyway be removed during normal operation, so there is not
+ * really any need for this verification with them. */
+
+#ifndef PRISM2_PCI
+#ifndef final_version
+ static unsigned long last_magic_err = 0;
+ struct net_device *dev = local->dev;
+
+ if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
+ if (!local->hw_ready)
+ return;
+ HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+ if (time_after(jiffies, last_magic_err + 10 * HZ)) {
+ printk("%s: Interrupt, but SWSUPPORT0 does not match: "
+ "%04X != %04X - card removed?\n", dev->name,
+ HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
+ HFA384X_MAGIC);
+ last_magic_err = jiffies;
+ } else if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x "
+ "MAGIC=%04x\n", dev->name,
+ HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
+ HFA384X_MAGIC);
+ }
+ if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff)
+ schedule_work(&local->reset_queue);
+ return;
+ }
+#endif /* final_version */
+#endif /* !PRISM2_PCI */
+}
+
+
+/* Called only from hardware IRQ */
+static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int events = 0;
+ u16 ev;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
+
+ if (local->func->card_present && !local->func->card_present(local)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n",
+ dev->name);
+ }
+ return IRQ_HANDLED;
+ }
+
+ prism2_check_magic(local);
+
+ for (;;) {
+ ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ if (ev == 0xffff) {
+ if (local->shutdown)
+ return IRQ_HANDLED;
+ HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
+ printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n",
+ dev->name);
+ return IRQ_HANDLED;
+ }
+
+ ev &= HFA384X_INW(HFA384X_INTEN_OFF);
+ if (ev == 0)
+ break;
+
+ if (ev & HFA384X_EV_CMD) {
+ prism2_cmd_ev(dev);
+ }
+
+ /* Above events are needed even before hw is ready, but other
+ * events should be skipped during initialization. This may
+ * change for AllocEv if allocate_fid is implemented without
+ * busy waiting. */
+ if (!local->hw_ready || local->hw_resetting ||
+ !local->dev_enabled) {
+ ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
+ if (ev & HFA384X_EV_CMD)
+ goto next_event;
+ if ((ev & HFA384X_EVENT_MASK) == 0)
+ return IRQ_HANDLED;
+ if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) &&
+ net_ratelimit()) {
+ printk(KERN_DEBUG "%s: prism2_interrupt: hw "
+ "not ready; skipping events 0x%04x "
+ "(IntEn=0x%04x)%s%s%s\n",
+ dev->name, ev,
+ HFA384X_INW(HFA384X_INTEN_OFF),
+ !local->hw_ready ? " (!hw_ready)" : "",
+ local->hw_resetting ?
+ " (hw_resetting)" : "",
+ !local->dev_enabled ?
+ " (!dev_enabled)" : "");
+ }
+ HFA384X_OUTW(ev, HFA384X_EVACK_OFF);
+ return IRQ_HANDLED;
+ }
+
+ if (ev & HFA384X_EV_TICK) {
+ prism2_ev_tick(dev);
+ HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF);
+ }
+
+ if (ev & HFA384X_EV_ALLOC) {
+ prism2_alloc_ev(dev);
+ HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
+ }
+
+ /* Reading data from the card is quite time consuming, so do it
+ * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed
+ * and unmasked after needed data has been read completely. */
+ if (ev & HFA384X_BAP0_EVENTS) {
+ hfa384x_events_no_bap0(dev);
+ tasklet_schedule(&local->bap_tasklet);
+ }
+
+#ifndef final_version
+ if (ev & HFA384X_EV_WTERR) {
+ PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name);
+ HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF);
+ }
+#endif /* final_version */
+
+ if (ev & HFA384X_EV_INFDROP) {
+ prism2_infdrop(dev);
+ HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF);
+ }
+
+ next_event:
+ events++;
+ if (events >= PRISM2_MAX_INTERRUPT_EVENTS) {
+ PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events "
+ "(EvStat=0x%04x)\n",
+ PRISM2_MAX_INTERRUPT_EVENTS,
+ HFA384X_INW(HFA384X_EVSTAT_OFF));
+ break;
+ }
+ }
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1);
+ return IRQ_RETVAL(events);
+}
+
+
+static void prism2_check_sta_fw_version(local_info_t *local)
+{
+ struct hfa384x_comp_ident comp;
+ int id, variant, major, minor;
+
+ if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID,
+ &comp, sizeof(comp), 1) < 0)
+ return;
+
+ local->fw_ap = 0;
+ id = le16_to_cpu(comp.id);
+ if (id != HFA384X_COMP_ID_STA) {
+ if (id == HFA384X_COMP_ID_FW_AP)
+ local->fw_ap = 1;
+ return;
+ }
+
+ major = __le16_to_cpu(comp.major);
+ minor = __le16_to_cpu(comp.minor);
+ variant = __le16_to_cpu(comp.variant);
+ local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant);
+
+ /* Station firmware versions before 1.4.x seem to have a bug in
+ * firmware-based WEP encryption when using Host AP mode, so use
+ * host_encrypt as a default for them. Firmware version 1.4.9 is the
+ * first one that has been seen to produce correct encryption, but the
+ * bug might be fixed before that (although, at least 1.4.2 is broken).
+ */
+ local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9);
+
+ if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
+ !local->fw_encrypt_ok) {
+ printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
+ "a workaround for firmware bug in Host AP mode WEP\n",
+ local->dev->name);
+ local->host_encrypt = 1;
+ }
+
+ /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken
+ * in station firmware versions before 1.5.x. With these versions, the
+ * driver uses a workaround with bogus frame format (4th address after
+ * the payload). This is not compatible with other AP devices. Since
+ * the firmware bug is fixed in the latest station firmware versions,
+ * automatically enable standard compliant mode for cards using station
+ * firmware version 1.5.0 or newer. */
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0))
+ local->wds_type |= HOSTAP_WDS_STANDARD_FRAME;
+ else {
+ printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a "
+ "workaround for firmware bug in Host AP mode WDS\n",
+ local->dev->name);
+ }
+
+ hostap_check_sta_fw_version(local->ap, local->sta_fw_ver);
+}
+
+
+static void prism2_crypt_deinit_entries(local_info_t *local, int force)
+{
+ struct list_head *ptr, *n;
+ struct ieee80211_crypt_data *entry;
+
+ for (ptr = local->crypt_deinit_list.next, n = ptr->next;
+ ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) {
+ entry = list_entry(ptr, struct ieee80211_crypt_data, list);
+
+ if (atomic_read(&entry->refcnt) != 0 && !force)
+ continue;
+
+ list_del(ptr);
+
+ if (entry->ops)
+ entry->ops->deinit(entry->priv);
+ kfree(entry);
+ }
+}
+
+
+static void prism2_crypt_deinit_handler(unsigned long data)
+{
+ local_info_t *local = (local_info_t *) data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_crypt_deinit_entries(local, 0);
+ if (!list_empty(&local->crypt_deinit_list)) {
+ printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+ "deletion list\n", local->dev->name);
+ local->crypt_deinit_timer.expires = jiffies + HZ;
+ add_timer(&local->crypt_deinit_timer);
+ }
+ spin_unlock_irqrestore(&local->lock, flags);
+
+}
+
+
+static void hostap_passive_scan(unsigned long data)
+{
+ local_info_t *local = (local_info_t *) data;
+ struct net_device *dev = local->dev;
+ u16 channel;
+
+ if (local->passive_scan_interval <= 0)
+ return;
+
+ if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) {
+ int max_tries = 16;
+
+ /* Even though host system does not really know when the WLAN
+ * MAC is sending frames, try to avoid changing channels for
+ * passive scanning when a host-generated frame is being
+ * transmitted */
+ if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
+ printk(KERN_DEBUG "%s: passive scan detected pending "
+ "TX - delaying\n", dev->name);
+ local->passive_scan_timer.expires = jiffies + HZ / 10;
+ add_timer(&local->passive_scan_timer);
+ return;
+ }
+
+ do {
+ local->passive_scan_channel++;
+ if (local->passive_scan_channel > 14)
+ local->passive_scan_channel = 1;
+ max_tries--;
+ } while (!(local->channel_mask &
+ (1 << (local->passive_scan_channel - 1))) &&
+ max_tries > 0);
+
+ if (max_tries == 0) {
+ printk(KERN_INFO "%s: no allowed passive scan channels"
+ " found\n", dev->name);
+ return;
+ }
+
+ printk(KERN_DEBUG "%s: passive scan channel %d\n",
+ dev->name, local->passive_scan_channel);
+ channel = local->passive_scan_channel;
+ local->passive_scan_state = PASSIVE_SCAN_WAIT;
+ local->passive_scan_timer.expires = jiffies + HZ / 10;
+ } else {
+ channel = local->channel;
+ local->passive_scan_state = PASSIVE_SCAN_LISTEN;
+ local->passive_scan_timer.expires = jiffies +
+ local->passive_scan_interval * HZ;
+ }
+
+ if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_CHANGE_CHANNEL << 8),
+ channel, NULL, 0))
+ printk(KERN_ERR "%s: passive scan channel set %d "
+ "failed\n", dev->name, channel);
+
+ add_timer(&local->passive_scan_timer);
+}
+
+
+/* Called only as a scheduled task when communications quality values should
+ * be updated. */
+static void handle_comms_qual_update(void *data)
+{
+ local_info_t *local = data;
+ prism2_update_comms_qual(local->dev);
+}
+
+
+/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is
+ * used to monitor that local->last_tick_timer is being updated. If not,
+ * interrupt busy-loop is assumed and driver tries to recover by masking out
+ * some events. */
+static void hostap_tick_timer(unsigned long data)
+{
+ static unsigned long last_inquire = 0;
+ local_info_t *local = (local_info_t *) data;
+ local->last_tick_timer = jiffies;
+
+ /* Inquire CommTallies every 10 seconds to keep the statistics updated
+ * more often during low load and when using 32-bit tallies. */
+ if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) &&
+ !local->hw_downloading && local->hw_ready &&
+ !local->hw_resetting && local->dev_enabled) {
+ hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE,
+ HFA384X_INFO_COMMTALLIES, NULL, 0);
+ last_inquire = jiffies;
+ }
+
+ if ((local->last_comms_qual_update == 0 ||
+ time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) &&
+ (local->iw_mode == IW_MODE_INFRA ||
+ local->iw_mode == IW_MODE_ADHOC)) {
+ schedule_work(&local->comms_qual_update);
+ }
+
+ local->tick_timer.expires = jiffies + 2 * HZ;
+ add_timer(&local->tick_timer);
+}
+
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+static int prism2_registers_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+#define SHOW_REG(n) \
+p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
+
+ SHOW_REG(CMD);
+ SHOW_REG(PARAM0);
+ SHOW_REG(PARAM1);
+ SHOW_REG(PARAM2);
+ SHOW_REG(STATUS);
+ SHOW_REG(RESP0);
+ SHOW_REG(RESP1);
+ SHOW_REG(RESP2);
+ SHOW_REG(INFOFID);
+ SHOW_REG(CONTROL);
+ SHOW_REG(SELECT0);
+ SHOW_REG(SELECT1);
+ SHOW_REG(OFFSET0);
+ SHOW_REG(OFFSET1);
+ SHOW_REG(RXFID);
+ SHOW_REG(ALLOCFID);
+ SHOW_REG(TXCOMPLFID);
+ SHOW_REG(SWSUPPORT0);
+ SHOW_REG(SWSUPPORT1);
+ SHOW_REG(SWSUPPORT2);
+ SHOW_REG(EVSTAT);
+ SHOW_REG(INTEN);
+ SHOW_REG(EVACK);
+ /* Do not read data registers, because they change the state of the
+ * MAC (offset += 2) */
+ /* SHOW_REG(DATA0); */
+ /* SHOW_REG(DATA1); */
+ SHOW_REG(AUXPAGE);
+ SHOW_REG(AUXOFFSET);
+ /* SHOW_REG(AUXDATA); */
+#ifdef PRISM2_PCI
+ SHOW_REG(PCICOR);
+ SHOW_REG(PCIHCR);
+ SHOW_REG(PCI_M0_ADDRH);
+ SHOW_REG(PCI_M0_ADDRL);
+ SHOW_REG(PCI_M0_LEN);
+ SHOW_REG(PCI_M0_CTL);
+ SHOW_REG(PCI_STATUS);
+ SHOW_REG(PCI_M1_ADDRH);
+ SHOW_REG(PCI_M1_ADDRL);
+ SHOW_REG(PCI_M1_LEN);
+ SHOW_REG(PCI_M1_CTL);
+#endif /* PRISM2_PCI */
+
+ return (p - page);
+}
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+
+struct set_tim_data {
+ struct list_head list;
+ int aid;
+ int set;
+};
+
+static int prism2_set_tim(struct net_device *dev, int aid, int set)
+{
+ struct list_head *ptr;
+ struct set_tim_data *new_entry;
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ new_entry = (struct set_tim_data *)
+ kmalloc(sizeof(*new_entry), GFP_ATOMIC);
+ if (new_entry == NULL) {
+ printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n",
+ local->dev->name);
+ return -ENOMEM;
+ }
+ memset(new_entry, 0, sizeof(*new_entry));
+ new_entry->aid = aid;
+ new_entry->set = set;
+
+ spin_lock_bh(&local->set_tim_lock);
+ list_for_each(ptr, &local->set_tim_list) {
+ struct set_tim_data *entry =
+ list_entry(ptr, struct set_tim_data, list);
+ if (entry->aid == aid) {
+ PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d "
+ "set=%d ==> %d\n",
+ local->dev->name, aid, entry->set, set);
+ entry->set = set;
+ kfree(new_entry);
+ new_entry = NULL;
+ break;
+ }
+ }
+ if (new_entry)
+ list_add_tail(&new_entry->list, &local->set_tim_list);
+ spin_unlock_bh(&local->set_tim_lock);
+
+ schedule_work(&local->set_tim_queue);
+
+ return 0;
+}
+
+
+static void handle_set_tim_queue(void *data)
+{
+ local_info_t *local = (local_info_t *) data;
+ struct set_tim_data *entry;
+ u16 val;
+
+ for (;;) {
+ entry = NULL;
+ spin_lock_bh(&local->set_tim_lock);
+ if (!list_empty(&local->set_tim_list)) {
+ entry = list_entry(local->set_tim_list.next,
+ struct set_tim_data, list);
+ list_del(&entry->list);
+ }
+ spin_unlock_bh(&local->set_tim_lock);
+ if (!entry)
+ break;
+
+ PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n",
+ local->dev->name, entry->aid, entry->set);
+
+ val = entry->aid;
+ if (entry->set)
+ val |= 0x8000;
+ if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) {
+ printk(KERN_DEBUG "%s: set_tim failed (aid=%d "
+ "set=%d)\n",
+ local->dev->name, entry->aid, entry->set);
+ }
+
+ kfree(entry);
+ }
+}
+
+
+static void prism2_clear_set_tim_queue(local_info_t *local)
+{
+ struct list_head *ptr, *n;
+
+ list_for_each_safe(ptr, n, &local->set_tim_list) {
+ struct set_tim_data *entry;
+ entry = list_entry(ptr, struct set_tim_data, list);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+}
+
+
+static struct net_device *
+prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
+ struct device *sdev)
+{
+ struct net_device *dev;
+ struct hostap_interface *iface;
+ struct local_info *local;
+ int len, i, ret;
+
+ if (funcs == NULL)
+ return NULL;
+
+ len = strlen(dev_template);
+ if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) {
+ printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n",
+ dev_template);
+ return NULL;
+ }
+
+ len = sizeof(struct hostap_interface) +
+ 3 + sizeof(struct local_info) +
+ 3 + sizeof(struct ap_data);
+
+ dev = alloc_etherdev(len);
+ if (dev == NULL)
+ return NULL;
+
+ iface = netdev_priv(dev);
+ local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3);
+ local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3);
+ local->dev = iface->dev = dev;
+ iface->local = local;
+ iface->type = HOSTAP_INTERFACE_MASTER;
+ INIT_LIST_HEAD(&local->hostap_interfaces);
+
+ local->hw_module = THIS_MODULE;
+
+#ifdef PRISM2_IO_DEBUG
+ local->io_debug_enabled = 1;
+#endif /* PRISM2_IO_DEBUG */
+
+ local->func = funcs;
+ local->func->cmd = hfa384x_cmd;
+ local->func->read_regs = hfa384x_read_regs;
+ local->func->get_rid = hfa384x_get_rid;
+ local->func->set_rid = hfa384x_set_rid;
+ local->func->hw_enable = prism2_hw_enable;
+ local->func->hw_config = prism2_hw_config;
+ local->func->hw_reset = prism2_hw_reset;
+ local->func->hw_shutdown = prism2_hw_shutdown;
+ local->func->reset_port = prism2_reset_port;
+ local->func->schedule_reset = prism2_schedule_reset;
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ local->func->read_aux = prism2_download_aux_dump;
+ local->func->download = prism2_download;
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+ local->func->tx = prism2_tx_80211;
+ local->func->set_tim = prism2_set_tim;
+ local->func->need_tx_headroom = 0; /* no need to add txdesc in
+ * skb->data (FIX: maybe for DMA bus
+ * mastering? */
+
+ local->mtu = mtu;
+
+ rwlock_init(&local->iface_lock);
+ spin_lock_init(&local->txfidlock);
+ spin_lock_init(&local->cmdlock);
+ spin_lock_init(&local->baplock);
+ spin_lock_init(&local->lock);
+ init_MUTEX(&local->rid_bap_sem);
+
+ if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
+ card_idx = 0;
+ local->card_idx = card_idx;
+
+ len = strlen(essid);
+ memcpy(local->essid, essid,
+ len > MAX_SSID_LEN ? MAX_SSID_LEN : len);
+ local->essid[MAX_SSID_LEN] = '\0';
+ i = GET_INT_PARM(iw_mode, card_idx);
+ if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) ||
+ i == IW_MODE_MONITOR) {
+ local->iw_mode = i;
+ } else {
+ printk(KERN_WARNING "prism2: Unknown iw_mode %d; using "
+ "IW_MODE_MASTER\n", i);
+ local->iw_mode = IW_MODE_MASTER;
+ }
+ local->channel = GET_INT_PARM(channel, card_idx);
+ local->beacon_int = GET_INT_PARM(beacon_int, card_idx);
+ local->dtim_period = GET_INT_PARM(dtim_period, card_idx);
+ local->wds_max_connections = 16;
+ local->tx_control = HFA384X_TX_CTRL_FLAGS;
+ local->manual_retry_count = -1;
+ local->rts_threshold = 2347;
+ local->fragm_threshold = 2346;
+ local->rssi_to_dBm = 100; /* default; to be overriden by
+ * cnfDbmAdjust, if available */
+ local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY;
+ local->sram_type = -1;
+ local->scan_channel_mask = 0xffff;
+
+ /* Initialize task queue structures */
+ INIT_WORK(&local->reset_queue, handle_reset_queue, local);
+ INIT_WORK(&local->set_multicast_list_queue,
+ hostap_set_multicast_list_queue, local->dev);
+
+ INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local);
+ INIT_LIST_HEAD(&local->set_tim_list);
+ spin_lock_init(&local->set_tim_lock);
+
+ INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local);
+
+ /* Initialize tasklets for handling hardware IRQ related operations
+ * outside hw IRQ handler */
+#define HOSTAP_TASKLET_INIT(q, f, d) \
+do { memset((q), 0, sizeof(*(q))); (q)->func = (f); (q)->data = (d); } \
+while (0)
+ HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet,
+ (unsigned long) local);
+
+ HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet,
+ (unsigned long) local);
+ hostap_info_init(local);
+
+ HOSTAP_TASKLET_INIT(&local->rx_tasklet,
+ hostap_rx_tasklet, (unsigned long) local);
+ skb_queue_head_init(&local->rx_list);
+
+ HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet,
+ hostap_sta_tx_exc_tasklet, (unsigned long) local);
+ skb_queue_head_init(&local->sta_tx_exc_list);
+
+ INIT_LIST_HEAD(&local->cmd_queue);
+ init_waitqueue_head(&local->hostscan_wq);
+ INIT_LIST_HEAD(&local->crypt_deinit_list);
+ init_timer(&local->crypt_deinit_timer);
+ local->crypt_deinit_timer.data = (unsigned long) local;
+ local->crypt_deinit_timer.function = prism2_crypt_deinit_handler;
+
+ init_timer(&local->passive_scan_timer);
+ local->passive_scan_timer.data = (unsigned long) local;
+ local->passive_scan_timer.function = hostap_passive_scan;
+
+ init_timer(&local->tick_timer);
+ local->tick_timer.data = (unsigned long) local;
+ local->tick_timer.function = hostap_tick_timer;
+ local->tick_timer.expires = jiffies + 2 * HZ;
+ add_timer(&local->tick_timer);
+
+ INIT_LIST_HEAD(&local->bss_list);
+
+ hostap_setup_dev(dev, local, 1);
+ local->saved_eth_header_parse = dev->hard_header_parse;
+
+ dev->hard_start_xmit = hostap_master_start_xmit;
+ dev->type = ARPHRD_IEEE80211;
+ dev->hard_header_parse = hostap_80211_header_parse;
+
+ rtnl_lock();
+ ret = dev_alloc_name(dev, "wifi%d");
+ SET_NETDEV_DEV(dev, sdev);
+ if (ret >= 0)
+ ret = register_netdevice(dev);
+ rtnl_unlock();
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: register netdevice failed!\n",
+ dev_info);
+ goto fail;
+ }
+ printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name);
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ create_proc_read_entry("registers", 0, local->proc,
+ prism2_registers_proc_read, local);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+ hostap_init_data(local);
+ return dev;
+
+ fail:
+ free_netdev(dev);
+ return NULL;
+}
+
+
+static int hostap_hw_ready(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ struct local_info *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+ local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0,
+ "", dev_template);
+
+ if (local->ddev) {
+ if (local->iw_mode == IW_MODE_INFRA ||
+ local->iw_mode == IW_MODE_ADHOC) {
+ netif_carrier_off(local->dev);
+ netif_carrier_off(local->ddev);
+ }
+ hostap_init_proc(local);
+ hostap_init_ap_proc(local);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static void prism2_free_local_data(struct net_device *dev)
+{
+ struct hostap_tx_callback_info *tx_cb, *tx_cb_prev;
+ int i;
+ struct hostap_interface *iface;
+ struct local_info *local;
+ struct list_head *ptr, *n;
+
+ if (dev == NULL)
+ return;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ flush_scheduled_work();
+
+ if (timer_pending(&local->crypt_deinit_timer))
+ del_timer(&local->crypt_deinit_timer);
+ prism2_crypt_deinit_entries(local, 1);
+
+ if (timer_pending(&local->passive_scan_timer))
+ del_timer(&local->passive_scan_timer);
+
+ if (timer_pending(&local->tick_timer))
+ del_timer(&local->tick_timer);
+
+ prism2_clear_cmd_queue(local);
+
+ skb_queue_purge(&local->info_list);
+ skb_queue_purge(&local->rx_list);
+ skb_queue_purge(&local->sta_tx_exc_list);
+
+ if (local->dev_enabled)
+ prism2_callback(local, PRISM2_CALLBACK_DISABLE);
+
+ for (i = 0; i < WEP_KEYS; i++) {
+ struct ieee80211_crypt_data *crypt = local->crypt[i];
+ if (crypt) {
+ if (crypt->ops)
+ crypt->ops->deinit(crypt->priv);
+ kfree(crypt);
+ local->crypt[i] = NULL;
+ }
+ }
+
+ if (local->ap != NULL)
+ hostap_free_data(local->ap);
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ if (local->proc != NULL)
+ remove_proc_entry("registers", local->proc);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+ hostap_remove_proc(local);
+
+ tx_cb = local->tx_callback;
+ while (tx_cb != NULL) {
+ tx_cb_prev = tx_cb;
+ tx_cb = tx_cb->next;
+ kfree(tx_cb_prev);
+ }
+
+ hostap_set_hostapd(local, 0, 0);
+ hostap_set_hostapd_sta(local, 0, 0);
+
+ for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
+ if (local->frag_cache[i].skb != NULL)
+ dev_kfree_skb(local->frag_cache[i].skb);
+ }
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ prism2_download_free_data(local->dl_pri);
+ prism2_download_free_data(local->dl_sec);
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+ list_for_each_safe(ptr, n, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type == HOSTAP_INTERFACE_MASTER) {
+ /* special handling for this interface below */
+ continue;
+ }
+ hostap_remove_interface(iface->dev, 0, 1);
+ }
+
+ prism2_clear_set_tim_queue(local);
+
+ list_for_each_safe(ptr, n, &local->bss_list) {
+ struct hostap_bss_info *bss =
+ list_entry(ptr, struct hostap_bss_info, list);
+ kfree(bss);
+ }
+
+ kfree(local->pda);
+ kfree(local->last_scan_results);
+ kfree(local->generic_elem);
+
+ unregister_netdev(local->dev);
+ free_netdev(local->dev);
+}
+
+
+#ifndef PRISM2_PLX
+static void prism2_suspend(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ struct local_info *local;
+ union iwreq_data wrqu;
+
+ iface = dev->priv;
+ local = iface->local;
+
+ /* Send disconnect event, e.g., to trigger reassociation after resume
+ * if wpa_supplicant is used. */
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
+
+ /* Disable hardware and firmware */
+ prism2_hw_shutdown(dev, 0);
+}
+#endif /* PRISM2_PLX */
+
+
+/* These might at some point be compiled separately and used as separate
+ * kernel modules or linked into one */
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+#include "hostap_download.c"
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+#ifdef PRISM2_CALLBACK
+/* External hostap_callback.c file can be used to, e.g., blink activity led.
+ * This can use platform specific code and must define prism2_callback()
+ * function (if PRISM2_CALLBACK is not defined, these function calls are not
+ * used. */
+#include "hostap_callback.c"
+#endif /* PRISM2_CALLBACK */
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
new file mode 100644
index 0000000..5aa998f
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -0,0 +1,499 @@
+/* Host AP driver Info Frame processing (part of hostap.o module) */
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
+ int left)
+{
+ struct hfa384x_comm_tallies *tallies;
+
+ if (left < sizeof(struct hfa384x_comm_tallies)) {
+ printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
+ "info frame\n", local->dev->name, left);
+ return;
+ }
+
+ tallies = (struct hfa384x_comm_tallies *) buf;
+#define ADD_COMM_TALLIES(name) \
+local->comm_tallies.name += le16_to_cpu(tallies->name)
+ ADD_COMM_TALLIES(tx_unicast_frames);
+ ADD_COMM_TALLIES(tx_multicast_frames);
+ ADD_COMM_TALLIES(tx_fragments);
+ ADD_COMM_TALLIES(tx_unicast_octets);
+ ADD_COMM_TALLIES(tx_multicast_octets);
+ ADD_COMM_TALLIES(tx_deferred_transmissions);
+ ADD_COMM_TALLIES(tx_single_retry_frames);
+ ADD_COMM_TALLIES(tx_multiple_retry_frames);
+ ADD_COMM_TALLIES(tx_retry_limit_exceeded);
+ ADD_COMM_TALLIES(tx_discards);
+ ADD_COMM_TALLIES(rx_unicast_frames);
+ ADD_COMM_TALLIES(rx_multicast_frames);
+ ADD_COMM_TALLIES(rx_fragments);
+ ADD_COMM_TALLIES(rx_unicast_octets);
+ ADD_COMM_TALLIES(rx_multicast_octets);
+ ADD_COMM_TALLIES(rx_fcs_errors);
+ ADD_COMM_TALLIES(rx_discards_no_buffer);
+ ADD_COMM_TALLIES(tx_discards_wrong_sa);
+ ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
+ ADD_COMM_TALLIES(rx_message_in_msg_fragments);
+ ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
+#undef ADD_COMM_TALLIES
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
+ int left)
+{
+ struct hfa384x_comm_tallies32 *tallies;
+
+ if (left < sizeof(struct hfa384x_comm_tallies32)) {
+ printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
+ "info frame\n", local->dev->name, left);
+ return;
+ }
+
+ tallies = (struct hfa384x_comm_tallies32 *) buf;
+#define ADD_COMM_TALLIES(name) \
+local->comm_tallies.name += le32_to_cpu(tallies->name)
+ ADD_COMM_TALLIES(tx_unicast_frames);
+ ADD_COMM_TALLIES(tx_multicast_frames);
+ ADD_COMM_TALLIES(tx_fragments);
+ ADD_COMM_TALLIES(tx_unicast_octets);
+ ADD_COMM_TALLIES(tx_multicast_octets);
+ ADD_COMM_TALLIES(tx_deferred_transmissions);
+ ADD_COMM_TALLIES(tx_single_retry_frames);
+ ADD_COMM_TALLIES(tx_multiple_retry_frames);
+ ADD_COMM_TALLIES(tx_retry_limit_exceeded);
+ ADD_COMM_TALLIES(tx_discards);
+ ADD_COMM_TALLIES(rx_unicast_frames);
+ ADD_COMM_TALLIES(rx_multicast_frames);
+ ADD_COMM_TALLIES(rx_fragments);
+ ADD_COMM_TALLIES(rx_unicast_octets);
+ ADD_COMM_TALLIES(rx_multicast_octets);
+ ADD_COMM_TALLIES(rx_fcs_errors);
+ ADD_COMM_TALLIES(rx_discards_no_buffer);
+ ADD_COMM_TALLIES(tx_discards_wrong_sa);
+ ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
+ ADD_COMM_TALLIES(rx_message_in_msg_fragments);
+ ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
+#undef ADD_COMM_TALLIES
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
+ int left)
+{
+ if (local->tallies32)
+ prism2_info_commtallies32(local, buf, left);
+ else
+ prism2_info_commtallies16(local, buf, left);
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+#ifndef PRISM2_NO_DEBUG
+static const char* hfa384x_linkstatus_str(u16 linkstatus)
+{
+ switch (linkstatus) {
+ case HFA384X_LINKSTATUS_CONNECTED:
+ return "Connected";
+ case HFA384X_LINKSTATUS_DISCONNECTED:
+ return "Disconnected";
+ case HFA384X_LINKSTATUS_AP_CHANGE:
+ return "Access point change";
+ case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
+ return "Access point out of range";
+ case HFA384X_LINKSTATUS_AP_IN_RANGE:
+ return "Access point in range";
+ case HFA384X_LINKSTATUS_ASSOC_FAILED:
+ return "Association failed";
+ default:
+ return "Unknown";
+ }
+}
+#endif /* PRISM2_NO_DEBUG */
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
+ int left)
+{
+ u16 val;
+ int non_sta_mode;
+
+ /* Alloc new JoinRequests to occur since LinkStatus for the previous
+ * has been received */
+ local->last_join_time = 0;
+
+ if (left != 2) {
+ printk(KERN_DEBUG "%s: invalid linkstatus info frame "
+ "length %d\n", local->dev->name, left);
+ return;
+ }
+
+ non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
+ local->iw_mode == IW_MODE_REPEAT ||
+ local->iw_mode == IW_MODE_MONITOR;
+
+ val = buf[0] | (buf[1] << 8);
+ if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
+ PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
+ local->dev->name, val, hfa384x_linkstatus_str(val));
+ }
+
+ if (non_sta_mode) {
+ netif_carrier_on(local->dev);
+ netif_carrier_on(local->ddev);
+ return;
+ }
+
+ /* Get current BSSID later in scheduled task */
+ set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
+ local->prev_link_status = val;
+ schedule_work(&local->info_queue);
+}
+
+
+static void prism2_host_roaming(local_info_t *local)
+{
+ struct hfa384x_join_request req;
+ struct net_device *dev = local->dev;
+ struct hfa384x_hostscan_result *selected, *entry;
+ int i;
+ unsigned long flags;
+
+ if (local->last_join_time &&
+ time_before(jiffies, local->last_join_time + 10 * HZ)) {
+ PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
+ "completed - waiting for it before issuing new one\n",
+ dev->name);
+ return;
+ }
+
+ /* ScanResults are sorted: first ESS results in decreasing signal
+ * quality then IBSS results in similar order.
+ * Trivial roaming policy: just select the first entry.
+ * This could probably be improved by adding hysteresis to limit
+ * number of handoffs, etc.
+ *
+ * Could do periodic RID_SCANREQUEST or Inquire F101 to get new
+ * ScanResults */
+ spin_lock_irqsave(&local->lock, flags);
+ if (local->last_scan_results == NULL ||
+ local->last_scan_results_count == 0) {
+ spin_unlock_irqrestore(&local->lock, flags);
+ PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
+ dev->name);
+ return;
+ }
+
+ selected = &local->last_scan_results[0];
+
+ if (local->preferred_ap[0] || local->preferred_ap[1] ||
+ local->preferred_ap[2] || local->preferred_ap[3] ||
+ local->preferred_ap[4] || local->preferred_ap[5]) {
+ /* Try to find preferred AP */
+ PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n",
+ dev->name, MAC2STR(local->preferred_ap));
+ for (i = 0; i < local->last_scan_results_count; i++) {
+ entry = &local->last_scan_results[i];
+ if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
+ {
+ PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
+ "selection\n", dev->name);
+ selected = entry;
+ break;
+ }
+ }
+ }
+
+ memcpy(req.bssid, selected->bssid, 6);
+ req.channel = selected->chid;
+ spin_unlock_irqrestore(&local->lock, flags);
+
+ PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n",
+ dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel));
+ if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
+ sizeof(req))) {
+ printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
+ }
+ local->last_join_time = jiffies;
+}
+
+
+static void hostap_report_scan_complete(local_info_t *local)
+{
+ union iwreq_data wrqu;
+
+ /* Inform user space about new scan results (just empty event,
+ * SIOCGIWSCAN can be used to fetch data */
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+ /* Allow SIOCGIWSCAN handling to occur since we have received
+ * scanning result */
+ local->scan_timestamp = 0;
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
+ int left)
+{
+ u16 *pos;
+ int new_count, i;
+ unsigned long flags;
+ struct hfa384x_scan_result *res;
+ struct hfa384x_hostscan_result *results, *prev;
+
+ if (left < 4) {
+ printk(KERN_DEBUG "%s: invalid scanresult info frame "
+ "length %d\n", local->dev->name, left);
+ return;
+ }
+
+ pos = (u16 *) buf;
+ pos++;
+ pos++;
+ left -= 4;
+
+ new_count = left / sizeof(struct hfa384x_scan_result);
+ results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
+ GFP_ATOMIC);
+ if (results == NULL)
+ return;
+
+ /* Convert to hostscan result format. */
+ res = (struct hfa384x_scan_result *) pos;
+ for (i = 0; i < new_count; i++) {
+ memcpy(&results[i], &res[i],
+ sizeof(struct hfa384x_scan_result));
+ results[i].atim = 0;
+ }
+
+ spin_lock_irqsave(&local->lock, flags);
+ local->last_scan_type = PRISM2_SCAN;
+ prev = local->last_scan_results;
+ local->last_scan_results = results;
+ local->last_scan_results_count = new_count;
+ spin_unlock_irqrestore(&local->lock, flags);
+ kfree(prev);
+
+ hostap_report_scan_complete(local);
+
+ /* Perform rest of ScanResults handling later in scheduled task */
+ set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
+ schedule_work(&local->info_queue);
+}
+
+
+/* Called only as a tasklet (software IRQ) */
+static void prism2_info_hostscanresults(local_info_t *local,
+ unsigned char *buf, int left)
+{
+ int i, result_size, copy_len, new_count;
+ struct hfa384x_hostscan_result *results, *prev;
+ unsigned long flags;
+ u16 *pos;
+ u8 *ptr;
+
+ wake_up_interruptible(&local->hostscan_wq);
+
+ if (left < 4) {
+ printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
+ "length %d\n", local->dev->name, left);
+ return;
+ }
+
+ pos = (u16 *) buf;
+ copy_len = result_size = le16_to_cpu(*pos);
+ if (result_size == 0) {
+ printk(KERN_DEBUG "%s: invalid result_size (0) in "
+ "hostscanresults\n", local->dev->name);
+ return;
+ }
+ if (copy_len > sizeof(struct hfa384x_hostscan_result))
+ copy_len = sizeof(struct hfa384x_hostscan_result);
+
+ pos++;
+ pos++;
+ left -= 4;
+ ptr = (u8 *) pos;
+
+ new_count = left / result_size;
+ results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
+ GFP_ATOMIC);
+ if (results == NULL)
+ return;
+ memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result));
+
+ for (i = 0; i < new_count; i++) {
+ memcpy(&results[i], ptr, copy_len);
+ ptr += result_size;
+ left -= result_size;
+ }
+
+ if (left) {
+ printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
+ local->dev->name, left, result_size);
+ }
+
+ spin_lock_irqsave(&local->lock, flags);
+ local->last_scan_type = PRISM2_HOSTSCAN;
+ prev = local->last_scan_results;
+ local->last_scan_results = results;
+ local->last_scan_results_count = new_count;
+ spin_unlock_irqrestore(&local->lock, flags);
+ kfree(prev);
+
+ hostap_report_scan_complete(local);
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+/* Called only as a tasklet (software IRQ) */
+void hostap_info_process(local_info_t *local, struct sk_buff *skb)
+{
+ struct hfa384x_info_frame *info;
+ unsigned char *buf;
+ int left;
+#ifndef PRISM2_NO_DEBUG
+ int i;
+#endif /* PRISM2_NO_DEBUG */
+
+ info = (struct hfa384x_info_frame *) skb->data;
+ buf = skb->data + sizeof(*info);
+ left = skb->len - sizeof(*info);
+
+ switch (info->type) {
+ case HFA384X_INFO_COMMTALLIES:
+ prism2_info_commtallies(local, buf, left);
+ break;
+
+#ifndef PRISM2_NO_STATION_MODES
+ case HFA384X_INFO_LINKSTATUS:
+ prism2_info_linkstatus(local, buf, left);
+ break;
+
+ case HFA384X_INFO_SCANRESULTS:
+ prism2_info_scanresults(local, buf, left);
+ break;
+
+ case HFA384X_INFO_HOSTSCANRESULTS:
+ prism2_info_hostscanresults(local, buf, left);
+ break;
+#endif /* PRISM2_NO_STATION_MODES */
+
+#ifndef PRISM2_NO_DEBUG
+ default:
+ PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
+ local->dev->name, info->len, info->type);
+ PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
+ for (i = 0; i < (left < 100 ? left : 100); i++)
+ PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
+ PDEBUG2(DEBUG_EXTRA, "\n");
+ break;
+#endif /* PRISM2_NO_DEBUG */
+ }
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static void handle_info_queue_linkstatus(local_info_t *local)
+{
+ int val = local->prev_link_status;
+ int connected;
+ union iwreq_data wrqu;
+
+ connected =
+ val == HFA384X_LINKSTATUS_CONNECTED ||
+ val == HFA384X_LINKSTATUS_AP_CHANGE ||
+ val == HFA384X_LINKSTATUS_AP_IN_RANGE;
+
+ if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
+ local->bssid, ETH_ALEN, 1) < 0) {
+ printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
+ "LinkStatus event\n", local->dev->name);
+ } else {
+ PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n",
+ local->dev->name,
+ MAC2STR((unsigned char *) local->bssid));
+ if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
+ hostap_add_sta(local->ap, local->bssid);
+ }
+
+ /* Get BSSID if we have a valid AP address */
+ if (connected) {
+ netif_carrier_on(local->dev);
+ netif_carrier_on(local->ddev);
+ memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
+ } else {
+ netif_carrier_off(local->dev);
+ netif_carrier_off(local->ddev);
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ }
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /*
+ * Filter out sequential disconnect events in order not to cause a
+ * flood of SIOCGIWAP events that have a race condition with EAPOL
+ * frames and can confuse wpa_supplicant about the current association
+ * status.
+ */
+ if (connected || local->prev_linkstatus_connected)
+ wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
+ local->prev_linkstatus_connected = connected;
+}
+
+
+static void handle_info_queue_scanresults(local_info_t *local)
+{
+ if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
+ prism2_host_roaming(local);
+
+ if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
+ memcmp(local->preferred_ap, "\x00\x00\x00\x00\x00\x00",
+ ETH_ALEN) != 0) {
+ /*
+ * Firmware seems to be getting into odd state in host_roaming
+ * mode 2 when hostscan is used without join command, so try
+ * to fix this by re-joining the current AP. This does not
+ * actually trigger a new association if the current AP is
+ * still in the scan results.
+ */
+ prism2_host_roaming(local);
+ }
+}
+
+
+/* Called only as scheduled task after receiving info frames (used to avoid
+ * pending too much time in HW IRQ handler). */
+static void handle_info_queue(void *data)
+{
+ local_info_t *local = (local_info_t *) data;
+
+ if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
+ &local->pending_info))
+ handle_info_queue_linkstatus(local);
+
+ if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
+ &local->pending_info))
+ handle_info_queue_scanresults(local);
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+void hostap_info_init(local_info_t *local)
+{
+ skb_queue_head_init(&local->info_list);
+#ifndef PRISM2_NO_STATION_MODES
+ INIT_WORK(&local->info_queue, handle_info_queue, local);
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+EXPORT_SYMBOL(hostap_info_init);
+EXPORT_SYMBOL(hostap_info_process);
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
new file mode 100644
index 0000000..e720369
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -0,0 +1,4102 @@
+/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
+
+#ifdef in_atomic
+/* Get kernel_locked() for in_atomic() */
+#include <linux/smp_lock.h>
+#endif
+#include <linux/ethtool.h>
+
+
+static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct iw_statistics *wstats;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* Why are we doing that ? Jean II */
+ if (iface->type != HOSTAP_INTERFACE_MAIN)
+ return NULL;
+
+ wstats = &local->wstats;
+
+ wstats->status = 0;
+ wstats->discard.code =
+ local->comm_tallies.rx_discards_wep_undecryptable;
+ wstats->discard.misc =
+ local->comm_tallies.rx_fcs_errors +
+ local->comm_tallies.rx_discards_no_buffer +
+ local->comm_tallies.tx_discards_wrong_sa;
+
+ wstats->discard.retries =
+ local->comm_tallies.tx_retry_limit_exceeded;
+ wstats->discard.fragment =
+ local->comm_tallies.rx_message_in_bad_msg_fragments;
+
+ if (local->iw_mode != IW_MODE_MASTER &&
+ local->iw_mode != IW_MODE_REPEAT) {
+ int update = 1;
+#ifdef in_atomic
+ /* RID reading might sleep and it must not be called in
+ * interrupt context or while atomic. However, this
+ * function seems to be called while atomic (at least in Linux
+ * 2.5.59). Update signal quality values only if in suitable
+ * context. Otherwise, previous values read from tick timer
+ * will be used. */
+ if (in_atomic())
+ update = 0;
+#endif /* in_atomic */
+
+ if (update && prism2_update_comms_qual(dev) == 0)
+ wstats->qual.updated = 7;
+
+ wstats->qual.qual = local->comms_qual;
+ wstats->qual.level = local->avg_signal;
+ wstats->qual.noise = local->avg_noise;
+ } else {
+ wstats->qual.qual = 0;
+ wstats->qual.level = 0;
+ wstats->qual.noise = 0;
+ wstats->qual.updated = 0;
+ }
+
+ return wstats;
+}
+
+
+static int prism2_get_datarates(struct net_device *dev, u8 *rates)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u8 buf[12];
+ int len;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf,
+ sizeof(buf), 0);
+ if (len < 2)
+ return 0;
+
+ val = le16_to_cpu(*(u16 *) buf); /* string length */
+
+ if (len - 2 < val || val > 10)
+ return 0;
+
+ memcpy(rates, buf + 2, val);
+ return val;
+}
+
+
+static int prism2_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ char *name, char *extra)
+{
+ u8 rates[10];
+ int len, i, over2 = 0;
+
+ len = prism2_get_datarates(dev, rates);
+
+ for (i = 0; i < len; i++) {
+ if (rates[i] == 0x0b || rates[i] == 0x16) {
+ over2 = 1;
+ break;
+ }
+ }
+
+ strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS");
+
+ return 0;
+}
+
+
+static void prism2_crypt_delayed_deinit(local_info_t *local,
+ struct ieee80211_crypt_data **crypt)
+{
+ struct ieee80211_crypt_data *tmp;
+ unsigned long flags;
+
+ tmp = *crypt;
+ *crypt = NULL;
+
+ if (tmp == NULL)
+ return;
+
+ /* must not run ops->deinit() while there may be pending encrypt or
+ * decrypt operations. Use a list of delayed deinits to avoid needing
+ * locking. */
+
+ spin_lock_irqsave(&local->lock, flags);
+ list_add(&tmp->list, &local->crypt_deinit_list);
+ if (!timer_pending(&local->crypt_deinit_timer)) {
+ local->crypt_deinit_timer.expires = jiffies + HZ;
+ add_timer(&local->crypt_deinit_timer);
+ }
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+
+static int prism2_ioctl_siwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int i;
+ struct ieee80211_crypt_data **crypt;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ i = erq->flags & IW_ENCODE_INDEX;
+ if (i < 1 || i > 4)
+ i = local->tx_keyidx;
+ else
+ i--;
+ if (i < 0 || i >= WEP_KEYS)
+ return -EINVAL;
+
+ crypt = &local->crypt[i];
+
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ if (*crypt)
+ prism2_crypt_delayed_deinit(local, crypt);
+ goto done;
+ }
+
+ if (*crypt != NULL && (*crypt)->ops != NULL &&
+ strcmp((*crypt)->ops->name, "WEP") != 0) {
+ /* changing to use WEP; deinit previously used algorithm */
+ prism2_crypt_delayed_deinit(local, crypt);
+ }
+
+ if (*crypt == NULL) {
+ struct ieee80211_crypt_data *new_crypt;
+
+ /* take WEP into use */
+ new_crypt = (struct ieee80211_crypt_data *)
+ kmalloc(sizeof(struct ieee80211_crypt_data),
+ GFP_KERNEL);
+ if (new_crypt == NULL)
+ return -ENOMEM;
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+ new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+ if (!new_crypt->ops) {
+ request_module("ieee80211_crypt_wep");
+ new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+ }
+ if (new_crypt->ops)
+ new_crypt->priv = new_crypt->ops->init(i);
+ if (!new_crypt->ops || !new_crypt->priv) {
+ kfree(new_crypt);
+ new_crypt = NULL;
+
+ printk(KERN_WARNING "%s: could not initialize WEP: "
+ "load module hostap_crypt_wep.o\n",
+ dev->name);
+ return -EOPNOTSUPP;
+ }
+ *crypt = new_crypt;
+ }
+
+ if (erq->length > 0) {
+ int len = erq->length <= 5 ? 5 : 13;
+ int first = 1, j;
+ if (len > erq->length)
+ memset(keybuf + erq->length, 0, len - erq->length);
+ (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv);
+ for (j = 0; j < WEP_KEYS; j++) {
+ if (j != i && local->crypt[j]) {
+ first = 0;
+ break;
+ }
+ }
+ if (first)
+ local->tx_keyidx = i;
+ } else {
+ /* No key data - just set the default TX key index */
+ local->tx_keyidx = i;
+ }
+
+ done:
+ local->open_wep = erq->flags & IW_ENCODE_OPEN;
+
+ if (hostap_set_encryption(local)) {
+ printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name);
+ return -EINVAL;
+ }
+
+ /* Do not reset port0 if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. Prism2 documentation seem to require port reset
+ * after WEP configuration. However, keys are apparently changed at
+ * least in Managed mode. */
+ if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) {
+ printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int prism2_ioctl_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *key)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int i, len;
+ u16 val;
+ struct ieee80211_crypt_data *crypt;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ i = erq->flags & IW_ENCODE_INDEX;
+ if (i < 1 || i > 4)
+ i = local->tx_keyidx;
+ else
+ i--;
+ if (i < 0 || i >= WEP_KEYS)
+ return -EINVAL;
+
+ crypt = local->crypt[i];
+ erq->flags = i + 1;
+
+ if (crypt == NULL || crypt->ops == NULL) {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ return 0;
+ }
+
+ if (strcmp(crypt->ops->name, "WEP") != 0) {
+ /* only WEP is supported with wireless extensions, so just
+ * report that encryption is used */
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_ENABLED;
+ return 0;
+ }
+
+ /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show
+ * the keys from driver buffer */
+ len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv);
+ erq->length = (len >= 0 ? len : 0);
+
+ if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0)
+ {
+ printk("CNFWEPFLAGS reading failed\n");
+ return -EOPNOTSUPP;
+ }
+ le16_to_cpus(&val);
+ if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED)
+ erq->flags |= IW_ENCODE_ENABLED;
+ else
+ erq->flags |= IW_ENCODE_DISABLED;
+ if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED)
+ erq->flags |= IW_ENCODE_RESTRICTED;
+ else
+ erq->flags |= IW_ENCODE_OPEN;
+
+ return 0;
+}
+
+
+static int hostap_set_rate(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret, basic_rates;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ basic_rates = local->basic_rates & local->tx_rate_control;
+ if (!basic_rates || basic_rates != local->basic_rates) {
+ printk(KERN_INFO "%s: updating basic rate set automatically "
+ "to match with the new supported rate set\n",
+ dev->name);
+ if (!basic_rates)
+ basic_rates = local->tx_rate_control;
+
+ local->basic_rates = basic_rates;
+ if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
+ basic_rates))
+ printk(KERN_WARNING "%s: failed to set "
+ "cnfBasicRates\n", dev->name);
+ }
+
+ ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
+ local->tx_rate_control) ||
+ hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
+ local->tx_rate_control) ||
+ local->func->reset_port(dev));
+
+ if (ret) {
+ printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates "
+ "setting to 0x%x failed\n",
+ dev->name, local->tx_rate_control);
+ }
+
+ /* Update TX rate configuration for all STAs based on new operational
+ * rate set. */
+ hostap_update_rates(local);
+
+ return ret;
+}
+
+
+static int prism2_ioctl_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (rrq->fixed) {
+ switch (rrq->value) {
+ case 11000000:
+ local->tx_rate_control = HFA384X_RATES_11MBPS;
+ break;
+ case 5500000:
+ local->tx_rate_control = HFA384X_RATES_5MBPS;
+ break;
+ case 2000000:
+ local->tx_rate_control = HFA384X_RATES_2MBPS;
+ break;
+ case 1000000:
+ local->tx_rate_control = HFA384X_RATES_1MBPS;
+ break;
+ default:
+ local->tx_rate_control = HFA384X_RATES_1MBPS |
+ HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
+ HFA384X_RATES_11MBPS;
+ break;
+ }
+ } else {
+ switch (rrq->value) {
+ case 11000000:
+ local->tx_rate_control = HFA384X_RATES_1MBPS |
+ HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
+ HFA384X_RATES_11MBPS;
+ break;
+ case 5500000:
+ local->tx_rate_control = HFA384X_RATES_1MBPS |
+ HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS;
+ break;
+ case 2000000:
+ local->tx_rate_control = HFA384X_RATES_1MBPS |
+ HFA384X_RATES_2MBPS;
+ break;
+ case 1000000:
+ local->tx_rate_control = HFA384X_RATES_1MBPS;
+ break;
+ default:
+ local->tx_rate_control = HFA384X_RATES_1MBPS |
+ HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
+ HFA384X_RATES_11MBPS;
+ break;
+ }
+ }
+
+ return hostap_set_rate(dev);
+}
+
+
+static int prism2_ioctl_giwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ u16 val;
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) <
+ 0)
+ return -EINVAL;
+
+ if ((val & 0x1) && (val > 1))
+ rrq->fixed = 0;
+ else
+ rrq->fixed = 1;
+
+ if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL &&
+ !local->fw_tx_rate_control) {
+ /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in
+ * Host AP mode, so use the recorded TX rate of the last sent
+ * frame */
+ rrq->value = local->ap->last_tx_rate > 0 ?
+ local->ap->last_tx_rate * 100000 : 11000000;
+ return 0;
+ }
+
+ if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) <
+ 0)
+ return -EINVAL;
+
+ switch (val) {
+ case HFA384X_RATES_1MBPS:
+ rrq->value = 1000000;
+ break;
+ case HFA384X_RATES_2MBPS:
+ rrq->value = 2000000;
+ break;
+ case HFA384X_RATES_5MBPS:
+ rrq->value = 5500000;
+ break;
+ case HFA384X_RATES_11MBPS:
+ rrq->value = 11000000;
+ break;
+ default:
+ /* should not happen */
+ rrq->value = 11000000;
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int prism2_ioctl_siwsens(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *sens, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* Set the desired AP density */
+ if (sens->value < 1 || sens->value > 3)
+ return -EINVAL;
+
+ if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int prism2_ioctl_giwsens(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *sens, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* Get the current AP density */
+ if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) <
+ 0)
+ return -EINVAL;
+
+ sens->value = __le16_to_cpu(val);
+ sens->fixed = 1;
+
+ return 0;
+}
+
+
+/* Deprecated in new wireless extension API */
+static int prism2_ioctl_giwaplist(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct sockaddr *addr;
+ struct iw_quality *qual;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->iw_mode != IW_MODE_MASTER) {
+ printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported "
+ "in Host AP mode\n");
+ data->length = 0;
+ return -EOPNOTSUPP;
+ }
+
+ addr = kmalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL);
+ qual = kmalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL);
+ if (addr == NULL || qual == NULL) {
+ kfree(addr);
+ kfree(qual);
+ data->length = 0;
+ return -ENOMEM;
+ }
+
+ data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
+
+ memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
+ data->flags = 1; /* has quality information */
+ memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
+ sizeof(struct iw_quality) * data->length);
+
+ kfree(addr);
+ kfree(qual);
+
+ return 0;
+}
+
+
+static int prism2_ioctl_siwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (rts->disabled)
+ val = __constant_cpu_to_le16(2347);
+ else if (rts->value < 0 || rts->value > 2347)
+ return -EINVAL;
+ else
+ val = __cpu_to_le16(rts->value);
+
+ if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+
+ local->rts_threshold = rts->value;
+
+ return 0;
+}
+
+static int prism2_ioctl_giwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) <
+ 0)
+ return -EINVAL;
+
+ rts->value = __le16_to_cpu(val);
+ rts->disabled = (rts->value == 2347);
+ rts->fixed = 1;
+
+ return 0;
+}
+
+
+static int prism2_ioctl_siwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (rts->disabled)
+ val = __constant_cpu_to_le16(2346);
+ else if (rts->value < 256 || rts->value > 2346)
+ return -EINVAL;
+ else
+ val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */
+
+ local->fragm_threshold = rts->value & ~0x1;
+ if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val,
+ 2)
+ || local->func->reset_port(dev))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int prism2_ioctl_giwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
+ &val, 2, 1) < 0)
+ return -EINVAL;
+
+ rts->value = __le16_to_cpu(val);
+ rts->disabled = (rts->value == 2346);
+ rts->fixed = 1;
+
+ return 0;
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static int hostap_join_ap(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hfa384x_join_request req;
+ unsigned long flags;
+ int i;
+ struct hfa384x_hostscan_result *entry;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ memcpy(req.bssid, local->preferred_ap, ETH_ALEN);
+ req.channel = 0;
+
+ spin_lock_irqsave(&local->lock, flags);
+ for (i = 0; i < local->last_scan_results_count; i++) {
+ if (!local->last_scan_results)
+ break;
+ entry = &local->last_scan_results[i];
+ if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) {
+ req.channel = entry->chid;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&local->lock, flags);
+
+ if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
+ sizeof(req))) {
+ printk(KERN_DEBUG "%s: JoinRequest " MACSTR
+ " failed\n",
+ dev->name, MAC2STR(local->preferred_ap));
+ return -1;
+ }
+
+ printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n",
+ dev->name, MAC2STR(local->preferred_ap));
+
+ return 0;
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+static int prism2_ioctl_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+ return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN);
+
+ if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) {
+ struct hfa384x_scan_request scan_req;
+ memset(&scan_req, 0, sizeof(scan_req));
+ scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
+ scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+ if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST,
+ &scan_req, sizeof(scan_req))) {
+ printk(KERN_DEBUG "%s: ScanResults request failed - "
+ "preferred AP delayed to next unsolicited "
+ "scan\n", dev->name);
+ }
+ } else if (local->host_roaming == 2 &&
+ local->iw_mode == IW_MODE_INFRA) {
+ if (hostap_join_ap(dev))
+ return -EINVAL;
+ } else {
+ printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only "
+ "in Managed mode when host_roaming is enabled\n",
+ dev->name);
+ }
+
+ return 0;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+static int prism2_ioctl_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+ switch (iface->type) {
+ case HOSTAP_INTERFACE_AP:
+ memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN);
+ break;
+ case HOSTAP_INTERFACE_STA:
+ memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN);
+ break;
+ case HOSTAP_INTERFACE_WDS:
+ memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN);
+ break;
+ default:
+ if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID,
+ &ap_addr->sa_data, ETH_ALEN, 1) < 0)
+ return -EOPNOTSUPP;
+
+ /* local->bssid is also updated in LinkStatus handler when in
+ * station mode */
+ memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int prism2_ioctl_siwnickn(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *nickname)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ memset(local->name, 0, sizeof(local->name));
+ memcpy(local->name, nickname, data->length);
+ local->name_set = 1;
+
+ if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int prism2_ioctl_giwnickn(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *nickname)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int len;
+ char name[MAX_NAME_LEN + 3];
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME,
+ &name, MAX_NAME_LEN + 2, 0);
+ val = __le16_to_cpu(*(u16 *) name);
+ if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN)
+ return -EOPNOTSUPP;
+
+ name[val + 2] = '\0';
+ data->length = val + 1;
+ memcpy(nickname, name + 2, val + 1);
+
+ return 0;
+}
+
+
+static int prism2_ioctl_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* freq => chan. */
+ if (freq->e == 1 &&
+ freq->m / 100000 >= freq_list[0] &&
+ freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) {
+ int ch;
+ int fr = freq->m / 100000;
+ for (ch = 0; ch < FREQ_COUNT; ch++) {
+ if (fr == freq_list[ch]) {
+ freq->e = 0;
+ freq->m = ch + 1;
+ break;
+ }
+ }
+ }
+
+ if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT ||
+ !(local->channel_mask & (1 << (freq->m - 1))))
+ return -EINVAL;
+
+ local->channel = freq->m; /* channel is used in prism2_setup_rids() */
+ if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int prism2_ioctl_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) <
+ 0)
+ return -EINVAL;
+
+ le16_to_cpus(&val);
+ if (val < 1 || val > FREQ_COUNT)
+ return -EINVAL;
+
+ freq->m = freq_list[val - 1] * 100000;
+ freq->e = 1;
+
+ return 0;
+}
+
+
+static void hostap_monitor_set_type(local_info_t *local)
+{
+ struct net_device *dev = local->ddev;
+
+ if (dev == NULL)
+ return;
+
+ if (local->monitor_type == PRISM2_MONITOR_PRISM ||
+ local->monitor_type == PRISM2_MONITOR_CAPHDR) {
+ dev->type = ARPHRD_IEEE80211_PRISM;
+ dev->hard_header_parse =
+ hostap_80211_prism_header_parse;
+ } else {
+ dev->type = ARPHRD_IEEE80211;
+ dev->hard_header_parse = hostap_80211_header_parse;
+ }
+}
+
+
+static int prism2_ioctl_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (iface->type == HOSTAP_INTERFACE_WDS)
+ return -EOPNOTSUPP;
+
+ if (data->flags == 0)
+ ssid[0] = '\0'; /* ANY */
+
+ if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') {
+ /* Setting SSID to empty string seems to kill the card in
+ * Host AP mode */
+ printk(KERN_DEBUG "%s: Host AP mode does not support "
+ "'Any' essid\n", dev->name);
+ return -EINVAL;
+ }
+
+ memcpy(local->essid, ssid, data->length);
+ local->essid[data->length] = '\0';
+
+ if ((!local->fw_ap &&
+ hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid))
+ || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int prism2_ioctl_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *essid)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (iface->type == HOSTAP_INTERFACE_WDS)
+ return -EOPNOTSUPP;
+
+ data->flags = 1; /* active */
+ if (local->iw_mode == IW_MODE_MASTER) {
+ data->length = strlen(local->essid);
+ memcpy(essid, local->essid, IW_ESSID_MAX_SIZE);
+ } else {
+ int len;
+ char ssid[MAX_SSID_LEN + 2];
+ memset(ssid, 0, sizeof(ssid));
+ len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID,
+ &ssid, MAX_SSID_LEN + 2, 0);
+ val = __le16_to_cpu(*(u16 *) ssid);
+ if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) {
+ return -EOPNOTSUPP;
+ }
+ data->length = val;
+ memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE);
+ }
+
+ return 0;
+}
+
+
+static int prism2_ioctl_giwrange(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct iw_range *range = (struct iw_range *) extra;
+ u8 rates[10];
+ u16 val;
+ int i, len, over2;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ data->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ /* TODO: could fill num_txpower and txpower array with
+ * something; however, there are 128 different values.. */
+
+ range->txpower_capa = IW_TXPOW_DBM;
+
+ if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC)
+ {
+ range->min_pmp = 1 * 1024;
+ range->max_pmp = 65535 * 1024;
+ range->min_pmt = 1 * 1024;
+ range->max_pmt = 1000 * 1024;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT |
+ IW_POWER_UNICAST_R | IW_POWER_ALL_R;
+ }
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 18;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->min_retry = 0;
+ range->max_retry = 255;
+
+ range->num_channels = FREQ_COUNT;
+
+ val = 0;
+ for (i = 0; i < FREQ_COUNT; i++) {
+ if (local->channel_mask & (1 << i)) {
+ range->freq[val].i = i + 1;
+ range->freq[val].m = freq_list[i] * 100000;
+ range->freq[val].e = 1;
+ val++;
+ }
+ if (val == IW_MAX_FREQUENCIES)
+ break;
+ }
+ range->num_frequency = val;
+
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
+ range->max_qual.qual = 70; /* what is correct max? This was not
+ * documented exactly. At least
+ * 69 has been observed. */
+ range->max_qual.level = 0; /* dB */
+ range->max_qual.noise = 0; /* dB */
+
+ /* What would be suitable values for "average/typical" qual? */
+ range->avg_qual.qual = 20;
+ range->avg_qual.level = -60;
+ range->avg_qual.noise = -95;
+ } else {
+ range->max_qual.qual = 92; /* 0 .. 92 */
+ range->max_qual.level = 154; /* 27 .. 154 */
+ range->max_qual.noise = 154; /* 27 .. 154 */
+ }
+ range->sensitivity = 3;
+
+ range->max_encoding_tokens = WEP_KEYS;
+ range->num_encoding_sizes = 2;
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+
+ over2 = 0;
+ len = prism2_get_datarates(dev, rates);
+ range->num_bitrates = 0;
+ for (i = 0; i < len; i++) {
+ if (range->num_bitrates < IW_MAX_BITRATES) {
+ range->bitrate[range->num_bitrates] =
+ rates[i] * 500000;
+ range->num_bitrates++;
+ }
+ if (rates[i] == 0x0b || rates[i] == 0x16)
+ over2 = 1;
+ }
+ /* estimated maximum TCP throughput values (bps) */
+ range->throughput = over2 ? 5500000 : 1500000;
+
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ /* Event capability (kernel + driver) */
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+ IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) |
+ IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
+ IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
+ IW_EVENT_CAPA_MASK(IWEVEXPIRED));
+
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+ return 0;
+}
+
+
+static int hostap_monitor_mode_enable(local_info_t *local)
+{
+ struct net_device *dev = local->dev;
+
+ printk(KERN_DEBUG "Enabling monitor mode\n");
+ hostap_monitor_set_type(local);
+
+ if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+ HFA384X_PORTTYPE_PSEUDO_IBSS)) {
+ printk(KERN_DEBUG "Port type setting for monitor mode "
+ "failed\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* Host decrypt is needed to get the IV and ICV fields;
+ * however, monitor mode seems to remove WEP flag from frame
+ * control field */
+ if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS,
+ HFA384X_WEPFLAGS_HOSTENCRYPT |
+ HFA384X_WEPFLAGS_HOSTDECRYPT)) {
+ printk(KERN_DEBUG "WEP flags setting failed\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (local->func->reset_port(dev) ||
+ local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_MONITOR << 8),
+ 0, NULL, NULL)) {
+ printk(KERN_DEBUG "Setting monitor mode failed\n");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+
+static int hostap_monitor_mode_disable(local_info_t *local)
+{
+ struct net_device *dev = local->ddev;
+
+ if (dev == NULL)
+ return -1;
+
+ printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_parse = local->saved_eth_header_parse;
+ if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_STOP << 8),
+ 0, NULL, NULL))
+ return -1;
+ return hostap_set_encryption(local);
+}
+
+
+static int prism2_ioctl_siwmode(struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int double_reset = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
+ *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT &&
+ *mode != IW_MODE_MONITOR)
+ return -EOPNOTSUPP;
+
+#ifdef PRISM2_NO_STATION_MODES
+ if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA)
+ return -EOPNOTSUPP;
+#endif /* PRISM2_NO_STATION_MODES */
+
+ if (*mode == local->iw_mode)
+ return 0;
+
+ if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') {
+ printk(KERN_WARNING "%s: empty SSID not allowed in Master "
+ "mode\n", dev->name);
+ return -EINVAL;
+ }
+
+ if (local->iw_mode == IW_MODE_MONITOR)
+ hostap_monitor_mode_disable(local);
+
+ if ((local->iw_mode == IW_MODE_ADHOC ||
+ local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) {
+ /* There seems to be a firmware bug in at least STA f/w v1.5.6
+ * that leaves beacon frames to use IBSS type when moving from
+ * IBSS to Host AP mode. Doing double Port0 reset seems to be
+ * enough to workaround this. */
+ double_reset = 1;
+ }
+
+ printk(KERN_DEBUG "prism2: %s: operating mode changed "
+ "%d -> %d\n", dev->name, local->iw_mode, *mode);
+ local->iw_mode = *mode;
+
+ if (local->iw_mode == IW_MODE_MONITOR)
+ hostap_monitor_mode_enable(local);
+ else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
+ !local->fw_encrypt_ok) {
+ printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
+ "a workaround for firmware bug in Host AP mode WEP\n",
+ dev->name);
+ local->host_encrypt = 1;
+ }
+
+ if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+ hostap_get_porttype(local)))
+ return -EOPNOTSUPP;
+
+ if (local->func->reset_port(dev))
+ return -EINVAL;
+ if (double_reset && local->func->reset_port(dev))
+ return -EINVAL;
+
+ if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC)
+ {
+ /* netif_carrier is used only in client modes for now, so make
+ * sure carrier is on when moving to non-client modes. */
+ netif_carrier_on(local->dev);
+ netif_carrier_on(local->ddev);
+ }
+ return 0;
+}
+
+
+static int prism2_ioctl_giwmode(struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ switch (iface->type) {
+ case HOSTAP_INTERFACE_STA:
+ *mode = IW_MODE_INFRA;
+ break;
+ case HOSTAP_INTERFACE_WDS:
+ *mode = IW_MODE_REPEAT;
+ break;
+ default:
+ *mode = local->iw_mode;
+ break;
+ }
+ return 0;
+}
+
+
+static int prism2_ioctl_siwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+ return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+ int ret = 0;
+
+ if (wrq->disabled)
+ return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0);
+
+ switch (wrq->flags & IW_POWER_MODE) {
+ case IW_POWER_UNICAST_R:
+ ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0);
+ if (ret)
+ return ret;
+ ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+ if (ret)
+ return ret;
+ break;
+ case IW_POWER_ALL_R:
+ ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1);
+ if (ret)
+ return ret;
+ ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+ if (ret)
+ return ret;
+ break;
+ case IW_POWER_ON:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (wrq->flags & IW_POWER_TIMEOUT) {
+ ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+ if (ret)
+ return ret;
+ ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION,
+ wrq->value / 1024);
+ if (ret)
+ return ret;
+ }
+ if (wrq->flags & IW_POWER_PERIOD) {
+ ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
+ if (ret)
+ return ret;
+ ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
+ wrq->value / 1024);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_giwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+ return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 enable, mcast;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1)
+ < 0)
+ return -EINVAL;
+
+ if (!__le16_to_cpu(enable)) {
+ rrq->disabled = 1;
+ return 0;
+ }
+
+ rrq->disabled = 0;
+
+ if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ u16 timeout;
+ if (local->func->get_rid(dev,
+ HFA384X_RID_CNFPMHOLDOVERDURATION,
+ &timeout, 2, 1) < 0)
+ return -EINVAL;
+
+ rrq->flags = IW_POWER_TIMEOUT;
+ rrq->value = __le16_to_cpu(timeout) * 1024;
+ } else {
+ u16 period;
+ if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
+ &period, 2, 1) < 0)
+ return -EINVAL;
+
+ rrq->flags = IW_POWER_PERIOD;
+ rrq->value = __le16_to_cpu(period) * 1024;
+ }
+
+ if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast,
+ 2, 1) < 0)
+ return -EINVAL;
+
+ if (__le16_to_cpu(mcast))
+ rrq->flags |= IW_POWER_ALL_R;
+ else
+ rrq->flags |= IW_POWER_UNICAST_R;
+
+ return 0;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_siwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (rrq->disabled)
+ return -EINVAL;
+
+ /* setting retry limits is not supported with the current station
+ * firmware code; simulate this with alternative retry count for now */
+ if (rrq->flags == IW_RETRY_LIMIT) {
+ if (rrq->value < 0) {
+ /* disable manual retry count setting and use firmware
+ * defaults */
+ local->manual_retry_count = -1;
+ local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY;
+ } else {
+ if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
+ rrq->value)) {
+ printk(KERN_DEBUG "%s: Alternate retry count "
+ "setting to %d failed\n",
+ dev->name, rrq->value);
+ return -EOPNOTSUPP;
+ }
+
+ local->manual_retry_count = rrq->value;
+ local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY;
+ }
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+
+#if 0
+ /* what could be done, if firmware would support this.. */
+
+ if (rrq->flags & IW_RETRY_LIMIT) {
+ if (rrq->flags & IW_RETRY_MAX)
+ HFA384X_RID_LONGRETRYLIMIT = rrq->value;
+ else if (rrq->flags & IW_RETRY_MIN)
+ HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
+ else {
+ HFA384X_RID_LONGRETRYLIMIT = rrq->value;
+ HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
+ }
+
+ }
+
+ if (rrq->flags & IW_RETRY_LIFETIME) {
+ HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024;
+ }
+
+ return 0;
+#endif /* 0 */
+}
+
+static int prism2_ioctl_giwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 shortretry, longretry, lifetime, altretry;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry,
+ 2, 1) < 0 ||
+ local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry,
+ 2, 1) < 0 ||
+ local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME,
+ &lifetime, 2, 1) < 0)
+ return -EINVAL;
+
+ le16_to_cpus(&shortretry);
+ le16_to_cpus(&longretry);
+ le16_to_cpus(&lifetime);
+
+ rrq->disabled = 0;
+
+ if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+ rrq->flags = IW_RETRY_LIFETIME;
+ rrq->value = lifetime * 1024;
+ } else {
+ if (local->manual_retry_count >= 0) {
+ rrq->flags = IW_RETRY_LIMIT;
+ if (local->func->get_rid(dev,
+ HFA384X_RID_CNFALTRETRYCOUNT,
+ &altretry, 2, 1) >= 0)
+ rrq->value = le16_to_cpu(altretry);
+ else
+ rrq->value = local->manual_retry_count;
+ } else if ((rrq->flags & IW_RETRY_MAX)) {
+ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ rrq->value = longretry;
+ } else {
+ rrq->flags = IW_RETRY_LIMIT;
+ rrq->value = shortretry;
+ if (shortretry != longretry)
+ rrq->flags |= IW_RETRY_MIN;
+ }
+ }
+ return 0;
+}
+
+
+/* Note! This TX power controlling is experimental and should not be used in
+ * production use. It just sets raw power register and does not use any kind of
+ * feedback information from the measured TX power (CR58). This is now
+ * commented out to make sure that it is not used by accident. TX power
+ * configuration will be enabled again after proper algorithm using feedback
+ * has been implemented. */
+
+#ifdef RAW_TXPOWER_SETTING
+/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping..
+ * This version assumes following mapping:
+ * CR31 is 7-bit value with -64 to +63 range.
+ * -64 is mapped into +20dBm and +63 into -43dBm.
+ * This is certainly not an exact mapping for every card, but at least
+ * increasing dBm value should correspond to increasing TX power.
+ */
+
+static int prism2_txpower_hfa386x_to_dBm(u16 val)
+{
+ signed char tmp;
+
+ if (val > 255)
+ val = 255;
+
+ tmp = val;
+ tmp >>= 2;
+
+ return -12 - tmp;
+}
+
+static u16 prism2_txpower_dBm_to_hfa386x(int val)
+{
+ signed char tmp;
+
+ if (val > 20)
+ return 128;
+ else if (val < -43)
+ return 127;
+
+ tmp = val;
+ tmp = -12 - tmp;
+ tmp <<= 2;
+
+ return (unsigned char) tmp;
+}
+#endif /* RAW_TXPOWER_SETTING */
+
+
+static int prism2_ioctl_siwtxpow(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+#ifdef RAW_TXPOWER_SETTING
+ char *tmp;
+#endif
+ u16 val;
+ int ret = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (rrq->disabled) {
+ if (local->txpower_type != PRISM2_TXPOWER_OFF) {
+ val = 0xff; /* use all standby and sleep modes */
+ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_A_D_TEST_MODES2,
+ &val, NULL);
+ printk(KERN_DEBUG "%s: Turning radio off: %s\n",
+ dev->name, ret ? "failed" : "OK");
+ local->txpower_type = PRISM2_TXPOWER_OFF;
+ }
+ return (ret ? -EOPNOTSUPP : 0);
+ }
+
+ if (local->txpower_type == PRISM2_TXPOWER_OFF) {
+ val = 0; /* disable all standby and sleep modes */
+ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_A_D_TEST_MODES2, &val, NULL);
+ printk(KERN_DEBUG "%s: Turning radio on: %s\n",
+ dev->name, ret ? "failed" : "OK");
+ local->txpower_type = PRISM2_TXPOWER_UNKNOWN;
+ }
+
+#ifdef RAW_TXPOWER_SETTING
+ if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) {
+ printk(KERN_DEBUG "Setting ALC on\n");
+ val = HFA384X_TEST_CFG_BIT_ALC;
+ local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL);
+ local->txpower_type = PRISM2_TXPOWER_AUTO;
+ return 0;
+ }
+
+ if (local->txpower_type != PRISM2_TXPOWER_FIXED) {
+ printk(KERN_DEBUG "Setting ALC off\n");
+ val = HFA384X_TEST_CFG_BIT_ALC;
+ local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
+ local->txpower_type = PRISM2_TXPOWER_FIXED;
+ }
+
+ if (rrq->flags == IW_TXPOW_DBM)
+ tmp = "dBm";
+ else if (rrq->flags == IW_TXPOW_MWATT)
+ tmp = "mW";
+ else
+ tmp = "UNKNOWN";
+ printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp);
+
+ if (rrq->flags != IW_TXPOW_DBM) {
+ printk("SIOCSIWTXPOW with mW is not supported; use dBm\n");
+ return -EOPNOTSUPP;
+ }
+
+ local->txpower = rrq->value;
+ val = prism2_txpower_dBm_to_hfa386x(local->txpower);
+ if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_MANUAL_TX_POWER, &val, NULL))
+ ret = -EOPNOTSUPP;
+#else /* RAW_TXPOWER_SETTING */
+ if (rrq->fixed)
+ ret = -EOPNOTSUPP;
+#endif /* RAW_TXPOWER_SETTING */
+
+ return ret;
+}
+
+static int prism2_ioctl_giwtxpow(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq, char *extra)
+{
+#ifdef RAW_TXPOWER_SETTING
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 resp0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ rrq->flags = IW_TXPOW_DBM;
+ rrq->disabled = 0;
+ rrq->fixed = 0;
+
+ if (local->txpower_type == PRISM2_TXPOWER_AUTO) {
+ if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF,
+ HFA386X_CR_MANUAL_TX_POWER,
+ NULL, &resp0) == 0) {
+ rrq->value = prism2_txpower_hfa386x_to_dBm(resp0);
+ } else {
+ /* Could not get real txpower; guess 15 dBm */
+ rrq->value = 15;
+ }
+ } else if (local->txpower_type == PRISM2_TXPOWER_OFF) {
+ rrq->value = 0;
+ rrq->disabled = 1;
+ } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
+ rrq->value = local->txpower;
+ rrq->fixed = 1;
+ } else {
+ printk("SIOCGIWTXPOW - unknown txpower_type=%d\n",
+ local->txpower_type);
+ }
+ return 0;
+#else /* RAW_TXPOWER_SETTING */
+ return -EOPNOTSUPP;
+#endif /* RAW_TXPOWER_SETTING */
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+
+/* HostScan request works with and without host_roaming mode. In addition, it
+ * does not break current association. However, it requires newer station
+ * firmware version (>= 1.3.1) than scan request. */
+static int prism2_request_hostscan(struct net_device *dev,
+ u8 *ssid, u8 ssid_len)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hfa384x_hostscan_request scan_req;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ memset(&scan_req, 0, sizeof(scan_req));
+ scan_req.channel_list = cpu_to_le16(local->channel_mask &
+ local->scan_channel_mask);
+ scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+ if (ssid) {
+ if (ssid_len > 32)
+ return -EINVAL;
+ scan_req.target_ssid_len = cpu_to_le16(ssid_len);
+ memcpy(scan_req.target_ssid, ssid, ssid_len);
+ }
+
+ if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
+ sizeof(scan_req))) {
+ printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int prism2_request_scan(struct net_device *dev)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ struct hfa384x_scan_request scan_req;
+ int ret = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ memset(&scan_req, 0, sizeof(scan_req));
+ scan_req.channel_list = cpu_to_le16(local->channel_mask &
+ local->scan_channel_mask);
+ scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+
+ /* FIX:
+ * It seems to be enough to set roaming mode for a short moment to
+ * host-based and then setup scanrequest data and return the mode to
+ * firmware-based.
+ *
+ * Master mode would need to drop to Managed mode for a short while
+ * to make scanning work.. Or sweep through the different channels and
+ * use passive scan based on beacons. */
+
+ if (!local->host_roaming)
+ hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
+ HFA384X_ROAMING_HOST);
+
+ if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req,
+ sizeof(scan_req))) {
+ printk(KERN_DEBUG "SCANREQUEST failed\n");
+ ret = -EINVAL;
+ }
+
+ if (!local->host_roaming)
+ hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
+ HFA384X_ROAMING_FIRMWARE);
+
+ return 0;
+}
+
+#else /* !PRISM2_NO_STATION_MODES */
+
+static inline int prism2_request_hostscan(struct net_device *dev,
+ u8 *ssid, u8 ssid_len)
+{
+ return -EOPNOTSUPP;
+}
+
+
+static inline int prism2_request_scan(struct net_device *dev)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif /* !PRISM2_NO_STATION_MODES */
+
+
+static int prism2_ioctl_siwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret;
+ u8 *ssid = NULL, ssid_len = 0;
+ struct iw_scan_req *req = (struct iw_scan_req *) extra;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (data->length < sizeof(struct iw_scan_req))
+ req = NULL;
+
+ if (local->iw_mode == IW_MODE_MASTER) {
+ /* In master mode, we just return the results of our local
+ * tables, so we don't need to start anything...
+ * Jean II */
+ data->length = 0;
+ return 0;
+ }
+
+ if (!local->dev_enabled)
+ return -ENETDOWN;
+
+ if (req && data->flags & IW_SCAN_THIS_ESSID) {
+ ssid = req->essid;
+ ssid_len = req->essid_len;
+
+ if (ssid_len &&
+ ((local->iw_mode != IW_MODE_INFRA &&
+ local->iw_mode != IW_MODE_ADHOC) ||
+ (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))))
+ return -EOPNOTSUPP;
+ }
+
+ if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
+ ret = prism2_request_hostscan(dev, ssid, ssid_len);
+ else
+ ret = prism2_request_scan(dev);
+
+ if (ret == 0)
+ local->scan_timestamp = jiffies;
+
+ /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */
+
+ return ret;
+}
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static char * __prism2_translate_scan(local_info_t *local,
+ struct hfa384x_hostscan_result *scan,
+ struct hostap_bss_info *bss,
+ char *current_ev, char *end_buf)
+{
+ int i, chan;
+ struct iw_event iwe;
+ char *current_val;
+ u16 capabilities;
+ u8 *pos;
+ u8 *ssid, *bssid;
+ size_t ssid_len;
+ char *buf;
+
+ if (bss) {
+ ssid = bss->ssid;
+ ssid_len = bss->ssid_len;
+ bssid = bss->bssid;
+ } else {
+ ssid = scan->ssid;
+ ssid_len = le16_to_cpu(scan->ssid_len);
+ bssid = scan->bssid;
+ }
+ if (ssid_len > 32)
+ ssid_len = 32;
+
+ /* First entry *MUST* be the AP MAC address */
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ /* FIX:
+ * I do not know how this is possible, but iwe_stream_add_event
+ * seems to re-order memcpy execution so that len is set only
+ * after copying.. Pre-setting len here "fixes" this, but real
+ * problems should be solved (after which these iwe.len
+ * settings could be removed from this function). */
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_ADDR_LEN);
+
+ /* Other entries will be displayed in the order we give them */
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = ssid_len;
+ iwe.u.data.flags = 1;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWMODE;
+ if (bss) {
+ capabilities = bss->capab_info;
+ } else {
+ capabilities = le16_to_cpu(scan->capability);
+ }
+ if (capabilities & (WLAN_CAPABILITY_ESS |
+ WLAN_CAPABILITY_IBSS)) {
+ if (capabilities & WLAN_CAPABILITY_ESS)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_UINT_LEN);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ if (scan) {
+ chan = scan->chid;
+ } else if (bss) {
+ chan = bss->chan;
+ } else {
+ chan = 0;
+ }
+
+ if (chan > 0) {
+ iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000;
+ iwe.u.freq.e = 1;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+ }
+
+ if (scan) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ if (local->last_scan_type == PRISM2_HOSTSCAN) {
+ iwe.u.qual.level = le16_to_cpu(scan->sl);
+ iwe.u.qual.noise = le16_to_cpu(scan->anl);
+ } else {
+ iwe.u.qual.level =
+ HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl));
+ iwe.u.qual.noise =
+ HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl));
+ }
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_QUAL_LEN);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWENCODE;
+ if (capabilities & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
+
+ /* TODO: add SuppRates into BSS table */
+ if (scan) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWRATE;
+ current_val = current_ev + IW_EV_LCP_LEN;
+ pos = scan->sup_rates;
+ for (i = 0; i < sizeof(scan->sup_rates); i++) {
+ if (pos[i] == 0)
+ break;
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
+ current_val = iwe_stream_add_value(
+ current_ev, current_val, end_buf, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ /* Check if we added any event */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ /* TODO: add BeaconInt,resp_rate,atim into BSS table */
+ buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL);
+ if (buf && scan) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ buf);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ buf);
+
+ if (local->last_scan_type == PRISM2_HOSTSCAN &&
+ (capabilities & WLAN_CAPABILITY_IBSS)) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ }
+ }
+ kfree(buf);
+
+ if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->wpa_ie_len;
+ current_ev = iwe_stream_add_point(
+ current_ev, end_buf, &iwe, bss->wpa_ie);
+ }
+
+ if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->rsn_ie_len;
+ current_ev = iwe_stream_add_point(
+ current_ev, end_buf, &iwe, bss->rsn_ie);
+ }
+
+ return current_ev;
+}
+
+
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int prism2_translate_scan(local_info_t *local,
+ char *buffer, int buflen)
+{
+ struct hfa384x_hostscan_result *scan;
+ int entry, hostscan;
+ char *current_ev = buffer;
+ char *end_buf = buffer + buflen;
+ struct list_head *ptr;
+
+ spin_lock_bh(&local->lock);
+
+ list_for_each(ptr, &local->bss_list) {
+ struct hostap_bss_info *bss;
+ bss = list_entry(ptr, struct hostap_bss_info, list);
+ bss->included = 0;
+ }
+
+ hostscan = local->last_scan_type == PRISM2_HOSTSCAN;
+ for (entry = 0; entry < local->last_scan_results_count; entry++) {
+ int found = 0;
+ scan = &local->last_scan_results[entry];
+
+ /* Report every SSID if the AP is using multiple SSIDs. If no
+ * BSS record is found (e.g., when WPA mode is disabled),
+ * report the AP once. */
+ list_for_each(ptr, &local->bss_list) {
+ struct hostap_bss_info *bss;
+ bss = list_entry(ptr, struct hostap_bss_info, list);
+ if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) {
+ bss->included = 1;
+ current_ev = __prism2_translate_scan(
+ local, scan, bss, current_ev, end_buf);
+ found++;
+ }
+ }
+ if (!found) {
+ current_ev = __prism2_translate_scan(
+ local, scan, NULL, current_ev, end_buf);
+ }
+ /* Check if there is space for one more entry */
+ if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
+ /* Ask user space to try again with a bigger buffer */
+ spin_unlock_bh(&local->lock);
+ return -E2BIG;
+ }
+ }
+
+ /* Prism2 firmware has limits (32 at least in some versions) for number
+ * of BSSes in scan results. Extend this limit by using local BSS list.
+ */
+ list_for_each(ptr, &local->bss_list) {
+ struct hostap_bss_info *bss;
+ bss = list_entry(ptr, struct hostap_bss_info, list);
+ if (bss->included)
+ continue;
+ current_ev = __prism2_translate_scan(local, NULL, bss,
+ current_ev, end_buf);
+ /* Check if there is space for one more entry */
+ if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
+ /* Ask user space to try again with a bigger buffer */
+ spin_unlock_bh(&local->lock);
+ return -E2BIG;
+ }
+ }
+
+ spin_unlock_bh(&local->lock);
+
+ return current_ev - buffer;
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+#ifdef PRISM2_NO_STATION_MODES
+ return -EOPNOTSUPP;
+#else /* PRISM2_NO_STATION_MODES */
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int res;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ /* Wait until the scan is finished. We can probably do better
+ * than that - Jean II */
+ if (local->scan_timestamp &&
+ time_before(jiffies, local->scan_timestamp + 3 * HZ)) {
+ /* Important note : we don't want to block the caller
+ * until results are ready for various reasons.
+ * First, managing wait queues is complex and racy
+ * (there may be multiple simultaneous callers).
+ * Second, we grab some rtnetlink lock before comming
+ * here (in dev_ioctl()).
+ * Third, the caller can wait on the Wireless Event
+ * - Jean II */
+ return -EAGAIN;
+ }
+ local->scan_timestamp = 0;
+
+ res = prism2_translate_scan(local, extra, data->length);
+
+ if (res >= 0) {
+ data->length = res;
+ return 0;
+ } else {
+ data->length = 0;
+ return res;
+ }
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_giwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int res;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->iw_mode == IW_MODE_MASTER) {
+ /* In MASTER mode, it doesn't make sense to go around
+ * scanning the frequencies and make the stations we serve
+ * wait when what the user is really interested about is the
+ * list of stations and access points we are talking to.
+ * So, just extract results from our cache...
+ * Jean II */
+
+ /* Translate to WE format */
+ res = prism2_ap_translate_scan(dev, extra);
+ if (res >= 0) {
+ printk(KERN_DEBUG "Scan result translation succeeded "
+ "(length=%d)\n", res);
+ data->length = res;
+ return 0;
+ } else {
+ printk(KERN_DEBUG
+ "Scan result translation failed (res=%d)\n",
+ res);
+ data->length = 0;
+ return res;
+ }
+ } else {
+ /* Station mode */
+ return prism2_ioctl_giwscan_sta(dev, info, data, extra);
+ }
+}
+
+
+static const struct iw_priv_args prism2_priv[] = {
+ { PRISM2_IOCTL_MONITOR,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" },
+ { PRISM2_IOCTL_READMIF,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" },
+ { PRISM2_IOCTL_WRITEMIF,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" },
+ { PRISM2_IOCTL_RESET,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" },
+ { PRISM2_IOCTL_INQUIRE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" },
+ { PRISM2_IOCTL_SET_RID_WORD,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" },
+ { PRISM2_IOCTL_MACCMD,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" },
+ { PRISM2_IOCTL_WDS_ADD,
+ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" },
+ { PRISM2_IOCTL_WDS_DEL,
+ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" },
+ { PRISM2_IOCTL_ADDMAC,
+ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" },
+ { PRISM2_IOCTL_DELMAC,
+ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" },
+ { PRISM2_IOCTL_KICKMAC,
+ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" },
+ /* --- raw access to sub-ioctls --- */
+ { PRISM2_IOCTL_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" },
+ { PRISM2_IOCTL_GET_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" },
+ /* --- sub-ioctls handlers --- */
+ { PRISM2_IOCTL_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
+ { PRISM2_IOCTL_GET_PRISM2_PARAM,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
+ /* --- sub-ioctls definitions --- */
+ { PRISM2_PARAM_TXRATECTRL,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" },
+ { PRISM2_PARAM_TXRATECTRL,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" },
+ { PRISM2_PARAM_BEACON_INT,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" },
+ { PRISM2_PARAM_BEACON_INT,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" },
+#ifndef PRISM2_NO_STATION_MODES
+ { PRISM2_PARAM_PSEUDO_IBSS,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" },
+ { PRISM2_PARAM_PSEUDO_IBSS,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" },
+#endif /* PRISM2_NO_STATION_MODES */
+ { PRISM2_PARAM_ALC,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" },
+ { PRISM2_PARAM_ALC,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" },
+ { PRISM2_PARAM_DUMP,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" },
+ { PRISM2_PARAM_DUMP,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" },
+ { PRISM2_PARAM_OTHER_AP_POLICY,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" },
+ { PRISM2_PARAM_OTHER_AP_POLICY,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" },
+ { PRISM2_PARAM_AP_MAX_INACTIVITY,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" },
+ { PRISM2_PARAM_AP_MAX_INACTIVITY,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" },
+ { PRISM2_PARAM_AP_BRIDGE_PACKETS,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" },
+ { PRISM2_PARAM_AP_BRIDGE_PACKETS,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" },
+ { PRISM2_PARAM_DTIM_PERIOD,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" },
+ { PRISM2_PARAM_DTIM_PERIOD,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" },
+ { PRISM2_PARAM_AP_NULLFUNC_ACK,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" },
+ { PRISM2_PARAM_AP_NULLFUNC_ACK,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" },
+ { PRISM2_PARAM_MAX_WDS,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" },
+ { PRISM2_PARAM_MAX_WDS,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" },
+ { PRISM2_PARAM_AP_AUTOM_AP_WDS,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" },
+ { PRISM2_PARAM_AP_AUTOM_AP_WDS,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" },
+ { PRISM2_PARAM_AP_AUTH_ALGS,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" },
+ { PRISM2_PARAM_AP_AUTH_ALGS,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" },
+ { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" },
+ { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" },
+ { PRISM2_PARAM_HOST_ENCRYPT,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" },
+ { PRISM2_PARAM_HOST_ENCRYPT,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" },
+ { PRISM2_PARAM_HOST_DECRYPT,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" },
+ { PRISM2_PARAM_HOST_DECRYPT,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" },
+#ifndef PRISM2_NO_STATION_MODES
+ { PRISM2_PARAM_HOST_ROAMING,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" },
+ { PRISM2_PARAM_HOST_ROAMING,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" },
+#endif /* PRISM2_NO_STATION_MODES */
+ { PRISM2_PARAM_BCRX_STA_KEY,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" },
+ { PRISM2_PARAM_BCRX_STA_KEY,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" },
+ { PRISM2_PARAM_IEEE_802_1X,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" },
+ { PRISM2_PARAM_IEEE_802_1X,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" },
+ { PRISM2_PARAM_ANTSEL_TX,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" },
+ { PRISM2_PARAM_ANTSEL_TX,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" },
+ { PRISM2_PARAM_ANTSEL_RX,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" },
+ { PRISM2_PARAM_ANTSEL_RX,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" },
+ { PRISM2_PARAM_MONITOR_TYPE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" },
+ { PRISM2_PARAM_MONITOR_TYPE,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" },
+ { PRISM2_PARAM_WDS_TYPE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" },
+ { PRISM2_PARAM_WDS_TYPE,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" },
+ { PRISM2_PARAM_HOSTSCAN,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" },
+ { PRISM2_PARAM_HOSTSCAN,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" },
+ { PRISM2_PARAM_AP_SCAN,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" },
+ { PRISM2_PARAM_AP_SCAN,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" },
+ { PRISM2_PARAM_ENH_SEC,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" },
+ { PRISM2_PARAM_ENH_SEC,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" },
+#ifdef PRISM2_IO_DEBUG
+ { PRISM2_PARAM_IO_DEBUG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" },
+ { PRISM2_PARAM_IO_DEBUG,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" },
+#endif /* PRISM2_IO_DEBUG */
+ { PRISM2_PARAM_BASIC_RATES,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" },
+ { PRISM2_PARAM_BASIC_RATES,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" },
+ { PRISM2_PARAM_OPER_RATES,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" },
+ { PRISM2_PARAM_OPER_RATES,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" },
+ { PRISM2_PARAM_HOSTAPD,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" },
+ { PRISM2_PARAM_HOSTAPD,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" },
+ { PRISM2_PARAM_HOSTAPD_STA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" },
+ { PRISM2_PARAM_HOSTAPD_STA,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" },
+ { PRISM2_PARAM_WPA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" },
+ { PRISM2_PARAM_WPA,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" },
+ { PRISM2_PARAM_PRIVACY_INVOKED,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" },
+ { PRISM2_PARAM_PRIVACY_INVOKED,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" },
+ { PRISM2_PARAM_TKIP_COUNTERMEASURES,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" },
+ { PRISM2_PARAM_TKIP_COUNTERMEASURES,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" },
+ { PRISM2_PARAM_DROP_UNENCRYPTED,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" },
+ { PRISM2_PARAM_DROP_UNENCRYPTED,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" },
+ { PRISM2_PARAM_SCAN_CHANNEL_MASK,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" },
+ { PRISM2_PARAM_SCAN_CHANNEL_MASK,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" },
+};
+
+
+static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+
+static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int *i = (int *) extra;
+ int param = *i;
+ int value = *(i + 1);
+ int ret = 0;
+ u16 val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ switch (param) {
+ case PRISM2_PARAM_TXRATECTRL:
+ local->fw_tx_rate_control = value;
+ break;
+
+ case PRISM2_PARAM_BEACON_INT:
+ if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) ||
+ local->func->reset_port(dev))
+ ret = -EINVAL;
+ else
+ local->beacon_int = value;
+ break;
+
+#ifndef PRISM2_NO_STATION_MODES
+ case PRISM2_PARAM_PSEUDO_IBSS:
+ if (value == local->pseudo_adhoc)
+ break;
+
+ if (value != 0 && value != 1) {
+ ret = -EINVAL;
+ break;
+ }
+
+ printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n",
+ dev->name, local->pseudo_adhoc, value);
+ local->pseudo_adhoc = value;
+ if (local->iw_mode != IW_MODE_ADHOC)
+ break;
+
+ if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+ hostap_get_porttype(local))) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (local->func->reset_port(dev))
+ ret = -EINVAL;
+ break;
+#endif /* PRISM2_NO_STATION_MODES */
+
+ case PRISM2_PARAM_ALC:
+ printk(KERN_DEBUG "%s: %s ALC\n", dev->name,
+ value == 0 ? "Disabling" : "Enabling");
+ val = HFA384X_TEST_CFG_BIT_ALC;
+ local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_CFG_BITS << 8),
+ value == 0 ? 0 : 1, &val, NULL);
+ break;
+
+ case PRISM2_PARAM_DUMP:
+ local->frame_dump = value;
+ break;
+
+ case PRISM2_PARAM_OTHER_AP_POLICY:
+ if (value < 0 || value > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ if (local->ap != NULL)
+ local->ap->ap_policy = value;
+ break;
+
+ case PRISM2_PARAM_AP_MAX_INACTIVITY:
+ if (value < 0 || value > 7 * 24 * 60 * 60) {
+ ret = -EINVAL;
+ break;
+ }
+ if (local->ap != NULL)
+ local->ap->max_inactivity = value * HZ;
+ break;
+
+ case PRISM2_PARAM_AP_BRIDGE_PACKETS:
+ if (local->ap != NULL)
+ local->ap->bridge_packets = value;
+ break;
+
+ case PRISM2_PARAM_DTIM_PERIOD:
+ if (value < 0 || value > 65535) {
+ ret = -EINVAL;
+ break;
+ }
+ if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value)
+ || local->func->reset_port(dev))
+ ret = -EINVAL;
+ else
+ local->dtim_period = value;
+ break;
+
+ case PRISM2_PARAM_AP_NULLFUNC_ACK:
+ if (local->ap != NULL)
+ local->ap->nullfunc_ack = value;
+ break;
+
+ case PRISM2_PARAM_MAX_WDS:
+ local->wds_max_connections = value;
+ break;
+
+ case PRISM2_PARAM_AP_AUTOM_AP_WDS:
+ if (local->ap != NULL) {
+ if (!local->ap->autom_ap_wds && value) {
+ /* add WDS link to all APs in STA table */
+ hostap_add_wds_links(local);
+ }
+ local->ap->autom_ap_wds = value;
+ }
+ break;
+
+ case PRISM2_PARAM_AP_AUTH_ALGS:
+ local->auth_algs = value;
+ if (hostap_set_auth_algs(local))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
+ local->monitor_allow_fcserr = value;
+ break;
+
+ case PRISM2_PARAM_HOST_ENCRYPT:
+ local->host_encrypt = value;
+ if (hostap_set_encryption(local) ||
+ local->func->reset_port(dev))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_HOST_DECRYPT:
+ local->host_decrypt = value;
+ if (hostap_set_encryption(local) ||
+ local->func->reset_port(dev))
+ ret = -EINVAL;
+ break;
+
+#ifndef PRISM2_NO_STATION_MODES
+ case PRISM2_PARAM_HOST_ROAMING:
+ if (value < 0 || value > 2) {
+ ret = -EINVAL;
+ break;
+ }
+ local->host_roaming = value;
+ if (hostap_set_roaming(local) || local->func->reset_port(dev))
+ ret = -EINVAL;
+ break;
+#endif /* PRISM2_NO_STATION_MODES */
+
+ case PRISM2_PARAM_BCRX_STA_KEY:
+ local->bcrx_sta_key = value;
+ break;
+
+ case PRISM2_PARAM_IEEE_802_1X:
+ local->ieee_802_1x = value;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_TX:
+ if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
+ ret = -EINVAL;
+ break;
+ }
+ local->antsel_tx = value;
+ hostap_set_antsel(local);
+ break;
+
+ case PRISM2_PARAM_ANTSEL_RX:
+ if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
+ ret = -EINVAL;
+ break;
+ }
+ local->antsel_rx = value;
+ hostap_set_antsel(local);
+ break;
+
+ case PRISM2_PARAM_MONITOR_TYPE:
+ if (value != PRISM2_MONITOR_80211 &&
+ value != PRISM2_MONITOR_CAPHDR &&
+ value != PRISM2_MONITOR_PRISM) {
+ ret = -EINVAL;
+ break;
+ }
+ local->monitor_type = value;
+ if (local->iw_mode == IW_MODE_MONITOR)
+ hostap_monitor_set_type(local);
+ break;
+
+ case PRISM2_PARAM_WDS_TYPE:
+ local->wds_type = value;
+ break;
+
+ case PRISM2_PARAM_HOSTSCAN:
+ {
+ struct hfa384x_hostscan_request scan_req;
+ u16 rate;
+
+ memset(&scan_req, 0, sizeof(scan_req));
+ scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
+ switch (value) {
+ case 1: rate = HFA384X_RATES_1MBPS; break;
+ case 2: rate = HFA384X_RATES_2MBPS; break;
+ case 3: rate = HFA384X_RATES_5MBPS; break;
+ case 4: rate = HFA384X_RATES_11MBPS; break;
+ default: rate = HFA384X_RATES_1MBPS; break;
+ }
+ scan_req.txrate = cpu_to_le16(rate);
+ /* leave SSID empty to accept all SSIDs */
+
+ if (local->iw_mode == IW_MODE_MASTER) {
+ if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+ HFA384X_PORTTYPE_BSS) ||
+ local->func->reset_port(dev))
+ printk(KERN_DEBUG "Leaving Host AP mode "
+ "for HostScan failed\n");
+ }
+
+ if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
+ sizeof(scan_req))) {
+ printk(KERN_DEBUG "HOSTSCAN failed\n");
+ ret = -EINVAL;
+ }
+ if (local->iw_mode == IW_MODE_MASTER) {
+ wait_queue_t __wait;
+ init_waitqueue_entry(&__wait, current);
+ add_wait_queue(&local->hostscan_wq, &__wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ if (signal_pending(current))
+ ret = -EINTR;
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&local->hostscan_wq, &__wait);
+
+ if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
+ HFA384X_PORTTYPE_HOSTAP) ||
+ local->func->reset_port(dev))
+ printk(KERN_DEBUG "Returning to Host AP mode "
+ "after HostScan failed\n");
+ }
+ break;
+ }
+
+ case PRISM2_PARAM_AP_SCAN:
+ local->passive_scan_interval = value;
+ if (timer_pending(&local->passive_scan_timer))
+ del_timer(&local->passive_scan_timer);
+ if (value > 0) {
+ local->passive_scan_timer.expires = jiffies +
+ local->passive_scan_interval * HZ;
+ add_timer(&local->passive_scan_timer);
+ }
+ break;
+
+ case PRISM2_PARAM_ENH_SEC:
+ if (value < 0 || value > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ local->enh_sec = value;
+ if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY,
+ local->enh_sec) ||
+ local->func->reset_port(dev)) {
+ printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w "
+ "1.6.3 or newer\n", dev->name);
+ ret = -EOPNOTSUPP;
+ }
+ break;
+
+#ifdef PRISM2_IO_DEBUG
+ case PRISM2_PARAM_IO_DEBUG:
+ local->io_debug_enabled = value;
+ break;
+#endif /* PRISM2_IO_DEBUG */
+
+ case PRISM2_PARAM_BASIC_RATES:
+ if ((value & local->tx_rate_control) != value || value == 0) {
+ printk(KERN_INFO "%s: invalid basic rate set - basic "
+ "rates must be in supported rate set\n",
+ dev->name);
+ ret = -EINVAL;
+ break;
+ }
+ local->basic_rates = value;
+ if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
+ local->basic_rates) ||
+ local->func->reset_port(dev))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_OPER_RATES:
+ local->tx_rate_control = value;
+ if (hostap_set_rate(dev))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_HOSTAPD:
+ ret = hostap_set_hostapd(local, value, 1);
+ break;
+
+ case PRISM2_PARAM_HOSTAPD_STA:
+ ret = hostap_set_hostapd_sta(local, value, 1);
+ break;
+
+ case PRISM2_PARAM_WPA:
+ local->wpa = value;
+ if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+ ret = -EOPNOTSUPP;
+ else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
+ value ? 1 : 0))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_PRIVACY_INVOKED:
+ local->privacy_invoked = value;
+ if (hostap_set_encryption(local) ||
+ local->func->reset_port(dev))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_TKIP_COUNTERMEASURES:
+ local->tkip_countermeasures = value;
+ break;
+
+ case PRISM2_PARAM_DROP_UNENCRYPTED:
+ local->drop_unencrypted = value;
+ break;
+
+ case PRISM2_PARAM_SCAN_CHANNEL_MASK:
+ local->scan_channel_mask = value;
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n",
+ dev->name, param);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int *param = (int *) extra;
+ int ret = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ switch (*param) {
+ case PRISM2_PARAM_TXRATECTRL:
+ *param = local->fw_tx_rate_control;
+ break;
+
+ case PRISM2_PARAM_BEACON_INT:
+ *param = local->beacon_int;
+ break;
+
+ case PRISM2_PARAM_PSEUDO_IBSS:
+ *param = local->pseudo_adhoc;
+ break;
+
+ case PRISM2_PARAM_ALC:
+ ret = -EOPNOTSUPP; /* FIX */
+ break;
+
+ case PRISM2_PARAM_DUMP:
+ *param = local->frame_dump;
+ break;
+
+ case PRISM2_PARAM_OTHER_AP_POLICY:
+ if (local->ap != NULL)
+ *param = local->ap->ap_policy;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+
+ case PRISM2_PARAM_AP_MAX_INACTIVITY:
+ if (local->ap != NULL)
+ *param = local->ap->max_inactivity / HZ;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+
+ case PRISM2_PARAM_AP_BRIDGE_PACKETS:
+ if (local->ap != NULL)
+ *param = local->ap->bridge_packets;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+
+ case PRISM2_PARAM_DTIM_PERIOD:
+ *param = local->dtim_period;
+ break;
+
+ case PRISM2_PARAM_AP_NULLFUNC_ACK:
+ if (local->ap != NULL)
+ *param = local->ap->nullfunc_ack;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+
+ case PRISM2_PARAM_MAX_WDS:
+ *param = local->wds_max_connections;
+ break;
+
+ case PRISM2_PARAM_AP_AUTOM_AP_WDS:
+ if (local->ap != NULL)
+ *param = local->ap->autom_ap_wds;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+
+ case PRISM2_PARAM_AP_AUTH_ALGS:
+ *param = local->auth_algs;
+ break;
+
+ case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
+ *param = local->monitor_allow_fcserr;
+ break;
+
+ case PRISM2_PARAM_HOST_ENCRYPT:
+ *param = local->host_encrypt;
+ break;
+
+ case PRISM2_PARAM_HOST_DECRYPT:
+ *param = local->host_decrypt;
+ break;
+
+ case PRISM2_PARAM_HOST_ROAMING:
+ *param = local->host_roaming;
+ break;
+
+ case PRISM2_PARAM_BCRX_STA_KEY:
+ *param = local->bcrx_sta_key;
+ break;
+
+ case PRISM2_PARAM_IEEE_802_1X:
+ *param = local->ieee_802_1x;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_TX:
+ *param = local->antsel_tx;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_RX:
+ *param = local->antsel_rx;
+ break;
+
+ case PRISM2_PARAM_MONITOR_TYPE:
+ *param = local->monitor_type;
+ break;
+
+ case PRISM2_PARAM_WDS_TYPE:
+ *param = local->wds_type;
+ break;
+
+ case PRISM2_PARAM_HOSTSCAN:
+ ret = -EOPNOTSUPP;
+ break;
+
+ case PRISM2_PARAM_AP_SCAN:
+ *param = local->passive_scan_interval;
+ break;
+
+ case PRISM2_PARAM_ENH_SEC:
+ *param = local->enh_sec;
+ break;
+
+#ifdef PRISM2_IO_DEBUG
+ case PRISM2_PARAM_IO_DEBUG:
+ *param = local->io_debug_enabled;
+ break;
+#endif /* PRISM2_IO_DEBUG */
+
+ case PRISM2_PARAM_BASIC_RATES:
+ *param = local->basic_rates;
+ break;
+
+ case PRISM2_PARAM_OPER_RATES:
+ *param = local->tx_rate_control;
+ break;
+
+ case PRISM2_PARAM_HOSTAPD:
+ *param = local->hostapd;
+ break;
+
+ case PRISM2_PARAM_HOSTAPD_STA:
+ *param = local->hostapd_sta;
+ break;
+
+ case PRISM2_PARAM_WPA:
+ if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+ ret = -EOPNOTSUPP;
+ *param = local->wpa;
+ break;
+
+ case PRISM2_PARAM_PRIVACY_INVOKED:
+ *param = local->privacy_invoked;
+ break;
+
+ case PRISM2_PARAM_TKIP_COUNTERMEASURES:
+ *param = local->tkip_countermeasures;
+ break;
+
+ case PRISM2_PARAM_DROP_UNENCRYPTED:
+ *param = local->drop_unencrypted;
+ break;
+
+ case PRISM2_PARAM_SCAN_CHANNEL_MASK:
+ *param = local->scan_channel_mask;
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n",
+ dev->name, *param);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int prism2_ioctl_priv_readmif(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 resp0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL,
+ &resp0))
+ return -EOPNOTSUPP;
+ else
+ *extra = resp0;
+
+ return 0;
+}
+
+
+static int prism2_ioctl_priv_writemif(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ u16 cr, val;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ cr = *extra;
+ val = *(extra + 1);
+ if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+
+static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret = 0;
+ u32 mode;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor "
+ "- update software to use iwconfig mode monitor\n",
+ dev->name, current->pid, current->comm);
+
+ /* Backward compatibility code - this can be removed at some point */
+
+ if (*i == 0) {
+ /* Disable monitor mode - old mode was not saved, so go to
+ * Master mode */
+ mode = IW_MODE_MASTER;
+ ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL);
+ } else if (*i == 1) {
+ /* netlink socket mode is not supported anymore since it did
+ * not separate different devices from each other and was not
+ * best method for delivering large amount of packets to
+ * user space */
+ ret = -EOPNOTSUPP;
+ } else if (*i == 2 || *i == 3) {
+ switch (*i) {
+ case 2:
+ local->monitor_type = PRISM2_MONITOR_80211;
+ break;
+ case 3:
+ local->monitor_type = PRISM2_MONITOR_PRISM;
+ break;
+ }
+ mode = IW_MODE_MONITOR;
+ ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL);
+ hostap_monitor_mode_enable(local);
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+
+static int prism2_ioctl_priv_reset(struct net_device *dev, int *i)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i);
+ switch (*i) {
+ case 0:
+ /* Disable and enable card */
+ local->func->hw_shutdown(dev, 1);
+ local->func->hw_config(dev, 0);
+ break;
+
+ case 1:
+ /* COR sreset */
+ local->func->hw_reset(dev);
+ break;
+
+ case 2:
+ /* Disable and enable port 0 */
+ local->func->reset_port(dev);
+ break;
+
+ case 3:
+ prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
+ if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL,
+ NULL))
+ return -EINVAL;
+ break;
+
+ case 4:
+ if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL,
+ NULL))
+ return -EINVAL;
+ break;
+
+ default:
+ printk(KERN_DEBUG "Unknown reset request %d\n", *i);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+
+static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i)
+{
+ int rid = *i;
+ int value = *(i + 1);
+
+ printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value);
+
+ if (hostap_set_word(dev, rid, value))
+ return -EINVAL;
+
+ return 0;
+}
+
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd)
+{
+ int ret = 0;
+
+ switch (*cmd) {
+ case AP_MAC_CMD_POLICY_OPEN:
+ local->ap->mac_restrictions.policy = MAC_POLICY_OPEN;
+ break;
+ case AP_MAC_CMD_POLICY_ALLOW:
+ local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW;
+ break;
+ case AP_MAC_CMD_POLICY_DENY:
+ local->ap->mac_restrictions.policy = MAC_POLICY_DENY;
+ break;
+ case AP_MAC_CMD_FLUSH:
+ ap_control_flush_macs(&local->ap->mac_restrictions);
+ break;
+ case AP_MAC_CMD_KICKALL:
+ ap_control_kickall(local->ap);
+ hostap_deauth_all_stas(local->dev, local->ap, 0);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
+{
+ struct prism2_download_param *param;
+ int ret = 0;
+
+ if (p->length < sizeof(struct prism2_download_param) ||
+ p->length > 1024 || !p->pointer)
+ return -EINVAL;
+
+ param = (struct prism2_download_param *)
+ kmalloc(p->length, GFP_KERNEL);
+ if (param == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (p->length < sizeof(struct prism2_download_param) +
+ param->num_areas * sizeof(struct prism2_download_area)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = local->func->download(local, param);
+
+ out:
+ if (param != NULL)
+ kfree(param);
+
+ return ret;
+}
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+
+static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
+ size_t len)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+ u8 *buf;
+
+ /*
+ * Add 16-bit length in the beginning of the buffer because Prism2 RID
+ * includes it.
+ */
+ buf = kmalloc(len + 2, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ *((u16 *) buf) = cpu_to_le16(len);
+ memcpy(buf + 2, elem, len);
+
+ kfree(local->generic_elem);
+ local->generic_elem = buf;
+ local->generic_elem_len = len + 2;
+
+ return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT,
+ buf, len + 2);
+}
+
+
+static int prism2_ioctl_siwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+
+ switch (data->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * Host AP driver does not use these parameters and allows
+ * wpa_supplicant to control them internally.
+ */
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ local->tkip_countermeasures = data->value;
+ break;
+ case IW_AUTH_DROP_UNENCRYPTED:
+ local->drop_unencrypted = data->value;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ local->auth_algs = data->value;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (data->value == 0) {
+ local->wpa = 0;
+ if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+ break;
+ prism2_set_genericelement(dev, "", 0);
+ local->host_roaming = 0;
+ local->privacy_invoked = 0;
+ if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
+ 0) ||
+ hostap_set_roaming(local) ||
+ hostap_set_encryption(local) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+ break;
+ }
+ if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
+ return -EOPNOTSUPP;
+ local->host_roaming = 2;
+ local->privacy_invoked = 1;
+ local->wpa = 1;
+ if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) ||
+ hostap_set_roaming(local) ||
+ hostap_set_encryption(local) ||
+ local->func->reset_port(dev))
+ return -EINVAL;
+ break;
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ local->ieee_802_1x = data->value;
+ break;
+ case IW_AUTH_PRIVACY_INVOKED:
+ local->privacy_invoked = data->value;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+
+static int prism2_ioctl_giwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+
+ switch (data->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * Host AP driver does not use these parameters and allows
+ * wpa_supplicant to control them internally.
+ */
+ return -EOPNOTSUPP;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ data->value = local->tkip_countermeasures;
+ break;
+ case IW_AUTH_DROP_UNENCRYPTED:
+ data->value = local->drop_unencrypted;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ data->value = local->auth_algs;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ data->value = local->wpa;
+ break;
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ data->value = local->ieee_802_1x;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+
+static int prism2_ioctl_siwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ int i, ret = 0;
+ struct ieee80211_crypto_ops *ops;
+ struct ieee80211_crypt_data **crypt;
+ void *sta_ptr;
+ u8 *addr;
+ const char *alg, *module;
+
+ i = erq->flags & IW_ENCODE_INDEX;
+ if (i > WEP_KEYS)
+ return -EINVAL;
+ if (i < 1 || i > WEP_KEYS)
+ i = local->tx_keyidx;
+ else
+ i--;
+ if (i < 0 || i >= WEP_KEYS)
+ return -EINVAL;
+
+ addr = ext->addr.sa_data;
+ if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+ addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+ sta_ptr = NULL;
+ crypt = &local->crypt[i];
+ } else {
+ if (i != 0)
+ return -EINVAL;
+ sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
+ if (sta_ptr == NULL) {
+ if (local->iw_mode == IW_MODE_INFRA) {
+ /*
+ * TODO: add STA entry for the current AP so
+ * that unicast key can be used. For now, this
+ * is emulated by using default key idx 0.
+ */
+ i = 0;
+ crypt = &local->crypt[i];
+ } else
+ return -EINVAL;
+ }
+ }
+
+ if ((erq->flags & IW_ENCODE_DISABLED) ||
+ ext->alg == IW_ENCODE_ALG_NONE) {
+ if (*crypt)
+ prism2_crypt_delayed_deinit(local, crypt);
+ goto done;
+ }
+
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_WEP:
+ alg = "WEP";
+ module = "ieee80211_crypt_wep";
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ alg = "TKIP";
+ module = "ieee80211_crypt_tkip";
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ alg = "CCMP";
+ module = "ieee80211_crypt_ccmp";
+ break;
+ default:
+ printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
+ local->dev->name, ext->alg);
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ ops = ieee80211_get_crypto_ops(alg);
+ if (ops == NULL) {
+ request_module(module);
+ ops = ieee80211_get_crypto_ops(alg);
+ }
+ if (ops == NULL) {
+ printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
+ local->dev->name, alg);
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) {
+ /*
+ * Per station encryption and other than WEP algorithms
+ * require host-based encryption, so force them on
+ * automatically.
+ */
+ local->host_decrypt = local->host_encrypt = 1;
+ }
+
+ if (*crypt == NULL || (*crypt)->ops != ops) {
+ struct ieee80211_crypt_data *new_crypt;
+
+ prism2_crypt_delayed_deinit(local, crypt);
+
+ new_crypt = (struct ieee80211_crypt_data *)
+ kmalloc(sizeof(struct ieee80211_crypt_data),
+ GFP_KERNEL);
+ if (new_crypt == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+ new_crypt->ops = ops;
+ new_crypt->priv = new_crypt->ops->init(i);
+ if (new_crypt->priv == NULL) {
+ kfree(new_crypt);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *crypt = new_crypt;
+ }
+
+ /*
+ * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the
+ * existing seq# should not be changed.
+ * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq#
+ * should be changed to something else than zero.
+ */
+ if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0)
+ && (*crypt)->ops->set_key &&
+ (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
+ (*crypt)->priv) < 0) {
+ printk(KERN_DEBUG "%s: key setting failed\n",
+ local->dev->name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ if (!sta_ptr)
+ local->tx_keyidx = i;
+ else if (i) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+
+ if (sta_ptr == NULL && ext->key_len > 0) {
+ int first = 1, j;
+ for (j = 0; j < WEP_KEYS; j++) {
+ if (j != i && local->crypt[j]) {
+ first = 0;
+ break;
+ }
+ }
+ if (first)
+ local->tx_keyidx = i;
+ }
+
+ done:
+ if (sta_ptr)
+ hostap_handle_sta_release(sta_ptr);
+
+ local->open_wep = erq->flags & IW_ENCODE_OPEN;
+
+ /*
+ * Do not reset port0 if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. Prism2 documentation seem to require port reset
+ * after WEP configuration. However, keys are apparently changed at
+ * least in Managed mode.
+ */
+ if (ret == 0 &&
+ (hostap_set_encryption(local) ||
+ (local->iw_mode != IW_MODE_INFRA &&
+ local->func->reset_port(local->dev))))
+ ret = -EINVAL;
+
+ return ret;
+}
+
+
+static int prism2_ioctl_giwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+ struct ieee80211_crypt_data **crypt;
+ void *sta_ptr;
+ int max_key_len, i;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ u8 *addr;
+
+ max_key_len = erq->length - sizeof(*ext);
+ if (max_key_len < 0)
+ return -EINVAL;
+
+ i = erq->flags & IW_ENCODE_INDEX;
+ if (i < 1 || i > WEP_KEYS)
+ i = local->tx_keyidx;
+ else
+ i--;
+
+ addr = ext->addr.sa_data;
+ if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+ addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+ sta_ptr = NULL;
+ crypt = &local->crypt[i];
+ } else {
+ i = 0;
+ sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
+ if (sta_ptr == NULL)
+ return -EINVAL;
+ }
+ erq->flags = i + 1;
+ memset(ext, 0, sizeof(*ext));
+
+ if (*crypt == NULL || (*crypt)->ops == NULL) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (strcmp((*crypt)->ops->name, "WEP") == 0)
+ ext->alg = IW_ENCODE_ALG_WEP;
+ else if (strcmp((*crypt)->ops->name, "TKIP") == 0)
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ else if (strcmp((*crypt)->ops->name, "CCMP") == 0)
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ else
+ return -EINVAL;
+
+ if ((*crypt)->ops->get_key) {
+ ext->key_len =
+ (*crypt)->ops->get_key(ext->key,
+ max_key_len,
+ ext->tx_seq,
+ (*crypt)->priv);
+ if (ext->key_len &&
+ (ext->alg == IW_ENCODE_ALG_TKIP ||
+ ext->alg == IW_ENCODE_ALG_CCMP))
+ ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
+ }
+ }
+
+ if (sta_ptr)
+ hostap_handle_sta_release(sta_ptr);
+
+ return 0;
+}
+
+
+static int prism2_ioctl_set_encryption(local_info_t *local,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ int ret = 0;
+ struct ieee80211_crypto_ops *ops;
+ struct ieee80211_crypt_data **crypt;
+ void *sta_ptr;
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ if (param_len !=
+ (int) ((char *) param->u.crypt.key - (char *) param) +
+ param->u.crypt.key_len)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS)
+ return -EINVAL;
+ sta_ptr = NULL;
+ crypt = &local->crypt[param->u.crypt.idx];
+ } else {
+ if (param->u.crypt.idx)
+ return -EINVAL;
+ sta_ptr = ap_crypt_get_ptrs(
+ local->ap, param->sta_addr,
+ (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT),
+ &crypt);
+
+ if (sta_ptr == NULL) {
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+ return -EINVAL;
+ }
+ }
+
+ if (strcmp(param->u.crypt.alg, "none") == 0) {
+ if (crypt)
+ prism2_crypt_delayed_deinit(local, crypt);
+ goto done;
+ }
+
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
+ request_module("ieee80211_crypt_wep");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ request_module("ieee80211_crypt_tkip");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ request_module("ieee80211_crypt_ccmp");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ }
+ if (ops == NULL) {
+ printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
+ local->dev->name, param->u.crypt.alg);
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* station based encryption and other than WEP algorithms require
+ * host-based encryption, so force them on automatically */
+ local->host_decrypt = local->host_encrypt = 1;
+
+ if (*crypt == NULL || (*crypt)->ops != ops) {
+ struct ieee80211_crypt_data *new_crypt;
+
+ prism2_crypt_delayed_deinit(local, crypt);
+
+ new_crypt = (struct ieee80211_crypt_data *)
+ kmalloc(sizeof(struct ieee80211_crypt_data),
+ GFP_KERNEL);
+ if (new_crypt == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+ new_crypt->ops = ops;
+ new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
+ if (new_crypt->priv == NULL) {
+ kfree(new_crypt);
+ param->u.crypt.err =
+ HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *crypt = new_crypt;
+ }
+
+ if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) ||
+ param->u.crypt.key_len > 0) && (*crypt)->ops->set_key &&
+ (*crypt)->ops->set_key(param->u.crypt.key,
+ param->u.crypt.key_len, param->u.crypt.seq,
+ (*crypt)->priv) < 0) {
+ printk(KERN_DEBUG "%s: key setting failed\n",
+ local->dev->name);
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
+ if (!sta_ptr)
+ local->tx_keyidx = param->u.crypt.idx;
+ else if (param->u.crypt.idx) {
+ printk(KERN_DEBUG "%s: TX key idx setting failed\n",
+ local->dev->name);
+ param->u.crypt.err =
+ HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ done:
+ if (sta_ptr)
+ hostap_handle_sta_release(sta_ptr);
+
+ /* Do not reset port0 if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. Prism2 documentation seem to require port reset
+ * after WEP configuration. However, keys are apparently changed at
+ * least in Managed mode. */
+ if (ret == 0 &&
+ (hostap_set_encryption(local) ||
+ (local->iw_mode != IW_MODE_INFRA &&
+ local->func->reset_port(local->dev)))) {
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED;
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+
+static int prism2_ioctl_get_encryption(local_info_t *local,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ struct ieee80211_crypt_data **crypt;
+ void *sta_ptr;
+ int max_key_len;
+
+ param->u.crypt.err = 0;
+
+ max_key_len = param_len -
+ (int) ((char *) param->u.crypt.key - (char *) param);
+ if (max_key_len < 0)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ sta_ptr = NULL;
+ if (param->u.crypt.idx >= WEP_KEYS)
+ param->u.crypt.idx = local->tx_keyidx;
+ crypt = &local->crypt[param->u.crypt.idx];
+ } else {
+ param->u.crypt.idx = 0;
+ sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
+ &crypt);
+
+ if (sta_ptr == NULL) {
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+ return -EINVAL;
+ }
+ }
+
+ if (*crypt == NULL || (*crypt)->ops == NULL) {
+ memcpy(param->u.crypt.alg, "none", 5);
+ param->u.crypt.key_len = 0;
+ param->u.crypt.idx = 0xff;
+ } else {
+ strncpy(param->u.crypt.alg, (*crypt)->ops->name,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.key_len = 0;
+
+ memset(param->u.crypt.seq, 0, 8);
+ if ((*crypt)->ops->get_key) {
+ param->u.crypt.key_len =
+ (*crypt)->ops->get_key(param->u.crypt.key,
+ max_key_len,
+ param->u.crypt.seq,
+ (*crypt)->priv);
+ }
+ }
+
+ if (sta_ptr)
+ hostap_handle_sta_release(sta_ptr);
+
+ return 0;
+}
+
+
+static int prism2_ioctl_get_rid(local_info_t *local,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ int max_len, res;
+
+ max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
+ if (max_len < 0)
+ return -EINVAL;
+
+ res = local->func->get_rid(local->dev, param->u.rid.rid,
+ param->u.rid.data, param->u.rid.len, 0);
+ if (res >= 0) {
+ param->u.rid.len = res;
+ return 0;
+ }
+
+ return res;
+}
+
+
+static int prism2_ioctl_set_rid(local_info_t *local,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ int max_len;
+
+ max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
+ if (max_len < 0 || max_len < param->u.rid.len)
+ return -EINVAL;
+
+ return local->func->set_rid(local->dev, param->u.rid.rid,
+ param->u.rid.data, param->u.rid.len);
+}
+
+
+static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n",
+ local->dev->name, MAC2STR(param->sta_addr));
+ memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static int prism2_ioctl_siwgenie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ return prism2_set_genericelement(dev, extra, data->length);
+}
+
+
+static int prism2_ioctl_giwgenie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+ int len = local->generic_elem_len - 2;
+
+ if (len <= 0 || local->generic_elem == NULL) {
+ data->length = 0;
+ return 0;
+ }
+
+ if (data->length < len)
+ return -E2BIG;
+
+ data->length = len;
+ memcpy(extra, local->generic_elem + 2, len);
+
+ return 0;
+}
+
+
+static int prism2_ioctl_set_generic_element(local_info_t *local,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ int max_len, len;
+
+ len = param->u.generic_elem.len;
+ max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+ if (max_len < 0 || max_len < len)
+ return -EINVAL;
+
+ return prism2_set_genericelement(local->dev,
+ param->u.generic_elem.data, len);
+}
+
+
+static int prism2_ioctl_siwmlme(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ u16 reason;
+
+ reason = cpu_to_le16(mlme->reason_code);
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
+ IEEE80211_STYPE_DEAUTH,
+ (u8 *) &reason, 2);
+ case IW_MLME_DISASSOC:
+ return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
+ IEEE80211_STYPE_DISASSOC,
+ (u8 *) &reason, 2);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
+static int prism2_ioctl_mlme(local_info_t *local,
+ struct prism2_hostapd_param *param)
+{
+ u16 reason;
+
+ reason = cpu_to_le16(param->u.mlme.reason_code);
+ switch (param->u.mlme.cmd) {
+ case MLME_STA_DEAUTH:
+ return prism2_sta_send_mgmt(local, param->sta_addr,
+ IEEE80211_STYPE_DEAUTH,
+ (u8 *) &reason, 2);
+ case MLME_STA_DISASSOC:
+ return prism2_sta_send_mgmt(local, param->sta_addr,
+ IEEE80211_STYPE_DISASSOC,
+ (u8 *) &reason, 2);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
+static int prism2_ioctl_scan_req(local_info_t *local,
+ struct prism2_hostapd_param *param)
+{
+#ifndef PRISM2_NO_STATION_MODES
+ if ((local->iw_mode != IW_MODE_INFRA &&
+ local->iw_mode != IW_MODE_ADHOC) ||
+ (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))
+ return -EOPNOTSUPP;
+
+ if (!local->dev_enabled)
+ return -ENETDOWN;
+
+ return prism2_request_hostscan(local->dev, param->u.scan_req.ssid,
+ param->u.scan_req.ssid_len);
+#else /* PRISM2_NO_STATION_MODES */
+ return -EOPNOTSUPP;
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
+{
+ struct prism2_hostapd_param *param;
+ int ret = 0;
+ int ap_ioctl = 0;
+
+ if (p->length < sizeof(struct prism2_hostapd_param) ||
+ p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
+ return -EINVAL;
+
+ param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+ if (param == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ switch (param->cmd) {
+ case PRISM2_SET_ENCRYPTION:
+ ret = prism2_ioctl_set_encryption(local, param, p->length);
+ break;
+ case PRISM2_GET_ENCRYPTION:
+ ret = prism2_ioctl_get_encryption(local, param, p->length);
+ break;
+ case PRISM2_HOSTAPD_GET_RID:
+ ret = prism2_ioctl_get_rid(local, param, p->length);
+ break;
+ case PRISM2_HOSTAPD_SET_RID:
+ ret = prism2_ioctl_set_rid(local, param, p->length);
+ break;
+ case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR:
+ ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length);
+ break;
+ case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
+ ret = prism2_ioctl_set_generic_element(local, param,
+ p->length);
+ break;
+ case PRISM2_HOSTAPD_MLME:
+ ret = prism2_ioctl_mlme(local, param);
+ break;
+ case PRISM2_HOSTAPD_SCAN_REQ:
+ ret = prism2_ioctl_scan_req(local, param);
+ break;
+ default:
+ ret = prism2_hostapd(local->ap, param);
+ ap_ioctl = 1;
+ break;
+ }
+
+ if (ret == 1 || !ap_ioctl) {
+ if (copy_to_user(p->pointer, param, p->length)) {
+ ret = -EFAULT;
+ goto out;
+ } else if (ap_ioctl)
+ ret = 0;
+ }
+
+ out:
+ if (param != NULL)
+ kfree(param);
+
+ return ret;
+}
+
+
+static void prism2_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ strncpy(info->driver, "hostap", sizeof(info->driver) - 1);
+ strncpy(info->version, PRISM2_VERSION,
+ sizeof(info->version) - 1);
+ snprintf(info->fw_version, sizeof(info->fw_version) - 1,
+ "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
+ (local->sta_fw_ver >> 8) & 0xff,
+ local->sta_fw_ver & 0xff);
+}
+
+static struct ethtool_ops prism2_ethtool_ops = {
+ .get_drvinfo = prism2_get_drvinfo
+};
+
+
+/* Structures to export the Wireless Handlers */
+
+static const iw_handler prism2_handler[] =
+{
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+ (iw_handler) prism2_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) prism2_ioctl_siwfreq, /* SIOCSIWFREQ */
+ (iw_handler) prism2_ioctl_giwfreq, /* SIOCGIWFREQ */
+ (iw_handler) prism2_ioctl_siwmode, /* SIOCSIWMODE */
+ (iw_handler) prism2_ioctl_giwmode, /* SIOCGIWMODE */
+ (iw_handler) prism2_ioctl_siwsens, /* SIOCSIWSENS */
+ (iw_handler) prism2_ioctl_giwsens, /* SIOCGIWSENS */
+ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
+ (iw_handler) prism2_ioctl_giwrange, /* SIOCGIWRANGE */
+ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
+ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
+ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
+ (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+ (iw_handler) prism2_ioctl_siwap, /* SIOCSIWAP */
+ (iw_handler) prism2_ioctl_giwap, /* SIOCGIWAP */
+ (iw_handler) prism2_ioctl_siwmlme, /* SIOCSIWMLME */
+ (iw_handler) prism2_ioctl_giwaplist, /* SIOCGIWAPLIST */
+ (iw_handler) prism2_ioctl_siwscan, /* SIOCSIWSCAN */
+ (iw_handler) prism2_ioctl_giwscan, /* SIOCGIWSCAN */
+ (iw_handler) prism2_ioctl_siwessid, /* SIOCSIWESSID */
+ (iw_handler) prism2_ioctl_giwessid, /* SIOCGIWESSID */
+ (iw_handler) prism2_ioctl_siwnickn, /* SIOCSIWNICKN */
+ (iw_handler) prism2_ioctl_giwnickn, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) prism2_ioctl_siwrate, /* SIOCSIWRATE */
+ (iw_handler) prism2_ioctl_giwrate, /* SIOCGIWRATE */
+ (iw_handler) prism2_ioctl_siwrts, /* SIOCSIWRTS */
+ (iw_handler) prism2_ioctl_giwrts, /* SIOCGIWRTS */
+ (iw_handler) prism2_ioctl_siwfrag, /* SIOCSIWFRAG */
+ (iw_handler) prism2_ioctl_giwfrag, /* SIOCGIWFRAG */
+ (iw_handler) prism2_ioctl_siwtxpow, /* SIOCSIWTXPOW */
+ (iw_handler) prism2_ioctl_giwtxpow, /* SIOCGIWTXPOW */
+ (iw_handler) prism2_ioctl_siwretry, /* SIOCSIWRETRY */
+ (iw_handler) prism2_ioctl_giwretry, /* SIOCGIWRETRY */
+ (iw_handler) prism2_ioctl_siwencode, /* SIOCSIWENCODE */
+ (iw_handler) prism2_ioctl_giwencode, /* SIOCGIWENCODE */
+ (iw_handler) prism2_ioctl_siwpower, /* SIOCSIWPOWER */
+ (iw_handler) prism2_ioctl_giwpower, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) prism2_ioctl_siwgenie, /* SIOCSIWGENIE */
+ (iw_handler) prism2_ioctl_giwgenie, /* SIOCGIWGENIE */
+ (iw_handler) prism2_ioctl_siwauth, /* SIOCSIWAUTH */
+ (iw_handler) prism2_ioctl_giwauth, /* SIOCGIWAUTH */
+ (iw_handler) prism2_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) prism2_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCSIWPMKSA */
+ (iw_handler) NULL, /* -- hole -- */
+};
+
+static const iw_handler prism2_private_handler[] =
+{ /* SIOCIWFIRSTPRIV + */
+ (iw_handler) prism2_ioctl_priv_prism2_param, /* 0 */
+ (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */
+ (iw_handler) prism2_ioctl_priv_writemif, /* 2 */
+ (iw_handler) prism2_ioctl_priv_readmif, /* 3 */
+};
+
+static const struct iw_handler_def hostap_iw_handler_def =
+{
+ .num_standard = sizeof(prism2_handler) / sizeof(iw_handler),
+ .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler),
+ .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args),
+ .standard = (iw_handler *) prism2_handler,
+ .private = (iw_handler *) prism2_private_handler,
+ .private_args = (struct iw_priv_args *) prism2_priv,
+ .get_wireless_stats = hostap_get_wireless_stats,
+};
+
+
+int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct iwreq *wrq = (struct iwreq *) ifr;
+ struct hostap_interface *iface;
+ local_info_t *local;
+ int ret = 0;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ switch (cmd) {
+ /* Private ioctls (iwpriv) that have not yet been converted
+ * into new wireless extensions API */
+
+ case PRISM2_IOCTL_INQUIRE:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name);
+ break;
+
+ case PRISM2_IOCTL_MONITOR:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name);
+ break;
+
+ case PRISM2_IOCTL_RESET:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name);
+ break;
+
+ case PRISM2_IOCTL_WDS_ADD:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1);
+ break;
+
+ case PRISM2_IOCTL_WDS_DEL:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0);
+ break;
+
+ case PRISM2_IOCTL_SET_RID_WORD:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_ioctl_priv_set_rid_word(dev,
+ (int *) wrq->u.name);
+ break;
+
+#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ case PRISM2_IOCTL_MACCMD:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name);
+ break;
+
+ case PRISM2_IOCTL_ADDMAC:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = ap_control_add_mac(&local->ap->mac_restrictions,
+ wrq->u.ap_addr.sa_data);
+ break;
+ case PRISM2_IOCTL_DELMAC:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = ap_control_del_mac(&local->ap->mac_restrictions,
+ wrq->u.ap_addr.sa_data);
+ break;
+ case PRISM2_IOCTL_KICKMAC:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = ap_control_kick_mac(local->ap, local->dev,
+ wrq->u.ap_addr.sa_data);
+ break;
+#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
+
+
+ /* Private ioctls that are not used with iwpriv;
+ * in SIOCDEVPRIVATE range */
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ case PRISM2_IOCTL_DOWNLOAD:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_ioctl_priv_download(local, &wrq->u.data);
+ break;
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+ case PRISM2_IOCTL_HOSTAPD:
+ if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
+ else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
new file mode 100644
index 0000000..025f8cd
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -0,0 +1,473 @@
+#define PRISM2_PCI
+
+/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
+ * driver patches from Reyk Floeter <reyk@vantronix.net> and
+ * Andy Warner <andyw@pobox.com> */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "hostap_wlan.h"
+
+
+static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *dev_info = "hostap_pci";
+
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
+ "PCI cards.");
+MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+
+/* struct local_info::hw_priv */
+struct hostap_pci_priv {
+ void __iomem *mem_start;
+};
+
+
+/* FIX: do we need mb/wmb/rmb with memory operations? */
+
+
+static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
+ /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
+ { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
+ /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
+ { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
+ /* Samsung MagicLAN SWL-2210P */
+ { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
+ { 0 }
+};
+
+
+#ifdef PRISM2_IO_DEBUG
+
+static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
+ writeb(v, hw_priv->mem_start + a);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+ u8 v;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ v = readb(hw_priv->mem_start + a);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
+ spin_unlock_irqrestore(&local->lock, flags);
+ return v;
+}
+
+static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
+ writew(v, hw_priv->mem_start + a);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+ u16 v;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ v = readw(hw_priv->mem_start + a);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
+ spin_unlock_irqrestore(&local->lock, flags);
+ return v;
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
+#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v)))
+#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a)))
+
+#else /* PRISM2_IO_DEBUG */
+
+static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
+{
+ struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
+ iface = netdev_priv(dev);
+ hw_priv = iface->local->hw_priv;
+ writeb(v, hw_priv->mem_start + a);
+}
+
+static inline u8 hfa384x_inb(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
+ iface = netdev_priv(dev);
+ hw_priv = iface->local->hw_priv;
+ return readb(hw_priv->mem_start + a);
+}
+
+static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
+{
+ struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
+ iface = netdev_priv(dev);
+ hw_priv = iface->local->hw_priv;
+ writew(v, hw_priv->mem_start + a);
+}
+
+static inline u16 hfa384x_inw(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
+ iface = netdev_priv(dev);
+ hw_priv = iface->local->hw_priv;
+ return readw(hw_priv->mem_start + a);
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw(dev, (a))
+#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v)))
+#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a)))
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
+ int len)
+{
+ u16 d_off;
+ u16 *pos;
+
+ d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+ pos = (u16 *) buf;
+
+ for ( ; len > 1; len -= 2)
+ *pos++ = HFA384X_INW_DATA(d_off);
+
+ if (len & 1)
+ *((char *) pos) = HFA384X_INB(d_off);
+
+ return 0;
+}
+
+
+static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
+{
+ u16 d_off;
+ u16 *pos;
+
+ d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+ pos = (u16 *) buf;
+
+ for ( ; len > 1; len -= 2)
+ HFA384X_OUTW_DATA(*pos++, d_off);
+
+ if (len & 1)
+ HFA384X_OUTB(*((char *) pos), d_off);
+
+ return 0;
+}
+
+
+/* FIX: This might change at some point.. */
+#include "hostap_hw.c"
+
+static void prism2_pci_cor_sreset(local_info_t *local)
+{
+ struct net_device *dev = local->dev;
+ u16 reg;
+
+ reg = HFA384X_INB(HFA384X_PCICOR_OFF);
+ printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
+
+ /* linux-wlan-ng uses extremely long hold and settle times for
+ * COR sreset. A comment in the driver code mentions that the long
+ * delays appear to be necessary. However, at least IBM 22P6901 seems
+ * to work fine with shorter delays.
+ *
+ * Longer delays can be configured by uncommenting following line: */
+/* #define PRISM2_PCI_USE_LONG_DELAYS */
+
+#ifdef PRISM2_PCI_USE_LONG_DELAYS
+ int i;
+
+ HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
+ mdelay(250);
+
+ HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
+ mdelay(500);
+
+ /* Wait for f/w to complete initialization (CMD:BUSY == 0) */
+ i = 2000000 / 10;
+ while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
+ udelay(10);
+
+#else /* PRISM2_PCI_USE_LONG_DELAYS */
+
+ HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
+ mdelay(2);
+ HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
+ mdelay(2);
+
+#endif /* PRISM2_PCI_USE_LONG_DELAYS */
+
+ if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
+ printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
+ }
+}
+
+
+static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
+{
+ struct net_device *dev = local->dev;
+
+ HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
+ mdelay(10);
+ HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
+ mdelay(10);
+ HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
+ mdelay(10);
+}
+
+
+static struct prism2_helper_functions prism2_pci_funcs =
+{
+ .card_present = NULL,
+ .cor_sreset = prism2_pci_cor_sreset,
+ .dev_open = NULL,
+ .dev_close = NULL,
+ .genesis_reset = prism2_pci_genesis_reset,
+ .hw_type = HOSTAP_HW_PCI,
+};
+
+
+static int prism2_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned long phymem;
+ void __iomem *mem = NULL;
+ local_info_t *local = NULL;
+ struct net_device *dev = NULL;
+ static int cards_found /* = 0 */;
+ int irq_registered = 0;
+ struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
+
+ hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+ if (hw_priv == NULL)
+ return -ENOMEM;
+ memset(hw_priv, 0, sizeof(*hw_priv));
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ phymem = pci_resource_start(pdev, 0);
+
+ if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
+ printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
+ goto err_out_disable;
+ }
+
+ mem = ioremap(phymem, pci_resource_len(pdev, 0));
+ if (mem == NULL) {
+ printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
+ goto fail;
+ }
+
+ dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
+ &pdev->dev);
+ if (dev == NULL)
+ goto fail;
+ iface = netdev_priv(dev);
+ local = iface->local;
+ local->hw_priv = hw_priv;
+ cards_found++;
+
+ dev->irq = pdev->irq;
+ hw_priv->mem_start = mem;
+
+ prism2_pci_cor_sreset(local);
+
+ pci_set_drvdata(pdev, dev);
+
+ if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
+ dev)) {
+ printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
+ goto fail;
+ } else
+ irq_registered = 1;
+
+ if (!local->pri_only && prism2_hw_config(dev, 1)) {
+ printk(KERN_DEBUG "%s: hardware initialization failed\n",
+ dev_info);
+ goto fail;
+ }
+
+ printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
+ "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
+
+ return hostap_hw_ready(dev);
+
+ fail:
+ kfree(hw_priv);
+
+ if (irq_registered && dev)
+ free_irq(dev->irq, dev);
+
+ if (mem)
+ iounmap(mem);
+
+ release_mem_region(phymem, pci_resource_len(pdev, 0));
+
+ err_out_disable:
+ pci_disable_device(pdev);
+ kfree(hw_priv);
+ if (local)
+ local->hw_priv = NULL;
+ prism2_free_local_data(dev);
+
+ return -ENODEV;
+}
+
+
+static void prism2_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev;
+ struct hostap_interface *iface;
+ void __iomem *mem_start;
+ struct hostap_pci_priv *hw_priv;
+
+ dev = pci_get_drvdata(pdev);
+ iface = netdev_priv(dev);
+ hw_priv = iface->local->hw_priv;
+
+ /* Reset the hardware, and ensure interrupts are disabled. */
+ prism2_pci_cor_sreset(iface->local);
+ hfa384x_disable_interrupts(dev);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ mem_start = hw_priv->mem_start;
+ kfree(hw_priv);
+ iface->local->hw_priv = NULL;
+ prism2_free_local_data(dev);
+
+ iounmap(mem_start);
+
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ pci_disable_device(pdev);
+}
+
+
+#ifdef CONFIG_PM
+static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (netif_running(dev)) {
+ netif_stop_queue(dev);
+ netif_device_detach(dev);
+ }
+ prism2_suspend(dev);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+static int prism2_pci_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ pci_enable_device(pdev);
+ pci_restore_state(pdev);
+ prism2_hw_config(dev, 0);
+ if (netif_running(dev)) {
+ netif_device_attach(dev);
+ netif_start_queue(dev);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
+
+static struct pci_driver prism2_pci_drv_id = {
+ .name = "prism2_pci",
+ .id_table = prism2_pci_id_table,
+ .probe = prism2_pci_probe,
+ .remove = prism2_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = prism2_pci_suspend,
+ .resume = prism2_pci_resume,
+#endif /* CONFIG_PM */
+ /* Linux 2.4.6 added save_state and enable_wake that are not used here
+ */
+};
+
+
+static int __init init_prism2_pci(void)
+{
+ printk(KERN_INFO "%s: %s\n", dev_info, version);
+
+ return pci_register_driver(&prism2_pci_drv_id);
+}
+
+
+static void __exit exit_prism2_pci(void)
+{
+ pci_unregister_driver(&prism2_pci_drv_id);
+ printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+
+
+module_init(init_prism2_pci);
+module_exit(exit_prism2_pci);
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
new file mode 100644
index 0000000..474ef83d
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -0,0 +1,645 @@
+#define PRISM2_PLX
+
+/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
+ * based on:
+ * - Host AP driver patch from james@madingley.org
+ * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
+ */
+
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "hostap_wlan.h"
+
+
+static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *dev_info = "hostap_plx";
+
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
+ "cards (PLX).");
+MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PRISM2_VERSION);
+
+
+static int ignore_cis;
+module_param(ignore_cis, int, 0444);
+MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
+
+
+/* struct local_info::hw_priv */
+struct hostap_plx_priv {
+ void __iomem *attr_mem;
+ unsigned int cor_offset;
+};
+
+
+#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
+#define COR_SRESET 0x80
+#define COR_LEVLREQ 0x40
+#define COR_ENABLE_FUNC 0x01
+/* PCI Configuration Registers */
+#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
+/* Local Configuration Registers */
+#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
+#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
+#define PLX_CNTRL 0x50
+#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
+
+
+#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
+
+static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
+ PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
+ PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
+ PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+ PLXDEV(0x1385, 0x4100, "Netgear MA301"),
+ PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
+ PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
+ PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+ PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
+ PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
+ PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
+ PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
+ PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
+ { 0 }
+};
+
+
+/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
+ * is not listed here, you will need to add it here to get the driver
+ * initialized. */
+static struct prism2_plx_manfid {
+ u16 manfid1, manfid2;
+} prism2_plx_known_manfids[] = {
+ { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
+ { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
+ { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
+ { 0x0126, 0x8000 } /* Proxim RangeLAN */,
+ { 0x0138, 0x0002 } /* Compaq WL100 */,
+ { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
+ { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
+ { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
+ { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
+ { 0x028a, 0x0002 } /* D-Link DRC-650 */,
+ { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
+ { 0xc250, 0x0002 } /* EMTAC A2424i */,
+ { 0xd601, 0x0002 } /* Z-Com XI300 */,
+ { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
+ { 0, 0}
+};
+
+
+#ifdef PRISM2_IO_DEBUG
+
+static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
+ outb(v, dev->base_addr + a);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+ u8 v;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ v = inb(dev->base_addr + a);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
+ spin_unlock_irqrestore(&local->lock, flags);
+ return v;
+}
+
+static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
+ outw(v, dev->base_addr + a);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+ u16 v;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ v = inw(dev->base_addr + a);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
+ spin_unlock_irqrestore(&local->lock, flags);
+ return v;
+}
+
+static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
+ u8 *buf, int wc)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
+ outsw(dev->base_addr + a, buf, wc);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+static inline void hfa384x_insw_debug(struct net_device *dev, int a,
+ u8 *buf, int wc)
+{
+ struct hostap_interface *iface;
+ local_info_t *local;
+ unsigned long flags;
+
+ iface = netdev_priv(dev);
+ local = iface->local;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
+ insw(dev->base_addr + a, buf, wc);
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
+#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
+#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
+#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
+#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
+#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
+
+#else /* PRISM2_IO_DEBUG */
+
+#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
+#define HFA384X_INB(a) inb(dev->base_addr + (a))
+#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
+#define HFA384X_INW(a) inw(dev->base_addr + (a))
+#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
+#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
+ int len)
+{
+ u16 d_off;
+ u16 *pos;
+
+ d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+ pos = (u16 *) buf;
+
+ if (len / 2)
+ HFA384X_INSW(d_off, buf, len / 2);
+ pos += len / 2;
+
+ if (len & 1)
+ *((char *) pos) = HFA384X_INB(d_off);
+
+ return 0;
+}
+
+
+static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
+{
+ u16 d_off;
+ u16 *pos;
+
+ d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
+ pos = (u16 *) buf;
+
+ if (len / 2)
+ HFA384X_OUTSW(d_off, buf, len / 2);
+ pos += len / 2;
+
+ if (len & 1)
+ HFA384X_OUTB(*((char *) pos), d_off);
+
+ return 0;
+}
+
+
+/* FIX: This might change at some point.. */
+#include "hostap_hw.c"
+
+
+static void prism2_plx_cor_sreset(local_info_t *local)
+{
+ unsigned char corsave;
+ struct hostap_plx_priv *hw_priv = local->hw_priv;
+
+ printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
+ dev_info);
+
+ /* Set sreset bit of COR and clear it after hold time */
+
+ if (hw_priv->attr_mem == NULL) {
+ /* TMD7160 - COR at card's first I/O addr */
+ corsave = inb(hw_priv->cor_offset);
+ outb(corsave | COR_SRESET, hw_priv->cor_offset);
+ mdelay(2);
+ outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
+ mdelay(2);
+ } else {
+ /* PLX9052 */
+ corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
+ writeb(corsave | COR_SRESET,
+ hw_priv->attr_mem + hw_priv->cor_offset);
+ mdelay(2);
+ writeb(corsave & ~COR_SRESET,
+ hw_priv->attr_mem + hw_priv->cor_offset);
+ mdelay(2);
+ }
+}
+
+
+static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
+{
+ unsigned char corsave;
+ struct hostap_plx_priv *hw_priv = local->hw_priv;
+
+ if (hw_priv->attr_mem == NULL) {
+ /* TMD7160 - COR at card's first I/O addr */
+ corsave = inb(hw_priv->cor_offset);
+ outb(corsave | COR_SRESET, hw_priv->cor_offset);
+ mdelay(10);
+ outb(hcr, hw_priv->cor_offset + 2);
+ mdelay(10);
+ outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
+ mdelay(10);
+ } else {
+ /* PLX9052 */
+ corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
+ writeb(corsave | COR_SRESET,
+ hw_priv->attr_mem + hw_priv->cor_offset);
+ mdelay(10);
+ writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
+ mdelay(10);
+ writeb(corsave & ~COR_SRESET,
+ hw_priv->attr_mem + hw_priv->cor_offset);
+ mdelay(10);
+ }
+}
+
+
+static struct prism2_helper_functions prism2_plx_funcs =
+{
+ .card_present = NULL,
+ .cor_sreset = prism2_plx_cor_sreset,
+ .dev_open = NULL,
+ .dev_close = NULL,
+ .genesis_reset = prism2_plx_genesis_reset,
+ .hw_type = HOSTAP_HW_PLX,
+};
+
+
+static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
+ unsigned int *cor_offset,
+ unsigned int *cor_index)
+{
+#define CISTPL_CONFIG 0x1A
+#define CISTPL_MANFID 0x20
+#define CISTPL_END 0xFF
+#define CIS_MAX_LEN 256
+ u8 *cis;
+ int i, pos;
+ unsigned int rmsz, rasz, manfid1, manfid2;
+ struct prism2_plx_manfid *manfid;
+
+ cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
+ if (cis == NULL)
+ return -ENOMEM;
+
+ /* read CIS; it is in even offsets in the beginning of attr_mem */
+ for (i = 0; i < CIS_MAX_LEN; i++)
+ cis[i] = readb(attr_mem + 2 * i);
+ printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
+ dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
+
+ /* set reasonable defaults for Prism2 cards just in case CIS parsing
+ * fails */
+ *cor_offset = 0x3e0;
+ *cor_index = 0x01;
+ manfid1 = manfid2 = 0;
+
+ pos = 0;
+ while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
+ if (pos + cis[pos + 1] >= CIS_MAX_LEN)
+ goto cis_error;
+
+ switch (cis[pos]) {
+ case CISTPL_CONFIG:
+ if (cis[pos + 1] < 1)
+ goto cis_error;
+ rmsz = (cis[pos + 2] & 0x3c) >> 2;
+ rasz = cis[pos + 2] & 0x03;
+ if (4 + rasz + rmsz > cis[pos + 1])
+ goto cis_error;
+ *cor_index = cis[pos + 3] & 0x3F;
+ *cor_offset = 0;
+ for (i = 0; i <= rasz; i++)
+ *cor_offset += cis[pos + 4 + i] << (8 * i);
+ printk(KERN_DEBUG "%s: cor_index=0x%x "
+ "cor_offset=0x%x\n", dev_info,
+ *cor_index, *cor_offset);
+ if (*cor_offset > attr_len) {
+ printk(KERN_ERR "%s: COR offset not within "
+ "attr_mem\n", dev_info);
+ kfree(cis);
+ return -1;
+ }
+ break;
+
+ case CISTPL_MANFID:
+ if (cis[pos + 1] < 4)
+ goto cis_error;
+ manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
+ manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
+ printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
+ dev_info, manfid1, manfid2);
+ break;
+ }
+
+ pos += cis[pos + 1] + 2;
+ }
+
+ if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
+ goto cis_error;
+
+ for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
+ if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
+ kfree(cis);
+ return 0;
+ }
+
+ printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
+ " not supported card\n", dev_info, manfid1, manfid2);
+ goto fail;
+
+ cis_error:
+ printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
+
+ fail:
+ kfree(cis);
+ if (ignore_cis) {
+ printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
+ "errors during CIS verification\n", dev_info);
+ return 0;
+ }
+ return -1;
+}
+
+
+static int prism2_plx_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned int pccard_ioaddr, plx_ioaddr;
+ unsigned long pccard_attr_mem;
+ unsigned int pccard_attr_len;
+ void __iomem *attr_mem = NULL;
+ unsigned int cor_offset, cor_index;
+ u32 reg;
+ local_info_t *local = NULL;
+ struct net_device *dev = NULL;
+ struct hostap_interface *iface;
+ static int cards_found /* = 0 */;
+ int irq_registered = 0;
+ int tmd7160;
+ struct hostap_plx_priv *hw_priv;
+
+ hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+ if (hw_priv == NULL)
+ return -ENOMEM;
+ memset(hw_priv, 0, sizeof(*hw_priv));
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
+ tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
+
+ plx_ioaddr = pci_resource_start(pdev, 1);
+ pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
+
+ if (tmd7160) {
+ /* TMD7160 */
+ attr_mem = NULL; /* no access to PC Card attribute memory */
+
+ printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
+ "irq=%d, pccard_io=0x%x\n",
+ plx_ioaddr, pdev->irq, pccard_ioaddr);
+
+ cor_offset = plx_ioaddr;
+ cor_index = 0x04;
+
+ outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
+ mdelay(1);
+ reg = inb(plx_ioaddr);
+ if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
+ printk(KERN_ERR "%s: Error setting COR (expected="
+ "0x%02x, was=0x%02x)\n", dev_info,
+ cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
+ goto fail;
+ }
+ } else {
+ /* PLX9052 */
+ pccard_attr_mem = pci_resource_start(pdev, 2);
+ pccard_attr_len = pci_resource_len(pdev, 2);
+ if (pccard_attr_len < PLX_MIN_ATTR_LEN)
+ goto fail;
+
+
+ attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
+ if (attr_mem == NULL) {
+ printk(KERN_ERR "%s: cannot remap attr_mem\n",
+ dev_info);
+ goto fail;
+ }
+
+ printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
+ "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
+ pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
+
+ if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
+ &cor_offset, &cor_index)) {
+ printk(KERN_INFO "Unknown PC Card CIS - not a "
+ "Prism2/2.5 card?\n");
+ goto fail;
+ }
+
+ printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
+ "adapter\n");
+
+ /* Write COR to enable PC Card */
+ writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
+ attr_mem + cor_offset);
+
+ /* Enable PCI interrupts if they are not already enabled */
+ reg = inl(plx_ioaddr + PLX_INTCSR);
+ printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
+ if (!(reg & PLX_INTCSR_PCI_INTEN)) {
+ outl(reg | PLX_INTCSR_PCI_INTEN,
+ plx_ioaddr + PLX_INTCSR);
+ if (!(inl(plx_ioaddr + PLX_INTCSR) &
+ PLX_INTCSR_PCI_INTEN)) {
+ printk(KERN_WARNING "%s: Could not enable "
+ "Local Interrupts\n", dev_info);
+ goto fail;
+ }
+ }
+
+ reg = inl(plx_ioaddr + PLX_CNTRL);
+ printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
+ "present=%d)\n",
+ reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
+ /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
+ * not present; but are there really such cards in use(?) */
+ }
+
+ dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
+ &pdev->dev);
+ if (dev == NULL)
+ goto fail;
+ iface = netdev_priv(dev);
+ local = iface->local;
+ local->hw_priv = hw_priv;
+ cards_found++;
+
+ dev->irq = pdev->irq;
+ dev->base_addr = pccard_ioaddr;
+ hw_priv->attr_mem = attr_mem;
+ hw_priv->cor_offset = cor_offset;
+
+ pci_set_drvdata(pdev, dev);
+
+ if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
+ dev)) {
+ printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
+ goto fail;
+ } else
+ irq_registered = 1;
+
+ if (prism2_hw_config(dev, 1)) {
+ printk(KERN_DEBUG "%s: hardware initialization failed\n",
+ dev_info);
+ goto fail;
+ }
+
+ return hostap_hw_ready(dev);
+
+ fail:
+ kfree(hw_priv);
+ if (local)
+ local->hw_priv = NULL;
+ prism2_free_local_data(dev);
+
+ if (irq_registered && dev)
+ free_irq(dev->irq, dev);
+
+ if (attr_mem)
+ iounmap(attr_mem);
+
+ pci_disable_device(pdev);
+
+ return -ENODEV;
+}
+
+
+static void prism2_plx_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev;
+ struct hostap_interface *iface;
+ struct hostap_plx_priv *hw_priv;
+
+ dev = pci_get_drvdata(pdev);
+ iface = netdev_priv(dev);
+ hw_priv = iface->local->hw_priv;
+
+ /* Reset the hardware, and ensure interrupts are disabled. */
+ prism2_plx_cor_sreset(iface->local);
+ hfa384x_disable_interrupts(dev);
+
+ if (hw_priv->attr_mem)
+ iounmap(hw_priv->attr_mem);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ kfree(iface->local->hw_priv);
+ iface->local->hw_priv = NULL;
+ prism2_free_local_data(dev);
+ pci_disable_device(pdev);
+}
+
+
+MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
+
+static struct pci_driver prism2_plx_drv_id = {
+ .name = "prism2_plx",
+ .id_table = prism2_plx_id_table,
+ .probe = prism2_plx_probe,
+ .remove = prism2_plx_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .enable_wake = NULL
+};
+
+
+static int __init init_prism2_plx(void)
+{
+ printk(KERN_INFO "%s: %s\n", dev_info, version);
+
+ return pci_register_driver(&prism2_plx_drv_id);
+}
+
+
+static void __exit exit_prism2_plx(void)
+{
+ pci_unregister_driver(&prism2_plx_drv_id);
+ printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+
+
+module_init(init_prism2_plx);
+module_exit(exit_prism2_plx);
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
new file mode 100644
index 0000000..a0a4cbd
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -0,0 +1,448 @@
+/* /proc routines for Host AP driver */
+
+#define PROC_LIMIT (PAGE_SIZE - 80)
+
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+static int prism2_debug_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+ int i;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "next_txfid=%d next_alloc=%d\n",
+ local->next_txfid, local->next_alloc);
+ for (i = 0; i < PRISM2_TXFID_COUNT; i++)
+ p += sprintf(p, "FID: tx=%04X intransmit=%04X\n",
+ local->txfid[i], local->intransmitfid[i]);
+ p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control);
+ p += sprintf(p, "beacon_int=%d\n", local->beacon_int);
+ p += sprintf(p, "dtim_period=%d\n", local->dtim_period);
+ p += sprintf(p, "wds_max_connections=%d\n",
+ local->wds_max_connections);
+ p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled);
+ p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
+ for (i = 0; i < WEP_KEYS; i++) {
+ if (local->crypt[i] && local->crypt[i]->ops) {
+ p += sprintf(p, "crypt[%d]=%s\n",
+ i, local->crypt[i]->ops->name);
+ }
+ }
+ p += sprintf(p, "pri_only=%d\n", local->pri_only);
+ p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
+ p += sprintf(p, "sram_type=%d\n", local->sram_type);
+ p += sprintf(p, "no_pri=%d\n", local->no_pri);
+
+ return (p - page);
+}
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+
+
+static int prism2_stats_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+ struct comm_tallies_sums *sums = (struct comm_tallies_sums *)
+ &local->comm_tallies;
+
+ if (off != 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
+ p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
+ p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments);
+ p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
+ p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
+ p += sprintf(p, "TxDeferredTransmissions=%u\n",
+ sums->tx_deferred_transmissions);
+ p += sprintf(p, "TxSingleRetryFrames=%u\n",
+ sums->tx_single_retry_frames);
+ p += sprintf(p, "TxMultipleRetryFrames=%u\n",
+ sums->tx_multiple_retry_frames);
+ p += sprintf(p, "TxRetryLimitExceeded=%u\n",
+ sums->tx_retry_limit_exceeded);
+ p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards);
+ p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
+ p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
+ p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments);
+ p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
+ p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
+ p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
+ p += sprintf(p, "RxDiscardsNoBuffer=%u\n",
+ sums->rx_discards_no_buffer);
+ p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
+ p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n",
+ sums->rx_discards_wep_undecryptable);
+ p += sprintf(p, "RxMessageInMsgFragments=%u\n",
+ sums->rx_message_in_msg_fragments);
+ p += sprintf(p, "RxMessageInBadMsgFragments=%u\n",
+ sums->rx_message_in_bad_msg_fragments);
+ /* FIX: this may grow too long for one page(?) */
+
+ return (p - page);
+}
+
+
+static int prism2_wds_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+ struct list_head *ptr;
+ struct hostap_interface *iface;
+
+ if (off > PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ read_lock_bh(&local->iface_lock);
+ list_for_each(ptr, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type != HOSTAP_INTERFACE_WDS)
+ continue;
+ p += sprintf(p, "%s\t" MACSTR "\n",
+ iface->dev->name,
+ MAC2STR(iface->u.wds.remote_addr));
+ if ((p - page) > PROC_LIMIT) {
+ printk(KERN_DEBUG "%s: wds proc did not fit\n",
+ local->dev->name);
+ break;
+ }
+ }
+ read_unlock_bh(&local->iface_lock);
+
+ if ((p - page) <= off) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = page + off;
+
+ return (p - page - off);
+}
+
+
+static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+ struct list_head *ptr;
+ struct hostap_bss_info *bss;
+ int i;
+
+ if (off > PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
+ "SSID(hex)\tWPA IE\n");
+ spin_lock_bh(&local->lock);
+ list_for_each(ptr, &local->bss_list) {
+ bss = list_entry(ptr, struct hostap_bss_info, list);
+ p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t",
+ MAC2STR(bss->bssid), bss->last_update,
+ bss->count, bss->capab_info);
+ for (i = 0; i < bss->ssid_len; i++) {
+ p += sprintf(p, "%c",
+ bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
+ bss->ssid[i] : '_');
+ }
+ p += sprintf(p, "\t");
+ for (i = 0; i < bss->ssid_len; i++) {
+ p += sprintf(p, "%02x", bss->ssid[i]);
+ }
+ p += sprintf(p, "\t");
+ for (i = 0; i < bss->wpa_ie_len; i++) {
+ p += sprintf(p, "%02x", bss->wpa_ie[i]);
+ }
+ p += sprintf(p, "\n");
+ if ((p - page) > PROC_LIMIT) {
+ printk(KERN_DEBUG "%s: BSS proc did not fit\n",
+ local->dev->name);
+ break;
+ }
+ }
+ spin_unlock_bh(&local->lock);
+
+ if ((p - page) <= off) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = page + off;
+
+ return (p - page - off);
+}
+
+
+static int prism2_crypt_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+ int i;
+
+ if (off > PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx);
+ for (i = 0; i < WEP_KEYS; i++) {
+ if (local->crypt[i] && local->crypt[i]->ops &&
+ local->crypt[i]->ops->print_stats) {
+ p = local->crypt[i]->ops->print_stats(
+ p, local->crypt[i]->priv);
+ }
+ }
+
+ if ((p - page) <= off) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = page + off;
+
+ return (p - page - off);
+}
+
+
+static int prism2_pda_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ local_info_t *local = (local_info_t *) data;
+
+ if (local->pda == NULL || off >= PRISM2_PDA_SIZE) {
+ *eof = 1;
+ return 0;
+ }
+
+ if (off + count > PRISM2_PDA_SIZE)
+ count = PRISM2_PDA_SIZE - off;
+
+ memcpy(page, local->pda + off, count);
+ return count;
+}
+
+
+static int prism2_aux_dump_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ local_info_t *local = (local_info_t *) data;
+
+ if (local->func->read_aux == NULL) {
+ *eof = 1;
+ return 0;
+ }
+
+ if (local->func->read_aux(local->dev, off, count, page)) {
+ *eof = 1;
+ return 0;
+ }
+ *start = page;
+
+ return count;
+}
+
+
+#ifdef PRISM2_IO_DEBUG
+static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ local_info_t *local = (local_info_t *) data;
+ int head = local->io_debug_head;
+ int start_bytes, left, copy, copied;
+
+ if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
+ *eof = 1;
+ if (off >= PRISM2_IO_DEBUG_SIZE * 4)
+ return 0;
+ count = PRISM2_IO_DEBUG_SIZE * 4 - off;
+ }
+
+ copied = 0;
+ start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
+ left = count;
+
+ if (off < start_bytes) {
+ copy = start_bytes - off;
+ if (copy > count)
+ copy = count;
+ memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
+ left -= copy;
+ if (left > 0)
+ memcpy(&page[copy], local->io_debug, left);
+ } else {
+ memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
+ left);
+ }
+
+ *start = page;
+
+ return count;
+}
+#endif /* PRISM2_IO_DEBUG */
+
+
+#ifndef PRISM2_NO_STATION_MODES
+static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ local_info_t *local = (local_info_t *) data;
+ int entry, i, len, total = 0;
+ struct hfa384x_hostscan_result *scanres;
+ u8 *pos;
+
+ p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
+ "SSID\n");
+
+ spin_lock_bh(&local->lock);
+ for (entry = 0; entry < local->last_scan_results_count; entry++) {
+ scanres = &local->last_scan_results[entry];
+
+ if (total + (p - page) <= off) {
+ total += p - page;
+ p = page;
+ }
+ if (total + (p - page) > off + count)
+ break;
+ if ((p - page) > (PAGE_SIZE - 200))
+ break;
+
+ p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
+ le16_to_cpu(scanres->chid),
+ (s16) le16_to_cpu(scanres->anl),
+ (s16) le16_to_cpu(scanres->sl),
+ le16_to_cpu(scanres->beacon_interval),
+ le16_to_cpu(scanres->capability),
+ le16_to_cpu(scanres->rate),
+ MAC2STR(scanres->bssid),
+ le16_to_cpu(scanres->atim));
+
+ pos = scanres->sup_rates;
+ for (i = 0; i < sizeof(scanres->sup_rates); i++) {
+ if (pos[i] == 0)
+ break;
+ p += sprintf(p, "<%02x>", pos[i]);
+ }
+ p += sprintf(p, " ");
+
+ pos = scanres->ssid;
+ len = le16_to_cpu(scanres->ssid_len);
+ if (len > 32)
+ len = 32;
+ for (i = 0; i < len; i++) {
+ unsigned char c = pos[i];
+ if (c >= 32 && c < 127)
+ p += sprintf(p, "%c", c);
+ else
+ p += sprintf(p, "<%02x>", c);
+ }
+ p += sprintf(p, "\n");
+ }
+ spin_unlock_bh(&local->lock);
+
+ total += (p - page);
+ if (total >= off + count)
+ *eof = 1;
+
+ if (total < off) {
+ *eof = 1;
+ return 0;
+ }
+
+ len = total - off;
+ if (len > (p - page))
+ len = p - page;
+ *start = p - len;
+ if (len > count)
+ len = count;
+
+ return len;
+}
+#endif /* PRISM2_NO_STATION_MODES */
+
+
+void hostap_init_proc(local_info_t *local)
+{
+ local->proc = NULL;
+
+ if (hostap_proc == NULL) {
+ printk(KERN_WARNING "%s: hostap proc directory not created\n",
+ local->dev->name);
+ return;
+ }
+
+ local->proc = proc_mkdir(local->ddev->name, hostap_proc);
+ if (local->proc == NULL) {
+ printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
+ local->ddev->name);
+ return;
+ }
+
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ create_proc_read_entry("debug", 0, local->proc,
+ prism2_debug_proc_read, local);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+ create_proc_read_entry("stats", 0, local->proc,
+ prism2_stats_proc_read, local);
+ create_proc_read_entry("wds", 0, local->proc,
+ prism2_wds_proc_read, local);
+ create_proc_read_entry("pda", 0, local->proc,
+ prism2_pda_proc_read, local);
+ create_proc_read_entry("aux_dump", 0, local->proc,
+ prism2_aux_dump_proc_read, local);
+ create_proc_read_entry("bss_list", 0, local->proc,
+ prism2_bss_list_proc_read, local);
+ create_proc_read_entry("crypt", 0, local->proc,
+ prism2_crypt_proc_read, local);
+#ifdef PRISM2_IO_DEBUG
+ create_proc_read_entry("io_debug", 0, local->proc,
+ prism2_io_debug_proc_read, local);
+#endif /* PRISM2_IO_DEBUG */
+#ifndef PRISM2_NO_STATION_MODES
+ create_proc_read_entry("scan_results", 0, local->proc,
+ prism2_scan_results_proc_read, local);
+#endif /* PRISM2_NO_STATION_MODES */
+}
+
+
+void hostap_remove_proc(local_info_t *local)
+{
+ if (local->proc != NULL) {
+#ifndef PRISM2_NO_STATION_MODES
+ remove_proc_entry("scan_results", local->proc);
+#endif /* PRISM2_NO_STATION_MODES */
+#ifdef PRISM2_IO_DEBUG
+ remove_proc_entry("io_debug", local->proc);
+#endif /* PRISM2_IO_DEBUG */
+ remove_proc_entry("pda", local->proc);
+ remove_proc_entry("aux_dump", local->proc);
+ remove_proc_entry("wds", local->proc);
+ remove_proc_entry("stats", local->proc);
+ remove_proc_entry("bss_list", local->proc);
+ remove_proc_entry("crypt", local->proc);
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ remove_proc_entry("debug", local->proc);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
+ if (hostap_proc != NULL)
+ remove_proc_entry(local->proc->name, hostap_proc);
+ }
+}
+
+
+EXPORT_SYMBOL(hostap_init_proc);
+EXPORT_SYMBOL(hostap_remove_proc);
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
new file mode 100644
index 0000000..cc061e1
--- /dev/null
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -0,0 +1,1033 @@
+#ifndef HOSTAP_WLAN_H
+#define HOSTAP_WLAN_H
+
+#include "hostap_config.h"
+#include "hostap_common.h"
+
+#define MAX_PARM_DEVICES 8
+#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES)
+#define DEF_INTS -1, -1, -1, -1, -1, -1, -1
+#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx]
+
+
+/* Specific skb->protocol value that indicates that the packet already contains
+ * txdesc header.
+ * FIX: This might need own value that would be allocated especially for Prism2
+ * txdesc; ETH_P_CONTROL is commented as "Card specific control frames".
+ * However, these skb's should have only minimal path in the kernel side since
+ * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */
+#define ETH_P_HOSTAP ETH_P_CONTROL
+
+/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header
+ * (from linux-wlan-ng) */
+struct linux_wlan_ng_val {
+ u32 did;
+ u16 status, len;
+ u32 data;
+} __attribute__ ((packed));
+
+struct linux_wlan_ng_prism_hdr {
+ u32 msgcode, msglen;
+ char devname[16];
+ struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
+ noise, rate, istx, frmlen;
+} __attribute__ ((packed));
+
+struct linux_wlan_ng_cap_hdr {
+ u32 version;
+ u32 length;
+ u64 mactime;
+ u64 hosttime;
+ u32 phytype;
+ u32 channel;
+ u32 datarate;
+ u32 antenna;
+ u32 priority;
+ u32 ssi_type;
+ s32 ssi_signal;
+ s32 ssi_noise;
+ u32 preamble;
+ u32 encoding;
+} __attribute__ ((packed));
+
+#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */
+#define LWNG_CAPHDR_VERSION 0x80211001
+
+struct hfa384x_rx_frame {
+ /* HFA384X RX frame descriptor */
+ u16 status; /* HFA384X_RX_STATUS_ flags */
+ u32 time; /* timestamp, 1 microsecond resolution */
+ u8 silence; /* 27 .. 154; seems to be 0 */
+ u8 signal; /* 27 .. 154 */
+ u8 rate; /* 10, 20, 55, or 110 */
+ u8 rxflow;
+ u32 reserved;
+
+ /* 802.11 */
+ u16 frame_control;
+ u16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ u16 seq_ctrl;
+ u8 addr4[6];
+ u16 data_len;
+
+ /* 802.3 */
+ u8 dst_addr[6];
+ u8 src_addr[6];
+ u16 len;
+
+ /* followed by frame data; max 2304 bytes */
+} __attribute__ ((packed));
+
+
+struct hfa384x_tx_frame {
+ /* HFA384X TX frame descriptor */
+ u16 status; /* HFA384X_TX_STATUS_ flags */
+ u16 reserved1;
+ u16 reserved2;
+ u32 sw_support;
+ u8 retry_count; /* not yet implemented */
+ u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */
+ u16 tx_control; /* HFA384X_TX_CTRL_ flags */
+
+ /* 802.11 */
+ u16 frame_control; /* parts not used */
+ u16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6]; /* filled by firmware */
+ u8 addr3[6];
+ u16 seq_ctrl; /* filled by firmware */
+ u8 addr4[6];
+ u16 data_len;
+
+ /* 802.3 */
+ u8 dst_addr[6];
+ u8 src_addr[6];
+ u16 len;
+
+ /* followed by frame data; max 2304 bytes */
+} __attribute__ ((packed));
+
+
+struct hfa384x_rid_hdr
+{
+ u16 len;
+ u16 rid;
+} __attribute__ ((packed));
+
+
+/* Macro for converting signal levels (range 27 .. 154) to wireless ext
+ * dBm value with some accuracy */
+#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100
+
+#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100
+
+struct hfa384x_scan_request {
+ u16 channel_list;
+ u16 txrate; /* HFA384X_RATES_* */
+} __attribute__ ((packed));
+
+struct hfa384x_hostscan_request {
+ u16 channel_list;
+ u16 txrate;
+ u16 target_ssid_len;
+ u8 target_ssid[32];
+} __attribute__ ((packed));
+
+struct hfa384x_join_request {
+ u8 bssid[6];
+ u16 channel;
+} __attribute__ ((packed));
+
+struct hfa384x_info_frame {
+ u16 len;
+ u16 type;
+} __attribute__ ((packed));
+
+struct hfa384x_comm_tallies {
+ u16 tx_unicast_frames;
+ u16 tx_multicast_frames;
+ u16 tx_fragments;
+ u16 tx_unicast_octets;
+ u16 tx_multicast_octets;
+ u16 tx_deferred_transmissions;
+ u16 tx_single_retry_frames;
+ u16 tx_multiple_retry_frames;
+ u16 tx_retry_limit_exceeded;
+ u16 tx_discards;
+ u16 rx_unicast_frames;
+ u16 rx_multicast_frames;
+ u16 rx_fragments;
+ u16 rx_unicast_octets;
+ u16 rx_multicast_octets;
+ u16 rx_fcs_errors;
+ u16 rx_discards_no_buffer;
+ u16 tx_discards_wrong_sa;
+ u16 rx_discards_wep_undecryptable;
+ u16 rx_message_in_msg_fragments;
+ u16 rx_message_in_bad_msg_fragments;
+} __attribute__ ((packed));
+
+struct hfa384x_comm_tallies32 {
+ u32 tx_unicast_frames;
+ u32 tx_multicast_frames;
+ u32 tx_fragments;
+ u32 tx_unicast_octets;
+ u32 tx_multicast_octets;
+ u32 tx_deferred_transmissions;
+ u32 tx_single_retry_frames;
+ u32 tx_multiple_retry_frames;
+ u32 tx_retry_limit_exceeded;
+ u32 tx_discards;
+ u32 rx_unicast_frames;
+ u32 rx_multicast_frames;
+ u32 rx_fragments;
+ u32 rx_unicast_octets;
+ u32 rx_multicast_octets;
+ u32 rx_fcs_errors;
+ u32 rx_discards_no_buffer;
+ u32 tx_discards_wrong_sa;
+ u32 rx_discards_wep_undecryptable;
+ u32 rx_message_in_msg_fragments;
+ u32 rx_message_in_bad_msg_fragments;
+} __attribute__ ((packed));
+
+struct hfa384x_scan_result_hdr {
+ u16 reserved;
+ u16 scan_reason;
+#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */
+#define HFA384X_SCAN_HOST_INITIATED 1
+#define HFA384X_SCAN_FIRMWARE_INITIATED 2
+#define HFA384X_SCAN_INQUIRY_FROM_HOST 3
+} __attribute__ ((packed));
+
+#define HFA384X_SCAN_MAX_RESULTS 32
+
+struct hfa384x_scan_result {
+ u16 chid;
+ u16 anl;
+ u16 sl;
+ u8 bssid[6];
+ u16 beacon_interval;
+ u16 capability;
+ u16 ssid_len;
+ u8 ssid[32];
+ u8 sup_rates[10];
+ u16 rate;
+} __attribute__ ((packed));
+
+struct hfa384x_hostscan_result {
+ u16 chid;
+ u16 anl;
+ u16 sl;
+ u8 bssid[6];
+ u16 beacon_interval;
+ u16 capability;
+ u16 ssid_len;
+ u8 ssid[32];
+ u8 sup_rates[10];
+ u16 rate;
+ u16 atim;
+} __attribute__ ((packed));
+
+struct comm_tallies_sums {
+ unsigned int tx_unicast_frames;
+ unsigned int tx_multicast_frames;
+ unsigned int tx_fragments;
+ unsigned int tx_unicast_octets;
+ unsigned int tx_multicast_octets;
+ unsigned int tx_deferred_transmissions;
+ unsigned int tx_single_retry_frames;
+ unsigned int tx_multiple_retry_frames;
+ unsigned int tx_retry_limit_exceeded;
+ unsigned int tx_discards;
+ unsigned int rx_unicast_frames;
+ unsigned int rx_multicast_frames;
+ unsigned int rx_fragments;
+ unsigned int rx_unicast_octets;
+ unsigned int rx_multicast_octets;
+ unsigned int rx_fcs_errors;
+ unsigned int rx_discards_no_buffer;
+ unsigned int tx_discards_wrong_sa;
+ unsigned int rx_discards_wep_undecryptable;
+ unsigned int rx_message_in_msg_fragments;
+ unsigned int rx_message_in_bad_msg_fragments;
+};
+
+
+struct hfa384x_regs {
+ u16 cmd;
+ u16 evstat;
+ u16 offset0;
+ u16 offset1;
+ u16 swsupport0;
+};
+
+
+#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX)
+/* I/O ports for HFA384X Controller access */
+#define HFA384X_CMD_OFF 0x00
+#define HFA384X_PARAM0_OFF 0x02
+#define HFA384X_PARAM1_OFF 0x04
+#define HFA384X_PARAM2_OFF 0x06
+#define HFA384X_STATUS_OFF 0x08
+#define HFA384X_RESP0_OFF 0x0A
+#define HFA384X_RESP1_OFF 0x0C
+#define HFA384X_RESP2_OFF 0x0E
+#define HFA384X_INFOFID_OFF 0x10
+#define HFA384X_CONTROL_OFF 0x14
+#define HFA384X_SELECT0_OFF 0x18
+#define HFA384X_SELECT1_OFF 0x1A
+#define HFA384X_OFFSET0_OFF 0x1C
+#define HFA384X_OFFSET1_OFF 0x1E
+#define HFA384X_RXFID_OFF 0x20
+#define HFA384X_ALLOCFID_OFF 0x22
+#define HFA384X_TXCOMPLFID_OFF 0x24
+#define HFA384X_SWSUPPORT0_OFF 0x28
+#define HFA384X_SWSUPPORT1_OFF 0x2A
+#define HFA384X_SWSUPPORT2_OFF 0x2C
+#define HFA384X_EVSTAT_OFF 0x30
+#define HFA384X_INTEN_OFF 0x32
+#define HFA384X_EVACK_OFF 0x34
+#define HFA384X_DATA0_OFF 0x36
+#define HFA384X_DATA1_OFF 0x38
+#define HFA384X_AUXPAGE_OFF 0x3A
+#define HFA384X_AUXOFFSET_OFF 0x3C
+#define HFA384X_AUXDATA_OFF 0x3E
+#endif /* PRISM2_PCCARD || PRISM2_PLX */
+
+#ifdef PRISM2_PCI
+/* Memory addresses for ISL3874 controller access */
+#define HFA384X_CMD_OFF 0x00
+#define HFA384X_PARAM0_OFF 0x04
+#define HFA384X_PARAM1_OFF 0x08
+#define HFA384X_PARAM2_OFF 0x0C
+#define HFA384X_STATUS_OFF 0x10
+#define HFA384X_RESP0_OFF 0x14
+#define HFA384X_RESP1_OFF 0x18
+#define HFA384X_RESP2_OFF 0x1C
+#define HFA384X_INFOFID_OFF 0x20
+#define HFA384X_CONTROL_OFF 0x28
+#define HFA384X_SELECT0_OFF 0x30
+#define HFA384X_SELECT1_OFF 0x34
+#define HFA384X_OFFSET0_OFF 0x38
+#define HFA384X_OFFSET1_OFF 0x3C
+#define HFA384X_RXFID_OFF 0x40
+#define HFA384X_ALLOCFID_OFF 0x44
+#define HFA384X_TXCOMPLFID_OFF 0x48
+#define HFA384X_PCICOR_OFF 0x4C
+#define HFA384X_SWSUPPORT0_OFF 0x50
+#define HFA384X_SWSUPPORT1_OFF 0x54
+#define HFA384X_SWSUPPORT2_OFF 0x58
+#define HFA384X_PCIHCR_OFF 0x5C
+#define HFA384X_EVSTAT_OFF 0x60
+#define HFA384X_INTEN_OFF 0x64
+#define HFA384X_EVACK_OFF 0x68
+#define HFA384X_DATA0_OFF 0x6C
+#define HFA384X_DATA1_OFF 0x70
+#define HFA384X_AUXPAGE_OFF 0x74
+#define HFA384X_AUXOFFSET_OFF 0x78
+#define HFA384X_AUXDATA_OFF 0x7C
+#define HFA384X_PCI_M0_ADDRH_OFF 0x80
+#define HFA384X_PCI_M0_ADDRL_OFF 0x84
+#define HFA384X_PCI_M0_LEN_OFF 0x88
+#define HFA384X_PCI_M0_CTL_OFF 0x8C
+#define HFA384X_PCI_STATUS_OFF 0x98
+#define HFA384X_PCI_M1_ADDRH_OFF 0xA0
+#define HFA384X_PCI_M1_ADDRL_OFF 0xA4
+#define HFA384X_PCI_M1_LEN_OFF 0xA8
+#define HFA384X_PCI_M1_CTL_OFF 0xAC
+
+/* PCI bus master control bits (these are undocumented; based on guessing and
+ * experimenting..) */
+#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0))
+#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0))
+
+#endif /* PRISM2_PCI */
+
+
+/* Command codes for CMD reg. */
+#define HFA384X_CMDCODE_INIT 0x00
+#define HFA384X_CMDCODE_ENABLE 0x01
+#define HFA384X_CMDCODE_DISABLE 0x02
+#define HFA384X_CMDCODE_ALLOC 0x0A
+#define HFA384X_CMDCODE_TRANSMIT 0x0B
+#define HFA384X_CMDCODE_INQUIRE 0x11
+#define HFA384X_CMDCODE_ACCESS 0x21
+#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8))
+#define HFA384X_CMDCODE_DOWNLOAD 0x22
+#define HFA384X_CMDCODE_READMIF 0x30
+#define HFA384X_CMDCODE_WRITEMIF 0x31
+#define HFA384X_CMDCODE_TEST 0x38
+
+#define HFA384X_CMDCODE_MASK 0x3F
+
+/* Test mode operations */
+#define HFA384X_TEST_CHANGE_CHANNEL 0x08
+#define HFA384X_TEST_MONITOR 0x0B
+#define HFA384X_TEST_STOP 0x0F
+#define HFA384X_TEST_CFG_BITS 0x15
+#define HFA384X_TEST_CFG_BIT_ALC BIT(3)
+
+#define HFA384X_CMD_BUSY BIT(15)
+
+#define HFA384X_CMD_TX_RECLAIM BIT(8)
+
+#define HFA384X_OFFSET_ERR BIT(14)
+#define HFA384X_OFFSET_BUSY BIT(15)
+
+
+/* ProgMode for download command */
+#define HFA384X_PROGMODE_DISABLE 0
+#define HFA384X_PROGMODE_ENABLE_VOLATILE 1
+#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2
+#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3
+
+#define HFA384X_AUX_MAGIC0 0xfe01
+#define HFA384X_AUX_MAGIC1 0xdc23
+#define HFA384X_AUX_MAGIC2 0xba45
+
+#define HFA384X_AUX_PORT_DISABLED 0
+#define HFA384X_AUX_PORT_DISABLE BIT(14)
+#define HFA384X_AUX_PORT_ENABLE BIT(15)
+#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15))
+#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15))
+
+#define PRISM2_PDA_SIZE 1024
+
+
+/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */
+#define HFA384X_EV_TICK BIT(15)
+#define HFA384X_EV_WTERR BIT(14)
+#define HFA384X_EV_INFDROP BIT(13)
+#ifdef PRISM2_PCI
+#define HFA384X_EV_PCI_M1 BIT(9)
+#define HFA384X_EV_PCI_M0 BIT(8)
+#endif /* PRISM2_PCI */
+#define HFA384X_EV_INFO BIT(7)
+#define HFA384X_EV_DTIM BIT(5)
+#define HFA384X_EV_CMD BIT(4)
+#define HFA384X_EV_ALLOC BIT(3)
+#define HFA384X_EV_TXEXC BIT(2)
+#define HFA384X_EV_TX BIT(1)
+#define HFA384X_EV_RX BIT(0)
+
+
+/* HFA384X Information frames */
+#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */
+#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */
+#define HFA384X_INFO_COMMTALLIES 0xF100
+#define HFA384X_INFO_SCANRESULTS 0xF101
+#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */
+#define HFA384X_INFO_HOSTSCANRESULTS 0xF103
+#define HFA384X_INFO_LINKSTATUS 0xF200
+#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */
+#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */
+#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */
+#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */
+
+enum { HFA384X_LINKSTATUS_CONNECTED = 1,
+ HFA384X_LINKSTATUS_DISCONNECTED = 2,
+ HFA384X_LINKSTATUS_AP_CHANGE = 3,
+ HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4,
+ HFA384X_LINKSTATUS_AP_IN_RANGE = 5,
+ HFA384X_LINKSTATUS_ASSOC_FAILED = 6 };
+
+enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2,
+ HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0,
+ HFA384X_PORTTYPE_HOSTAP = 6 };
+
+#define HFA384X_RATES_1MBPS BIT(0)
+#define HFA384X_RATES_2MBPS BIT(1)
+#define HFA384X_RATES_5MBPS BIT(2)
+#define HFA384X_RATES_11MBPS BIT(3)
+
+#define HFA384X_ROAMING_FIRMWARE 1
+#define HFA384X_ROAMING_HOST 2
+#define HFA384X_ROAMING_DISABLED 3
+
+#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0)
+#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1)
+#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4)
+#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7)
+
+#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13))
+#define HFA384X_RX_STATUS_PCF BIT(12)
+#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8))
+#define HFA384X_RX_STATUS_UNDECR BIT(1)
+#define HFA384X_RX_STATUS_FCSERR BIT(0)
+
+#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \
+(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13)
+#define HFA384X_RX_STATUS_GET_MACPORT(s) \
+(((s) & HFA384X_RX_STATUS_MACPORT) >> 8)
+
+enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1,
+ HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 };
+
+
+#define HFA384X_TX_CTRL_ALT_RTRY BIT(5)
+#define HFA384X_TX_CTRL_802_11 BIT(3)
+#define HFA384X_TX_CTRL_802_3 0
+#define HFA384X_TX_CTRL_TX_EX BIT(2)
+#define HFA384X_TX_CTRL_TX_OK BIT(1)
+
+#define HFA384X_TX_STATUS_RETRYERR BIT(0)
+#define HFA384X_TX_STATUS_AGEDERR BIT(1)
+#define HFA384X_TX_STATUS_DISCON BIT(2)
+#define HFA384X_TX_STATUS_FORMERR BIT(3)
+
+/* HFA3861/3863 (BBP) Control Registers */
+#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */
+#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */
+#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */
+#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */
+#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */
+
+
+#ifdef __KERNEL__
+
+#define PRISM2_TXFID_COUNT 8
+#define PRISM2_DATA_MAXLEN 2304
+#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame))
+#define PRISM2_TXFID_EMPTY 0xffff
+#define PRISM2_TXFID_RESERVED 0xfffe
+#define PRISM2_DUMMY_FID 0xffff
+#define MAX_SSID_LEN 32
+#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */
+
+#define PRISM2_DUMP_RX_HDR BIT(0)
+#define PRISM2_DUMP_TX_HDR BIT(1)
+#define PRISM2_DUMP_TXEXC_HDR BIT(2)
+
+struct hostap_tx_callback_info {
+ u16 idx;
+ void (*func)(struct sk_buff *, int ok, void *);
+ void *data;
+ struct hostap_tx_callback_info *next;
+};
+
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define PRISM2_FRAG_CACHE_LEN 4
+
+struct prism2_frag_entry {
+ unsigned long first_frag_time;
+ unsigned int seq;
+ unsigned int last_frag;
+ struct sk_buff *skb;
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+};
+
+
+struct hostap_cmd_queue {
+ struct list_head list;
+ wait_queue_head_t compl;
+ volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type;
+ void (*callback)(struct net_device *dev, long context, u16 resp0,
+ u16 res);
+ long context;
+ u16 cmd, param0, param1;
+ u16 resp0, res;
+ volatile int issued, issuing;
+
+ atomic_t usecnt;
+ int del_req;
+};
+
+/* options for hw_shutdown */
+#define HOSTAP_HW_NO_DISABLE BIT(0)
+#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1)
+
+typedef struct local_info local_info_t;
+
+struct prism2_helper_functions {
+ /* these functions are defined in hardware model specific files
+ * (hostap_{cs,plx,pci}.c */
+ int (*card_present)(local_info_t *local);
+ void (*cor_sreset)(local_info_t *local);
+ int (*dev_open)(local_info_t *local);
+ int (*dev_close)(local_info_t *local);
+ void (*genesis_reset)(local_info_t *local, int hcr);
+
+ /* the following functions are from hostap_hw.c, but they may have some
+ * hardware model specific code */
+
+ /* FIX: low-level commands like cmd might disappear at some point to
+ * make it easier to change them if needed (e.g., cmd would be replaced
+ * with write_mif/read_mif/testcmd/inquire); at least get_rid and
+ * set_rid might move to hostap_{cs,plx,pci}.c */
+ int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1,
+ u16 *resp0);
+ void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs);
+ int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len,
+ int exact_len);
+ int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len);
+ int (*hw_enable)(struct net_device *dev, int initial);
+ int (*hw_config)(struct net_device *dev, int initial);
+ void (*hw_reset)(struct net_device *dev);
+ void (*hw_shutdown)(struct net_device *dev, int no_disable);
+ int (*reset_port)(struct net_device *dev);
+ void (*schedule_reset)(local_info_t *local);
+ int (*download)(local_info_t *local,
+ struct prism2_download_param *param);
+ int (*tx)(struct sk_buff *skb, struct net_device *dev);
+ int (*set_tim)(struct net_device *dev, int aid, int set);
+ int (*read_aux)(struct net_device *dev, unsigned addr, int len,
+ u8 *buf);
+
+ int need_tx_headroom; /* number of bytes of headroom needed before
+ * IEEE 802.11 header */
+ enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type;
+};
+
+
+struct prism2_download_data {
+ u32 dl_cmd;
+ u32 start_addr;
+ u32 num_areas;
+ struct prism2_download_data_area {
+ u32 addr; /* wlan card address */
+ u32 len;
+ u8 *data; /* allocated data */
+ } data[0];
+};
+
+
+#define HOSTAP_MAX_BSS_COUNT 64
+#define MAX_WPA_IE_LEN 64
+
+struct hostap_bss_info {
+ struct list_head list;
+ unsigned long last_update;
+ unsigned int count;
+ u8 bssid[ETH_ALEN];
+ u16 capab_info;
+ u8 ssid[32];
+ size_t ssid_len;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+ int chan;
+ int included;
+};
+
+
+/* Per radio private Host AP data - shared by all net devices interfaces used
+ * by each radio (wlan#, wlan#ap, wlan#sta, WDS).
+ * ((struct hostap_interface *) netdev_priv(dev))->local points to this
+ * structure. */
+struct local_info {
+ struct module *hw_module;
+ int card_idx;
+ int dev_enabled;
+ int master_dev_auto_open; /* was master device opened automatically */
+ int num_dev_open; /* number of open devices */
+ struct net_device *dev; /* master radio device */
+ struct net_device *ddev; /* main data device */
+ struct list_head hostap_interfaces; /* Host AP interface list (contains
+ * struct hostap_interface entries)
+ */
+ rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock
+ * when removing entries from the list.
+ * TX and RX paths can use read lock. */
+ spinlock_t cmdlock, baplock, lock;
+ struct semaphore rid_bap_sem;
+ u16 infofid; /* MAC buffer id for info frame */
+ /* txfid, intransmitfid, next_txtid, and next_alloc are protected by
+ * txfidlock */
+ spinlock_t txfidlock;
+ int txfid_len; /* length of allocated TX buffers */
+ u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */
+ /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if
+ * corresponding txfid is free for next TX frame */
+ u16 intransmitfid[PRISM2_TXFID_COUNT];
+ int next_txfid; /* index to the next txfid to be checked for
+ * availability */
+ int next_alloc; /* index to the next intransmitfid to be checked for
+ * allocation events */
+
+ /* bitfield for atomic bitops */
+#define HOSTAP_BITS_TRANSMIT 0
+#define HOSTAP_BITS_BAP_TASKLET 1
+#define HOSTAP_BITS_BAP_TASKLET2 2
+ long bits;
+
+ struct ap_data *ap;
+
+ char essid[MAX_SSID_LEN + 1];
+ char name[MAX_NAME_LEN + 1];
+ int name_set;
+ u16 channel_mask; /* mask of allowed channels */
+ u16 scan_channel_mask; /* mask of channels to be scanned */
+ struct comm_tallies_sums comm_tallies;
+ struct net_device_stats stats;
+ struct proc_dir_entry *proc;
+ int iw_mode; /* operating mode (IW_MODE_*) */
+ int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS
+ * 1: IW_MODE_ADHOC is "pseudo IBSS" */
+ char bssid[ETH_ALEN];
+ int channel;
+ int beacon_int;
+ int dtim_period;
+ int mtu;
+ int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */
+ int fw_tx_rate_control;
+ u16 tx_rate_control;
+ u16 basic_rates;
+ int hw_resetting;
+ int hw_ready;
+ int hw_reset_tries; /* how many times reset has been tried */
+ int hw_downloading;
+ int shutdown;
+ int pri_only;
+ int no_pri; /* no PRI f/w present */
+ int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */
+
+ enum {
+ PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF,
+ PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN
+ } txpower_type;
+ int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */
+
+ /* command queue for hfa384x_cmd(); protected with cmdlock */
+ struct list_head cmd_queue;
+ /* max_len for cmd_queue; in addition, cmd_callback can use two
+ * additional entries to prevent sleeping commands from stopping
+ * transmits */
+#define HOSTAP_CMD_QUEUE_MAX_LEN 16
+ int cmd_queue_len; /* number of entries in cmd_queue */
+
+ /* if card timeout is detected in interrupt context, reset_queue is
+ * used to schedule card reseting to be done in user context */
+ struct work_struct reset_queue;
+
+ /* For scheduling a change of the promiscuous mode RID */
+ int is_promisc;
+ struct work_struct set_multicast_list_queue;
+
+ struct work_struct set_tim_queue;
+ struct list_head set_tim_list;
+ spinlock_t set_tim_lock;
+
+ int wds_max_connections;
+ int wds_connections;
+#define HOSTAP_WDS_BROADCAST_RA BIT(0)
+#define HOSTAP_WDS_AP_CLIENT BIT(1)
+#define HOSTAP_WDS_STANDARD_FRAME BIT(2)
+ u32 wds_type;
+ u16 tx_control; /* flags to be used in TX description */
+ int manual_retry_count; /* -1 = use f/w default; otherwise retry count
+ * to be used with all frames */
+
+ struct iw_statistics wstats;
+ unsigned long scan_timestamp; /* Time started to scan */
+ enum {
+ PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
+ PRISM2_MONITOR_CAPHDR = 2
+ } monitor_type;
+ int (*saved_eth_header_parse)(struct sk_buff *skb,
+ unsigned char *haddr);
+ int monitor_allow_fcserr;
+
+ int hostapd; /* whether user space daemon, hostapd, is used for AP
+ * management */
+ int hostapd_sta; /* whether hostapd is used with an extra STA interface
+ */
+ struct net_device *apdev;
+ struct net_device_stats apdevstats;
+
+ char assoc_ap_addr[ETH_ALEN];
+ struct net_device *stadev;
+ struct net_device_stats stadevstats;
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+ struct ieee80211_crypt_data *crypt[WEP_KEYS];
+ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+ struct timer_list crypt_deinit_timer;
+ struct list_head crypt_deinit_list;
+
+ int open_wep; /* allow unencrypted frames */
+ int host_encrypt;
+ int host_decrypt;
+ int privacy_invoked; /* force privacy invoked flag even if no keys are
+ * configured */
+ int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working
+ * in Host AP mode (STA f/w 1.4.9 or newer) */
+ int bcrx_sta_key; /* use individual keys to override default keys even
+ * with RX of broad/multicast frames */
+
+ struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN];
+ unsigned int frag_next_idx;
+
+ int ieee_802_1x; /* is IEEE 802.1X used */
+
+ int antsel_tx, antsel_rx;
+ int rts_threshold; /* dot11RTSThreshold */
+ int fragm_threshold; /* dot11FragmentationThreshold */
+ int auth_algs; /* PRISM2_AUTH_ flags */
+
+ int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */
+ int tallies32; /* 32-bit tallies in use */
+
+ struct prism2_helper_functions *func;
+
+ u8 *pda;
+ int fw_ap;
+#define PRISM2_FW_VER(major, minor, variant) \
+(((major) << 16) | ((minor) << 8) | variant)
+ u32 sta_fw_ver;
+
+ /* Tasklets for handling hardware IRQ related operations outside hw IRQ
+ * handler */
+ struct tasklet_struct bap_tasklet;
+
+ struct tasklet_struct info_tasklet;
+ struct sk_buff_head info_list; /* info frames as skb's for
+ * info_tasklet */
+
+ struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks
+ */
+
+ struct tasklet_struct rx_tasklet;
+ struct sk_buff_head rx_list;
+
+ struct tasklet_struct sta_tx_exc_tasklet;
+ struct sk_buff_head sta_tx_exc_list;
+
+ int host_roaming;
+ unsigned long last_join_time; /* time of last JoinRequest */
+ struct hfa384x_hostscan_result *last_scan_results;
+ int last_scan_results_count;
+ enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type;
+ struct work_struct info_queue;
+ long pending_info; /* bit field of pending info_queue items */
+#define PRISM2_INFO_PENDING_LINKSTATUS 0
+#define PRISM2_INFO_PENDING_SCANRESULTS 1
+ int prev_link_status; /* previous received LinkStatus info */
+ int prev_linkstatus_connected;
+ u8 preferred_ap[6]; /* use this AP if possible */
+
+#ifdef PRISM2_CALLBACK
+ void *callback_data; /* Can be used in callbacks; e.g., allocate
+ * on enable event and free on disable event.
+ * Host AP driver code does not touch this. */
+#endif /* PRISM2_CALLBACK */
+
+ wait_queue_head_t hostscan_wq;
+
+ /* Passive scan in Host AP mode */
+ struct timer_list passive_scan_timer;
+ int passive_scan_interval; /* in seconds, 0 = disabled */
+ int passive_scan_channel;
+ enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state;
+
+ struct timer_list tick_timer;
+ unsigned long last_tick_timer;
+ unsigned int sw_tick_stuck;
+
+ /* commsQuality / dBmCommsQuality data from periodic polling; only
+ * valid for Managed and Ad-hoc modes */
+ unsigned long last_comms_qual_update;
+ int comms_qual; /* in some odd unit.. */
+ int avg_signal; /* in dB (note: negative) */
+ int avg_noise; /* in dB (note: negative) */
+ struct work_struct comms_qual_update;
+
+ /* RSSI to dBm adjustment (for RX descriptor fields) */
+ int rssi_to_dBm; /* substract from RSSI to get approximate dBm value */
+
+ /* BSS list / protected by local->lock */
+ struct list_head bss_list;
+ int num_bss_info;
+ int wpa; /* WPA support enabled */
+ int tkip_countermeasures;
+ int drop_unencrypted;
+ /* Generic IEEE 802.11 info element to be added to
+ * ProbeResp/Beacon/(Re)AssocReq */
+ u8 *generic_elem;
+ size_t generic_elem_len;
+
+#ifdef PRISM2_DOWNLOAD_SUPPORT
+ /* Persistent volatile download data */
+ struct prism2_download_data *dl_pri;
+ struct prism2_download_data *dl_sec;
+#endif /* PRISM2_DOWNLOAD_SUPPORT */
+
+#ifdef PRISM2_IO_DEBUG
+#define PRISM2_IO_DEBUG_SIZE 10000
+ u32 io_debug[PRISM2_IO_DEBUG_SIZE];
+ int io_debug_head;
+ int io_debug_enabled;
+#endif /* PRISM2_IO_DEBUG */
+
+ /* Pointer to hardware model specific (cs,pci,plx) private data. */
+ void *hw_priv;
+};
+
+
+/* Per interface private Host AP data
+ * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta,
+ * WDS) and netdev_priv(dev) points to this structure. */
+struct hostap_interface {
+ struct list_head list; /* list entry in Host AP interface list */
+ struct net_device *dev; /* pointer to this device */
+ struct local_info *local; /* pointer to shared private data */
+ struct net_device_stats stats;
+ struct iw_spy_data spy_data; /* iwspy support */
+ struct iw_public_data wireless_data;
+
+ enum {
+ HOSTAP_INTERFACE_MASTER,
+ HOSTAP_INTERFACE_MAIN,
+ HOSTAP_INTERFACE_AP,
+ HOSTAP_INTERFACE_STA,
+ HOSTAP_INTERFACE_WDS,
+ } type;
+
+ union {
+ struct hostap_interface_wds {
+ u8 remote_addr[ETH_ALEN];
+ } wds;
+ } u;
+};
+
+
+#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2
+
+/*
+ * TX meta data - stored in skb->cb buffer, so this must not be increased over
+ * the 40-byte limit
+ */
+struct hostap_skb_tx_data {
+ u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */
+ u8 rate; /* transmit rate */
+#define HOSTAP_TX_FLAGS_WDS BIT(0)
+#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1)
+#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2)
+ u8 flags; /* HOSTAP_TX_FLAGS_* */
+ u16 tx_cb_idx;
+ struct hostap_interface *iface;
+ unsigned long jiffies; /* queueing timestamp */
+ unsigned short ethertype;
+};
+
+
+#ifndef PRISM2_NO_DEBUG
+
+#define DEBUG_FID BIT(0)
+#define DEBUG_PS BIT(1)
+#define DEBUG_FLOW BIT(2)
+#define DEBUG_AP BIT(3)
+#define DEBUG_HW BIT(4)
+#define DEBUG_EXTRA BIT(5)
+#define DEBUG_EXTRA2 BIT(6)
+#define DEBUG_PS2 BIT(7)
+#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA)
+#define PDEBUG(n, args...) \
+do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0)
+#define PDEBUG2(n, args...) \
+do { if ((n) & DEBUG_MASK) printk(args); } while (0)
+
+#else /* PRISM2_NO_DEBUG */
+
+#define PDEBUG(n, args...)
+#define PDEBUG2(n, args...)
+
+#endif /* PRISM2_NO_DEBUG */
+
+enum { BAP0 = 0, BAP1 = 1 };
+
+#define PRISM2_IO_DEBUG_CMD_INB 0
+#define PRISM2_IO_DEBUG_CMD_INW 1
+#define PRISM2_IO_DEBUG_CMD_INSW 2
+#define PRISM2_IO_DEBUG_CMD_OUTB 3
+#define PRISM2_IO_DEBUG_CMD_OUTW 4
+#define PRISM2_IO_DEBUG_CMD_OUTSW 5
+#define PRISM2_IO_DEBUG_CMD_ERROR 6
+#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7
+
+#ifdef PRISM2_IO_DEBUG
+
+#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \
+(((cmd) << 24) | ((reg) << 16) | value)
+
+static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
+ int reg, int value)
+{
+ struct hostap_interface *iface = netdev_priv(dev);
+ local_info_t *local = iface->local;
+
+ if (!local->io_debug_enabled)
+ return;
+
+ local->io_debug[local->io_debug_head] = jiffies & 0xffffffff;
+ if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
+ local->io_debug_head = 0;
+ local->io_debug[local->io_debug_head] =
+ PRISM2_IO_DEBUG_ENTRY(cmd, reg, value);
+ if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
+ local->io_debug_head = 0;
+}
+
+
+static inline void prism2_io_debug_error(struct net_device *dev, int err)
+{
+ struct hostap_interface *iface = netdev_priv(dev);
+ local_info_t *local = iface->local;
+ unsigned long flags;
+
+ if (!local->io_debug_enabled)
+ return;
+
+ spin_lock_irqsave(&local->lock, flags);
+ prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err);
+ if (local->io_debug_enabled == 1) {
+ local->io_debug_enabled = 0;
+ printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name);
+ }
+ spin_unlock_irqrestore(&local->lock, flags);
+}
+
+#else /* PRISM2_IO_DEBUG */
+
+static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
+ int reg, int value)
+{
+}
+
+static inline void prism2_io_debug_error(struct net_device *dev, int err)
+{
+}
+
+#endif /* PRISM2_IO_DEBUG */
+
+
+#ifdef PRISM2_CALLBACK
+enum {
+ /* Called when card is enabled */
+ PRISM2_CALLBACK_ENABLE,
+
+ /* Called when card is disabled */
+ PRISM2_CALLBACK_DISABLE,
+
+ /* Called when RX/TX starts/ends */
+ PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END,
+ PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END
+};
+void prism2_callback(local_info_t *local, int event);
+#else /* PRISM2_CALLBACK */
+#define prism2_callback(d, e) do { } while (0)
+#endif /* PRISM2_CALLBACK */
+
+#endif /* __KERNEL__ */
+
+#endif /* HOSTAP_WLAN_H */
diff --git a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h
deleted file mode 100644
index 53dd524..0000000
--- a/drivers/net/wireless/ieee802_11.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef _IEEE802_11_H
-#define _IEEE802_11_H
-
-#define IEEE802_11_DATA_LEN 2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- 6.2.1.1.2.
-
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-
-
-#define IEEE802_11_HLEN 30
-#define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
-
-struct ieee802_11_hdr {
- u16 frame_ctl;
- u16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- u16 seq_ctl;
- u8 addr4[ETH_ALEN];
-} __attribute__ ((packed));
-
-/* Frame control field constants */
-#define IEEE802_11_FCTL_VERS 0x0002
-#define IEEE802_11_FCTL_FTYPE 0x000c
-#define IEEE802_11_FCTL_STYPE 0x00f0
-#define IEEE802_11_FCTL_TODS 0x0100
-#define IEEE802_11_FCTL_FROMDS 0x0200
-#define IEEE802_11_FCTL_MOREFRAGS 0x0400
-#define IEEE802_11_FCTL_RETRY 0x0800
-#define IEEE802_11_FCTL_PM 0x1000
-#define IEEE802_11_FCTL_MOREDATA 0x2000
-#define IEEE802_11_FCTL_WEP 0x4000
-#define IEEE802_11_FCTL_ORDER 0x8000
-
-#define IEEE802_11_FTYPE_MGMT 0x0000
-#define IEEE802_11_FTYPE_CTL 0x0004
-#define IEEE802_11_FTYPE_DATA 0x0008
-
-/* management */
-#define IEEE802_11_STYPE_ASSOC_REQ 0x0000
-#define IEEE802_11_STYPE_ASSOC_RESP 0x0010
-#define IEEE802_11_STYPE_REASSOC_REQ 0x0020
-#define IEEE802_11_STYPE_REASSOC_RESP 0x0030
-#define IEEE802_11_STYPE_PROBE_REQ 0x0040
-#define IEEE802_11_STYPE_PROBE_RESP 0x0050
-#define IEEE802_11_STYPE_BEACON 0x0080
-#define IEEE802_11_STYPE_ATIM 0x0090
-#define IEEE802_11_STYPE_DISASSOC 0x00A0
-#define IEEE802_11_STYPE_AUTH 0x00B0
-#define IEEE802_11_STYPE_DEAUTH 0x00C0
-
-/* control */
-#define IEEE802_11_STYPE_PSPOLL 0x00A0
-#define IEEE802_11_STYPE_RTS 0x00B0
-#define IEEE802_11_STYPE_CTS 0x00C0
-#define IEEE802_11_STYPE_ACK 0x00D0
-#define IEEE802_11_STYPE_CFEND 0x00E0
-#define IEEE802_11_STYPE_CFENDACK 0x00F0
-
-/* data */
-#define IEEE802_11_STYPE_DATA 0x0000
-#define IEEE802_11_STYPE_DATA_CFACK 0x0010
-#define IEEE802_11_STYPE_DATA_CFPOLL 0x0020
-#define IEEE802_11_STYPE_DATA_CFACKPOLL 0x0030
-#define IEEE802_11_STYPE_NULLFUNC 0x0040
-#define IEEE802_11_STYPE_CFACK 0x0050
-#define IEEE802_11_STYPE_CFPOLL 0x0060
-#define IEEE802_11_STYPE_CFACKPOLL 0x0070
-
-#define IEEE802_11_SCTL_FRAG 0x000F
-#define IEEE802_11_SCTL_SEQ 0xFFF0
-
-#endif /* _IEEE802_11_H */
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
new file mode 100644
index 0000000..2414e64
--- /dev/null
+++ b/drivers/net/wireless/ipw2100.c
@@ -0,0 +1,8680 @@
+/******************************************************************************
+
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+ Portions of this file are based on the sample_* files provided by Wireless
+ Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
+ <jt@hpl.hp.com>
+
+ Portions of this file are based on the Host AP project,
+ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ <jkmaline@cc.hut.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+ Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
+ ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
+ available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
+
+******************************************************************************/
+/*
+
+ Initial driver on which this is based was developed by Janusz Gorycki,
+ Maciej Urbaniak, and Maciej Sosnowski.
+
+ Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
+
+Theory of Operation
+
+Tx - Commands and Data
+
+Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
+Each TBD contains a pointer to the physical (dma_addr_t) address of data being
+sent to the firmware as well as the length of the data.
+
+The host writes to the TBD queue at the WRITE index. The WRITE index points
+to the _next_ packet to be written and is advanced when after the TBD has been
+filled.
+
+The firmware pulls from the TBD queue at the READ index. The READ index points
+to the currently being read entry, and is advanced once the firmware is
+done with a packet.
+
+When data is sent to the firmware, the first TBD is used to indicate to the
+firmware if a Command or Data is being sent. If it is Command, all of the
+command information is contained within the physical address referred to by the
+TBD. If it is Data, the first TBD indicates the type of data packet, number
+of fragments, etc. The next TBD then referrs to the actual packet location.
+
+The Tx flow cycle is as follows:
+
+1) ipw2100_tx() is called by kernel with SKB to transmit
+2) Packet is move from the tx_free_list and appended to the transmit pending
+ list (tx_pend_list)
+3) work is scheduled to move pending packets into the shared circular queue.
+4) when placing packet in the circular queue, the incoming SKB is DMA mapped
+ to a physical address. That address is entered into a TBD. Two TBDs are
+ filled out. The first indicating a data packet, the second referring to the
+ actual payload data.
+5) the packet is removed from tx_pend_list and placed on the end of the
+ firmware pending list (fw_pend_list)
+6) firmware is notified that the WRITE index has
+7) Once the firmware has processed the TBD, INTA is triggered.
+8) For each Tx interrupt received from the firmware, the READ index is checked
+ to see which TBDs are done being processed.
+9) For each TBD that has been processed, the ISR pulls the oldest packet
+ from the fw_pend_list.
+10)The packet structure contained in the fw_pend_list is then used
+ to unmap the DMA address and to free the SKB originally passed to the driver
+ from the kernel.
+11)The packet structure is placed onto the tx_free_list
+
+The above steps are the same for commands, only the msg_free_list/msg_pend_list
+are used instead of tx_free_list/tx_pend_list
+
+...
+
+Critical Sections / Locking :
+
+There are two locks utilized. The first is the low level lock (priv->low_lock)
+that protects the following:
+
+- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
+
+ tx_free_list : Holds pre-allocated Tx buffers.
+ TAIL modified in __ipw2100_tx_process()
+ HEAD modified in ipw2100_tx()
+
+ tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
+ TAIL modified ipw2100_tx()
+ HEAD modified by ipw2100_tx_send_data()
+
+ msg_free_list : Holds pre-allocated Msg (Command) buffers
+ TAIL modified in __ipw2100_tx_process()
+ HEAD modified in ipw2100_hw_send_command()
+
+ msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
+ TAIL modified in ipw2100_hw_send_command()
+ HEAD modified in ipw2100_tx_send_commands()
+
+ The flow of data on the TX side is as follows:
+
+ MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
+ TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
+
+ The methods that work on the TBD ring are protected via priv->low_lock.
+
+- The internal data state of the device itself
+- Access to the firmware read/write indexes for the BD queues
+ and associated logic
+
+All external entry functions are locked with the priv->action_lock to ensure
+that only one external action is invoked at a time.
+
+
+*/
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/unistd.h>
+#include <linux/stringify.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/time.h>
+#include <linux/firmware.h>
+#include <linux/acpi.h>
+#include <linux/ctype.h>
+
+#include "ipw2100.h"
+
+#define IPW2100_VERSION "1.1.0"
+
+#define DRV_NAME "ipw2100"
+#define DRV_VERSION IPW2100_VERSION
+#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation"
+
+
+/* Debugging stuff */
+#ifdef CONFIG_IPW_DEBUG
+#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */
+#endif
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+static int mode = 0;
+static int channel = 0;
+static int associate = 1;
+static int disable = 0;
+#ifdef CONFIG_PM
+static struct ipw2100_fw ipw2100_firmware;
+#endif
+
+#include <linux/moduleparam.h>
+module_param(debug, int, 0444);
+module_param(mode, int, 0444);
+module_param(channel, int, 0444);
+module_param(associate, int, 0444);
+module_param(disable, int, 0444);
+
+MODULE_PARM_DESC(debug, "debug level");
+MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
+MODULE_PARM_DESC(channel, "channel");
+MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+
+static u32 ipw2100_debug_level = IPW_DL_NONE;
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW_DEBUG(level, message...) \
+do { \
+ if (ipw2100_debug_level & (level)) { \
+ printk(KERN_DEBUG "ipw2100: %c %s ", \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__); \
+ printk(message); \
+ } \
+} while (0)
+#else
+#define IPW_DEBUG(level, message...) do {} while (0)
+#endif /* CONFIG_IPW_DEBUG */
+
+#ifdef CONFIG_IPW_DEBUG
+static const char *command_types[] = {
+ "undefined",
+ "unused", /* HOST_ATTENTION */
+ "HOST_COMPLETE",
+ "unused", /* SLEEP */
+ "unused", /* HOST_POWER_DOWN */
+ "unused",
+ "SYSTEM_CONFIG",
+ "unused", /* SET_IMR */
+ "SSID",
+ "MANDATORY_BSSID",
+ "AUTHENTICATION_TYPE",
+ "ADAPTER_ADDRESS",
+ "PORT_TYPE",
+ "INTERNATIONAL_MODE",
+ "CHANNEL",
+ "RTS_THRESHOLD",
+ "FRAG_THRESHOLD",
+ "POWER_MODE",
+ "TX_RATES",
+ "BASIC_TX_RATES",
+ "WEP_KEY_INFO",
+ "unused",
+ "unused",
+ "unused",
+ "unused",
+ "WEP_KEY_INDEX",
+ "WEP_FLAGS",
+ "ADD_MULTICAST",
+ "CLEAR_ALL_MULTICAST",
+ "BEACON_INTERVAL",
+ "ATIM_WINDOW",
+ "CLEAR_STATISTICS",
+ "undefined",
+ "undefined",
+ "undefined",
+ "undefined",
+ "TX_POWER_INDEX",
+ "undefined",
+ "undefined",
+ "undefined",
+ "undefined",
+ "undefined",
+ "undefined",
+ "BROADCAST_SCAN",
+ "CARD_DISABLE",
+ "PREFERRED_BSSID",
+ "SET_SCAN_OPTIONS",
+ "SCAN_DWELL_TIME",
+ "SWEEP_TABLE",
+ "AP_OR_STATION_TABLE",
+ "GROUP_ORDINALS",
+ "SHORT_RETRY_LIMIT",
+ "LONG_RETRY_LIMIT",
+ "unused", /* SAVE_CALIBRATION */
+ "unused", /* RESTORE_CALIBRATION */
+ "undefined",
+ "undefined",
+ "undefined",
+ "HOST_PRE_POWER_DOWN",
+ "unused", /* HOST_INTERRUPT_COALESCING */
+ "undefined",
+ "CARD_DISABLE_PHY_OFF",
+ "MSDU_TX_RATES"
+ "undefined",
+ "undefined",
+ "SET_STATION_STAT_BITS",
+ "CLEAR_STATIONS_STAT_BITS",
+ "LEAP_ROGUE_MODE",
+ "SET_SECURITY_INFORMATION",
+ "DISASSOCIATION_BSSID",
+ "SET_WPA_ASS_IE"
+};
+#endif
+
+
+/* Pre-decl until we get the code solid and then we can clean it up */
+static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
+static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
+static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
+
+static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
+static void ipw2100_queues_free(struct ipw2100_priv *priv);
+static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
+
+static int ipw2100_fw_download(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw);
+static int ipw2100_get_firmware(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw);
+static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
+ size_t max);
+static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
+ size_t max);
+static void ipw2100_release_firmware(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw);
+static int ipw2100_ucode_download(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw);
+static void ipw2100_wx_event_work(struct ipw2100_priv *priv);
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev);
+static struct iw_handler_def ipw2100_wx_handler_def;
+
+
+static inline void read_register(struct net_device *dev, u32 reg, u32 *val)
+{
+ *val = readl((void __iomem *)(dev->base_addr + reg));
+ IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
+}
+
+static inline void write_register(struct net_device *dev, u32 reg, u32 val)
+{
+ writel(val, (void __iomem *)(dev->base_addr + reg));
+ IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
+}
+
+static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val)
+{
+ *val = readw((void __iomem *)(dev->base_addr + reg));
+ IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
+}
+
+static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val)
+{
+ *val = readb((void __iomem *)(dev->base_addr + reg));
+ IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
+}
+
+static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
+{
+ writew(val, (void __iomem *)(dev->base_addr + reg));
+ IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
+}
+
+
+static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
+{
+ writeb(val, (void __iomem *)(dev->base_addr + reg));
+ IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
+}
+
+static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 *val)
+{
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+ read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
+{
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void read_nic_word(struct net_device *dev, u32 addr, u16 *val)
+{
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+ read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
+{
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+ write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 *val)
+{
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+ read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
+{
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+ write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
+}
+
+static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
+{
+ write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
+ addr & IPW_REG_INDIRECT_ADDR_MASK);
+}
+
+static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
+{
+ write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
+}
+
+static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
+ const u8 *buf)
+{
+ u32 aligned_addr;
+ u32 aligned_len;
+ u32 dif_len;
+ u32 i;
+
+ /* read first nibble byte by byte */
+ aligned_addr = addr & (~0x3);
+ dif_len = addr - aligned_addr;
+ if (dif_len) {
+ /* Start reading at aligned_addr + dif_len */
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ aligned_addr);
+ for (i = dif_len; i < 4; i++, buf++)
+ write_register_byte(
+ dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
+ *buf);
+
+ len -= dif_len;
+ aligned_addr += 4;
+ }
+
+ /* read DWs through autoincrement registers */
+ write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
+ aligned_addr);
+ aligned_len = len & (~0x3);
+ for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+ write_register(
+ dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *)buf);
+
+ /* copy the last nibble */
+ dif_len = len - aligned_len;
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
+ for (i = 0; i < dif_len; i++, buf++)
+ write_register_byte(
+ dev, IPW_REG_INDIRECT_ACCESS_DATA + i, *buf);
+}
+
+static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
+ u8 *buf)
+{
+ u32 aligned_addr;
+ u32 aligned_len;
+ u32 dif_len;
+ u32 i;
+
+ /* read first nibble byte by byte */
+ aligned_addr = addr & (~0x3);
+ dif_len = addr - aligned_addr;
+ if (dif_len) {
+ /* Start reading at aligned_addr + dif_len */
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ aligned_addr);
+ for (i = dif_len; i < 4; i++, buf++)
+ read_register_byte(
+ dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
+
+ len -= dif_len;
+ aligned_addr += 4;
+ }
+
+ /* read DWs through autoincrement registers */
+ write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
+ aligned_addr);
+ aligned_len = len & (~0x3);
+ for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+ read_register(dev, IPW_REG_AUTOINCREMENT_DATA,
+ (u32 *)buf);
+
+ /* copy the last nibble */
+ dif_len = len - aligned_len;
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
+ aligned_addr);
+ for (i = 0; i < dif_len; i++, buf++)
+ read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA +
+ i, buf);
+}
+
+static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
+{
+ return (dev->base_addr &&
+ (readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START))
+ == IPW_DATA_DOA_DEBUG_VALUE));
+}
+
+static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
+ void *val, u32 *len)
+{
+ struct ipw2100_ordinals *ordinals = &priv->ordinals;
+ u32 addr;
+ u32 field_info;
+ u16 field_len;
+ u16 field_count;
+ u32 total_length;
+
+ if (ordinals->table1_addr == 0) {
+ printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
+ "before they have been loaded.\n");
+ return -EINVAL;
+ }
+
+ if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
+ if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
+ *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+
+ printk(KERN_WARNING DRV_NAME
+ ": ordinal buffer length too small, need %zd\n",
+ IPW_ORD_TAB_1_ENTRY_SIZE);
+
+ return -EINVAL;
+ }
+
+ read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
+ &addr);
+ read_nic_dword(priv->net_dev, addr, val);
+
+ *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+
+ return 0;
+ }
+
+ if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
+
+ ord -= IPW_START_ORD_TAB_2;
+
+ /* get the address of statistic */
+ read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3),
+ &addr);
+
+ /* get the second DW of statistics ;
+ * two 16-bit words - first is length, second is count */
+ read_nic_dword(priv->net_dev,
+ ordinals->table2_addr + (ord << 3) + sizeof(u32),
+ &field_info);
+
+ /* get each entry length */
+ field_len = *((u16 *)&field_info);
+
+ /* get number of entries */
+ field_count = *(((u16 *)&field_info) + 1);
+
+ /* abort if no enought memory */
+ total_length = field_len * field_count;
+ if (total_length > *len) {
+ *len = total_length;
+ return -EINVAL;
+ }
+
+ *len = total_length;
+ if (!total_length)
+ return 0;
+
+ /* read the ordinal data from the SRAM */
+ read_nic_memory(priv->net_dev, addr, total_length, val);
+
+ return 0;
+ }
+
+ printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
+ "in table 2\n", ord);
+
+ return -EINVAL;
+}
+
+static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val,
+ u32 *len)
+{
+ struct ipw2100_ordinals *ordinals = &priv->ordinals;
+ u32 addr;
+
+ if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
+ if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
+ *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+ IPW_DEBUG_INFO("wrong size\n");
+ return -EINVAL;
+ }
+
+ read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
+ &addr);
+
+ write_nic_dword(priv->net_dev, addr, *val);
+
+ *len = IPW_ORD_TAB_1_ENTRY_SIZE;
+
+ return 0;
+ }
+
+ IPW_DEBUG_INFO("wrong table\n");
+ if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
+ return -EINVAL;
+
+ return -EINVAL;
+}
+
+static char *snprint_line(char *buf, size_t count,
+ const u8 *data, u32 len, u32 ofs)
+{
+ int out, i, j, l;
+ char c;
+
+ out = snprintf(buf, count, "%08X", ofs);
+
+ for (l = 0, i = 0; i < 2; i++) {
+ out += snprintf(buf + out, count - out, " ");
+ for (j = 0; j < 8 && l < len; j++, l++)
+ out += snprintf(buf + out, count - out, "%02X ",
+ data[(i * 8 + j)]);
+ for (; j < 8; j++)
+ out += snprintf(buf + out, count - out, " ");
+ }
+
+ out += snprintf(buf + out, count - out, " ");
+ for (l = 0, i = 0; i < 2; i++) {
+ out += snprintf(buf + out, count - out, " ");
+ for (j = 0; j < 8 && l < len; j++, l++) {
+ c = data[(i * 8 + j)];
+ if (!isascii(c) || !isprint(c))
+ c = '.';
+
+ out += snprintf(buf + out, count - out, "%c", c);
+ }
+
+ for (; j < 8; j++)
+ out += snprintf(buf + out, count - out, " ");
+ }
+
+ return buf;
+}
+
+static void printk_buf(int level, const u8 *data, u32 len)
+{
+ char line[81];
+ u32 ofs = 0;
+ if (!(ipw2100_debug_level & level))
+ return;
+
+ while (len) {
+ printk(KERN_DEBUG "%s\n",
+ snprint_line(line, sizeof(line), &data[ofs],
+ min(len, 16U), ofs));
+ ofs += 16;
+ len -= min(len, 16U);
+ }
+}
+
+
+
+#define MAX_RESET_BACKOFF 10
+
+static inline void schedule_reset(struct ipw2100_priv *priv)
+{
+ unsigned long now = get_seconds();
+
+ /* If we haven't received a reset request within the backoff period,
+ * then we can reset the backoff interval so this reset occurs
+ * immediately */
+ if (priv->reset_backoff &&
+ (now - priv->last_reset > priv->reset_backoff))
+ priv->reset_backoff = 0;
+
+ priv->last_reset = get_seconds();
+
+ if (!(priv->status & STATUS_RESET_PENDING)) {
+ IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",
+ priv->net_dev->name, priv->reset_backoff);
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+ priv->status |= STATUS_RESET_PENDING;
+ if (priv->reset_backoff)
+ queue_delayed_work(priv->workqueue, &priv->reset_work,
+ priv->reset_backoff * HZ);
+ else
+ queue_work(priv->workqueue, &priv->reset_work);
+
+ if (priv->reset_backoff < MAX_RESET_BACKOFF)
+ priv->reset_backoff++;
+
+ wake_up_interruptible(&priv->wait_command_queue);
+ } else
+ IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
+ priv->net_dev->name);
+
+}
+
+#define HOST_COMPLETE_TIMEOUT (2 * HZ)
+static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
+ struct host_command * cmd)
+{
+ struct list_head *element;
+ struct ipw2100_tx_packet *packet;
+ unsigned long flags;
+ int err = 0;
+
+ IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
+ command_types[cmd->host_command], cmd->host_command,
+ cmd->host_command_length);
+ printk_buf(IPW_DL_HC, (u8*)cmd->host_command_parameters,
+ cmd->host_command_length);
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+
+ if (priv->fatal_error) {
+ IPW_DEBUG_INFO("Attempt to send command while hardware in fatal error condition.\n");
+ err = -EIO;
+ goto fail_unlock;
+ }
+
+ if (!(priv->status & STATUS_RUNNING)) {
+ IPW_DEBUG_INFO("Attempt to send command while hardware is not running.\n");
+ err = -EIO;
+ goto fail_unlock;
+ }
+
+ if (priv->status & STATUS_CMD_ACTIVE) {
+ IPW_DEBUG_INFO("Attempt to send command while another command is pending.\n");
+ err = -EBUSY;
+ goto fail_unlock;
+ }
+
+ if (list_empty(&priv->msg_free_list)) {
+ IPW_DEBUG_INFO("no available msg buffers\n");
+ goto fail_unlock;
+ }
+
+ priv->status |= STATUS_CMD_ACTIVE;
+ priv->messages_sent++;
+
+ element = priv->msg_free_list.next;
+
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
+ packet->jiffy_start = jiffies;
+
+ /* initialize the firmware command packet */
+ packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
+ packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
+ packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length;
+ packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
+
+ memcpy(packet->info.c_struct.cmd->host_command_params_reg,
+ cmd->host_command_parameters,
+ sizeof(packet->info.c_struct.cmd->host_command_params_reg));
+
+ list_del(element);
+ DEC_STAT(&priv->msg_free_stat);
+
+ list_add_tail(element, &priv->msg_pend_list);
+ INC_STAT(&priv->msg_pend_stat);
+
+ ipw2100_tx_send_commands(priv);
+ ipw2100_tx_send_data(priv);
+
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ /*
+ * We must wait for this command to complete before another
+ * command can be sent... but if we wait more than 3 seconds
+ * then there is a problem.
+ */
+
+ err = wait_event_interruptible_timeout(
+ priv->wait_command_queue, !(priv->status & STATUS_CMD_ACTIVE),
+ HOST_COMPLETE_TIMEOUT);
+
+ if (err == 0) {
+ IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
+ HOST_COMPLETE_TIMEOUT / (HZ / 100));
+ priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
+ priv->status &= ~STATUS_CMD_ACTIVE;
+ schedule_reset(priv);
+ return -EIO;
+ }
+
+ if (priv->fatal_error) {
+ printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
+ priv->net_dev->name);
+ return -EIO;
+ }
+
+ /* !!!!! HACK TEST !!!!!
+ * When lots of debug trace statements are enabled, the driver
+ * doesn't seem to have as many firmware restart cycles...
+ *
+ * As a test, we're sticking in a 1/100s delay here */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 100);
+
+ return 0;
+
+ fail_unlock:
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ return err;
+}
+
+
+/*
+ * Verify the values and data access of the hardware
+ * No locks needed or used. No functions called.
+ */
+static int ipw2100_verify(struct ipw2100_priv *priv)
+{
+ u32 data1, data2;
+ u32 address;
+
+ u32 val1 = 0x76543210;
+ u32 val2 = 0xFEDCBA98;
+
+ /* Domain 0 check - all values should be DOA_DEBUG */
+ for (address = IPW_REG_DOA_DEBUG_AREA_START;
+ address < IPW_REG_DOA_DEBUG_AREA_END;
+ address += sizeof(u32)) {
+ read_register(priv->net_dev, address, &data1);
+ if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
+ return -EIO;
+ }
+
+ /* Domain 1 check - use arbitrary read/write compare */
+ for (address = 0; address < 5; address++) {
+ /* The memory area is not used now */
+ write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
+ val1);
+ write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
+ val2);
+ read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
+ &data1);
+ read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
+ &data2);
+ if (val1 == data1 && val2 == data2)
+ return 0;
+ }
+
+ return -EIO;
+}
+
+/*
+ *
+ * Loop until the CARD_DISABLED bit is the same value as the
+ * supplied parameter
+ *
+ * TODO: See if it would be more efficient to do a wait/wake
+ * cycle and have the completion event trigger the wakeup
+ *
+ */
+#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
+static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
+{
+ int i;
+ u32 card_state;
+ u32 len = sizeof(card_state);
+ int err;
+
+ for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
+ err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
+ &card_state, &len);
+ if (err) {
+ IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
+ "failed.\n");
+ return 0;
+ }
+
+ /* We'll break out if either the HW state says it is
+ * in the state we want, or if HOST_COMPLETE command
+ * finishes */
+ if ((card_state == state) ||
+ ((priv->status & STATUS_ENABLED) ?
+ IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
+ if (state == IPW_HW_STATE_ENABLED)
+ priv->status |= STATUS_ENABLED;
+ else
+ priv->status &= ~STATUS_ENABLED;
+
+ return 0;
+ }
+
+ udelay(50);
+ }
+
+ IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
+ state ? "DISABLED" : "ENABLED");
+ return -EIO;
+}
+
+
+/*********************************************************************
+ Procedure : sw_reset_and_clock
+ Purpose : Asserts s/w reset, asserts clock initialization
+ and waits for clock stabilization
+ ********************************************************************/
+static int sw_reset_and_clock(struct ipw2100_priv *priv)
+{
+ int i;
+ u32 r;
+
+ // assert s/w reset
+ write_register(priv->net_dev, IPW_REG_RESET_REG,
+ IPW_AUX_HOST_RESET_REG_SW_RESET);
+
+ // wait for clock stabilization
+ for (i = 0; i < 1000; i++) {
+ udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
+
+ // check clock ready bit
+ read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
+ if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
+ break;
+ }
+
+ if (i == 1000)
+ return -EIO; // TODO: better error value
+
+ /* set "initialization complete" bit to move adapter to
+ * D0 state */
+ write_register(priv->net_dev, IPW_REG_GP_CNTRL,
+ IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
+
+ /* wait for clock stabilization */
+ for (i = 0; i < 10000; i++) {
+ udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
+
+ /* check clock ready bit */
+ read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
+ if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
+ break;
+ }
+
+ if (i == 10000)
+ return -EIO; /* TODO: better error value */
+
+ /* set D0 standby bit */
+ read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
+ write_register(priv->net_dev, IPW_REG_GP_CNTRL,
+ r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
+
+ return 0;
+}
+
+/*********************************************************************
+ Procedure : ipw2100_download_firmware
+ Purpose : Initiaze adapter after power on.
+ The sequence is:
+ 1. assert s/w reset first!
+ 2. awake clocks & wait for clock stabilization
+ 3. hold ARC (don't ask me why...)
+ 4. load Dino ucode and reset/clock init again
+ 5. zero-out shared mem
+ 6. download f/w
+ *******************************************************************/
+static int ipw2100_download_firmware(struct ipw2100_priv *priv)
+{
+ u32 address;
+ int err;
+
+#ifndef CONFIG_PM
+ /* Fetch the firmware and microcode */
+ struct ipw2100_fw ipw2100_firmware;
+#endif
+
+ if (priv->fatal_error) {
+ IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
+ "fatal error %d. Interface must be brought down.\n",
+ priv->net_dev->name, priv->fatal_error);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_PM
+ if (!ipw2100_firmware.version) {
+ err = ipw2100_get_firmware(priv, &ipw2100_firmware);
+ if (err) {
+ IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
+ priv->net_dev->name, err);
+ priv->fatal_error = IPW2100_ERR_FW_LOAD;
+ goto fail;
+ }
+ }
+#else
+ err = ipw2100_get_firmware(priv, &ipw2100_firmware);
+ if (err) {
+ IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
+ priv->net_dev->name, err);
+ priv->fatal_error = IPW2100_ERR_FW_LOAD;
+ goto fail;
+ }
+#endif
+ priv->firmware_version = ipw2100_firmware.version;
+
+ /* s/w reset and clock stabilization */
+ err = sw_reset_and_clock(priv);
+ if (err) {
+ IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
+ priv->net_dev->name, err);
+ goto fail;
+ }
+
+ err = ipw2100_verify(priv);
+ if (err) {
+ IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
+ priv->net_dev->name, err);
+ goto fail;
+ }
+
+ /* Hold ARC */
+ write_nic_dword(priv->net_dev,
+ IPW_INTERNAL_REGISTER_HALT_AND_RESET,
+ 0x80000000);
+
+ /* allow ARC to run */
+ write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
+
+ /* load microcode */
+ err = ipw2100_ucode_download(priv, &ipw2100_firmware);
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
+ priv->net_dev->name, err);
+ goto fail;
+ }
+
+ /* release ARC */
+ write_nic_dword(priv->net_dev,
+ IPW_INTERNAL_REGISTER_HALT_AND_RESET,
+ 0x00000000);
+
+ /* s/w reset and clock stabilization (again!!!) */
+ err = sw_reset_and_clock(priv);
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n",
+ priv->net_dev->name, err);
+ goto fail;
+ }
+
+ /* load f/w */
+ err = ipw2100_fw_download(priv, &ipw2100_firmware);
+ if (err) {
+ IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
+ priv->net_dev->name, err);
+ goto fail;
+ }
+
+#ifndef CONFIG_PM
+ /*
+ * When the .resume method of the driver is called, the other
+ * part of the system, i.e. the ide driver could still stay in
+ * the suspend stage. This prevents us from loading the firmware
+ * from the disk. --YZ
+ */
+
+ /* free any storage allocated for firmware image */
+ ipw2100_release_firmware(priv, &ipw2100_firmware);
+#endif
+
+ /* zero out Domain 1 area indirectly (Si requirement) */
+ for (address = IPW_HOST_FW_SHARED_AREA0;
+ address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
+ write_nic_dword(priv->net_dev, address, 0);
+ for (address = IPW_HOST_FW_SHARED_AREA1;
+ address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
+ write_nic_dword(priv->net_dev, address, 0);
+ for (address = IPW_HOST_FW_SHARED_AREA2;
+ address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
+ write_nic_dword(priv->net_dev, address, 0);
+ for (address = IPW_HOST_FW_SHARED_AREA3;
+ address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
+ write_nic_dword(priv->net_dev, address, 0);
+ for (address = IPW_HOST_FW_INTERRUPT_AREA;
+ address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
+ write_nic_dword(priv->net_dev, address, 0);
+
+ return 0;
+
+ fail:
+ ipw2100_release_firmware(priv, &ipw2100_firmware);
+ return err;
+}
+
+static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
+{
+ if (priv->status & STATUS_INT_ENABLED)
+ return;
+ priv->status |= STATUS_INT_ENABLED;
+ write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
+}
+
+static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
+{
+ if (!(priv->status & STATUS_INT_ENABLED))
+ return;
+ priv->status &= ~STATUS_INT_ENABLED;
+ write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
+}
+
+
+static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
+{
+ struct ipw2100_ordinals *ord = &priv->ordinals;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
+ &ord->table1_addr);
+
+ read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
+ &ord->table2_addr);
+
+ read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
+ read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
+
+ ord->table2_size &= 0x0000FFFF;
+
+ IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
+ IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
+ IPW_DEBUG_INFO("exit\n");
+}
+
+static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
+{
+ u32 reg = 0;
+ /*
+ * Set GPIO 3 writable by FW; GPIO 1 writable
+ * by driver and enable clock
+ */
+ reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
+ IPW_BIT_GPIO_LED_OFF);
+ write_register(priv->net_dev, IPW_REG_GPIO, reg);
+}
+
+static inline int rf_kill_active(struct ipw2100_priv *priv)
+{
+#define MAX_RF_KILL_CHECKS 5
+#define RF_KILL_CHECK_DELAY 40
+
+ unsigned short value = 0;
+ u32 reg = 0;
+ int i;
+
+ if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
+ priv->status &= ~STATUS_RF_KILL_HW;
+ return 0;
+ }
+
+ for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
+ udelay(RF_KILL_CHECK_DELAY);
+ read_register(priv->net_dev, IPW_REG_GPIO, ®);
+ value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
+ }
+
+ if (value == 0)
+ priv->status |= STATUS_RF_KILL_HW;
+ else
+ priv->status &= ~STATUS_RF_KILL_HW;
+
+ return (value == 0);
+}
+
+static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
+{
+ u32 addr, len;
+ u32 val;
+
+ /*
+ * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
+ */
+ len = sizeof(addr);
+ if (ipw2100_get_ordinal(
+ priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
+ &addr, &len)) {
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+ return -EIO;
+ }
+
+ IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
+
+ /*
+ * EEPROM version is the byte at offset 0xfd in firmware
+ * We read 4 bytes, then shift out the byte we actually want */
+ read_nic_dword(priv->net_dev, addr + 0xFC, &val);
+ priv->eeprom_version = (val >> 24) & 0xFF;
+ IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
+
+ /*
+ * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
+ *
+ * notice that the EEPROM bit is reverse polarity, i.e.
+ * bit = 0 signifies HW RF kill switch is supported
+ * bit = 1 signifies HW RF kill switch is NOT supported
+ */
+ read_nic_dword(priv->net_dev, addr + 0x20, &val);
+ if (!((val >> 24) & 0x01))
+ priv->hw_features |= HW_FEATURE_RFKILL;
+
+ IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
+ (priv->hw_features & HW_FEATURE_RFKILL) ?
+ "" : "not ");
+
+ return 0;
+}
+
+/*
+ * Start firmware execution after power on and intialization
+ * The sequence is:
+ * 1. Release ARC
+ * 2. Wait for f/w initialization completes;
+ */
+static int ipw2100_start_adapter(struct ipw2100_priv *priv)
+{
+ int i;
+ u32 inta, inta_mask, gpio;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ if (priv->status & STATUS_RUNNING)
+ return 0;
+
+ /*
+ * Initialize the hw - drive adapter to DO state by setting
+ * init_done bit. Wait for clk_ready bit and Download
+ * fw & dino ucode
+ */
+ if (ipw2100_download_firmware(priv)) {
+ printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n",
+ priv->net_dev->name);
+ return -EIO;
+ }
+
+ /* Clear the Tx, Rx and Msg queues and the r/w indexes
+ * in the firmware RBD and TBD ring queue */
+ ipw2100_queues_initialize(priv);
+
+ ipw2100_hw_set_gpio(priv);
+
+ /* TODO -- Look at disabling interrupts here to make sure none
+ * get fired during FW initialization */
+
+ /* Release ARC - clear reset bit */
+ write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
+
+ /* wait for f/w intialization complete */
+ IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
+ i = 5000;
+ do {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(40 * HZ / 1000);
+ /* Todo... wait for sync command ... */
+
+ read_register(priv->net_dev, IPW_REG_INTA, &inta);
+
+ /* check "init done" bit */
+ if (inta & IPW2100_INTA_FW_INIT_DONE) {
+ /* reset "init done" bit */
+ write_register(priv->net_dev, IPW_REG_INTA,
+ IPW2100_INTA_FW_INIT_DONE);
+ break;
+ }
+
+ /* check error conditions : we check these after the firmware
+ * check so that if there is an error, the interrupt handler
+ * will see it and the adapter will be reset */
+ if (inta &
+ (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
+ /* clear error conditions */
+ write_register(priv->net_dev, IPW_REG_INTA,
+ IPW2100_INTA_FATAL_ERROR |
+ IPW2100_INTA_PARITY_ERROR);
+ }
+ } while (i--);
+
+ /* Clear out any pending INTAs since we aren't supposed to have
+ * interrupts enabled at this point... */
+ read_register(priv->net_dev, IPW_REG_INTA, &inta);
+ read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
+ inta &= IPW_INTERRUPT_MASK;
+ /* Clear out any pending interrupts */
+ if (inta & inta_mask)
+ write_register(priv->net_dev, IPW_REG_INTA, inta);
+
+ IPW_DEBUG_FW("f/w initialization complete: %s\n",
+ i ? "SUCCESS" : "FAILED");
+
+ if (!i) {
+ printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n",
+ priv->net_dev->name);
+ return -EIO;
+ }
+
+ /* allow firmware to write to GPIO1 & GPIO3 */
+ read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
+
+ gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
+
+ write_register(priv->net_dev, IPW_REG_GPIO, gpio);
+
+ /* Ready to receive commands */
+ priv->status |= STATUS_RUNNING;
+
+ /* The adapter has been reset; we are not associated */
+ priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+}
+
+static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
+{
+ if (!priv->fatal_error)
+ return;
+
+ priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
+ priv->fatal_index %= IPW2100_ERROR_QUEUE;
+ priv->fatal_error = 0;
+}
+
+
+/* NOTE: Our interrupt is disabled when this method is called */
+static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
+{
+ u32 reg;
+ int i;
+
+ IPW_DEBUG_INFO("Power cycling the hardware.\n");
+
+ ipw2100_hw_set_gpio(priv);
+
+ /* Step 1. Stop Master Assert */
+ write_register(priv->net_dev, IPW_REG_RESET_REG,
+ IPW_AUX_HOST_RESET_REG_STOP_MASTER);
+
+ /* Step 2. Wait for stop Master Assert
+ * (not more then 50us, otherwise ret error */
+ i = 5;
+ do {
+ udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
+ read_register(priv->net_dev, IPW_REG_RESET_REG, ®);
+
+ if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
+ break;
+ } while(i--);
+
+ priv->status &= ~STATUS_RESET_PENDING;
+
+ if (!i) {
+ IPW_DEBUG_INFO("exit - waited too long for master assert stop\n");
+ return -EIO;
+ }
+
+ write_register(priv->net_dev, IPW_REG_RESET_REG,
+ IPW_AUX_HOST_RESET_REG_SW_RESET);
+
+
+ /* Reset any fatal_error conditions */
+ ipw2100_reset_fatalerror(priv);
+
+ /* At this point, the adapter is now stopped and disabled */
+ priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
+ STATUS_ASSOCIATED | STATUS_ENABLED);
+
+ return 0;
+}
+
+/*
+ * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it
+ *
+ * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
+ *
+ * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
+ * if STATUS_ASSN_LOST is sent.
+ */
+static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
+{
+
+#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000)
+
+ struct host_command cmd = {
+ .host_command = CARD_DISABLE_PHY_OFF,
+ .host_command_sequence = 0,
+ .host_command_length = 0,
+ };
+ int err, i;
+ u32 val1, val2;
+
+ IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
+
+ /* Turn off the radio */
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+
+ for (i = 0; i < 2500; i++) {
+ read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
+ read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
+
+ if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
+ (val2 & IPW2100_COMMAND_PHY_OFF))
+ return 0;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HW_PHY_OFF_LOOP_DELAY);
+ }
+
+ return -EIO;
+}
+
+
+static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
+{
+ struct host_command cmd = {
+ .host_command = HOST_COMPLETE,
+ .host_command_sequence = 0,
+ .host_command_length = 0
+ };
+ int err = 0;
+
+ IPW_DEBUG_HC("HOST_COMPLETE\n");
+
+ if (priv->status & STATUS_ENABLED)
+ return 0;
+
+ down(&priv->adapter_sem);
+
+ if (rf_kill_active(priv)) {
+ IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
+ goto fail_up;
+ }
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err) {
+ IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
+ goto fail_up;
+ }
+
+ err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
+ if (err) {
+ IPW_DEBUG_INFO(
+ "%s: card not responding to init command.\n",
+ priv->net_dev->name);
+ goto fail_up;
+ }
+
+ if (priv->stop_hang_check) {
+ priv->stop_hang_check = 0;
+ queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+ }
+
+fail_up:
+ up(&priv->adapter_sem);
+ return err;
+}
+
+static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
+{
+#define HW_POWER_DOWN_DELAY (HZ / 10)
+
+ struct host_command cmd = {
+ .host_command = HOST_PRE_POWER_DOWN,
+ .host_command_sequence = 0,
+ .host_command_length = 0,
+ };
+ int err, i;
+ u32 reg;
+
+ if (!(priv->status & STATUS_RUNNING))
+ return 0;
+
+ priv->status |= STATUS_STOPPING;
+
+ /* We can only shut down the card if the firmware is operational. So,
+ * if we haven't reset since a fatal_error, then we can not send the
+ * shutdown commands. */
+ if (!priv->fatal_error) {
+ /* First, make sure the adapter is enabled so that the PHY_OFF
+ * command can shut it down */
+ ipw2100_enable_adapter(priv);
+
+ err = ipw2100_hw_phy_off(priv);
+ if (err)
+ printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err);
+
+ /*
+ * If in D0-standby mode going directly to D3 may cause a
+ * PCI bus violation. Therefore we must change out of the D0
+ * state.
+ *
+ * Sending the PREPARE_FOR_POWER_DOWN will restrict the
+ * hardware from going into standby mode and will transition
+ * out of D0-standy if it is already in that state.
+ *
+ * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
+ * driver upon completion. Once received, the driver can
+ * proceed to the D3 state.
+ *
+ * Prepare for power down command to fw. This command would
+ * take HW out of D0-standby and prepare it for D3 state.
+ *
+ * Currently FW does not support event notification for this
+ * event. Therefore, skip waiting for it. Just wait a fixed
+ * 100ms
+ */
+ IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ printk(KERN_WARNING DRV_NAME ": "
+ "%s: Power down command failed: Error %d\n",
+ priv->net_dev->name, err);
+ else {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HW_POWER_DOWN_DELAY);
+ }
+ }
+
+ priv->status &= ~STATUS_ENABLED;
+
+ /*
+ * Set GPIO 3 writable by FW; GPIO 1 writable
+ * by driver and enable clock
+ */
+ ipw2100_hw_set_gpio(priv);
+
+ /*
+ * Power down adapter. Sequence:
+ * 1. Stop master assert (RESET_REG[9]=1)
+ * 2. Wait for stop master (RESET_REG[8]==1)
+ * 3. S/w reset assert (RESET_REG[7] = 1)
+ */
+
+ /* Stop master assert */
+ write_register(priv->net_dev, IPW_REG_RESET_REG,
+ IPW_AUX_HOST_RESET_REG_STOP_MASTER);
+
+ /* wait stop master not more than 50 usec.
+ * Otherwise return error. */
+ for (i = 5; i > 0; i--) {
+ udelay(10);
+
+ /* Check master stop bit */
+ read_register(priv->net_dev, IPW_REG_RESET_REG, ®);
+
+ if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
+ break;
+ }
+
+ if (i == 0)
+ printk(KERN_WARNING DRV_NAME
+ ": %s: Could now power down adapter.\n",
+ priv->net_dev->name);
+
+ /* assert s/w reset */
+ write_register(priv->net_dev, IPW_REG_RESET_REG,
+ IPW_AUX_HOST_RESET_REG_SW_RESET);
+
+ priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
+
+ return 0;
+}
+
+
+static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
+{
+ struct host_command cmd = {
+ .host_command = CARD_DISABLE,
+ .host_command_sequence = 0,
+ .host_command_length = 0
+ };
+ int err = 0;
+
+ IPW_DEBUG_HC("CARD_DISABLE\n");
+
+ if (!(priv->status & STATUS_ENABLED))
+ return 0;
+
+ /* Make sure we clear the associated state */
+ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+
+ if (!priv->stop_hang_check) {
+ priv->stop_hang_check = 1;
+ cancel_delayed_work(&priv->hang_check);
+ }
+
+ down(&priv->adapter_sem);
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n");
+ goto fail_up;
+ }
+
+ err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n");
+ goto fail_up;
+ }
+
+ IPW_DEBUG_INFO("TODO: implement scan state machine\n");
+
+fail_up:
+ up(&priv->adapter_sem);
+ return err;
+}
+
+static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
+{
+ struct host_command cmd = {
+ .host_command = SET_SCAN_OPTIONS,
+ .host_command_sequence = 0,
+ .host_command_length = 8
+ };
+ int err;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ IPW_DEBUG_SCAN("setting scan options\n");
+
+ cmd.host_command_parameters[0] = 0;
+
+ if (!(priv->config & CFG_ASSOCIATE))
+ cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
+ if ((priv->sec.flags & SEC_ENABLED) && priv->sec.enabled)
+ cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
+ if (priv->config & CFG_PASSIVE_SCAN)
+ cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
+
+ cmd.host_command_parameters[1] = priv->channel_mask;
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
+ cmd.host_command_parameters[0]);
+
+ return err;
+}
+
+static int ipw2100_start_scan(struct ipw2100_priv *priv)
+{
+ struct host_command cmd = {
+ .host_command = BROADCAST_SCAN,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ IPW_DEBUG_HC("START_SCAN\n");
+
+ cmd.host_command_parameters[0] = 0;
+
+ /* No scanning if in monitor mode */
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+ return 1;
+
+ if (priv->status & STATUS_SCANNING) {
+ IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
+ return 0;
+ }
+
+ IPW_DEBUG_INFO("enter\n");
+
+ /* Not clearing here; doing so makes iwlist always return nothing...
+ *
+ * We should modify the table logic to use aging tables vs. clearing
+ * the table on each scan start.
+ */
+ IPW_DEBUG_SCAN("starting scan\n");
+
+ priv->status |= STATUS_SCANNING;
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ priv->status &= ~STATUS_SCANNING;
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return err;
+}
+
+static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
+{
+ unsigned long flags;
+ int rc = 0;
+ u32 lock;
+ u32 ord_len = sizeof(lock);
+
+ /* Quite if manually disabled. */
+ if (priv->status & STATUS_RF_KILL_SW) {
+ IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
+ "switch\n", priv->net_dev->name);
+ return 0;
+ }
+
+ /* If the interrupt is enabled, turn it off... */
+ spin_lock_irqsave(&priv->low_lock, flags);
+ ipw2100_disable_interrupts(priv);
+
+ /* Reset any fatal_error conditions */
+ ipw2100_reset_fatalerror(priv);
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ if (priv->status & STATUS_POWERED ||
+ (priv->status & STATUS_RESET_PENDING)) {
+ /* Power cycle the card ... */
+ if (ipw2100_power_cycle_adapter(priv)) {
+ printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n",
+ priv->net_dev->name);
+ rc = 1;
+ goto exit;
+ }
+ } else
+ priv->status |= STATUS_POWERED;
+
+ /* Load the firmware, start the clocks, etc. */
+ if (ipw2100_start_adapter(priv)) {
+ printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n",
+ priv->net_dev->name);
+ rc = 1;
+ goto exit;
+ }
+
+ ipw2100_initialize_ordinals(priv);
+
+ /* Determine capabilities of this particular HW configuration */
+ if (ipw2100_get_hw_features(priv)) {
+ printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n",
+ priv->net_dev->name);
+ rc = 1;
+ goto exit;
+ }
+
+ lock = LOCK_NONE;
+ if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
+ printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n",
+ priv->net_dev->name);
+ rc = 1;
+ goto exit;
+ }
+
+ priv->status &= ~STATUS_SCANNING;
+
+ if (rf_kill_active(priv)) {
+ printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
+ priv->net_dev->name);
+
+ if (priv->stop_rf_kill) {
+ priv->stop_rf_kill = 0;
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+ }
+
+ deferred = 1;
+ }
+
+ /* Turn on the interrupt so that commands can be processed */
+ ipw2100_enable_interrupts(priv);
+
+ /* Send all of the commands that must be sent prior to
+ * HOST_COMPLETE */
+ if (ipw2100_adapter_setup(priv)) {
+ printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
+ priv->net_dev->name);
+ rc = 1;
+ goto exit;
+ }
+
+ if (!deferred) {
+ /* Enable the adapter - sends HOST_COMPLETE */
+ if (ipw2100_enable_adapter(priv)) {
+ printk(KERN_ERR DRV_NAME ": "
+ "%s: failed in call to enable adapter.\n",
+ priv->net_dev->name);
+ ipw2100_hw_stop_adapter(priv);
+ rc = 1;
+ goto exit;
+ }
+
+
+ /* Start a scan . . . */
+ ipw2100_set_scan_options(priv);
+ ipw2100_start_scan(priv);
+ }
+
+ exit:
+ return rc;
+}
+
+/* Called by register_netdev() */
+static int ipw2100_net_init(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return ipw2100_up(priv, 1);
+}
+
+static void ipw2100_down(struct ipw2100_priv *priv)
+{
+ unsigned long flags;
+ union iwreq_data wrqu = {
+ .ap_addr = {
+ .sa_family = ARPHRD_ETHER
+ }
+ };
+ int associated = priv->status & STATUS_ASSOCIATED;
+
+ /* Kill the RF switch timer */
+ if (!priv->stop_rf_kill) {
+ priv->stop_rf_kill = 1;
+ cancel_delayed_work(&priv->rf_kill);
+ }
+
+ /* Kill the firmare hang check timer */
+ if (!priv->stop_hang_check) {
+ priv->stop_hang_check = 1;
+ cancel_delayed_work(&priv->hang_check);
+ }
+
+ /* Kill any pending resets */
+ if (priv->status & STATUS_RESET_PENDING)
+ cancel_delayed_work(&priv->reset_work);
+
+ /* Make sure the interrupt is on so that FW commands will be
+ * processed correctly */
+ spin_lock_irqsave(&priv->low_lock, flags);
+ ipw2100_enable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ if (ipw2100_hw_stop_adapter(priv))
+ printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
+ priv->net_dev->name);
+
+ /* Do not disable the interrupt until _after_ we disable
+ * the adaptor. Otherwise the CARD_DISABLE command will never
+ * be ack'd by the firmware */
+ spin_lock_irqsave(&priv->low_lock, flags);
+ ipw2100_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+ if (priv->config & CFG_C3_DISABLED) {
+ IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+ acpi_set_cstate_limit(priv->cstate_limit);
+ priv->config &= ~CFG_C3_DISABLED;
+ }
+#endif
+
+ /* We have to signal any supplicant if we are disassociating */
+ if (associated)
+ wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+
+ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+}
+
+static void ipw2100_reset_adapter(struct ipw2100_priv *priv)
+{
+ unsigned long flags;
+ union iwreq_data wrqu = {
+ .ap_addr = {
+ .sa_family = ARPHRD_ETHER
+ }
+ };
+ int associated = priv->status & STATUS_ASSOCIATED;
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+ IPW_DEBUG_INFO(DRV_NAME ": %s: Restarting adapter.\n",
+ priv->net_dev->name);
+ priv->resets++;
+ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+ priv->status |= STATUS_SECURITY_UPDATED;
+
+ /* Force a power cycle even if interface hasn't been opened
+ * yet */
+ cancel_delayed_work(&priv->reset_work);
+ priv->status |= STATUS_RESET_PENDING;
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ down(&priv->action_sem);
+ /* stop timed checks so that they don't interfere with reset */
+ priv->stop_hang_check = 1;
+ cancel_delayed_work(&priv->hang_check);
+
+ /* We have to signal any supplicant if we are disassociating */
+ if (associated)
+ wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+
+ ipw2100_up(priv, 0);
+ up(&priv->action_sem);
+
+}
+
+
+static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
+{
+
+#define MAC_ASSOCIATION_READ_DELAY (HZ)
+ int ret, len, essid_len;
+ char essid[IW_ESSID_MAX_SIZE];
+ u32 txrate;
+ u32 chan;
+ char *txratename;
+ u8 bssid[ETH_ALEN];
+
+ /*
+ * TBD: BSSID is usually 00:00:00:00:00:00 here and not
+ * an actual MAC of the AP. Seems like FW sets this
+ * address too late. Read it later and expose through
+ * /proc or schedule a later task to query and update
+ */
+
+ essid_len = IW_ESSID_MAX_SIZE;
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
+ essid, &essid_len);
+ if (ret) {
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+ return;
+ }
+
+ len = sizeof(u32);
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE,
+ &txrate, &len);
+ if (ret) {
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+ return;
+ }
+
+ len = sizeof(u32);
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
+ if (ret) {
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+ return;
+ }
+ len = ETH_ALEN;
+ ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
+ if (ret) {
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+ return;
+ }
+ memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
+
+
+ switch (txrate) {
+ case TX_RATE_1_MBIT:
+ txratename = "1Mbps";
+ break;
+ case TX_RATE_2_MBIT:
+ txratename = "2Mbsp";
+ break;
+ case TX_RATE_5_5_MBIT:
+ txratename = "5.5Mbps";
+ break;
+ case TX_RATE_11_MBIT:
+ txratename = "11Mbps";
+ break;
+ default:
+ IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
+ txratename = "unknown rate";
+ break;
+ }
+
+ IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
+ MAC_FMT ")\n",
+ priv->net_dev->name, escape_essid(essid, essid_len),
+ txratename, chan, MAC_ARG(bssid));
+
+ /* now we copy read ssid into dev */
+ if (!(priv->config & CFG_STATIC_ESSID)) {
+ priv->essid_len = min((u8)essid_len, (u8)IW_ESSID_MAX_SIZE);
+ memcpy(priv->essid, essid, priv->essid_len);
+ }
+ priv->channel = chan;
+ memcpy(priv->bssid, bssid, ETH_ALEN);
+
+ priv->status |= STATUS_ASSOCIATING;
+ priv->connect_start = get_seconds();
+
+ queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
+}
+
+
+static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
+ int length, int batch_mode)
+{
+ int ssid_len = min(length, IW_ESSID_MAX_SIZE);
+ struct host_command cmd = {
+ .host_command = SSID,
+ .host_command_sequence = 0,
+ .host_command_length = ssid_len
+ };
+ int err;
+
+ IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len));
+
+ if (ssid_len)
+ memcpy((char*)cmd.host_command_parameters,
+ essid, ssid_len);
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
+ * disable auto association -- so we cheat by setting a bogus SSID */
+ if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
+ int i;
+ u8 *bogus = (u8*)cmd.host_command_parameters;
+ for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
+ bogus[i] = 0x18 + i;
+ cmd.host_command_length = IW_ESSID_MAX_SIZE;
+ }
+
+ /* NOTE: We always send the SSID command even if the provided ESSID is
+ * the same as what we currently think is set. */
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (!err) {
+ memset(priv->essid + ssid_len, 0,
+ IW_ESSID_MAX_SIZE - ssid_len);
+ memcpy(priv->essid, essid, ssid_len);
+ priv->essid_len = ssid_len;
+ }
+
+ if (!batch_mode) {
+ if (ipw2100_enable_adapter(priv))
+ err = -EIO;
+ }
+
+ return err;
+}
+
+static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
+{
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
+ "disassociated: '%s' " MAC_FMT " \n",
+ escape_essid(priv->essid, priv->essid_len),
+ MAC_ARG(priv->bssid));
+
+ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
+
+ if (priv->status & STATUS_STOPPING) {
+ IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
+ return;
+ }
+
+ memset(priv->bssid, 0, ETH_ALEN);
+ memset(priv->ieee->bssid, 0, ETH_ALEN);
+
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+
+ if (!(priv->status & STATUS_RUNNING))
+ return;
+
+ if (priv->status & STATUS_SECURITY_UPDATED)
+ queue_work(priv->workqueue, &priv->security_work);
+
+ queue_work(priv->workqueue, &priv->wx_event_work);
+}
+
+static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
+{
+ IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
+ priv->net_dev->name);
+
+ /* RF_KILL is now enabled (else we wouldn't be here) */
+ priv->status |= STATUS_RF_KILL_HW;
+
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+ if (priv->config & CFG_C3_DISABLED) {
+ IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+ acpi_set_cstate_limit(priv->cstate_limit);
+ priv->config &= ~CFG_C3_DISABLED;
+ }
+#endif
+
+ /* Make sure the RF Kill check timer is running */
+ priv->stop_rf_kill = 0;
+ cancel_delayed_work(&priv->rf_kill);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+}
+
+static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
+{
+ IPW_DEBUG_SCAN("scan complete\n");
+ /* Age the scan results... */
+ priv->ieee->scans++;
+ priv->status &= ~STATUS_SCANNING;
+}
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW2100_HANDLER(v, f) { v, f, # v }
+struct ipw2100_status_indicator {
+ int status;
+ void (*cb)(struct ipw2100_priv *priv, u32 status);
+ char *name;
+};
+#else
+#define IPW2100_HANDLER(v, f) { v, f }
+struct ipw2100_status_indicator {
+ int status;
+ void (*cb)(struct ipw2100_priv *priv, u32 status);
+};
+#endif /* CONFIG_IPW_DEBUG */
+
+static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
+{
+ IPW_DEBUG_SCAN("Scanning...\n");
+ priv->status |= STATUS_SCANNING;
+}
+
+static const struct ipw2100_status_indicator status_handlers[] = {
+ IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
+ IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
+ IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
+ IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
+ IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
+ IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
+ IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
+ IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
+ IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
+ IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
+ IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
+ IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
+ IPW2100_HANDLER(-1, NULL)
+};
+
+
+static void isr_status_change(struct ipw2100_priv *priv, int status)
+{
+ int i;
+
+ if (status == IPW_STATE_SCANNING &&
+ priv->status & STATUS_ASSOCIATED &&
+ !(priv->status & STATUS_SCANNING)) {
+ IPW_DEBUG_INFO("Scan detected while associated, with "
+ "no scan request. Restarting firmware.\n");
+
+ /* Wake up any sleeping jobs */
+ schedule_reset(priv);
+ }
+
+ for (i = 0; status_handlers[i].status != -1; i++) {
+ if (status == status_handlers[i].status) {
+ IPW_DEBUG_NOTIF("Status change: %s\n",
+ status_handlers[i].name);
+ if (status_handlers[i].cb)
+ status_handlers[i].cb(priv, status);
+ priv->wstats.status = status;
+ return;
+ }
+ }
+
+ IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
+}
+
+static void isr_rx_complete_command(
+ struct ipw2100_priv *priv,
+ struct ipw2100_cmd_header *cmd)
+{
+#ifdef CONFIG_IPW_DEBUG
+ if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
+ IPW_DEBUG_HC("Command completed '%s (%d)'\n",
+ command_types[cmd->host_command_reg],
+ cmd->host_command_reg);
+ }
+#endif
+ if (cmd->host_command_reg == HOST_COMPLETE)
+ priv->status |= STATUS_ENABLED;
+
+ if (cmd->host_command_reg == CARD_DISABLE)
+ priv->status &= ~STATUS_ENABLED;
+
+ priv->status &= ~STATUS_CMD_ACTIVE;
+
+ wake_up_interruptible(&priv->wait_command_queue);
+}
+
+#ifdef CONFIG_IPW_DEBUG
+static const char *frame_types[] = {
+ "COMMAND_STATUS_VAL",
+ "STATUS_CHANGE_VAL",
+ "P80211_DATA_VAL",
+ "P8023_DATA_VAL",
+ "HOST_NOTIFICATION_VAL"
+};
+#endif
+
+
+static inline int ipw2100_alloc_skb(
+ struct ipw2100_priv *priv,
+ struct ipw2100_rx_packet *packet)
+{
+ packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
+ if (!packet->skb)
+ return -ENOMEM;
+
+ packet->rxp = (struct ipw2100_rx *)packet->skb->data;
+ packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
+ sizeof(struct ipw2100_rx),
+ PCI_DMA_FROMDEVICE);
+ /* NOTE: pci_map_single does not return an error code, and 0 is a valid
+ * dma_addr */
+
+ return 0;
+}
+
+
+#define SEARCH_ERROR 0xffffffff
+#define SEARCH_FAIL 0xfffffffe
+#define SEARCH_SUCCESS 0xfffffff0
+#define SEARCH_DISCARD 0
+#define SEARCH_SNAPSHOT 1
+
+#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
+static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
+{
+ int i;
+ if (priv->snapshot[0])
+ return 1;
+ for (i = 0; i < 0x30; i++) {
+ priv->snapshot[i] = (u8*)kmalloc(0x1000, GFP_ATOMIC);
+ if (!priv->snapshot[i]) {
+ IPW_DEBUG_INFO("%s: Error allocating snapshot "
+ "buffer %d\n", priv->net_dev->name, i);
+ while (i > 0)
+ kfree(priv->snapshot[--i]);
+ priv->snapshot[0] = NULL;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv)
+{
+ int i;
+ if (!priv->snapshot[0])
+ return;
+ for (i = 0; i < 0x30; i++)
+ kfree(priv->snapshot[i]);
+ priv->snapshot[0] = NULL;
+}
+
+static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf,
+ size_t len, int mode)
+{
+ u32 i, j;
+ u32 tmp;
+ u8 *s, *d;
+ u32 ret;
+
+ s = in_buf;
+ if (mode == SEARCH_SNAPSHOT) {
+ if (!ipw2100_snapshot_alloc(priv))
+ mode = SEARCH_DISCARD;
+ }
+
+ for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
+ read_nic_dword(priv->net_dev, i, &tmp);
+ if (mode == SEARCH_SNAPSHOT)
+ *(u32 *)SNAPSHOT_ADDR(i) = tmp;
+ if (ret == SEARCH_FAIL) {
+ d = (u8*)&tmp;
+ for (j = 0; j < 4; j++) {
+ if (*s != *d) {
+ s = in_buf;
+ continue;
+ }
+
+ s++;
+ d++;
+
+ if ((s - in_buf) == len)
+ ret = (i + j) - len + 1;
+ }
+ } else if (mode == SEARCH_DISCARD)
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ *
+ * 0) Disconnect the SKB from the firmware (just unmap)
+ * 1) Pack the ETH header into the SKB
+ * 2) Pass the SKB to the network stack
+ *
+ * When packet is provided by the firmware, it contains the following:
+ *
+ * . ieee80211_hdr
+ * . ieee80211_snap_hdr
+ *
+ * The size of the constructed ethernet
+ *
+ */
+#ifdef CONFIG_IPW2100_RX_DEBUG
+static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
+#endif
+
+static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
+ int i)
+{
+#ifdef CONFIG_IPW_DEBUG_C3
+ struct ipw2100_status *status = &priv->status_queue.drv[i];
+ u32 match, reg;
+ int j;
+#endif
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+ int limit;
+#endif
+
+ IPW_DEBUG_INFO(DRV_NAME ": PCI latency error detected at "
+ "0x%04zX.\n", i * sizeof(struct ipw2100_status));
+
+#ifdef ACPI_CSTATE_LIMIT_DEFINED
+ IPW_DEBUG_INFO(DRV_NAME ": Disabling C3 transitions.\n");
+ limit = acpi_get_cstate_limit();
+ if (limit > 2) {
+ priv->cstate_limit = limit;
+ acpi_set_cstate_limit(2);
+ priv->config |= CFG_C3_DISABLED;
+ }
+#endif
+
+#ifdef CONFIG_IPW_DEBUG_C3
+ /* Halt the fimrware so we can get a good image */
+ write_register(priv->net_dev, IPW_REG_RESET_REG,
+ IPW_AUX_HOST_RESET_REG_STOP_MASTER);
+ j = 5;
+ do {
+ udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
+ read_register(priv->net_dev, IPW_REG_RESET_REG, ®);
+
+ if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
+ break;
+ } while (j--);
+
+ match = ipw2100_match_buf(priv, (u8*)status,
+ sizeof(struct ipw2100_status),
+ SEARCH_SNAPSHOT);
+ if (match < SEARCH_SUCCESS)
+ IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
+ "offset 0x%06X, length %d:\n",
+ priv->net_dev->name, match,
+ sizeof(struct ipw2100_status));
+ else
+ IPW_DEBUG_INFO("%s: No DMA status match in "
+ "Firmware.\n", priv->net_dev->name);
+
+ printk_buf((u8*)priv->status_queue.drv,
+ sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
+#endif
+
+ priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
+ priv->ieee->stats.rx_errors++;
+ schedule_reset(priv);
+}
+
+static inline void isr_rx(struct ipw2100_priv *priv, int i,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ipw2100_status *status = &priv->status_queue.drv[i];
+ struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
+
+ IPW_DEBUG_RX("Handler...\n");
+
+ if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
+ IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
+ " Dropping.\n",
+ priv->net_dev->name,
+ status->frame_size, skb_tailroom(packet->skb));
+ priv->ieee->stats.rx_errors++;
+ return;
+ }
+
+ if (unlikely(!netif_running(priv->net_dev))) {
+ priv->ieee->stats.rx_errors++;
+ priv->wstats.discard.misc++;
+ IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+ return;
+ }
+
+ if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR &&
+ status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
+ IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
+ priv->ieee->stats.rx_errors++;
+ return;
+ }
+
+ if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
+ !(priv->status & STATUS_ASSOCIATED))) {
+ IPW_DEBUG_DROP("Dropping packet while not associated.\n");
+ priv->wstats.discard.misc++;
+ return;
+ }
+
+
+ pci_unmap_single(priv->pci_dev,
+ packet->dma_addr,
+ sizeof(struct ipw2100_rx),
+ PCI_DMA_FROMDEVICE);
+
+ skb_put(packet->skb, status->frame_size);
+
+#ifdef CONFIG_IPW2100_RX_DEBUG
+ /* Make a copy of the frame so we can dump it to the logs if
+ * ieee80211_rx fails */
+ memcpy(packet_data, packet->skb->data,
+ min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH));
+#endif
+
+ if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
+#ifdef CONFIG_IPW2100_RX_DEBUG
+ IPW_DEBUG_DROP("%s: Non consumed packet:\n",
+ priv->net_dev->name);
+ printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
+#endif
+ priv->ieee->stats.rx_errors++;
+
+ /* ieee80211_rx failed, so it didn't free the SKB */
+ dev_kfree_skb_any(packet->skb);
+ packet->skb = NULL;
+ }
+
+ /* We need to allocate a new SKB and attach it to the RDB. */
+ if (unlikely(ipw2100_alloc_skb(priv, packet))) {
+ printk(KERN_WARNING DRV_NAME ": "
+ "%s: Unable to allocate SKB onto RBD ring - disabling "
+ "adapter.\n", priv->net_dev->name);
+ /* TODO: schedule adapter shutdown */
+ IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
+ }
+
+ /* Update the RDB entry */
+ priv->rx_queue.drv[i].host_addr = packet->dma_addr;
+}
+
+static inline int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
+{
+ struct ipw2100_status *status = &priv->status_queue.drv[i];
+ struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
+ u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
+
+ switch (frame_type) {
+ case COMMAND_STATUS_VAL:
+ return (status->frame_size != sizeof(u->rx_data.command));
+ case STATUS_CHANGE_VAL:
+ return (status->frame_size != sizeof(u->rx_data.status));
+ case HOST_NOTIFICATION_VAL:
+ return (status->frame_size < sizeof(u->rx_data.notification));
+ case P80211_DATA_VAL:
+ case P8023_DATA_VAL:
+#ifdef CONFIG_IPW2100_MONITOR
+ return 0;
+#else
+ switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
+ case IEEE80211_FTYPE_MGMT:
+ case IEEE80211_FTYPE_CTL:
+ return 0;
+ case IEEE80211_FTYPE_DATA:
+ return (status->frame_size >
+ IPW_MAX_802_11_PAYLOAD_LENGTH);
+ }
+#endif
+ }
+
+ return 1;
+}
+
+/*
+ * ipw2100 interrupts are disabled at this point, and the ISR
+ * is the only code that calls this method. So, we do not need
+ * to play with any locks.
+ *
+ * RX Queue works as follows:
+ *
+ * Read index - firmware places packet in entry identified by the
+ * Read index and advances Read index. In this manner,
+ * Read index will always point to the next packet to
+ * be filled--but not yet valid.
+ *
+ * Write index - driver fills this entry with an unused RBD entry.
+ * This entry has not filled by the firmware yet.
+ *
+ * In between the W and R indexes are the RBDs that have been received
+ * but not yet processed.
+ *
+ * The process of handling packets will start at WRITE + 1 and advance
+ * until it reaches the READ index.
+ *
+ * The WRITE index is cached in the variable 'priv->rx_queue.next'.
+ *
+ */
+static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
+{
+ struct ipw2100_bd_queue *rxq = &priv->rx_queue;
+ struct ipw2100_status_queue *sq = &priv->status_queue;
+ struct ipw2100_rx_packet *packet;
+ u16 frame_type;
+ u32 r, w, i, s;
+ struct ipw2100_rx *u;
+ struct ieee80211_rx_stats stats = {
+ .mac_time = jiffies,
+ };
+
+ read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
+ read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
+
+ if (r >= rxq->entries) {
+ IPW_DEBUG_RX("exit - bad read index\n");
+ return;
+ }
+
+ i = (rxq->next + 1) % rxq->entries;
+ s = i;
+ while (i != r) {
+ /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
+ r, rxq->next, i); */
+
+ packet = &priv->rx_buffers[i];
+
+ /* Sync the DMA for the STATUS buffer so CPU is sure to get
+ * the correct values */
+ pci_dma_sync_single_for_cpu(
+ priv->pci_dev,
+ sq->nic + sizeof(struct ipw2100_status) * i,
+ sizeof(struct ipw2100_status),
+ PCI_DMA_FROMDEVICE);
+
+ /* Sync the DMA for the RX buffer so CPU is sure to get
+ * the correct values */
+ pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
+ sizeof(struct ipw2100_rx),
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(ipw2100_corruption_check(priv, i))) {
+ ipw2100_corruption_detected(priv, i);
+ goto increment;
+ }
+
+ u = packet->rxp;
+ frame_type = sq->drv[i].status_fields &
+ STATUS_TYPE_MASK;
+ stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
+ stats.len = sq->drv[i].frame_size;
+
+ stats.mask = 0;
+ if (stats.rssi != 0)
+ stats.mask |= IEEE80211_STATMASK_RSSI;
+ stats.freq = IEEE80211_24GHZ_BAND;
+
+ IPW_DEBUG_RX(
+ "%s: '%s' frame type received (%d).\n",
+ priv->net_dev->name, frame_types[frame_type],
+ stats.len);
+
+ switch (frame_type) {
+ case COMMAND_STATUS_VAL:
+ /* Reset Rx watchdog */
+ isr_rx_complete_command(
+ priv, &u->rx_data.command);
+ break;
+
+ case STATUS_CHANGE_VAL:
+ isr_status_change(priv, u->rx_data.status);
+ break;
+
+ case P80211_DATA_VAL:
+ case P8023_DATA_VAL:
+#ifdef CONFIG_IPW2100_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ isr_rx(priv, i, &stats);
+ break;
+ }
+#endif
+ if (stats.len < sizeof(u->rx_data.header))
+ break;
+ switch (WLAN_FC_GET_TYPE(u->rx_data.header.
+ frame_ctl)) {
+ case IEEE80211_FTYPE_MGMT:
+ ieee80211_rx_mgt(priv->ieee,
+ &u->rx_data.header,
+ &stats);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+ break;
+
+ case IEEE80211_FTYPE_DATA:
+ isr_rx(priv, i, &stats);
+ break;
+
+ }
+ break;
+ }
+
+ increment:
+ /* clear status field associated with this RBD */
+ rxq->drv[i].status.info.field = 0;
+
+ i = (i + 1) % rxq->entries;
+ }
+
+ if (i != s) {
+ /* backtrack one entry, wrapping to end if at 0 */
+ rxq->next = (i ? i : rxq->entries) - 1;
+
+ write_register(priv->net_dev,
+ IPW_MEM_HOST_SHARED_RX_WRITE_INDEX,
+ rxq->next);
+ }
+}
+
+
+/*
+ * __ipw2100_tx_process
+ *
+ * This routine will determine whether the next packet on
+ * the fw_pend_list has been processed by the firmware yet.
+ *
+ * If not, then it does nothing and returns.
+ *
+ * If so, then it removes the item from the fw_pend_list, frees
+ * any associated storage, and places the item back on the
+ * free list of its source (either msg_free_list or tx_free_list)
+ *
+ * TX Queue works as follows:
+ *
+ * Read index - points to the next TBD that the firmware will
+ * process. The firmware will read the data, and once
+ * done processing, it will advance the Read index.
+ *
+ * Write index - driver fills this entry with an constructed TBD
+ * entry. The Write index is not advanced until the
+ * packet has been configured.
+ *
+ * In between the W and R indexes are the TBDs that have NOT been
+ * processed. Lagging behind the R index are packets that have
+ * been processed but have not been freed by the driver.
+ *
+ * In order to free old storage, an internal index will be maintained
+ * that points to the next packet to be freed. When all used
+ * packets have been freed, the oldest index will be the same as the
+ * firmware's read index.
+ *
+ * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
+ *
+ * Because the TBD structure can not contain arbitrary data, the
+ * driver must keep an internal queue of cached allocations such that
+ * it can put that data back into the tx_free_list and msg_free_list
+ * for use by future command and data packets.
+ *
+ */
+static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
+{
+ struct ipw2100_bd_queue *txq = &priv->tx_queue;
+ struct ipw2100_bd *tbd;
+ struct list_head *element;
+ struct ipw2100_tx_packet *packet;
+ int descriptors_used;
+ int e, i;
+ u32 r, w, frag_num = 0;
+
+ if (list_empty(&priv->fw_pend_list))
+ return 0;
+
+ element = priv->fw_pend_list.next;
+
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
+ tbd = &txq->drv[packet->index];
+
+ /* Determine how many TBD entries must be finished... */
+ switch (packet->type) {
+ case COMMAND:
+ /* COMMAND uses only one slot; don't advance */
+ descriptors_used = 1;
+ e = txq->oldest;
+ break;
+
+ case DATA:
+ /* DATA uses two slots; advance and loop position. */
+ descriptors_used = tbd->num_fragments;
+ frag_num = tbd->num_fragments - 1;
+ e = txq->oldest + frag_num;
+ e %= txq->entries;
+ break;
+
+ default:
+ printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
+ priv->net_dev->name);
+ return 0;
+ }
+
+ /* if the last TBD is not done by NIC yet, then packet is
+ * not ready to be released.
+ *
+ */
+ read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
+ &r);
+ read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
+ &w);
+ if (w != txq->next)
+ printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
+ priv->net_dev->name);
+
+ /*
+ * txq->next is the index of the last packet written txq->oldest is
+ * the index of the r is the index of the next packet to be read by
+ * firmware
+ */
+
+
+ /*
+ * Quick graphic to help you visualize the following
+ * if / else statement
+ *
+ * ===>| s---->|===============
+ * e>|
+ * | a | b | c | d | e | f | g | h | i | j | k | l
+ * r---->|
+ * w
+ *
+ * w - updated by driver
+ * r - updated by firmware
+ * s - start of oldest BD entry (txq->oldest)
+ * e - end of oldest BD entry
+ *
+ */
+ if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
+ IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
+ return 0;
+ }
+
+ list_del(element);
+ DEC_STAT(&priv->fw_pend_stat);
+
+#ifdef CONFIG_IPW_DEBUG
+ {
+ int i = txq->oldest;
+ IPW_DEBUG_TX(
+ "TX%d V=%p P=%04X T=%04X L=%d\n", i,
+ &txq->drv[i],
+ (u32)(txq->nic + i * sizeof(struct ipw2100_bd)),
+ txq->drv[i].host_addr,
+ txq->drv[i].buf_length);
+
+ if (packet->type == DATA) {
+ i = (i + 1) % txq->entries;
+
+ IPW_DEBUG_TX(
+ "TX%d V=%p P=%04X T=%04X L=%d\n", i,
+ &txq->drv[i],
+ (u32)(txq->nic + i *
+ sizeof(struct ipw2100_bd)),
+ (u32)txq->drv[i].host_addr,
+ txq->drv[i].buf_length);
+ }
+ }
+#endif
+
+ switch (packet->type) {
+ case DATA:
+ if (txq->drv[txq->oldest].status.info.fields.txType != 0)
+ printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
+ "Expecting DATA TBD but pulled "
+ "something else: ids %d=%d.\n",
+ priv->net_dev->name, txq->oldest, packet->index);
+
+ /* DATA packet; we have to unmap and free the SKB */
+ priv->ieee->stats.tx_packets++;
+ for (i = 0; i < frag_num; i++) {
+ tbd = &txq->drv[(packet->index + 1 + i) %
+ txq->entries];
+
+ IPW_DEBUG_TX(
+ "TX%d P=%08x L=%d\n",
+ (packet->index + 1 + i) % txq->entries,
+ tbd->host_addr, tbd->buf_length);
+
+ pci_unmap_single(priv->pci_dev,
+ tbd->host_addr,
+ tbd->buf_length,
+ PCI_DMA_TODEVICE);
+ }
+
+ priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size;
+ ieee80211_txb_free(packet->info.d_struct.txb);
+ packet->info.d_struct.txb = NULL;
+
+ list_add_tail(element, &priv->tx_free_list);
+ INC_STAT(&priv->tx_free_stat);
+
+ /* We have a free slot in the Tx queue, so wake up the
+ * transmit layer if it is stopped. */
+ if (priv->status & STATUS_ASSOCIATED &&
+ netif_queue_stopped(priv->net_dev)) {
+ IPW_DEBUG_INFO(KERN_INFO
+ "%s: Waking net queue.\n",
+ priv->net_dev->name);
+ netif_wake_queue(priv->net_dev);
+ }
+
+ /* A packet was processed by the hardware, so update the
+ * watchdog */
+ priv->net_dev->trans_start = jiffies;
+
+ break;
+
+ case COMMAND:
+ if (txq->drv[txq->oldest].status.info.fields.txType != 1)
+ printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
+ "Expecting COMMAND TBD but pulled "
+ "something else: ids %d=%d.\n",
+ priv->net_dev->name, txq->oldest, packet->index);
+
+#ifdef CONFIG_IPW_DEBUG
+ if (packet->info.c_struct.cmd->host_command_reg <
+ sizeof(command_types) / sizeof(*command_types))
+ IPW_DEBUG_TX(
+ "Command '%s (%d)' processed: %d.\n",
+ command_types[packet->info.c_struct.cmd->host_command_reg],
+ packet->info.c_struct.cmd->host_command_reg,
+ packet->info.c_struct.cmd->cmd_status_reg);
+#endif
+
+ list_add_tail(element, &priv->msg_free_list);
+ INC_STAT(&priv->msg_free_stat);
+ break;
+ }
+
+ /* advance oldest used TBD pointer to start of next entry */
+ txq->oldest = (e + 1) % txq->entries;
+ /* increase available TBDs number */
+ txq->available += descriptors_used;
+ SET_STAT(&priv->txq_stat, txq->available);
+
+ IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
+ jiffies - packet->jiffy_start);
+
+ return (!list_empty(&priv->fw_pend_list));
+}
+
+
+static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
+{
+ int i = 0;
+
+ while (__ipw2100_tx_process(priv) && i < 200) i++;
+
+ if (i == 200) {
+ printk(KERN_WARNING DRV_NAME ": "
+ "%s: Driver is running slow (%d iters).\n",
+ priv->net_dev->name, i);
+ }
+}
+
+
+static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
+{
+ struct list_head *element;
+ struct ipw2100_tx_packet *packet;
+ struct ipw2100_bd_queue *txq = &priv->tx_queue;
+ struct ipw2100_bd *tbd;
+ int next = txq->next;
+
+ while (!list_empty(&priv->msg_pend_list)) {
+ /* if there isn't enough space in TBD queue, then
+ * don't stuff a new one in.
+ * NOTE: 3 are needed as a command will take one,
+ * and there is a minimum of 2 that must be
+ * maintained between the r and w indexes
+ */
+ if (txq->available <= 3) {
+ IPW_DEBUG_TX("no room in tx_queue\n");
+ break;
+ }
+
+ element = priv->msg_pend_list.next;
+ list_del(element);
+ DEC_STAT(&priv->msg_pend_stat);
+
+ packet = list_entry(element,
+ struct ipw2100_tx_packet, list);
+
+ IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
+ &txq->drv[txq->next],
+ (void*)(txq->nic + txq->next *
+ sizeof(struct ipw2100_bd)));
+
+ packet->index = txq->next;
+
+ tbd = &txq->drv[txq->next];
+
+ /* initialize TBD */
+ tbd->host_addr = packet->info.c_struct.cmd_phys;
+ tbd->buf_length = sizeof(struct ipw2100_cmd_header);
+ /* not marking number of fragments causes problems
+ * with f/w debug version */
+ tbd->num_fragments = 1;
+ tbd->status.info.field =
+ IPW_BD_STATUS_TX_FRAME_COMMAND |
+ IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+
+ /* update TBD queue counters */
+ txq->next++;
+ txq->next %= txq->entries;
+ txq->available--;
+ DEC_STAT(&priv->txq_stat);
+
+ list_add_tail(element, &priv->fw_pend_list);
+ INC_STAT(&priv->fw_pend_stat);
+ }
+
+ if (txq->next != next) {
+ /* kick off the DMA by notifying firmware the
+ * write index has moved; make sure TBD stores are sync'd */
+ wmb();
+ write_register(priv->net_dev,
+ IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
+ txq->next);
+ }
+}
+
+
+/*
+ * ipw2100_tx_send_data
+ *
+ */
+static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
+{
+ struct list_head *element;
+ struct ipw2100_tx_packet *packet;
+ struct ipw2100_bd_queue *txq = &priv->tx_queue;
+ struct ipw2100_bd *tbd;
+ int next = txq->next;
+ int i = 0;
+ struct ipw2100_data_header *ipw_hdr;
+ struct ieee80211_hdr *hdr;
+
+ while (!list_empty(&priv->tx_pend_list)) {
+ /* if there isn't enough space in TBD queue, then
+ * don't stuff a new one in.
+ * NOTE: 4 are needed as a data will take two,
+ * and there is a minimum of 2 that must be
+ * maintained between the r and w indexes
+ */
+ element = priv->tx_pend_list.next;
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
+
+ if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
+ IPW_MAX_BDS)) {
+ /* TODO: Support merging buffers if more than
+ * IPW_MAX_BDS are used */
+ IPW_DEBUG_INFO(
+ "%s: Maximum BD theshold exceeded. "
+ "Increase fragmentation level.\n",
+ priv->net_dev->name);
+ }
+
+ if (txq->available <= 3 +
+ packet->info.d_struct.txb->nr_frags) {
+ IPW_DEBUG_TX("no room in tx_queue\n");
+ break;
+ }
+
+ list_del(element);
+ DEC_STAT(&priv->tx_pend_stat);
+
+ tbd = &txq->drv[txq->next];
+
+ packet->index = txq->next;
+
+ ipw_hdr = packet->info.d_struct.data;
+ hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb->
+ fragments[0]->data;
+
+ if (priv->ieee->iw_mode == IW_MODE_INFRA) {
+ /* To DS: Addr1 = BSSID, Addr2 = SA,
+ Addr3 = DA */
+ memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
+ memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
+ } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ /* not From/To DS: Addr1 = DA, Addr2 = SA,
+ Addr3 = BSSID */
+ memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
+ memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
+ }
+
+ ipw_hdr->host_command_reg = SEND;
+ ipw_hdr->host_command_reg1 = 0;
+
+ /* For now we only support host based encryption */
+ ipw_hdr->needs_encryption = 0;
+ ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
+ if (packet->info.d_struct.txb->nr_frags > 1)
+ ipw_hdr->fragment_size =
+ packet->info.d_struct.txb->frag_size - IEEE80211_3ADDR_LEN;
+ else
+ ipw_hdr->fragment_size = 0;
+
+ tbd->host_addr = packet->info.d_struct.data_phys;
+ tbd->buf_length = sizeof(struct ipw2100_data_header);
+ tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
+ tbd->status.info.field =
+ IPW_BD_STATUS_TX_FRAME_802_3 |
+ IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+ txq->next++;
+ txq->next %= txq->entries;
+
+ IPW_DEBUG_TX(
+ "data header tbd TX%d P=%08x L=%d\n",
+ packet->index, tbd->host_addr,
+ tbd->buf_length);
+#ifdef CONFIG_IPW_DEBUG
+ if (packet->info.d_struct.txb->nr_frags > 1)
+ IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
+ packet->info.d_struct.txb->nr_frags);
+#endif
+
+ for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
+ tbd = &txq->drv[txq->next];
+ if (i == packet->info.d_struct.txb->nr_frags - 1)
+ tbd->status.info.field =
+ IPW_BD_STATUS_TX_FRAME_802_3 |
+ IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+ else
+ tbd->status.info.field =
+ IPW_BD_STATUS_TX_FRAME_802_3 |
+ IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+
+ tbd->buf_length = packet->info.d_struct.txb->
+ fragments[i]->len - IEEE80211_3ADDR_LEN;
+
+ tbd->host_addr = pci_map_single(
+ priv->pci_dev,
+ packet->info.d_struct.txb->fragments[i]->data +
+ IEEE80211_3ADDR_LEN,
+ tbd->buf_length,
+ PCI_DMA_TODEVICE);
+
+ IPW_DEBUG_TX(
+ "data frag tbd TX%d P=%08x L=%d\n",
+ txq->next, tbd->host_addr, tbd->buf_length);
+
+ pci_dma_sync_single_for_device(
+ priv->pci_dev, tbd->host_addr,
+ tbd->buf_length,
+ PCI_DMA_TODEVICE);
+
+ txq->next++;
+ txq->next %= txq->entries;
+ }
+
+ txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
+ SET_STAT(&priv->txq_stat, txq->available);
+
+ list_add_tail(element, &priv->fw_pend_list);
+ INC_STAT(&priv->fw_pend_stat);
+ }
+
+ if (txq->next != next) {
+ /* kick off the DMA by notifying firmware the
+ * write index has moved; make sure TBD stores are sync'd */
+ write_register(priv->net_dev,
+ IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
+ txq->next);
+ }
+ return;
+}
+
+static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
+{
+ struct net_device *dev = priv->net_dev;
+ unsigned long flags;
+ u32 inta, tmp;
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+ ipw2100_disable_interrupts(priv);
+
+ read_register(dev, IPW_REG_INTA, &inta);
+
+ IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
+ (unsigned long)inta & IPW_INTERRUPT_MASK);
+
+ priv->in_isr++;
+ priv->interrupts++;
+
+ /* We do not loop and keep polling for more interrupts as this
+ * is frowned upon and doesn't play nicely with other potentially
+ * chained IRQs */
+ IPW_DEBUG_ISR("INTA: 0x%08lX\n",
+ (unsigned long)inta & IPW_INTERRUPT_MASK);
+
+ if (inta & IPW2100_INTA_FATAL_ERROR) {
+ printk(KERN_WARNING DRV_NAME
+ ": Fatal interrupt. Scheduling firmware restart.\n");
+ priv->inta_other++;
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_FATAL_ERROR);
+
+ read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
+ IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
+ priv->net_dev->name, priv->fatal_error);
+
+ read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
+ IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
+ priv->net_dev->name, tmp);
+
+ /* Wake up any sleeping jobs */
+ schedule_reset(priv);
+ }
+
+ if (inta & IPW2100_INTA_PARITY_ERROR) {
+ printk(KERN_ERR DRV_NAME ": ***** PARITY ERROR INTERRUPT !!!! \n");
+ priv->inta_other++;
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_PARITY_ERROR);
+ }
+
+ if (inta & IPW2100_INTA_RX_TRANSFER) {
+ IPW_DEBUG_ISR("RX interrupt\n");
+
+ priv->rx_interrupts++;
+
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_RX_TRANSFER);
+
+ __ipw2100_rx_process(priv);
+ __ipw2100_tx_complete(priv);
+ }
+
+ if (inta & IPW2100_INTA_TX_TRANSFER) {
+ IPW_DEBUG_ISR("TX interrupt\n");
+
+ priv->tx_interrupts++;
+
+ write_register(dev, IPW_REG_INTA,
+ IPW2100_INTA_TX_TRANSFER);
+
+ __ipw2100_tx_complete(priv);
+ ipw2100_tx_send_commands(priv);
+ ipw2100_tx_send_data(priv);
+ }
+
+ if (inta & IPW2100_INTA_TX_COMPLETE) {
+ IPW_DEBUG_ISR("TX complete\n");
+ priv->inta_other++;
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_TX_COMPLETE);
+
+ __ipw2100_tx_complete(priv);
+ }
+
+ if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
+ /* ipw2100_handle_event(dev); */
+ priv->inta_other++;
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_EVENT_INTERRUPT);
+ }
+
+ if (inta & IPW2100_INTA_FW_INIT_DONE) {
+ IPW_DEBUG_ISR("FW init done interrupt\n");
+ priv->inta_other++;
+
+ read_register(dev, IPW_REG_INTA, &tmp);
+ if (tmp & (IPW2100_INTA_FATAL_ERROR |
+ IPW2100_INTA_PARITY_ERROR)) {
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_FATAL_ERROR |
+ IPW2100_INTA_PARITY_ERROR);
+ }
+
+ write_register(dev, IPW_REG_INTA,
+ IPW2100_INTA_FW_INIT_DONE);
+ }
+
+ if (inta & IPW2100_INTA_STATUS_CHANGE) {
+ IPW_DEBUG_ISR("Status change interrupt\n");
+ priv->inta_other++;
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_STATUS_CHANGE);
+ }
+
+ if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
+ IPW_DEBUG_ISR("slave host mode interrupt\n");
+ priv->inta_other++;
+ write_register(
+ dev, IPW_REG_INTA,
+ IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
+ }
+
+ priv->in_isr--;
+ ipw2100_enable_interrupts(priv);
+
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ IPW_DEBUG_ISR("exit\n");
+}
+
+
+static irqreturn_t ipw2100_interrupt(int irq, void *data,
+ struct pt_regs *regs)
+{
+ struct ipw2100_priv *priv = data;
+ u32 inta, inta_mask;
+
+ if (!data)
+ return IRQ_NONE;
+
+ spin_lock(&priv->low_lock);
+
+ /* We check to see if we should be ignoring interrupts before
+ * we touch the hardware. During ucode load if we try and handle
+ * an interrupt we can cause keyboard problems as well as cause
+ * the ucode to fail to initialize */
+ if (!(priv->status & STATUS_INT_ENABLED)) {
+ /* Shared IRQ */
+ goto none;
+ }
+
+ read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
+ read_register(priv->net_dev, IPW_REG_INTA, &inta);
+
+ if (inta == 0xFFFFFFFF) {
+ /* Hardware disappeared */
+ printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
+ goto none;
+ }
+
+ inta &= IPW_INTERRUPT_MASK;
+
+ if (!(inta & inta_mask)) {
+ /* Shared interrupt */
+ goto none;
+ }
+
+ /* We disable the hardware interrupt here just to prevent unneeded
+ * calls to be made. We disable this again within the actual
+ * work tasklet, so if another part of the code re-enables the
+ * interrupt, that is fine */
+ ipw2100_disable_interrupts(priv);
+
+ tasklet_schedule(&priv->irq_tasklet);
+ spin_unlock(&priv->low_lock);
+
+ return IRQ_HANDLED;
+ none:
+ spin_unlock(&priv->low_lock);
+ return IRQ_NONE;
+}
+
+static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct list_head *element;
+ struct ipw2100_tx_packet *packet;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ IPW_DEBUG_INFO("Can not transmit when not connected.\n");
+ priv->ieee->stats.tx_carrier_errors++;
+ netif_stop_queue(dev);
+ goto fail_unlock;
+ }
+
+ if (list_empty(&priv->tx_free_list))
+ goto fail_unlock;
+
+ element = priv->tx_free_list.next;
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
+
+ packet->info.d_struct.txb = txb;
+
+ IPW_DEBUG_TX("Sending fragment (%d bytes):\n",
+ txb->fragments[0]->len);
+ printk_buf(IPW_DL_TX, txb->fragments[0]->data,
+ txb->fragments[0]->len);
+
+ packet->jiffy_start = jiffies;
+
+ list_del(element);
+ DEC_STAT(&priv->tx_free_stat);
+
+ list_add_tail(element, &priv->tx_pend_list);
+ INC_STAT(&priv->tx_pend_stat);
+
+ ipw2100_tx_send_data(priv);
+
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+ return 0;
+
+ fail_unlock:
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+ return 1;
+}
+
+
+static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
+{
+ int i, j, err = -EINVAL;
+ void *v;
+ dma_addr_t p;
+
+ priv->msg_buffers = (struct ipw2100_tx_packet *)kmalloc(
+ IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
+ GFP_KERNEL);
+ if (!priv->msg_buffers) {
+ printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
+ "buffers.\n", priv->net_dev->name);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
+ v = pci_alloc_consistent(
+ priv->pci_dev,
+ sizeof(struct ipw2100_cmd_header),
+ &p);
+ if (!v) {
+ printk(KERN_ERR DRV_NAME ": "
+ "%s: PCI alloc failed for msg "
+ "buffers.\n",
+ priv->net_dev->name);
+ err = -ENOMEM;
+ break;
+ }
+
+ memset(v, 0, sizeof(struct ipw2100_cmd_header));
+
+ priv->msg_buffers[i].type = COMMAND;
+ priv->msg_buffers[i].info.c_struct.cmd =
+ (struct ipw2100_cmd_header*)v;
+ priv->msg_buffers[i].info.c_struct.cmd_phys = p;
+ }
+
+ if (i == IPW_COMMAND_POOL_SIZE)
+ return 0;
+
+ for (j = 0; j < i; j++) {
+ pci_free_consistent(
+ priv->pci_dev,
+ sizeof(struct ipw2100_cmd_header),
+ priv->msg_buffers[j].info.c_struct.cmd,
+ priv->msg_buffers[j].info.c_struct.cmd_phys);
+ }
+
+ kfree(priv->msg_buffers);
+ priv->msg_buffers = NULL;
+
+ return err;
+}
+
+static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
+{
+ int i;
+
+ INIT_LIST_HEAD(&priv->msg_free_list);
+ INIT_LIST_HEAD(&priv->msg_pend_list);
+
+ for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
+ list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
+ SET_STAT(&priv->msg_free_stat, i);
+
+ return 0;
+}
+
+static void ipw2100_msg_free(struct ipw2100_priv *priv)
+{
+ int i;
+
+ if (!priv->msg_buffers)
+ return;
+
+ for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct ipw2100_cmd_header),
+ priv->msg_buffers[i].info.c_struct.cmd,
+ priv->msg_buffers[i].info.c_struct.cmd_phys);
+ }
+
+ kfree(priv->msg_buffers);
+ priv->msg_buffers = NULL;
+}
+
+static ssize_t show_pci(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
+ char *out = buf;
+ int i, j;
+ u32 val;
+
+ for (i = 0; i < 16; i++) {
+ out += sprintf(out, "[%08X] ", i * 16);
+ for (j = 0; j < 16; j += 4) {
+ pci_read_config_dword(pci_dev, i * 16 + j, &val);
+ out += sprintf(out, "%08X ", val);
+ }
+ out += sprintf(out, "\n");
+ }
+
+ return out - buf;
+}
+static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
+
+static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->config);
+}
+static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+
+static ssize_t show_status(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->status);
+}
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t show_capability(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->capability);
+}
+static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
+
+
+#define IPW2100_REG(x) { IPW_ ##x, #x }
+static const struct {
+ u32 addr;
+ const char *name;
+} hw_data[] = {
+ IPW2100_REG(REG_GP_CNTRL),
+ IPW2100_REG(REG_GPIO),
+ IPW2100_REG(REG_INTA),
+ IPW2100_REG(REG_INTA_MASK),
+ IPW2100_REG(REG_RESET_REG),
+};
+#define IPW2100_NIC(x, s) { x, #x, s }
+static const struct {
+ u32 addr;
+ const char *name;
+ size_t size;
+} nic_data[] = {
+ IPW2100_NIC(IPW2100_CONTROL_REG, 2),
+ IPW2100_NIC(0x210014, 1),
+ IPW2100_NIC(0x210000, 1),
+};
+#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
+static const struct {
+ u8 index;
+ const char *name;
+ const char *desc;
+} ord_data[] = {
+ IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
+ IPW2100_ORD(STAT_TX_HOST_COMPLETE, "successful Host Tx's (MSDU)"),
+ IPW2100_ORD(STAT_TX_DIR_DATA, "successful Directed Tx's (MSDU)"),
+ IPW2100_ORD(STAT_TX_DIR_DATA1, "successful Directed Tx's (MSDU) @ 1MB"),
+ IPW2100_ORD(STAT_TX_DIR_DATA2, "successful Directed Tx's (MSDU) @ 2MB"),
+ IPW2100_ORD(STAT_TX_DIR_DATA5_5, "successful Directed Tx's (MSDU) @ 5_5MB"),
+ IPW2100_ORD(STAT_TX_DIR_DATA11, "successful Directed Tx's (MSDU) @ 11MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA1, "successful Non_Directed Tx's (MSDU) @ 1MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA2, "successful Non_Directed Tx's (MSDU) @ 2MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA5_5, "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA11, "successful Non_Directed Tx's (MSDU) @ 11MB"),
+ IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
+ IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
+ IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
+ IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
+ IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
+ IPW2100_ORD(STAT_TX_ASSN_RESP, "successful Association response Tx's"),
+ IPW2100_ORD(STAT_TX_REASSN, "successful Reassociation Tx's"),
+ IPW2100_ORD(STAT_TX_REASSN_RESP, "successful Reassociation response Tx's"),
+ IPW2100_ORD(STAT_TX_PROBE, "probes successfully transmitted"),
+ IPW2100_ORD(STAT_TX_PROBE_RESP, "probe responses successfully transmitted"),
+ IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
+ IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
+ IPW2100_ORD(STAT_TX_DISASSN, "successful Disassociation TX"),
+ IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
+ IPW2100_ORD(STAT_TX_DEAUTH, "successful Deauthentication TX"),
+ IPW2100_ORD(STAT_TX_TOTAL_BYTES, "Total successful Tx data bytes"),
+ IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
+ IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
+ IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
+ IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
+ IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
+ IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
+ IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,"times max tries in a hop failed"),
+ IPW2100_ORD(STAT_TX_DISASSN_FAIL, "times disassociation failed"),
+ IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
+ IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
+ IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
+ IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
+ IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
+ IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
+ IPW2100_ORD(STAT_RX_DIR_DATA5_5, "directed packets at 5.5MB"),
+ IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA,"nondirected packets"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA1, "nondirected packets at 1MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA2, "nondirected packets at 2MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA5_5, "nondirected packets at 5.5MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA11, "nondirected packets at 11MB"),
+ IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
+ IPW2100_ORD(STAT_RX_RTS, "Rx RTS"),
+ IPW2100_ORD(STAT_RX_CTS, "Rx CTS"),
+ IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
+ IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
+ IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
+ IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
+ IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
+ IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
+ IPW2100_ORD(STAT_RX_REASSN_RESP, "Reassociation response Rx's"),
+ IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
+ IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
+ IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
+ IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
+ IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
+ IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
+ IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
+ IPW2100_ORD(STAT_RX_TOTAL_BYTES,"Total rx data bytes received"),
+ IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
+ IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
+ IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
+ IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
+ IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE1, "duplicate rx packets at 1MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE2, "duplicate rx packets at 2MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE5_5, "duplicate rx packets at 5.5MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE11, "duplicate rx packets at 11MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
+ IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
+ IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
+ IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
+ IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, "rx frames with invalid protocol"),
+ IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
+ IPW2100_ORD(STAT_RX_NO_BUFFER, "rx frames rejected due to no buffer"),
+ IPW2100_ORD(STAT_RX_MISSING_FRAG, "rx frames dropped due to missing fragment"),
+ IPW2100_ORD(STAT_RX_ORPHAN_FRAG, "rx frames dropped due to non-sequential fragment"),
+ IPW2100_ORD(STAT_RX_ORPHAN_FRAME, "rx frames dropped due to unmatched 1st frame"),
+ IPW2100_ORD(STAT_RX_FRAG_AGEOUT, "rx frames dropped due to uncompleted frame"),
+ IPW2100_ORD(STAT_RX_ICV_ERRORS, "ICV errors during decryption"),
+ IPW2100_ORD(STAT_PSP_SUSPENSION,"times adapter suspended"),
+ IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
+ IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, "poll response timeouts"),
+ IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, "timeouts waiting for last {broad,multi}cast pkt"),
+ IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
+ IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
+ IPW2100_ORD(STAT_PSP_STATION_ID,"PSP Station ID"),
+ IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
+ IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,"current calculation of % missed beacons"),
+ IPW2100_ORD(STAT_PERCENT_RETRIES,"current calculation of % missed tx retries"),
+ IPW2100_ORD(ASSOCIATED_AP_PTR, "0 if not associated, else pointer to AP table entry"),
+ IPW2100_ORD(AVAILABLE_AP_CNT, "AP's decsribed in the AP table"),
+ IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
+ IPW2100_ORD(STAT_AP_ASSNS, "associations"),
+ IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
+ IPW2100_ORD(STAT_ASSN_RESP_FAIL,"failures due to response fail"),
+ IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
+ IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
+ IPW2100_ORD(STAT_ROAM_INHIBIT, "times roaming was inhibited due to activity"),
+ IPW2100_ORD(RSSI_AT_ASSN, "RSSI of associated AP at time of association"),
+ IPW2100_ORD(STAT_ASSN_CAUSE1, "reassociation: no probe response or TX on hop"),
+ IPW2100_ORD(STAT_ASSN_CAUSE2, "reassociation: poor tx/rx quality"),
+ IPW2100_ORD(STAT_ASSN_CAUSE3, "reassociation: tx/rx quality (excessive AP load"),
+ IPW2100_ORD(STAT_ASSN_CAUSE4, "reassociation: AP RSSI level"),
+ IPW2100_ORD(STAT_ASSN_CAUSE5, "reassociations due to load leveling"),
+ IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
+ IPW2100_ORD(STAT_AUTH_RESP_FAIL,"times authentication response failed"),
+ IPW2100_ORD(STATION_TABLE_CNT, "entries in association table"),
+ IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
+ IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
+ IPW2100_ORD(COUNTRY_CODE, "IEEE country code as recv'd from beacon"),
+ IPW2100_ORD(COUNTRY_CHANNELS, "channels suported by country"),
+ IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
+ IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
+ IPW2100_ORD(ANTENNA_DIVERSITY, "TRUE if antenna diversity is disabled"),
+ IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
+ IPW2100_ORD(OUR_FREQ, "current radio freq lower digits - channel ID"),
+ IPW2100_ORD(RTC_TIME, "current RTC time"),
+ IPW2100_ORD(PORT_TYPE, "operating mode"),
+ IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
+ IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
+ IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
+ IPW2100_ORD(BASIC_RATES, "basic tx rates"),
+ IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
+ IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
+ IPW2100_ORD(CAPABILITIES, "Management frame capability field"),
+ IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
+ IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
+ IPW2100_ORD(RTS_THRESHOLD, "Min packet length for RTS handshaking"),
+ IPW2100_ORD(INT_MODE, "International mode"),
+ IPW2100_ORD(FRAGMENTATION_THRESHOLD, "protocol frag threshold"),
+ IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, "EEPROM offset in SRAM"),
+ IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, "EEPROM size in SRAM"),
+ IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
+ IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, "EEPROM IBSS 11b channel set"),
+ IPW2100_ORD(MAC_VERSION, "MAC Version"),
+ IPW2100_ORD(MAC_REVISION, "MAC Revision"),
+ IPW2100_ORD(RADIO_VERSION, "Radio Version"),
+ IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
+ IPW2100_ORD(UCODE_VERSION, "Ucode Version"),
+};
+
+
+static ssize_t show_registers(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ struct net_device *dev = priv->net_dev;
+ char * out = buf;
+ u32 val = 0;
+
+ out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
+
+ for (i = 0; i < (sizeof(hw_data) / sizeof(*hw_data)); i++) {
+ read_register(dev, hw_data[i].addr, &val);
+ out += sprintf(out, "%30s [%08X] : %08X\n",
+ hw_data[i].name, hw_data[i].addr, val);
+ }
+
+ return out - buf;
+}
+static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
+
+
+static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ struct net_device *dev = priv->net_dev;
+ char * out = buf;
+ int i;
+
+ out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
+
+ for (i = 0; i < (sizeof(nic_data) / sizeof(*nic_data)); i++) {
+ u8 tmp8;
+ u16 tmp16;
+ u32 tmp32;
+
+ switch (nic_data[i].size) {
+ case 1:
+ read_nic_byte(dev, nic_data[i].addr, &tmp8);
+ out += sprintf(out, "%30s [%08X] : %02X\n",
+ nic_data[i].name, nic_data[i].addr,
+ tmp8);
+ break;
+ case 2:
+ read_nic_word(dev, nic_data[i].addr, &tmp16);
+ out += sprintf(out, "%30s [%08X] : %04X\n",
+ nic_data[i].name, nic_data[i].addr,
+ tmp16);
+ break;
+ case 4:
+ read_nic_dword(dev, nic_data[i].addr, &tmp32);
+ out += sprintf(out, "%30s [%08X] : %08X\n",
+ nic_data[i].name, nic_data[i].addr,
+ tmp32);
+ break;
+ }
+ }
+ return out - buf;
+}
+static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+
+
+static ssize_t show_memory(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ struct net_device *dev = priv->net_dev;
+ static unsigned long loop = 0;
+ int len = 0;
+ u32 buffer[4];
+ int i;
+ char line[81];
+
+ if (loop >= 0x30000)
+ loop = 0;
+
+ /* sysfs provides us PAGE_SIZE buffer */
+ while (len < PAGE_SIZE - 128 && loop < 0x30000) {
+
+ if (priv->snapshot[0]) for (i = 0; i < 4; i++)
+ buffer[i] = *(u32 *)SNAPSHOT_ADDR(loop + i * 4);
+ else for (i = 0; i < 4; i++)
+ read_nic_dword(dev, loop + i * 4, &buffer[i]);
+
+ if (priv->dump_raw)
+ len += sprintf(buf + len,
+ "%c%c%c%c"
+ "%c%c%c%c"
+ "%c%c%c%c"
+ "%c%c%c%c",
+ ((u8*)buffer)[0x0],
+ ((u8*)buffer)[0x1],
+ ((u8*)buffer)[0x2],
+ ((u8*)buffer)[0x3],
+ ((u8*)buffer)[0x4],
+ ((u8*)buffer)[0x5],
+ ((u8*)buffer)[0x6],
+ ((u8*)buffer)[0x7],
+ ((u8*)buffer)[0x8],
+ ((u8*)buffer)[0x9],
+ ((u8*)buffer)[0xa],
+ ((u8*)buffer)[0xb],
+ ((u8*)buffer)[0xc],
+ ((u8*)buffer)[0xd],
+ ((u8*)buffer)[0xe],
+ ((u8*)buffer)[0xf]);
+ else
+ len += sprintf(buf + len, "%s\n",
+ snprint_line(line, sizeof(line),
+ (u8*)buffer, 16, loop));
+ loop += 16;
+ }
+
+ return len;
+}
+
+static ssize_t store_memory(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ struct net_device *dev = priv->net_dev;
+ const char *p = buf;
+
+ if (count < 1)
+ return count;
+
+ if (p[0] == '1' ||
+ (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
+ IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
+ dev->name);
+ priv->dump_raw = 1;
+
+ } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
+ tolower(p[1]) == 'f')) {
+ IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
+ dev->name);
+ priv->dump_raw = 0;
+
+ } else if (tolower(p[0]) == 'r') {
+ IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n",
+ dev->name);
+ ipw2100_snapshot_free(priv);
+
+ } else
+ IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
+ "reset = clear memory snapshot\n",
+ dev->name);
+
+ return count;
+}
+static DEVICE_ATTR(memory, S_IWUSR|S_IRUGO, show_memory, store_memory);
+
+
+static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ u32 val = 0;
+ int len = 0;
+ u32 val_len;
+ static int loop = 0;
+
+ if (loop >= sizeof(ord_data) / sizeof(*ord_data))
+ loop = 0;
+
+ /* sysfs provides us PAGE_SIZE buffer */
+ while (len < PAGE_SIZE - 128 &&
+ loop < (sizeof(ord_data) / sizeof(*ord_data))) {
+
+ val_len = sizeof(u32);
+
+ if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
+ &val_len))
+ len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
+ ord_data[loop].index,
+ ord_data[loop].desc);
+ else
+ len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
+ ord_data[loop].index, val,
+ ord_data[loop].desc);
+ loop++;
+ }
+
+ return len;
+}
+static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
+
+
+static ssize_t show_stats(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ char * out = buf;
+
+ out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
+ priv->interrupts, priv->tx_interrupts,
+ priv->rx_interrupts, priv->inta_other);
+ out += sprintf(out, "firmware resets: %d\n", priv->resets);
+ out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
+#ifdef CONFIG_IPW_DEBUG
+ out += sprintf(out, "packet mismatch image: %s\n",
+ priv->snapshot[0] ? "YES" : "NO");
+#endif
+
+ return out - buf;
+}
+static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
+
+
+static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
+{
+ int err;
+
+ if (mode == priv->ieee->iw_mode)
+ return 0;
+
+ err = ipw2100_disable_adapter(priv);
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ priv->net_dev->name, err);
+ return err;
+ }
+
+ switch (mode) {
+ case IW_MODE_INFRA:
+ priv->net_dev->type = ARPHRD_ETHER;
+ break;
+ case IW_MODE_ADHOC:
+ priv->net_dev->type = ARPHRD_ETHER;
+ break;
+#ifdef CONFIG_IPW2100_MONITOR
+ case IW_MODE_MONITOR:
+ priv->last_mode = priv->ieee->iw_mode;
+ priv->net_dev->type = ARPHRD_IEEE80211;
+ break;
+#endif /* CONFIG_IPW2100_MONITOR */
+ }
+
+ priv->ieee->iw_mode = mode;
+
+#ifdef CONFIG_PM
+ /* Indicate ipw2100_download_firmware download firmware
+ * from disk instead of memory. */
+ ipw2100_firmware.version = 0;
+#endif
+
+ printk(KERN_INFO "%s: Reseting on mode change.\n",
+ priv->net_dev->name);
+ priv->reset_backoff = 0;
+ schedule_reset(priv);
+
+ return 0;
+}
+
+static ssize_t show_internals(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ int len = 0;
+
+#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" # y "\n", priv-> x)
+
+ if (priv->status & STATUS_ASSOCIATED)
+ len += sprintf(buf + len, "connected: %lu\n",
+ get_seconds() - priv->connect_start);
+ else
+ len += sprintf(buf + len, "not connected\n");
+
+ DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], p);
+ DUMP_VAR(status, 08lx);
+ DUMP_VAR(config, 08lx);
+ DUMP_VAR(capability, 08lx);
+
+ len += sprintf(buf + len, "last_rtc: %lu\n", (unsigned long)priv->last_rtc);
+
+ DUMP_VAR(fatal_error, d);
+ DUMP_VAR(stop_hang_check, d);
+ DUMP_VAR(stop_rf_kill, d);
+ DUMP_VAR(messages_sent, d);
+
+ DUMP_VAR(tx_pend_stat.value, d);
+ DUMP_VAR(tx_pend_stat.hi, d);
+
+ DUMP_VAR(tx_free_stat.value, d);
+ DUMP_VAR(tx_free_stat.lo, d);
+
+ DUMP_VAR(msg_free_stat.value, d);
+ DUMP_VAR(msg_free_stat.lo, d);
+
+ DUMP_VAR(msg_pend_stat.value, d);
+ DUMP_VAR(msg_pend_stat.hi, d);
+
+ DUMP_VAR(fw_pend_stat.value, d);
+ DUMP_VAR(fw_pend_stat.hi, d);
+
+ DUMP_VAR(txq_stat.value, d);
+ DUMP_VAR(txq_stat.lo, d);
+
+ DUMP_VAR(ieee->scans, d);
+ DUMP_VAR(reset_backoff, d);
+
+ return len;
+}
+static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
+
+
+static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ char essid[IW_ESSID_MAX_SIZE + 1];
+ u8 bssid[ETH_ALEN];
+ u32 chan = 0;
+ char * out = buf;
+ int length;
+ int ret;
+
+ memset(essid, 0, sizeof(essid));
+ memset(bssid, 0, sizeof(bssid));
+
+ length = IW_ESSID_MAX_SIZE;
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
+ if (ret)
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+
+ length = sizeof(bssid);
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
+ bssid, &length);
+ if (ret)
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+
+ length = sizeof(u32);
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
+ if (ret)
+ IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
+ __LINE__);
+
+ out += sprintf(out, "ESSID: %s\n", essid);
+ out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bssid[0], bssid[1], bssid[2],
+ bssid[3], bssid[4], bssid[5]);
+ out += sprintf(out, "Channel: %d\n", chan);
+
+ return out - buf;
+}
+static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
+
+
+#ifdef CONFIG_IPW_DEBUG
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+ return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
+}
+
+static ssize_t store_debug_level(struct device_driver *d, const char *buf,
+ size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ p++;
+ if (p[0] == 'x' || p[0] == 'X')
+ p++;
+ val = simple_strtoul(p, &p, 16);
+ } else
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ IPW_DEBUG_INFO(DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ ipw2100_debug_level = val;
+
+ return strnlen(buf, count);
+}
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
+ store_debug_level);
+#endif /* CONFIG_IPW_DEBUG */
+
+
+static ssize_t show_fatal_error(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ char *out = buf;
+ int i;
+
+ if (priv->fatal_error)
+ out += sprintf(out, "0x%08X\n",
+ priv->fatal_error);
+ else
+ out += sprintf(out, "0\n");
+
+ for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
+ if (!priv->fatal_errors[(priv->fatal_index - i) %
+ IPW2100_ERROR_QUEUE])
+ continue;
+
+ out += sprintf(out, "%d. 0x%08X\n", i,
+ priv->fatal_errors[(priv->fatal_index - i) %
+ IPW2100_ERROR_QUEUE]);
+ }
+
+ return out - buf;
+}
+
+static ssize_t store_fatal_error(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ schedule_reset(priv);
+ return count;
+}
+static DEVICE_ATTR(fatal_error, S_IWUSR|S_IRUGO, show_fatal_error, store_fatal_error);
+
+
+static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d\n", priv->ieee->scan_age);
+}
+
+static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ struct net_device *dev = priv->net_dev;
+ char buffer[] = "00000000";
+ unsigned long len =
+ (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
+ unsigned long val;
+ char *p = buffer;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ strncpy(buffer, buf, len);
+ buffer[len] = 0;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ p++;
+ if (p[0] == 'x' || p[0] == 'X')
+ p++;
+ val = simple_strtoul(p, &p, 16);
+ } else
+ val = simple_strtoul(p, &p, 10);
+ if (p == buffer) {
+ IPW_DEBUG_INFO("%s: user supplied invalid value.\n",
+ dev->name);
+ } else {
+ priv->ieee->scan_age = val;
+ IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+ return len;
+}
+static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
+
+
+static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ /* 0 - RF kill not enabled
+ 1 - SW based RF kill active (sysfs)
+ 2 - HW based RF kill active
+ 3 - Both HW and SW baed RF kill active */
+ struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data;
+ int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
+ (rf_kill_active(priv) ? 0x2 : 0x0);
+ return sprintf(buf, "%i\n", val);
+}
+
+static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
+{
+ if ((disable_radio ? 1 : 0) ==
+ (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
+ return 0 ;
+
+ IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
+ disable_radio ? "OFF" : "ON");
+
+ down(&priv->action_sem);
+
+ if (disable_radio) {
+ priv->status |= STATUS_RF_KILL_SW;
+ ipw2100_down(priv);
+ } else {
+ priv->status &= ~STATUS_RF_KILL_SW;
+ if (rf_kill_active(priv)) {
+ IPW_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by HW switch\n");
+ /* Make sure the RF_KILL check timer is running */
+ priv->stop_rf_kill = 0;
+ cancel_delayed_work(&priv->rf_kill);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ HZ);
+ } else
+ schedule_reset(priv);
+ }
+
+ up(&priv->action_sem);
+ return 1;
+}
+
+static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw2100_priv *priv = dev_get_drvdata(d);
+ ipw_radio_kill_sw(priv, buf[0] == '1');
+ return count;
+}
+static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill);
+
+
+static struct attribute *ipw2100_sysfs_entries[] = {
+ &dev_attr_hardware.attr,
+ &dev_attr_registers.attr,
+ &dev_attr_ordinals.attr,
+ &dev_attr_pci.attr,
+ &dev_attr_stats.attr,
+ &dev_attr_internals.attr,
+ &dev_attr_bssinfo.attr,
+ &dev_attr_memory.attr,
+ &dev_attr_scan_age.attr,
+ &dev_attr_fatal_error.attr,
+ &dev_attr_rf_kill.attr,
+ &dev_attr_cfg.attr,
+ &dev_attr_status.attr,
+ &dev_attr_capability.attr,
+ NULL,
+};
+
+static struct attribute_group ipw2100_attribute_group = {
+ .attrs = ipw2100_sysfs_entries,
+};
+
+
+static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
+{
+ struct ipw2100_status_queue *q = &priv->status_queue;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ q->size = entries * sizeof(struct ipw2100_status);
+ q->drv = (struct ipw2100_status *)pci_alloc_consistent(
+ priv->pci_dev, q->size, &q->nic);
+ if (!q->drv) {
+ IPW_DEBUG_WARNING(
+ "Can not allocate status queue.\n");
+ return -ENOMEM;
+ }
+
+ memset(q->drv, 0, q->size);
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+}
+
+static void status_queue_free(struct ipw2100_priv *priv)
+{
+ IPW_DEBUG_INFO("enter\n");
+
+ if (priv->status_queue.drv) {
+ pci_free_consistent(
+ priv->pci_dev, priv->status_queue.size,
+ priv->status_queue.drv, priv->status_queue.nic);
+ priv->status_queue.drv = NULL;
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+static int bd_queue_allocate(struct ipw2100_priv *priv,
+ struct ipw2100_bd_queue *q, int entries)
+{
+ IPW_DEBUG_INFO("enter\n");
+
+ memset(q, 0, sizeof(struct ipw2100_bd_queue));
+
+ q->entries = entries;
+ q->size = entries * sizeof(struct ipw2100_bd);
+ q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
+ if (!q->drv) {
+ IPW_DEBUG_INFO("can't allocate shared memory for buffer descriptors\n");
+ return -ENOMEM;
+ }
+ memset(q->drv, 0, q->size);
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+}
+
+static void bd_queue_free(struct ipw2100_priv *priv,
+ struct ipw2100_bd_queue *q)
+{
+ IPW_DEBUG_INFO("enter\n");
+
+ if (!q)
+ return;
+
+ if (q->drv) {
+ pci_free_consistent(priv->pci_dev,
+ q->size, q->drv, q->nic);
+ q->drv = NULL;
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+static void bd_queue_initialize(
+ struct ipw2100_priv *priv, struct ipw2100_bd_queue * q,
+ u32 base, u32 size, u32 r, u32 w)
+{
+ IPW_DEBUG_INFO("enter\n");
+
+ IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, (u32)q->nic);
+
+ write_register(priv->net_dev, base, q->nic);
+ write_register(priv->net_dev, size, q->entries);
+ write_register(priv->net_dev, r, q->oldest);
+ write_register(priv->net_dev, w, q->next);
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
+{
+ if (priv->workqueue) {
+ priv->stop_rf_kill = 1;
+ priv->stop_hang_check = 1;
+ cancel_delayed_work(&priv->reset_work);
+ cancel_delayed_work(&priv->security_work);
+ cancel_delayed_work(&priv->wx_event_work);
+ cancel_delayed_work(&priv->hang_check);
+ cancel_delayed_work(&priv->rf_kill);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ }
+}
+
+static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
+{
+ int i, j, err = -EINVAL;
+ void *v;
+ dma_addr_t p;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
+ if (err) {
+ IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
+ priv->net_dev->name);
+ return err;
+ }
+
+ priv->tx_buffers = (struct ipw2100_tx_packet *)kmalloc(
+ TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
+ GFP_ATOMIC);
+ if (!priv->tx_buffers) {
+ printk(KERN_ERR DRV_NAME ": %s: alloc failed form tx buffers.\n",
+ priv->net_dev->name);
+ bd_queue_free(priv, &priv->tx_queue);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
+ v = pci_alloc_consistent(
+ priv->pci_dev, sizeof(struct ipw2100_data_header), &p);
+ if (!v) {
+ printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx "
+ "buffers.\n", priv->net_dev->name);
+ err = -ENOMEM;
+ break;
+ }
+
+ priv->tx_buffers[i].type = DATA;
+ priv->tx_buffers[i].info.d_struct.data = (struct ipw2100_data_header*)v;
+ priv->tx_buffers[i].info.d_struct.data_phys = p;
+ priv->tx_buffers[i].info.d_struct.txb = NULL;
+ }
+
+ if (i == TX_PENDED_QUEUE_LENGTH)
+ return 0;
+
+ for (j = 0; j < i; j++) {
+ pci_free_consistent(
+ priv->pci_dev,
+ sizeof(struct ipw2100_data_header),
+ priv->tx_buffers[j].info.d_struct.data,
+ priv->tx_buffers[j].info.d_struct.data_phys);
+ }
+
+ kfree(priv->tx_buffers);
+ priv->tx_buffers = NULL;
+
+ return err;
+}
+
+static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
+{
+ int i;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ /*
+ * reinitialize packet info lists
+ */
+ INIT_LIST_HEAD(&priv->fw_pend_list);
+ INIT_STAT(&priv->fw_pend_stat);
+
+ /*
+ * reinitialize lists
+ */
+ INIT_LIST_HEAD(&priv->tx_pend_list);
+ INIT_LIST_HEAD(&priv->tx_free_list);
+ INIT_STAT(&priv->tx_pend_stat);
+ INIT_STAT(&priv->tx_free_stat);
+
+ for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
+ /* We simply drop any SKBs that have been queued for
+ * transmit */
+ if (priv->tx_buffers[i].info.d_struct.txb) {
+ ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+ priv->tx_buffers[i].info.d_struct.txb = NULL;
+ }
+
+ list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
+ }
+
+ SET_STAT(&priv->tx_free_stat, i);
+
+ priv->tx_queue.oldest = 0;
+ priv->tx_queue.available = priv->tx_queue.entries;
+ priv->tx_queue.next = 0;
+ INIT_STAT(&priv->txq_stat);
+ SET_STAT(&priv->txq_stat, priv->tx_queue.available);
+
+ bd_queue_initialize(priv, &priv->tx_queue,
+ IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
+ IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
+ IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
+ IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
+
+ IPW_DEBUG_INFO("exit\n");
+
+}
+
+static void ipw2100_tx_free(struct ipw2100_priv *priv)
+{
+ int i;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ bd_queue_free(priv, &priv->tx_queue);
+
+ if (!priv->tx_buffers)
+ return;
+
+ for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
+ if (priv->tx_buffers[i].info.d_struct.txb) {
+ ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+ priv->tx_buffers[i].info.d_struct.txb = NULL;
+ }
+ if (priv->tx_buffers[i].info.d_struct.data)
+ pci_free_consistent(
+ priv->pci_dev,
+ sizeof(struct ipw2100_data_header),
+ priv->tx_buffers[i].info.d_struct.data,
+ priv->tx_buffers[i].info.d_struct.data_phys);
+ }
+
+ kfree(priv->tx_buffers);
+ priv->tx_buffers = NULL;
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+
+
+static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
+{
+ int i, j, err = -EINVAL;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
+ if (err) {
+ IPW_DEBUG_INFO("failed bd_queue_allocate\n");
+ return err;
+ }
+
+ err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
+ if (err) {
+ IPW_DEBUG_INFO("failed status_queue_allocate\n");
+ bd_queue_free(priv, &priv->rx_queue);
+ return err;
+ }
+
+ /*
+ * allocate packets
+ */
+ priv->rx_buffers = (struct ipw2100_rx_packet *)
+ kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
+ GFP_KERNEL);
+ if (!priv->rx_buffers) {
+ IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
+
+ bd_queue_free(priv, &priv->rx_queue);
+
+ status_queue_free(priv);
+
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < RX_QUEUE_LENGTH; i++) {
+ struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
+
+ err = ipw2100_alloc_skb(priv, packet);
+ if (unlikely(err)) {
+ err = -ENOMEM;
+ break;
+ }
+
+ /* The BD holds the cache aligned address */
+ priv->rx_queue.drv[i].host_addr = packet->dma_addr;
+ priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
+ priv->status_queue.drv[i].status_fields = 0;
+ }
+
+ if (i == RX_QUEUE_LENGTH)
+ return 0;
+
+ for (j = 0; j < i; j++) {
+ pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
+ sizeof(struct ipw2100_rx_packet),
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(priv->rx_buffers[j].skb);
+ }
+
+ kfree(priv->rx_buffers);
+ priv->rx_buffers = NULL;
+
+ bd_queue_free(priv, &priv->rx_queue);
+
+ status_queue_free(priv);
+
+ return err;
+}
+
+static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
+{
+ IPW_DEBUG_INFO("enter\n");
+
+ priv->rx_queue.oldest = 0;
+ priv->rx_queue.available = priv->rx_queue.entries - 1;
+ priv->rx_queue.next = priv->rx_queue.entries - 1;
+
+ INIT_STAT(&priv->rxq_stat);
+ SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
+
+ bd_queue_initialize(priv, &priv->rx_queue,
+ IPW_MEM_HOST_SHARED_RX_BD_BASE,
+ IPW_MEM_HOST_SHARED_RX_BD_SIZE,
+ IPW_MEM_HOST_SHARED_RX_READ_INDEX,
+ IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
+
+ /* set up the status queue */
+ write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
+ priv->status_queue.nic);
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+static void ipw2100_rx_free(struct ipw2100_priv *priv)
+{
+ int i;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ bd_queue_free(priv, &priv->rx_queue);
+ status_queue_free(priv);
+
+ if (!priv->rx_buffers)
+ return;
+
+ for (i = 0; i < RX_QUEUE_LENGTH; i++) {
+ if (priv->rx_buffers[i].rxp) {
+ pci_unmap_single(priv->pci_dev,
+ priv->rx_buffers[i].dma_addr,
+ sizeof(struct ipw2100_rx),
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(priv->rx_buffers[i].skb);
+ }
+ }
+
+ kfree(priv->rx_buffers);
+ priv->rx_buffers = NULL;
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
+{
+ u32 length = ETH_ALEN;
+ u8 mac[ETH_ALEN];
+
+ int err;
+
+ err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC,
+ mac, &length);
+ if (err) {
+ IPW_DEBUG_INFO("MAC address read failed\n");
+ return -EIO;
+ }
+ IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
+
+ return 0;
+}
+
+/********************************************************************
+ *
+ * Firmware Commands
+ *
+ ********************************************************************/
+
+static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = ADAPTER_ADDRESS,
+ .host_command_sequence = 0,
+ .host_command_length = ETH_ALEN
+ };
+ int err;
+
+ IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
+
+ IPW_DEBUG_INFO("enter\n");
+
+ if (priv->config & CFG_CUSTOM_MAC) {
+ memcpy(cmd.host_command_parameters, priv->mac_addr,
+ ETH_ALEN);
+ memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
+ } else
+ memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
+ ETH_ALEN);
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ IPW_DEBUG_INFO("exit\n");
+ return err;
+}
+
+static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = PORT_TYPE,
+ .host_command_sequence = 0,
+ .host_command_length = sizeof(u32)
+ };
+ int err;
+
+ switch (port_type) {
+ case IW_MODE_INFRA:
+ cmd.host_command_parameters[0] = IPW_BSS;
+ break;
+ case IW_MODE_ADHOC:
+ cmd.host_command_parameters[0] = IPW_IBSS;
+ break;
+ }
+
+ IPW_DEBUG_HC("PORT_TYPE: %s\n",
+ port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ priv->net_dev->name, err);
+ return err;
+ }
+ }
+
+ /* send cmd to firmware */
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ return err;
+}
+
+
+static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = CHANNEL,
+ .host_command_sequence = 0,
+ .host_command_length = sizeof(u32)
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = channel;
+
+ IPW_DEBUG_HC("CHANNEL: %d\n", channel);
+
+ /* If BSS then we don't support channel selection */
+ if (priv->ieee->iw_mode == IW_MODE_INFRA)
+ return 0;
+
+ if ((channel != 0) &&
+ ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
+ return -EINVAL;
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err) {
+ IPW_DEBUG_INFO("Failed to set channel to %d",
+ channel);
+ return err;
+ }
+
+ if (channel)
+ priv->config |= CFG_STATIC_CHANNEL;
+ else
+ priv->config &= ~CFG_STATIC_CHANNEL;
+
+ priv->channel = channel;
+
+ if (!batch_mode) {
+ err = ipw2100_enable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = SYSTEM_CONFIG,
+ .host_command_sequence = 0,
+ .host_command_length = 12,
+ };
+ u32 ibss_mask, len = sizeof(u32);
+ int err;
+
+ /* Set system configuration */
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+ cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
+
+ cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
+ IPW_CFG_BSS_MASK |
+ IPW_CFG_802_1x_ENABLE;
+
+ if (!(priv->config & CFG_LONG_PREAMBLE))
+ cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
+
+ err = ipw2100_get_ordinal(priv,
+ IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
+ &ibss_mask, &len);
+ if (err)
+ ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
+
+ cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
+ cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
+
+ /* 11b only */
+ /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A;*/
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+
+/* If IPv6 is configured in the kernel then we don't want to filter out all
+ * of the multicast packets as IPv6 needs some. */
+#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
+ cmd.host_command = ADD_MULTICAST;
+ cmd.host_command_sequence = 0;
+ cmd.host_command_length = 0;
+
+ ipw2100_hw_send_command(priv, &cmd);
+#endif
+ if (!batch_mode) {
+ err = ipw2100_enable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = BASIC_TX_RATES,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ /* Set BASIC TX Rate first */
+ ipw2100_hw_send_command(priv, &cmd);
+
+ /* Set TX Rate */
+ cmd.host_command = TX_RATES;
+ ipw2100_hw_send_command(priv, &cmd);
+
+ /* Set MSDU TX Rate */
+ cmd.host_command = MSDU_TX_RATES;
+ ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode) {
+ err = ipw2100_enable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ priv->tx_rates = rate;
+
+ return 0;
+}
+
+static int ipw2100_set_power_mode(struct ipw2100_priv *priv,
+ int power_level)
+{
+ struct host_command cmd = {
+ .host_command = POWER_MODE,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = power_level;
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+
+ if (power_level == IPW_POWER_MODE_CAM)
+ priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
+ else
+ priv->power_mode = IPW_POWER_ENABLED | power_level;
+
+#ifdef CONFIG_IPW2100_TX_POWER
+ if (priv->port_type == IBSS &&
+ priv->adhoc_power != DFTL_IBSS_TX_POWER) {
+ /* Set beacon interval */
+ cmd.host_command = TX_POWER_INDEX;
+ cmd.host_command_parameters[0] = (u32)priv->adhoc_power;
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+ }
+#endif
+
+ return 0;
+}
+
+
+static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
+{
+ struct host_command cmd = {
+ .host_command = RTS_THRESHOLD,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ if (threshold & RTS_DISABLED)
+ cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
+ else
+ cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+
+ priv->rts_threshold = threshold;
+
+ return 0;
+}
+
+#if 0
+int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
+ u32 threshold, int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = FRAG_THRESHOLD,
+ .host_command_sequence = 0,
+ .host_command_length = 4,
+ .host_command_parameters[0] = 0,
+ };
+ int err;
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ if (threshold == 0)
+ threshold = DEFAULT_FRAG_THRESHOLD;
+ else {
+ threshold = max(threshold, MIN_FRAG_THRESHOLD);
+ threshold = min(threshold, MAX_FRAG_THRESHOLD);
+ }
+
+ cmd.host_command_parameters[0] = threshold;
+
+ IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ if (!err)
+ priv->frag_threshold = threshold;
+
+ return err;
+}
+#endif
+
+static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
+{
+ struct host_command cmd = {
+ .host_command = SHORT_RETRY_LIMIT,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = retry;
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+
+ priv->short_retry_limit = retry;
+
+ return 0;
+}
+
+static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
+{
+ struct host_command cmd = {
+ .host_command = LONG_RETRY_LIMIT,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = retry;
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (err)
+ return err;
+
+ priv->long_retry_limit = retry;
+
+ return 0;
+}
+
+
+static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = MANDATORY_BSSID,
+ .host_command_sequence = 0,
+ .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
+ };
+ int err;
+
+#ifdef CONFIG_IPW_DEBUG
+ if (bssid != NULL)
+ IPW_DEBUG_HC(
+ "MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
+ bssid[5]);
+ else
+ IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
+#endif
+ /* if BSSID is empty then we disable mandatory bssid mode */
+ if (bssid != NULL)
+ memcpy((u8 *)cmd.host_command_parameters, bssid, ETH_ALEN);
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ return err;
+}
+
+#ifdef CONFIG_IEEE80211_WPA
+static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
+{
+ struct host_command cmd = {
+ .host_command = DISASSOCIATION_BSSID,
+ .host_command_sequence = 0,
+ .host_command_length = ETH_ALEN
+ };
+ int err;
+ int len;
+
+ IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
+
+ len = ETH_ALEN;
+ /* The Firmware currently ignores the BSSID and just disassociates from
+ * the currently associated AP -- but in the off chance that a future
+ * firmware does use the BSSID provided here, we go ahead and try and
+ * set it to the currently associated AP's BSSID */
+ memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ return err;
+}
+#endif
+
+/*
+ * Pseudo code for setting up wpa_frame:
+ */
+#if 0
+void x(struct ieee80211_assoc_frame *wpa_assoc)
+{
+ struct ipw2100_wpa_assoc_frame frame;
+ frame->fixed_ie_mask = IPW_WPA_CAPABILTIES |
+ IPW_WPA_LISTENINTERVAL |
+ IPW_WPA_AP_ADDRESS;
+ frame->capab_info = wpa_assoc->capab_info;
+ frame->lisen_interval = wpa_assoc->listent_interval;
+ memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN);
+
+ /* UNKNOWN -- I'm not postivive about this part; don't have any WPA
+ * setup here to test it with.
+ *
+ * Walk the IEs in the wpa_assoc and figure out the total size of all
+ * that data. Stick that into frame->var_ie_len. Then memcpy() all of
+ * the IEs from wpa_frame into frame.
+ */
+ frame->var_ie_len = calculate_ie_len(wpa_assoc);
+ memcpy(frame->var_ie, wpa_assoc->variable, frame->var_ie_len);
+
+ ipw2100_set_wpa_ie(priv, &frame, 0);
+}
+#endif
+
+
+
+
+static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
+ struct ipw2100_wpa_assoc_frame *, int)
+__attribute__ ((unused));
+
+static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
+ struct ipw2100_wpa_assoc_frame *wpa_frame,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = SET_WPA_IE,
+ .host_command_sequence = 0,
+ .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
+ };
+ int err;
+
+ IPW_DEBUG_HC("SET_WPA_IE\n");
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ memcpy(cmd.host_command_parameters, wpa_frame,
+ sizeof(struct ipw2100_wpa_assoc_frame));
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode) {
+ if (ipw2100_enable_adapter(priv))
+ err = -EIO;
+ }
+
+ return err;
+}
+
+struct security_info_params {
+ u32 allowed_ciphers;
+ u16 version;
+ u8 auth_mode;
+ u8 replay_counters_number;
+ u8 unicast_using_group;
+} __attribute__ ((packed));
+
+static int ipw2100_set_security_information(struct ipw2100_priv *priv,
+ int auth_mode,
+ int security_level,
+ int unicast_using_group,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = SET_SECURITY_INFORMATION,
+ .host_command_sequence = 0,
+ .host_command_length = sizeof(struct security_info_params)
+ };
+ struct security_info_params *security =
+ (struct security_info_params *)&cmd.host_command_parameters;
+ int err;
+ memset(security, 0, sizeof(*security));
+
+ /* If shared key AP authentication is turned on, then we need to
+ * configure the firmware to try and use it.
+ *
+ * Actual data encryption/decryption is handled by the host. */
+ security->auth_mode = auth_mode;
+ security->unicast_using_group = unicast_using_group;
+
+ switch (security_level) {
+ default:
+ case SEC_LEVEL_0:
+ security->allowed_ciphers = IPW_NONE_CIPHER;
+ break;
+ case SEC_LEVEL_1:
+ security->allowed_ciphers = IPW_WEP40_CIPHER |
+ IPW_WEP104_CIPHER;
+ break;
+ case SEC_LEVEL_2:
+ security->allowed_ciphers = IPW_WEP40_CIPHER |
+ IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
+ break;
+ case SEC_LEVEL_2_CKIP:
+ security->allowed_ciphers = IPW_WEP40_CIPHER |
+ IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
+ break;
+ case SEC_LEVEL_3:
+ security->allowed_ciphers = IPW_WEP40_CIPHER |
+ IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
+ break;
+ }
+
+ IPW_DEBUG_HC(
+ "SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
+ security->auth_mode, security->allowed_ciphers, security_level);
+
+ security->replay_counters_number = 0;
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ return err;
+}
+
+static int ipw2100_set_tx_power(struct ipw2100_priv *priv,
+ u32 tx_power)
+{
+ struct host_command cmd = {
+ .host_command = TX_POWER_INDEX,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err = 0;
+
+ cmd.host_command_parameters[0] = tx_power;
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+ err = ipw2100_hw_send_command(priv, &cmd);
+ if (!err)
+ priv->tx_power = tx_power;
+
+ return 0;
+}
+
+static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
+ u32 interval, int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = BEACON_INTERVAL,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = interval;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode) {
+ err = ipw2100_enable_adapter(priv);
+ if (err)
+ return err;
+ }
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+}
+
+
+void ipw2100_queues_initialize(struct ipw2100_priv *priv)
+{
+ ipw2100_tx_initialize(priv);
+ ipw2100_rx_initialize(priv);
+ ipw2100_msg_initialize(priv);
+}
+
+void ipw2100_queues_free(struct ipw2100_priv *priv)
+{
+ ipw2100_tx_free(priv);
+ ipw2100_rx_free(priv);
+ ipw2100_msg_free(priv);
+}
+
+int ipw2100_queues_allocate(struct ipw2100_priv *priv)
+{
+ if (ipw2100_tx_allocate(priv) ||
+ ipw2100_rx_allocate(priv) ||
+ ipw2100_msg_allocate(priv))
+ goto fail;
+
+ return 0;
+
+ fail:
+ ipw2100_tx_free(priv);
+ ipw2100_rx_free(priv);
+ ipw2100_msg_free(priv);
+ return -ENOMEM;
+}
+
+#define IPW_PRIVACY_CAPABLE 0x0008
+
+static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
+ int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = WEP_FLAGS,
+ .host_command_sequence = 0,
+ .host_command_length = 4
+ };
+ int err;
+
+ cmd.host_command_parameters[0] = flags;
+
+ IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ priv->net_dev->name, err);
+ return err;
+ }
+ }
+
+ /* send cmd to firmware */
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ return err;
+}
+
+struct ipw2100_wep_key {
+ u8 idx;
+ u8 len;
+ u8 key[13];
+};
+
+/* Macros to ease up priting WEP keys */
+#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
+#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
+#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
+#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
+
+
+/**
+ * Set a the wep key
+ *
+ * @priv: struct to work on
+ * @idx: index of the key we want to set
+ * @key: ptr to the key data to set
+ * @len: length of the buffer at @key
+ * @batch_mode: FIXME perform the operation in batch mode, not
+ * disabling the device.
+ *
+ * @returns 0 if OK, < 0 errno code on error.
+ *
+ * Fill out a command structure with the new wep key, length an
+ * index and send it down the wire.
+ */
+static int ipw2100_set_key(struct ipw2100_priv *priv,
+ int idx, char *key, int len, int batch_mode)
+{
+ int keylen = len ? (len <= 5 ? 5 : 13) : 0;
+ struct host_command cmd = {
+ .host_command = WEP_KEY_INFO,
+ .host_command_sequence = 0,
+ .host_command_length = sizeof(struct ipw2100_wep_key),
+ };
+ struct ipw2100_wep_key *wep_key = (void*)cmd.host_command_parameters;
+ int err;
+
+ IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
+ idx, keylen, len);
+
+ /* NOTE: We don't check cached values in case the firmware was reset
+ * or some other problem is occuring. If the user is setting the key,
+ * then we push the change */
+
+ wep_key->idx = idx;
+ wep_key->len = keylen;
+
+ if (keylen) {
+ memcpy(wep_key->key, key, len);
+ memset(wep_key->key + len, 0, keylen - len);
+ }
+
+ /* Will be optimized out on debug not being configured in */
+ if (keylen == 0)
+ IPW_DEBUG_WEP("%s: Clearing key %d\n",
+ priv->net_dev->name, wep_key->idx);
+ else if (keylen == 5)
+ IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
+ priv->net_dev->name, wep_key->idx, wep_key->len,
+ WEP_STR_64(wep_key->key));
+ else
+ IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
+ "\n",
+ priv->net_dev->name, wep_key->idx, wep_key->len,
+ WEP_STR_128(wep_key->key));
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ priv->net_dev->name, err);
+ return err;
+ }
+ }
+
+ /* send cmd to firmware */
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode) {
+ int err2 = ipw2100_enable_adapter(priv);
+ if (err == 0)
+ err = err2;
+ }
+ return err;
+}
+
+static int ipw2100_set_key_index(struct ipw2100_priv *priv,
+ int idx, int batch_mode)
+{
+ struct host_command cmd = {
+ .host_command = WEP_KEY_INDEX,
+ .host_command_sequence = 0,
+ .host_command_length = 4,
+ .host_command_parameters = { idx },
+ };
+ int err;
+
+ IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
+
+ if (idx < 0 || idx > 3)
+ return -EINVAL;
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err) {
+ printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ priv->net_dev->name, err);
+ return err;
+ }
+ }
+
+ /* send cmd to firmware */
+ err = ipw2100_hw_send_command(priv, &cmd);
+
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ return err;
+}
+
+
+static int ipw2100_configure_security(struct ipw2100_priv *priv,
+ int batch_mode)
+{
+ int i, err, auth_mode, sec_level, use_group;
+
+ if (!(priv->status & STATUS_RUNNING))
+ return 0;
+
+ if (!batch_mode) {
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+ }
+
+ if (!priv->sec.enabled) {
+ err = ipw2100_set_security_information(
+ priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1);
+ } else {
+ auth_mode = IPW_AUTH_OPEN;
+ if ((priv->sec.flags & SEC_AUTH_MODE) &&
+ (priv->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
+ auth_mode = IPW_AUTH_SHARED;
+
+ sec_level = SEC_LEVEL_0;
+ if (priv->sec.flags & SEC_LEVEL)
+ sec_level = priv->sec.level;
+
+ use_group = 0;
+ if (priv->sec.flags & SEC_UNICAST_GROUP)
+ use_group = priv->sec.unicast_uses_group;
+
+ err = ipw2100_set_security_information(
+ priv, auth_mode, sec_level, use_group, 1);
+ }
+
+ if (err)
+ goto exit;
+
+ if (priv->sec.enabled) {
+ for (i = 0; i < 4; i++) {
+ if (!(priv->sec.flags & (1 << i))) {
+ memset(priv->sec.keys[i], 0, WEP_KEY_LEN);
+ priv->sec.key_sizes[i] = 0;
+ } else {
+ err = ipw2100_set_key(priv, i,
+ priv->sec.keys[i],
+ priv->sec.key_sizes[i],
+ 1);
+ if (err)
+ goto exit;
+ }
+ }
+
+ ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1);
+ }
+
+ /* Always enable privacy so the Host can filter WEP packets if
+ * encrypted data is sent up */
+ err = ipw2100_set_wep_flags(
+ priv, priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
+ if (err)
+ goto exit;
+
+ priv->status &= ~STATUS_SECURITY_UPDATED;
+
+ exit:
+ if (!batch_mode)
+ ipw2100_enable_adapter(priv);
+
+ return err;
+}
+
+static void ipw2100_security_work(struct ipw2100_priv *priv)
+{
+ /* If we happen to have reconnected before we get a chance to
+ * process this, then update the security settings--which causes
+ * a disassociation to occur */
+ if (!(priv->status & STATUS_ASSOCIATED) &&
+ priv->status & STATUS_SECURITY_UPDATED)
+ ipw2100_configure_security(priv, 0);
+}
+
+static void shim__set_security(struct net_device *dev,
+ struct ieee80211_security *sec)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int i, force_update = 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED))
+ goto done;
+
+ for (i = 0; i < 4; i++) {
+ if (sec->flags & (1 << i)) {
+ priv->sec.key_sizes[i] = sec->key_sizes[i];
+ if (sec->key_sizes[i] == 0)
+ priv->sec.flags &= ~(1 << i);
+ else
+ memcpy(priv->sec.keys[i], sec->keys[i],
+ sec->key_sizes[i]);
+ priv->sec.flags |= (1 << i);
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+ }
+
+ if ((sec->flags & SEC_ACTIVE_KEY) &&
+ priv->sec.active_key != sec->active_key) {
+ if (sec->active_key <= 3) {
+ priv->sec.active_key = sec->active_key;
+ priv->sec.flags |= SEC_ACTIVE_KEY;
+ } else
+ priv->sec.flags &= ~SEC_ACTIVE_KEY;
+
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+
+ if ((sec->flags & SEC_AUTH_MODE) &&
+ (priv->sec.auth_mode != sec->auth_mode)) {
+ priv->sec.auth_mode = sec->auth_mode;
+ priv->sec.flags |= SEC_AUTH_MODE;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+
+ if (sec->flags & SEC_ENABLED &&
+ priv->sec.enabled != sec->enabled) {
+ priv->sec.flags |= SEC_ENABLED;
+ priv->sec.enabled = sec->enabled;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ force_update = 1;
+ }
+
+ if (sec->flags & SEC_LEVEL &&
+ priv->sec.level != sec->level) {
+ priv->sec.level = sec->level;
+ priv->sec.flags |= SEC_LEVEL;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+
+ IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
+ priv->sec.flags & (1<<8) ? '1' : '0',
+ priv->sec.flags & (1<<7) ? '1' : '0',
+ priv->sec.flags & (1<<6) ? '1' : '0',
+ priv->sec.flags & (1<<5) ? '1' : '0',
+ priv->sec.flags & (1<<4) ? '1' : '0',
+ priv->sec.flags & (1<<3) ? '1' : '0',
+ priv->sec.flags & (1<<2) ? '1' : '0',
+ priv->sec.flags & (1<<1) ? '1' : '0',
+ priv->sec.flags & (1<<0) ? '1' : '0');
+
+/* As a temporary work around to enable WPA until we figure out why
+ * wpa_supplicant toggles the security capability of the driver, which
+ * forces a disassocation with force_update...
+ *
+ * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
+ if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
+ ipw2100_configure_security(priv, 0);
+done:
+ up(&priv->action_sem);
+}
+
+static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
+{
+ int err;
+ int batch_mode = 1;
+ u8 *bssid;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ err = ipw2100_disable_adapter(priv);
+ if (err)
+ return err;
+#ifdef CONFIG_IPW2100_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ err = ipw2100_set_channel(priv, priv->channel, batch_mode);
+ if (err)
+ return err;
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+ }
+#endif /* CONFIG_IPW2100_MONITOR */
+
+ err = ipw2100_read_mac_address(priv);
+ if (err)
+ return -EIO;
+
+ err = ipw2100_set_mac_address(priv, batch_mode);
+ if (err)
+ return err;
+
+ err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
+ if (err)
+ return err;
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ err = ipw2100_set_channel(priv, priv->channel, batch_mode);
+ if (err)
+ return err;
+ }
+
+ err = ipw2100_system_config(priv, batch_mode);
+ if (err)
+ return err;
+
+ err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
+ if (err)
+ return err;
+
+ /* Default to power mode OFF */
+ err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
+ if (err)
+ return err;
+
+ err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
+ if (err)
+ return err;
+
+ if (priv->config & CFG_STATIC_BSSID)
+ bssid = priv->bssid;
+ else
+ bssid = NULL;
+ err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
+ if (err)
+ return err;
+
+ if (priv->config & CFG_STATIC_ESSID)
+ err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
+ batch_mode);
+ else
+ err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
+ if (err)
+ return err;
+
+ err = ipw2100_configure_security(priv, batch_mode);
+ if (err)
+ return err;
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ err = ipw2100_set_ibss_beacon_interval(
+ priv, priv->beacon_interval, batch_mode);
+ if (err)
+ return err;
+
+ err = ipw2100_set_tx_power(priv, priv->tx_power);
+ if (err)
+ return err;
+ }
+
+ /*
+ err = ipw2100_set_fragmentation_threshold(
+ priv, priv->frag_threshold, batch_mode);
+ if (err)
+ return err;
+ */
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+}
+
+
+/*************************************************************************
+ *
+ * EXTERNALLY CALLED METHODS
+ *
+ *************************************************************************/
+
+/* This method is called by the network layer -- not to be confused with
+ * ipw2100_set_mac_address() declared above called by this driver (and this
+ * method as well) to talk to the firmware */
+static int ipw2100_set_address(struct net_device *dev, void *p)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct sockaddr *addr = p;
+ int err = 0;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ down(&priv->action_sem);
+
+ priv->config |= CFG_CUSTOM_MAC;
+ memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
+
+ err = ipw2100_set_mac_address(priv, 0);
+ if (err)
+ goto done;
+
+ priv->reset_backoff = 0;
+ up(&priv->action_sem);
+ ipw2100_reset_adapter(priv);
+ return 0;
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_open(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ unsigned long flags;
+ IPW_DEBUG_INFO("dev->open\n");
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+ if (priv->status & STATUS_ASSOCIATED) {
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ return 0;
+}
+
+static int ipw2100_close(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ unsigned long flags;
+ struct list_head *element;
+ struct ipw2100_tx_packet *packet;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+
+ if (priv->status & STATUS_ASSOCIATED)
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+
+ /* Flush the TX queue ... */
+ while (!list_empty(&priv->tx_pend_list)) {
+ element = priv->tx_pend_list.next;
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
+
+ list_del(element);
+ DEC_STAT(&priv->tx_pend_stat);
+
+ ieee80211_txb_free(packet->info.d_struct.txb);
+ packet->info.d_struct.txb = NULL;
+
+ list_add_tail(element, &priv->tx_free_list);
+ INC_STAT(&priv->tx_free_stat);
+ }
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+
+ IPW_DEBUG_INFO("exit\n");
+
+ return 0;
+}
+
+
+
+/*
+ * TODO: Fix this function... its just wrong
+ */
+static void ipw2100_tx_timeout(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ priv->ieee->stats.tx_errors++;
+
+#ifdef CONFIG_IPW2100_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+ return;
+#endif
+
+ IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
+ dev->name);
+ schedule_reset(priv);
+}
+
+
+/*
+ * TODO: reimplement it so that it reads statistics
+ * from the adapter using ordinal tables
+ * instead of/in addition to collecting them
+ * in the driver
+ */
+static struct net_device_stats *ipw2100_stats(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ return &priv->ieee->stats;
+}
+
+/* Support for wpa_supplicant. Will be replaced with WEXT once
+ * they get WPA support. */
+#ifdef CONFIG_IEEE80211_WPA
+
+/* following definitions must match definitions in driver_ipw2100.c */
+
+#define IPW2100_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
+
+#define IPW2100_CMD_SET_WPA_PARAM 1
+#define IPW2100_CMD_SET_WPA_IE 2
+#define IPW2100_CMD_SET_ENCRYPTION 3
+#define IPW2100_CMD_MLME 4
+
+#define IPW2100_PARAM_WPA_ENABLED 1
+#define IPW2100_PARAM_TKIP_COUNTERMEASURES 2
+#define IPW2100_PARAM_DROP_UNENCRYPTED 3
+#define IPW2100_PARAM_PRIVACY_INVOKED 4
+#define IPW2100_PARAM_AUTH_ALGS 5
+#define IPW2100_PARAM_IEEE_802_1X 6
+
+#define IPW2100_MLME_STA_DEAUTH 1
+#define IPW2100_MLME_STA_DISASSOC 2
+
+#define IPW2100_CRYPT_ERR_UNKNOWN_ALG 2
+#define IPW2100_CRYPT_ERR_UNKNOWN_ADDR 3
+#define IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define IPW2100_CRYPT_ERR_KEY_SET_FAILED 5
+#define IPW2100_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define IPW2100_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#define IPW2100_CRYPT_ALG_NAME_LEN 16
+
+struct ipw2100_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u8 name;
+ u32 value;
+ } wpa_param;
+ struct {
+ u32 len;
+ u8 *data;
+ } wpa_ie;
+ struct{
+ int command;
+ int reason_code;
+ } mlme;
+ struct {
+ u8 alg[IPW2100_CRYPT_ALG_NAME_LEN];
+ u8 set_tx;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+
+ } u;
+};
+
+/* end of driver_ipw2100.c code */
+
+static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){
+
+ struct ieee80211_device *ieee = priv->ieee;
+ struct ieee80211_security sec = {
+ .flags = SEC_LEVEL | SEC_ENABLED,
+ };
+ int ret = 0;
+
+ ieee->wpa_enabled = value;
+
+ if (value){
+ sec.level = SEC_LEVEL_3;
+ sec.enabled = 1;
+ } else {
+ sec.level = SEC_LEVEL_0;
+ sec.enabled = 0;
+ }
+
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+ else
+ ret = -EOPNOTSUPP;
+
+ return ret;
+}
+
+#define AUTH_ALG_OPEN_SYSTEM 0x1
+#define AUTH_ALG_SHARED_KEY 0x2
+
+static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){
+
+ struct ieee80211_device *ieee = priv->ieee;
+ struct ieee80211_security sec = {
+ .flags = SEC_AUTH_MODE,
+ };
+ int ret = 0;
+
+ if (value & AUTH_ALG_SHARED_KEY){
+ sec.auth_mode = WLAN_AUTH_SHARED_KEY;
+ ieee->open_wep = 0;
+ } else {
+ sec.auth_mode = WLAN_AUTH_OPEN;
+ ieee->open_wep = 1;
+ }
+
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+ else
+ ret = -EOPNOTSUPP;
+
+ return ret;
+}
+
+
+static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value){
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int ret=0;
+
+ switch(name){
+ case IPW2100_PARAM_WPA_ENABLED:
+ ret = ipw2100_wpa_enable(priv, value);
+ break;
+
+ case IPW2100_PARAM_TKIP_COUNTERMEASURES:
+ priv->ieee->tkip_countermeasures=value;
+ break;
+
+ case IPW2100_PARAM_DROP_UNENCRYPTED:
+ priv->ieee->drop_unencrypted=value;
+ break;
+
+ case IPW2100_PARAM_PRIVACY_INVOKED:
+ priv->ieee->privacy_invoked=value;
+ break;
+
+ case IPW2100_PARAM_AUTH_ALGS:
+ ret = ipw2100_wpa_set_auth_algs(priv, value);
+ break;
+
+ case IPW2100_PARAM_IEEE_802_1X:
+ priv->ieee->ieee802_1x=value;
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n",
+ dev->name, name);
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason){
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int ret=0;
+
+ switch(command){
+ case IPW2100_MLME_STA_DEAUTH:
+ // silently ignore
+ break;
+
+ case IPW2100_MLME_STA_DISASSOC:
+ ipw2100_disassociate_bssid(priv);
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n",
+ dev->name, command);
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+
+void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
+ char *wpa_ie, int wpa_ie_len){
+
+ struct ipw2100_wpa_assoc_frame frame;
+
+ frame.fixed_ie_mask = 0;
+
+ /* copy WPA IE */
+ memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
+ frame.var_ie_len = wpa_ie_len;
+
+ /* make sure WPA is enabled */
+ ipw2100_wpa_enable(priv, 1);
+ ipw2100_set_wpa_ie(priv, &frame, 0);
+}
+
+
+static int ipw2100_wpa_set_wpa_ie(struct net_device *dev,
+ struct ipw2100_param *param, int plen){
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ u8 *buf;
+
+ if (! ieee->wpa_enabled)
+ return -EOPNOTSUPP;
+
+ if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
+ (param->u.wpa_ie.len &&
+ param->u.wpa_ie.data==NULL))
+ return -EINVAL;
+
+ if (param->u.wpa_ie.len){
+ buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len);
+
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = buf;
+ ieee->wpa_ie_len = param->u.wpa_ie.len;
+
+ } else {
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = NULL;
+ ieee->wpa_ie_len = 0;
+ }
+
+ ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+
+ return 0;
+}
+
+/* implementation borrowed from hostap driver */
+
+static int ipw2100_wpa_set_encryption(struct net_device *dev,
+ struct ipw2100_param *param, int param_len){
+
+ int ret = 0;
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ struct ieee80211_crypto_ops *ops;
+ struct ieee80211_crypt_data **crypt;
+
+ struct ieee80211_security sec = {
+ .flags = 0,
+ };
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ if (param_len !=
+ (int) ((char *) param->u.crypt.key - (char *) param) +
+ param->u.crypt.key_len){
+ IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, param->u.crypt.key_len);
+ return -EINVAL;
+ }
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS)
+ return -EINVAL;
+ crypt = &ieee->crypt[param->u.crypt.idx];
+ } else {
+ return -EINVAL;
+ }
+
+ if (strcmp(param->u.crypt.alg, "none") == 0) {
+ if (crypt){
+ sec.enabled = 0;
+ sec.level = SEC_LEVEL_0;
+ sec.flags |= SEC_ENABLED | SEC_LEVEL;
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
+ }
+ goto done;
+ }
+ sec.enabled = 1;
+ sec.flags |= SEC_ENABLED;
+
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
+ request_module("ieee80211_crypt_wep");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ request_module("ieee80211_crypt_tkip");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ request_module("ieee80211_crypt_ccmp");
+ ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ }
+ if (ops == NULL) {
+ IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n",
+ dev->name, param->u.crypt.alg);
+ param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (*crypt == NULL || (*crypt)->ops != ops) {
+ struct ieee80211_crypt_data *new_crypt;
+
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
+
+ new_crypt = (struct ieee80211_crypt_data *)
+ kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL);
+ if (new_crypt == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+ new_crypt->ops = ops;
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+ new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
+
+ if (new_crypt->priv == NULL) {
+ kfree(new_crypt);
+ param->u.crypt.err =
+ IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *crypt = new_crypt;
+ }
+
+ if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key &&
+ (*crypt)->ops->set_key(param->u.crypt.key,
+ param->u.crypt.key_len, param->u.crypt.seq,
+ (*crypt)->priv) < 0) {
+ IPW_DEBUG_INFO("%s: key setting failed\n",
+ dev->name);
+ param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED;
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (param->u.crypt.set_tx){
+ ieee->tx_keyidx = param->u.crypt.idx;
+ sec.active_key = param->u.crypt.idx;
+ sec.flags |= SEC_ACTIVE_KEY;
+ }
+
+ if (ops->name != NULL){
+
+ if (strcmp(ops->name, "WEP") == 0) {
+ memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, param->u.crypt.key_len);
+ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+ sec.flags |= (1 << param->u.crypt.idx);
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ } else if (strcmp(ops->name, "TKIP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_2;
+ } else if (strcmp(ops->name, "CCMP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_3;
+ }
+ }
+ done:
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+
+ /* Do not reset port if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. If your hardware requires a reset after WEP
+ * configuration (for example... Prism2), implement the reset_port in
+ * the callbacks structures used to initialize the 802.11 stack. */
+ if (ieee->reset_on_keychange &&
+ ieee->iw_mode != IW_MODE_INFRA &&
+ ieee->reset_port &&
+ ieee->reset_port(dev)) {
+ IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name);
+ param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED;
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+
+static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
+
+ struct ipw2100_param *param;
+ int ret=0;
+
+ IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length);
+
+ if (p->length < sizeof(struct ipw2100_param) || !p->pointer)
+ return -EINVAL;
+
+ param = (struct ipw2100_param *)kmalloc(p->length, GFP_KERNEL);
+ if (param == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)){
+ kfree(param);
+ return -EFAULT;
+ }
+
+ switch (param->cmd){
+
+ case IPW2100_CMD_SET_WPA_PARAM:
+ ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name,
+ param->u.wpa_param.value);
+ break;
+
+ case IPW2100_CMD_SET_WPA_IE:
+ ret = ipw2100_wpa_set_wpa_ie(dev, param, p->length);
+ break;
+
+ case IPW2100_CMD_SET_ENCRYPTION:
+ ret = ipw2100_wpa_set_encryption(dev, param, p->length);
+ break;
+
+ case IPW2100_CMD_MLME:
+ ret = ipw2100_wpa_mlme(dev, param->u.mlme.command,
+ param->u.mlme.reason_code);
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME ": %s: Unknown WPA supplicant request: %d\n",
+ dev->name, param->cmd);
+ ret = -EOPNOTSUPP;
+
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+ kfree(param);
+ return ret;
+}
+#endif /* CONFIG_IEEE80211_WPA */
+
+static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+#ifdef CONFIG_IEEE80211_WPA
+ struct iwreq *wrq = (struct iwreq *) rq;
+ int ret=-1;
+ switch (cmd){
+ case IPW2100_IOCTL_WPA_SUPPLICANT:
+ ret = ipw2100_wpa_supplicant(dev, &wrq->u.data);
+ return ret;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+#endif /* CONFIG_IEEE80211_WPA */
+
+ return -EOPNOTSUPP;
+}
+
+
+static void ipw_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ char fw_ver[64], ucode_ver[64];
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+
+ ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
+ ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
+
+ snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
+ fw_ver, priv->eeprom_version, ucode_ver);
+
+ strcpy(info->bus_info, pci_name(priv->pci_dev));
+}
+
+static u32 ipw2100_ethtool_get_link(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
+}
+
+
+static struct ethtool_ops ipw2100_ethtool_ops = {
+ .get_link = ipw2100_ethtool_get_link,
+ .get_drvinfo = ipw_ethtool_get_drvinfo,
+};
+
+static void ipw2100_hang_check(void *adapter)
+{
+ struct ipw2100_priv *priv = adapter;
+ unsigned long flags;
+ u32 rtc = 0xa5a5a5a5;
+ u32 len = sizeof(rtc);
+ int restart = 0;
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+
+ if (priv->fatal_error != 0) {
+ /* If fatal_error is set then we need to restart */
+ IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
+ priv->net_dev->name);
+
+ restart = 1;
+ } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
+ (rtc == priv->last_rtc)) {
+ /* Check if firmware is hung */
+ IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
+ priv->net_dev->name);
+
+ restart = 1;
+ }
+
+ if (restart) {
+ /* Kill timer */
+ priv->stop_hang_check = 1;
+ priv->hangs++;
+
+ /* Restart the NIC */
+ schedule_reset(priv);
+ }
+
+ priv->last_rtc = rtc;
+
+ if (!priv->stop_hang_check)
+ queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+}
+
+
+static void ipw2100_rf_kill(void *adapter)
+{
+ struct ipw2100_priv *priv = adapter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->low_lock, flags);
+
+ if (rf_kill_active(priv)) {
+ IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
+ if (!priv->stop_rf_kill)
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+ goto exit_unlock;
+ }
+
+ /* RF Kill is now disabled, so bring the device back up */
+
+ if (!(priv->status & STATUS_RF_KILL_MASK)) {
+ IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
+ "device\n");
+ schedule_reset(priv);
+ } else
+ IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
+ "enabled\n");
+
+ exit_unlock:
+ spin_unlock_irqrestore(&priv->low_lock, flags);
+}
+
+static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
+
+/* Look into using netdev destructor to shutdown ieee80211? */
+
+static struct net_device *ipw2100_alloc_device(
+ struct pci_dev *pci_dev,
+ void __iomem *base_addr,
+ unsigned long mem_start,
+ unsigned long mem_len)
+{
+ struct ipw2100_priv *priv;
+ struct net_device *dev;
+
+ dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
+ if (!dev)
+ return NULL;
+ priv = ieee80211_priv(dev);
+ priv->ieee = netdev_priv(dev);
+ priv->pci_dev = pci_dev;
+ priv->net_dev = dev;
+
+ priv->ieee->hard_start_xmit = ipw2100_tx;
+ priv->ieee->set_security = shim__set_security;
+
+ dev->open = ipw2100_open;
+ dev->stop = ipw2100_close;
+ dev->init = ipw2100_net_init;
+ dev->do_ioctl = ipw2100_ioctl;
+ dev->get_stats = ipw2100_stats;
+ dev->ethtool_ops = &ipw2100_ethtool_ops;
+ dev->tx_timeout = ipw2100_tx_timeout;
+ dev->wireless_handlers = &ipw2100_wx_handler_def;
+ dev->get_wireless_stats = ipw2100_wx_wireless_stats;
+ dev->set_mac_address = ipw2100_set_address;
+ dev->watchdog_timeo = 3*HZ;
+ dev->irq = 0;
+
+ dev->base_addr = (unsigned long)base_addr;
+ dev->mem_start = mem_start;
+ dev->mem_end = dev->mem_start + mem_len - 1;
+
+ /* NOTE: We don't use the wireless_handlers hook
+ * in dev as the system will start throwing WX requests
+ * to us before we're actually initialized and it just
+ * ends up causing problems. So, we just handle
+ * the WX extensions through the ipw2100_ioctl interface */
+
+
+ /* memset() puts everything to 0, so we only have explicitely set
+ * those values that need to be something else */
+
+ /* If power management is turned on, default to AUTO mode */
+ priv->power_mode = IPW_POWER_AUTO;
+
+
+
+#ifdef CONFIG_IEEE80211_WPA
+ priv->ieee->wpa_enabled = 0;
+ priv->ieee->tkip_countermeasures = 0;
+ priv->ieee->drop_unencrypted = 0;
+ priv->ieee->privacy_invoked = 0;
+ priv->ieee->ieee802_1x = 1;
+#endif /* CONFIG_IEEE80211_WPA */
+
+ /* Set module parameters */
+ switch (mode) {
+ case 1:
+ priv->ieee->iw_mode = IW_MODE_ADHOC;
+ break;
+#ifdef CONFIG_IPW2100_MONITOR
+ case 2:
+ priv->ieee->iw_mode = IW_MODE_MONITOR;
+ break;
+#endif
+ default:
+ case 0:
+ priv->ieee->iw_mode = IW_MODE_INFRA;
+ break;
+ }
+
+ if (disable == 1)
+ priv->status |= STATUS_RF_KILL_SW;
+
+ if (channel != 0 &&
+ ((channel >= REG_MIN_CHANNEL) &&
+ (channel <= REG_MAX_CHANNEL))) {
+ priv->config |= CFG_STATIC_CHANNEL;
+ priv->channel = channel;
+ }
+
+ if (associate)
+ priv->config |= CFG_ASSOCIATE;
+
+ priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
+ priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
+ priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
+ priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
+ priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
+ priv->tx_power = IPW_TX_POWER_DEFAULT;
+ priv->tx_rates = DEFAULT_TX_RATES;
+
+ strcpy(priv->nick, "ipw2100");
+
+ spin_lock_init(&priv->low_lock);
+ sema_init(&priv->action_sem, 1);
+ sema_init(&priv->adapter_sem, 1);
+
+ init_waitqueue_head(&priv->wait_command_queue);
+
+ netif_carrier_off(dev);
+
+ INIT_LIST_HEAD(&priv->msg_free_list);
+ INIT_LIST_HEAD(&priv->msg_pend_list);
+ INIT_STAT(&priv->msg_free_stat);
+ INIT_STAT(&priv->msg_pend_stat);
+
+ INIT_LIST_HEAD(&priv->tx_free_list);
+ INIT_LIST_HEAD(&priv->tx_pend_list);
+ INIT_STAT(&priv->tx_free_stat);
+ INIT_STAT(&priv->tx_pend_stat);
+
+ INIT_LIST_HEAD(&priv->fw_pend_list);
+ INIT_STAT(&priv->fw_pend_stat);
+
+
+#ifdef CONFIG_SOFTWARE_SUSPEND2
+ priv->workqueue = create_workqueue(DRV_NAME, 0);
+#else
+ priv->workqueue = create_workqueue(DRV_NAME);
+#endif
+ INIT_WORK(&priv->reset_work,
+ (void (*)(void *))ipw2100_reset_adapter, priv);
+ INIT_WORK(&priv->security_work,
+ (void (*)(void *))ipw2100_security_work, priv);
+ INIT_WORK(&priv->wx_event_work,
+ (void (*)(void *))ipw2100_wx_event_work, priv);
+ INIT_WORK(&priv->hang_check, ipw2100_hang_check, priv);
+ INIT_WORK(&priv->rf_kill, ipw2100_rf_kill, priv);
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ ipw2100_irq_tasklet, (unsigned long)priv);
+
+ /* NOTE: We do not start the deferred work for status checks yet */
+ priv->stop_rf_kill = 1;
+ priv->stop_hang_check = 1;
+
+ return dev;
+}
+
+static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
+ const struct pci_device_id *ent)
+{
+ unsigned long mem_start, mem_len, mem_flags;
+ void __iomem *base_addr = NULL;
+ struct net_device *dev = NULL;
+ struct ipw2100_priv *priv = NULL;
+ int err = 0;
+ int registered = 0;
+ u32 val;
+
+ IPW_DEBUG_INFO("enter\n");
+
+ mem_start = pci_resource_start(pci_dev, 0);
+ mem_len = pci_resource_len(pci_dev, 0);
+ mem_flags = pci_resource_flags(pci_dev, 0);
+
+ if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
+ IPW_DEBUG_INFO("weird - resource type is not memory\n");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ base_addr = ioremap_nocache(mem_start, mem_len);
+ if (!base_addr) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling ioremap_nocache.\n");
+ err = -EIO;
+ goto fail;
+ }
+
+ /* allocate and initialize our net_device */
+ dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
+ if (!dev) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling ipw2100_alloc_device.\n");
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ /* set up PCI mappings for device */
+ err = pci_enable_device(pci_dev);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling pci_enable_device.\n");
+ return err;
+ }
+
+ priv = ieee80211_priv(dev);
+
+ pci_set_master(pci_dev);
+ pci_set_drvdata(pci_dev, priv);
+
+ err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling pci_set_dma_mask.\n");
+ pci_disable_device(pci_dev);
+ return err;
+ }
+
+ err = pci_request_regions(pci_dev, DRV_NAME);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling pci_request_regions.\n");
+ pci_disable_device(pci_dev);
+ return err;
+ }
+
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_read_config_dword(pci_dev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
+
+ pci_set_power_state(pci_dev, PCI_D0);
+
+ if (!ipw2100_hw_is_adapter_in_system(dev)) {
+ printk(KERN_WARNING DRV_NAME
+ "Device not found via register read.\n");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ SET_NETDEV_DEV(dev, &pci_dev->dev);
+
+ /* Force interrupts to be shut off on the device */
+ priv->status |= STATUS_INT_ENABLED;
+ ipw2100_disable_interrupts(priv);
+
+ /* Allocate and initialize the Tx/Rx queues and lists */
+ if (ipw2100_queues_allocate(priv)) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calilng ipw2100_queues_allocate.\n");
+ err = -ENOMEM;
+ goto fail;
+ }
+ ipw2100_queues_initialize(priv);
+
+ err = request_irq(pci_dev->irq,
+ ipw2100_interrupt, SA_SHIRQ,
+ dev->name, priv);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling request_irq: %d.\n",
+ pci_dev->irq);
+ goto fail;
+ }
+ dev->irq = pci_dev->irq;
+
+ IPW_DEBUG_INFO("Attempting to register device...\n");
+
+ SET_MODULE_OWNER(dev);
+
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 2100 Network Connection\n");
+
+ /* Bring up the interface. Pre 0.46, after we registered the
+ * network device we would call ipw2100_up. This introduced a race
+ * condition with newer hotplug configurations (network was coming
+ * up and making calls before the device was initialized).
+ *
+ * If we called ipw2100_up before we registered the device, then the
+ * device name wasn't registered. So, we instead use the net_dev->init
+ * member to call a function that then just turns and calls ipw2100_up.
+ * net_dev->init is called after name allocation but before the
+ * notifier chain is called */
+ down(&priv->action_sem);
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ "Error calling register_netdev.\n");
+ goto fail_unlock;
+ }
+ registered = 1;
+
+ IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
+
+ /* perform this after register_netdev so that dev->name is set */
+ sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+ netif_carrier_off(dev);
+
+ /* If the RF Kill switch is disabled, go ahead and complete the
+ * startup sequence */
+ if (!(priv->status & STATUS_RF_KILL_MASK)) {
+ /* Enable the adapter - sends HOST_COMPLETE */
+ if (ipw2100_enable_adapter(priv)) {
+ printk(KERN_WARNING DRV_NAME
+ ": %s: failed in call to enable adapter.\n",
+ priv->net_dev->name);
+ ipw2100_hw_stop_adapter(priv);
+ err = -EIO;
+ goto fail_unlock;
+ }
+
+ /* Start a scan . . . */
+ ipw2100_set_scan_options(priv);
+ ipw2100_start_scan(priv);
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+
+ priv->status |= STATUS_INITIALIZED;
+
+ up(&priv->action_sem);
+
+ return 0;
+
+ fail_unlock:
+ up(&priv->action_sem);
+
+ fail:
+ if (dev) {
+ if (registered)
+ unregister_netdev(dev);
+
+ ipw2100_hw_stop_adapter(priv);
+
+ ipw2100_disable_interrupts(priv);
+
+ if (dev->irq)
+ free_irq(dev->irq, priv);
+
+ ipw2100_kill_workqueue(priv);
+
+ /* These are safe to call even if they weren't allocated */
+ ipw2100_queues_free(priv);
+ sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+
+ free_ieee80211(dev);
+ pci_set_drvdata(pci_dev, NULL);
+ }
+
+ if (base_addr)
+ iounmap(base_addr);
+
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+
+ return err;
+}
+
+static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
+{
+ struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+ struct net_device *dev;
+
+ if (priv) {
+ down(&priv->action_sem);
+
+ priv->status &= ~STATUS_INITIALIZED;
+
+ dev = priv->net_dev;
+ sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+
+#ifdef CONFIG_PM
+ if (ipw2100_firmware.version)
+ ipw2100_release_firmware(priv, &ipw2100_firmware);
+#endif
+ /* Take down the hardware */
+ ipw2100_down(priv);
+
+ /* Release the semaphore so that the network subsystem can
+ * complete any needed calls into the driver... */
+ up(&priv->action_sem);
+
+ /* Unregister the device first - this results in close()
+ * being called if the device is open. If we free storage
+ * first, then close() will crash. */
+ unregister_netdev(dev);
+
+ /* ipw2100_down will ensure that there is no more pending work
+ * in the workqueue's, so we can safely remove them now. */
+ ipw2100_kill_workqueue(priv);
+
+ ipw2100_queues_free(priv);
+
+ /* Free potential debugging firmware snapshot */
+ ipw2100_snapshot_free(priv);
+
+ if (dev->irq)
+ free_irq(dev->irq, priv);
+
+ if (dev->base_addr)
+ iounmap((void __iomem *)dev->base_addr);
+
+ free_ieee80211(dev);
+ }
+
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+
+ IPW_DEBUG_INFO("exit\n");
+}
+
+
+#ifdef CONFIG_PM
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state)
+#else
+static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
+#endif
+{
+ struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+ struct net_device *dev = priv->net_dev;
+
+ IPW_DEBUG_INFO("%s: Going into suspend...\n",
+ dev->name);
+
+ down(&priv->action_sem);
+ if (priv->status & STATUS_INITIALIZED) {
+ /* Take down the device; powers it off, etc. */
+ ipw2100_down(priv);
+ }
+
+ /* Remove the PRESENT state of the device */
+ netif_device_detach(dev);
+
+ pci_save_state(pci_dev);
+ pci_disable_device (pci_dev);
+ pci_set_power_state(pci_dev, PCI_D3hot);
+
+ up(&priv->action_sem);
+
+ return 0;
+}
+
+static int ipw2100_resume(struct pci_dev *pci_dev)
+{
+ struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+ struct net_device *dev = priv->net_dev;
+ u32 val;
+
+ if (IPW2100_PM_DISABLED)
+ return 0;
+
+ down(&priv->action_sem);
+
+ IPW_DEBUG_INFO("%s: Coming out of suspend...\n",
+ dev->name);
+
+ pci_set_power_state(pci_dev, PCI_D0);
+ pci_enable_device(pci_dev);
+ pci_restore_state(pci_dev);
+
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_read_config_dword(pci_dev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
+
+ /* Set the device back into the PRESENT state; this will also wake
+ * the queue of needed */
+ netif_device_attach(dev);
+
+ /* Bring the device back up */
+ if (!(priv->status & STATUS_RF_KILL_SW))
+ ipw2100_up(priv, 0);
+
+ up(&priv->action_sem);
+
+ return 0;
+}
+#endif
+
+
+#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
+
+static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
+ IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
+ IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
+
+ IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
+
+ IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
+ {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
+
+static struct pci_driver ipw2100_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ipw2100_pci_id_table,
+ .probe = ipw2100_pci_init_one,
+ .remove = __devexit_p(ipw2100_pci_remove_one),
+#ifdef CONFIG_PM
+ .suspend = ipw2100_suspend,
+ .resume = ipw2100_resume,
+#endif
+};
+
+
+/**
+ * Initialize the ipw2100 driver/module
+ *
+ * @returns 0 if ok, < 0 errno node con error.
+ *
+ * Note: we cannot init the /proc stuff until the PCI driver is there,
+ * or we risk an unlikely race condition on someone accessing
+ * uninitialized data in the PCI dev struct through /proc.
+ */
+static int __init ipw2100_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+ printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
+
+#ifdef CONFIG_IEEE80211_NOWEP
+ IPW_DEBUG_INFO(DRV_NAME ": Compiled with WEP disabled.\n");
+#endif
+
+ ret = pci_module_init(&ipw2100_pci_driver);
+
+#ifdef CONFIG_IPW_DEBUG
+ ipw2100_debug_level = debug;
+ driver_create_file(&ipw2100_pci_driver.driver,
+ &driver_attr_debug_level);
+#endif
+
+ return ret;
+}
+
+
+/**
+ * Cleanup ipw2100 driver registration
+ */
+static void __exit ipw2100_exit(void)
+{
+ /* FIXME: IPG: check that we have no instances of the devices open */
+#ifdef CONFIG_IPW_DEBUG
+ driver_remove_file(&ipw2100_pci_driver.driver,
+ &driver_attr_debug_level);
+#endif
+ pci_unregister_driver(&ipw2100_pci_driver);
+}
+
+module_init(ipw2100_init);
+module_exit(ipw2100_exit);
+
+#define WEXT_USECHANNELS 1
+
+static const long ipw2100_frequencies[] = {
+ 2412, 2417, 2422, 2427,
+ 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467,
+ 2472, 2484
+};
+
+#define FREQ_COUNT (sizeof(ipw2100_frequencies) / \
+ sizeof(ipw2100_frequencies[0]))
+
+static const long ipw2100_rates_11b[] = {
+ 1000000,
+ 2000000,
+ 5500000,
+ 11000000
+};
+
+#define RATE_COUNT (sizeof(ipw2100_rates_11b) / sizeof(ipw2100_rates_11b[0]))
+
+static int ipw2100_wx_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ if (!(priv->status & STATUS_ASSOCIATED))
+ strcpy(wrqu->name, "unassociated");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
+
+ IPW_DEBUG_WX("Name: %s\n", wrqu->name);
+ return 0;
+}
+
+
+static int ipw2100_wx_set_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct iw_freq *fwrq = &wrqu->freq;
+ int err = 0;
+
+ if (priv->ieee->iw_mode == IW_MODE_INFRA)
+ return -EOPNOTSUPP;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ /* if setting by freq convert to channel */
+ if (fwrq->e == 1) {
+ if ((fwrq->m >= (int) 2.412e8 &&
+ fwrq->m <= (int) 2.487e8)) {
+ int f = fwrq->m / 100000;
+ int c = 0;
+
+ while ((c < REG_MAX_CHANNEL) &&
+ (f != ipw2100_frequencies[c]))
+ c++;
+
+ /* hack to fall through */
+ fwrq->e = 0;
+ fwrq->m = c + 1;
+ }
+ }
+
+ if (fwrq->e > 0 || fwrq->m > 1000)
+ return -EOPNOTSUPP;
+ else { /* Set the channel */
+ IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+ err = ipw2100_set_channel(priv, fwrq->m, 0);
+ }
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+
+static int ipw2100_wx_get_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ wrqu->freq.e = 0;
+
+ /* If we are associated, trying to associate, or have a statically
+ * configured CHANNEL then return that; otherwise return ANY */
+ if (priv->config & CFG_STATIC_CHANNEL ||
+ priv->status & STATUS_ASSOCIATED)
+ wrqu->freq.m = priv->channel;
+ else
+ wrqu->freq.m = 0;
+
+ IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+ return 0;
+
+}
+
+static int ipw2100_wx_set_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0;
+
+ IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
+
+ if (wrqu->mode == priv->ieee->iw_mode)
+ return 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ switch (wrqu->mode) {
+#ifdef CONFIG_IPW2100_MONITOR
+ case IW_MODE_MONITOR:
+ err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
+ break;
+#endif /* CONFIG_IPW2100_MONITOR */
+ case IW_MODE_ADHOC:
+ err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
+ break;
+ case IW_MODE_INFRA:
+ case IW_MODE_AUTO:
+ default:
+ err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
+ break;
+ }
+
+done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ wrqu->mode = priv->ieee->iw_mode;
+ IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
+
+ return 0;
+}
+
+
+#define POWER_MODES 5
+
+/* Values are in microsecond */
+static const s32 timeout_duration[POWER_MODES] = {
+ 350000,
+ 250000,
+ 75000,
+ 37000,
+ 25000,
+};
+
+static const s32 period_duration[POWER_MODES] = {
+ 400000,
+ 700000,
+ 1000000,
+ 1000000,
+ 1000000
+};
+
+static int ipw2100_wx_get_range(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct iw_range *range = (struct iw_range *)extra;
+ u16 val;
+ int i, level;
+
+ wrqu->data.length = sizeof(*range);
+ memset(range, 0, sizeof(*range));
+
+ /* Let's try to keep this struct in the same order as in
+ * linux/include/wireless.h
+ */
+
+ /* TODO: See what values we can set, and remove the ones we can't
+ * set, or fill them with some default data.
+ */
+
+ /* ~5 Mb/s real (802.11b) */
+ range->throughput = 5 * 1000 * 1000;
+
+// range->sensitivity; /* signal level threshold range */
+
+ range->max_qual.qual = 100;
+ /* TODO: Find real max RSSI and stick here */
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+ range->max_qual.updated = 7; /* Updated all three */
+
+ range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
+ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = 7; /* Updated all three */
+
+ range->num_bitrates = RATE_COUNT;
+
+ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
+ range->bitrate[i] = ipw2100_rates_11b[i];
+ }
+
+ range->min_rts = MIN_RTS_THRESHOLD;
+ range->max_rts = MAX_RTS_THRESHOLD;
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->min_pmp = period_duration[0]; /* Minimal PM period */
+ range->max_pmp = period_duration[POWER_MODES-1];/* Maximal PM period */
+ range->min_pmt = timeout_duration[POWER_MODES-1]; /* Minimal PM timeout */
+ range->max_pmt = timeout_duration[0];/* Maximal PM timeout */
+
+ /* How to decode max/min PM period */
+ range->pmp_flags = IW_POWER_PERIOD;
+ /* How to decode max/min PM period */
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ /* What PM options are supported */
+ range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13; /* Different token sizes */
+ range->num_encoding_sizes = 2; /* Number of entry in the list */
+ range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
+// range->encoding_login_index; /* token index for login token */
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ range->txpower_capa = IW_TXPOW_DBM;
+ range->num_txpower = IW_MAX_TXPOWER;
+ for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); i < IW_MAX_TXPOWER;
+ i++, level -= ((IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM) * 16) /
+ (IW_MAX_TXPOWER - 1))
+ range->txpower[i] = level / 16;
+ } else {
+ range->txpower_capa = 0;
+ range->num_txpower = 0;
+ }
+
+
+ /* Set the Wireless Extension versions */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 16;
+
+// range->retry_capa; /* What retry options are supported */
+// range->retry_flags; /* How to decode max/min retry limit */
+// range->r_time_flags; /* How to decode max/min retry life */
+// range->min_retry; /* Minimal number of retries */
+// range->max_retry; /* Maximal number of retries */
+// range->min_r_time; /* Minimal retry lifetime */
+// range->max_r_time; /* Maximal retry lifetime */
+
+ range->num_channels = FREQ_COUNT;
+
+ val = 0;
+ for (i = 0; i < FREQ_COUNT; i++) {
+ // TODO: Include only legal frequencies for some countries
+// if (local->channel_mask & (1 << i)) {
+ range->freq[val].i = i + 1;
+ range->freq[val].m = ipw2100_frequencies[i] * 100000;
+ range->freq[val].e = 1;
+ val++;
+// }
+ if (val == IW_MAX_FREQUENCIES)
+ break;
+ }
+ range->num_frequency = val;
+
+ IPW_DEBUG_WX("GET Range\n");
+
+ return 0;
+}
+
+static int ipw2100_wx_set_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0;
+
+ static const unsigned char any[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+ static const unsigned char off[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ // sanity checks
+ if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
+ !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+ /* we disable mandatory BSSID association */
+ IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
+ priv->config &= ~CFG_STATIC_BSSID;
+ err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
+ goto done;
+ }
+
+ priv->config |= CFG_STATIC_BSSID;
+ memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
+
+ err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
+
+ IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
+ wrqu->ap_addr.sa_data[0] & 0xff,
+ wrqu->ap_addr.sa_data[1] & 0xff,
+ wrqu->ap_addr.sa_data[2] & 0xff,
+ wrqu->ap_addr.sa_data[3] & 0xff,
+ wrqu->ap_addr.sa_data[4] & 0xff,
+ wrqu->ap_addr.sa_data[5] & 0xff);
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ /* If we are associated, trying to associate, or have a statically
+ * configured BSSID then return that; otherwise return ANY */
+ if (priv->config & CFG_STATIC_BSSID ||
+ priv->status & STATUS_ASSOCIATED) {
+ wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+ } else
+ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+ IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
+ MAC_ARG(wrqu->ap_addr.sa_data));
+ return 0;
+}
+
+static int ipw2100_wx_set_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ char *essid = ""; /* ANY */
+ int length = 0;
+ int err = 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (wrqu->essid.flags && wrqu->essid.length) {
+ length = wrqu->essid.length - 1;
+ essid = extra;
+ }
+
+ if (length == 0) {
+ IPW_DEBUG_WX("Setting ESSID to ANY\n");
+ priv->config &= ~CFG_STATIC_ESSID;
+ err = ipw2100_set_essid(priv, NULL, 0, 0);
+ goto done;
+ }
+
+ length = min(length, IW_ESSID_MAX_SIZE);
+
+ priv->config |= CFG_STATIC_ESSID;
+
+ if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
+ IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+ err = 0;
+ goto done;
+ }
+
+ IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
+ length);
+
+ priv->essid_len = length;
+ memcpy(priv->essid, essid, priv->essid_len);
+
+ err = ipw2100_set_essid(priv, essid, length, 0);
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ /* If we are associated, trying to associate, or have a statically
+ * configured ESSID then return that; otherwise return ANY */
+ if (priv->config & CFG_STATIC_ESSID ||
+ priv->status & STATUS_ASSOCIATED) {
+ IPW_DEBUG_WX("Getting essid: '%s'\n",
+ escape_essid(priv->essid, priv->essid_len));
+ memcpy(extra, priv->essid, priv->essid_len);
+ wrqu->essid.length = priv->essid_len;
+ wrqu->essid.flags = 1; /* active */
+ } else {
+ IPW_DEBUG_WX("Getting essid: ANY\n");
+ wrqu->essid.length = 0;
+ wrqu->essid.flags = 0; /* active */
+ }
+
+ return 0;
+}
+
+static int ipw2100_wx_set_nick(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ if (wrqu->data.length > IW_ESSID_MAX_SIZE)
+ return -E2BIG;
+
+ wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick));
+ memset(priv->nick, 0, sizeof(priv->nick));
+ memcpy(priv->nick, extra, wrqu->data.length);
+
+ IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
+
+ return 0;
+}
+
+static int ipw2100_wx_get_nick(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ wrqu->data.length = strlen(priv->nick) + 1;
+ memcpy(extra, priv->nick, wrqu->data.length);
+ wrqu->data.flags = 1; /* active */
+
+ IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
+
+ return 0;
+}
+
+static int ipw2100_wx_set_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ u32 target_rate = wrqu->bitrate.value;
+ u32 rate;
+ int err = 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ rate = 0;
+
+ if (target_rate == 1000000 ||
+ (!wrqu->bitrate.fixed && target_rate > 1000000))
+ rate |= TX_RATE_1_MBIT;
+ if (target_rate == 2000000 ||
+ (!wrqu->bitrate.fixed && target_rate > 2000000))
+ rate |= TX_RATE_2_MBIT;
+ if (target_rate == 5500000 ||
+ (!wrqu->bitrate.fixed && target_rate > 5500000))
+ rate |= TX_RATE_5_5_MBIT;
+ if (target_rate == 11000000 ||
+ (!wrqu->bitrate.fixed && target_rate > 11000000))
+ rate |= TX_RATE_11_MBIT;
+ if (rate == 0)
+ rate = DEFAULT_TX_RATES;
+
+ err = ipw2100_set_tx_rates(priv, rate, 0);
+
+ IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+
+static int ipw2100_wx_get_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int val;
+ int len = sizeof(val);
+ int err = 0;
+
+ if (!(priv->status & STATUS_ENABLED) ||
+ priv->status & STATUS_RF_KILL_MASK ||
+ !(priv->status & STATUS_ASSOCIATED)) {
+ wrqu->bitrate.value = 0;
+ return 0;
+ }
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
+ if (err) {
+ IPW_DEBUG_WX("failed querying ordinals.\n");
+ return err;
+ }
+
+ switch (val & TX_RATE_MASK) {
+ case TX_RATE_1_MBIT:
+ wrqu->bitrate.value = 1000000;
+ break;
+ case TX_RATE_2_MBIT:
+ wrqu->bitrate.value = 2000000;
+ break;
+ case TX_RATE_5_5_MBIT:
+ wrqu->bitrate.value = 5500000;
+ break;
+ case TX_RATE_11_MBIT:
+ wrqu->bitrate.value = 11000000;
+ break;
+ default:
+ wrqu->bitrate.value = 0;
+ }
+
+ IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_set_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int value, err;
+
+ /* Auto RTS not yet supported */
+ if (wrqu->rts.fixed == 0)
+ return -EINVAL;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (wrqu->rts.disabled)
+ value = priv->rts_threshold | RTS_DISABLED;
+ else {
+ if (wrqu->rts.value < 1 ||
+ wrqu->rts.value > 2304) {
+ err = -EINVAL;
+ goto done;
+ }
+ value = wrqu->rts.value;
+ }
+
+ err = ipw2100_set_rts_threshold(priv, value);
+
+ IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
+ wrqu->rts.fixed = 1; /* no auto select */
+
+ /* If RTS is set to the default value, then it is disabled */
+ wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
+
+ IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value);
+
+ return 0;
+}
+
+static int ipw2100_wx_set_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0, value;
+
+ if (priv->ieee->iw_mode != IW_MODE_ADHOC)
+ return -EINVAL;
+
+ if (wrqu->txpower.disabled == 1 || wrqu->txpower.fixed == 0)
+ value = IPW_TX_POWER_DEFAULT;
+ else {
+ if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
+ wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
+ return -EINVAL;
+
+ value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 /
+ (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+ }
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ err = ipw2100_set_tx_power(priv, value);
+
+ IPW_DEBUG_WX("SET TX Power -> %d \n", value);
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ if (priv->ieee->iw_mode != IW_MODE_ADHOC) {
+ wrqu->power.disabled = 1;
+ return 0;
+ }
+
+ if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
+ wrqu->power.fixed = 0;
+ wrqu->power.value = IPW_TX_POWER_MAX_DBM;
+ wrqu->power.disabled = 1;
+ } else {
+ wrqu->power.disabled = 0;
+ wrqu->power.fixed = 1;
+ wrqu->power.value =
+ (priv->tx_power *
+ (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) /
+ (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) +
+ IPW_TX_POWER_MIN_DBM;
+ }
+
+ wrqu->power.flags = IW_TXPOW_DBM;
+
+ IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->power.value);
+
+ return 0;
+}
+
+static int ipw2100_wx_set_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ if (!wrqu->frag.fixed)
+ return -EINVAL;
+
+ if (wrqu->frag.disabled) {
+ priv->frag_threshold |= FRAG_DISABLED;
+ priv->ieee->fts = DEFAULT_FTS;
+ } else {
+ if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+ wrqu->frag.value > MAX_FRAG_THRESHOLD)
+ return -EINVAL;
+
+ priv->ieee->fts = wrqu->frag.value & ~0x1;
+ priv->frag_threshold = priv->ieee->fts;
+ }
+
+ IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts);
+
+ return 0;
+}
+
+static int ipw2100_wx_get_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
+ wrqu->frag.fixed = 0; /* no auto select */
+ wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
+
+ IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+
+ return 0;
+}
+
+static int ipw2100_wx_set_retry(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0;
+
+ if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
+ wrqu->retry.disabled)
+ return -EINVAL;
+
+ if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
+ return 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (wrqu->retry.flags & IW_RETRY_MIN) {
+ err = ipw2100_set_short_retry(priv, wrqu->retry.value);
+ IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
+ wrqu->retry.value);
+ goto done;
+ }
+
+ if (wrqu->retry.flags & IW_RETRY_MAX) {
+ err = ipw2100_set_long_retry(priv, wrqu->retry.value);
+ IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
+ wrqu->retry.value);
+ goto done;
+ }
+
+ err = ipw2100_set_short_retry(priv, wrqu->retry.value);
+ if (!err)
+ err = ipw2100_set_long_retry(priv, wrqu->retry.value);
+
+ IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_retry(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ wrqu->retry.disabled = 0; /* can't be disabled */
+
+ if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
+ IW_RETRY_LIFETIME)
+ return -EINVAL;
+
+ if (wrqu->retry.flags & IW_RETRY_MAX) {
+ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
+ wrqu->retry.value = priv->long_retry_limit;
+ } else {
+ wrqu->retry.flags =
+ (priv->short_retry_limit !=
+ priv->long_retry_limit) ?
+ IW_RETRY_LIMIT & IW_RETRY_MIN : IW_RETRY_LIMIT;
+
+ wrqu->retry.value = priv->short_retry_limit;
+ }
+
+ IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value);
+
+ return 0;
+}
+
+static int ipw2100_wx_set_scan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ IPW_DEBUG_WX("Initiating scan...\n");
+ if (ipw2100_set_scan_options(priv) ||
+ ipw2100_start_scan(priv)) {
+ IPW_DEBUG_WX("Start scan failed.\n");
+
+ /* TODO: Mark a scan as pending so when hardware initialized
+ * a scan starts */
+ }
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_scan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
+}
+
+
+/*
+ * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
+ */
+static int ipw2100_wx_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key)
+{
+ /*
+ * No check of STATUS_INITIALIZED required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw2100_wx_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw2100_wx_set_power(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (wrqu->power.disabled) {
+ priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
+ err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
+ IPW_DEBUG_WX("SET Power Management Mode -> off\n");
+ goto done;
+ }
+
+ switch (wrqu->power.flags & IW_POWER_MODE) {
+ case IW_POWER_ON: /* If not specified */
+ case IW_POWER_MODE: /* If set all mask */
+ case IW_POWER_ALL_R: /* If explicitely state all */
+ break;
+ default: /* Otherwise we don't support it */
+ IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
+ wrqu->power.flags);
+ err = -EOPNOTSUPP;
+ goto done;
+ }
+
+ /* If the user hasn't specified a power management mode yet, default
+ * to BATTERY */
+ priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+ err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
+
+ IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n",
+ priv->power_mode);
+
+ done:
+ up(&priv->action_sem);
+ return err;
+
+}
+
+static int ipw2100_wx_get_power(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+ wrqu->power.disabled = 1;
+ } else {
+ wrqu->power.disabled = 0;
+ wrqu->power.flags = 0;
+ }
+
+ IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
+
+ return 0;
+}
+
+
+/*
+ *
+ * IWPRIV handlers
+ *
+ */
+#ifdef CONFIG_IPW2100_MONITOR
+static int ipw2100_wx_set_promisc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int *parms = (int *)extra;
+ int enable = (parms[0] > 0);
+ int err = 0;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (enable) {
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ err = ipw2100_set_channel(priv, parms[1], 0);
+ goto done;
+ }
+ priv->channel = parms[1];
+ err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
+ } else {
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+ err = ipw2100_switch_mode(priv, priv->last_mode);
+ }
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_reset(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ if (priv->status & STATUS_INITIALIZED)
+ schedule_reset(priv);
+ return 0;
+}
+
+#endif
+
+static int ipw2100_wx_set_powermode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err = 0, mode = *(int *)extra;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if ((mode < 1) || (mode > POWER_MODES))
+ mode = IPW_POWER_AUTO;
+
+ if (priv->power_mode != mode)
+ err = ipw2100_set_power_mode(priv, mode);
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+#define MAX_POWER_STRING 80
+static int ipw2100_wx_get_powermode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int level = IPW_POWER_LEVEL(priv->power_mode);
+ s32 timeout, period;
+
+ if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+ snprintf(extra, MAX_POWER_STRING,
+ "Power save level: %d (Off)", level);
+ } else {
+ switch (level) {
+ case IPW_POWER_MODE_CAM:
+ snprintf(extra, MAX_POWER_STRING,
+ "Power save level: %d (None)", level);
+ break;
+ case IPW_POWER_AUTO:
+ snprintf(extra, MAX_POWER_STRING,
+ "Power save level: %d (Auto)", 0);
+ break;
+ default:
+ timeout = timeout_duration[level - 1] / 1000;
+ period = period_duration[level - 1] / 1000;
+ snprintf(extra, MAX_POWER_STRING,
+ "Power save level: %d "
+ "(Timeout %dms, Period %dms)",
+ level, timeout, period);
+ }
+ }
+
+ wrqu->data.length = strlen(extra) + 1;
+
+ return 0;
+}
+
+
+static int ipw2100_wx_set_preamble(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err, mode = *(int *)extra;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (mode == 1)
+ priv->config |= CFG_LONG_PREAMBLE;
+ else if (mode == 0)
+ priv->config &= ~CFG_LONG_PREAMBLE;
+ else {
+ err = -EINVAL;
+ goto done;
+ }
+
+ err = ipw2100_system_config(priv, 0);
+
+done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_preamble(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ if (priv->config & CFG_LONG_PREAMBLE)
+ snprintf(wrqu->name, IFNAMSIZ, "long (1)");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
+
+ return 0;
+}
+
+static iw_handler ipw2100_wx_handlers[] =
+{
+ NULL, /* SIOCSIWCOMMIT */
+ ipw2100_wx_get_name, /* SIOCGIWNAME */
+ NULL, /* SIOCSIWNWID */
+ NULL, /* SIOCGIWNWID */
+ ipw2100_wx_set_freq, /* SIOCSIWFREQ */
+ ipw2100_wx_get_freq, /* SIOCGIWFREQ */
+ ipw2100_wx_set_mode, /* SIOCSIWMODE */
+ ipw2100_wx_get_mode, /* SIOCGIWMODE */
+ NULL, /* SIOCSIWSENS */
+ NULL, /* SIOCGIWSENS */
+ NULL, /* SIOCSIWRANGE */
+ ipw2100_wx_get_range, /* SIOCGIWRANGE */
+ NULL, /* SIOCSIWPRIV */
+ NULL, /* SIOCGIWPRIV */
+ NULL, /* SIOCSIWSTATS */
+ NULL, /* SIOCGIWSTATS */
+ NULL, /* SIOCSIWSPY */
+ NULL, /* SIOCGIWSPY */
+ NULL, /* SIOCGIWTHRSPY */
+ NULL, /* SIOCWIWTHRSPY */
+ ipw2100_wx_set_wap, /* SIOCSIWAP */
+ ipw2100_wx_get_wap, /* SIOCGIWAP */
+ NULL, /* -- hole -- */
+ NULL, /* SIOCGIWAPLIST -- deprecated */
+ ipw2100_wx_set_scan, /* SIOCSIWSCAN */
+ ipw2100_wx_get_scan, /* SIOCGIWSCAN */
+ ipw2100_wx_set_essid, /* SIOCSIWESSID */
+ ipw2100_wx_get_essid, /* SIOCGIWESSID */
+ ipw2100_wx_set_nick, /* SIOCSIWNICKN */
+ ipw2100_wx_get_nick, /* SIOCGIWNICKN */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ ipw2100_wx_set_rate, /* SIOCSIWRATE */
+ ipw2100_wx_get_rate, /* SIOCGIWRATE */
+ ipw2100_wx_set_rts, /* SIOCSIWRTS */
+ ipw2100_wx_get_rts, /* SIOCGIWRTS */
+ ipw2100_wx_set_frag, /* SIOCSIWFRAG */
+ ipw2100_wx_get_frag, /* SIOCGIWFRAG */
+ ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */
+ ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */
+ ipw2100_wx_set_retry, /* SIOCSIWRETRY */
+ ipw2100_wx_get_retry, /* SIOCGIWRETRY */
+ ipw2100_wx_set_encode, /* SIOCSIWENCODE */
+ ipw2100_wx_get_encode, /* SIOCGIWENCODE */
+ ipw2100_wx_set_power, /* SIOCSIWPOWER */
+ ipw2100_wx_get_power, /* SIOCGIWPOWER */
+};
+
+#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
+#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
+#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
+#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
+#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
+#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
+
+static const struct iw_priv_args ipw2100_private_args[] = {
+
+#ifdef CONFIG_IPW2100_MONITOR
+ {
+ IPW2100_PRIV_SET_MONITOR,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"
+ },
+ {
+ IPW2100_PRIV_RESET,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"
+ },
+#endif /* CONFIG_IPW2100_MONITOR */
+
+ {
+ IPW2100_PRIV_SET_POWER,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"
+ },
+ {
+ IPW2100_PRIV_GET_POWER,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, "get_power"
+ },
+ {
+ IPW2100_PRIV_SET_LONGPREAMBLE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"
+ },
+ {
+ IPW2100_PRIV_GET_LONGPREAMBLE,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"
+ },
+};
+
+static iw_handler ipw2100_private_handler[] = {
+#ifdef CONFIG_IPW2100_MONITOR
+ ipw2100_wx_set_promisc,
+ ipw2100_wx_reset,
+#else /* CONFIG_IPW2100_MONITOR */
+ NULL,
+ NULL,
+#endif /* CONFIG_IPW2100_MONITOR */
+ ipw2100_wx_set_powermode,
+ ipw2100_wx_get_powermode,
+ ipw2100_wx_set_preamble,
+ ipw2100_wx_get_preamble,
+};
+
+static struct iw_handler_def ipw2100_wx_handler_def =
+{
+ .standard = ipw2100_wx_handlers,
+ .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
+ .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
+ .num_private_args = sizeof(ipw2100_private_args) /
+ sizeof(struct iw_priv_args),
+ .private = (iw_handler *)ipw2100_private_handler,
+ .private_args = (struct iw_priv_args *)ipw2100_private_args,
+};
+
+/*
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
+ * Also called by SIOCGIWSTATS
+ */
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
+{
+ enum {
+ POOR = 30,
+ FAIR = 60,
+ GOOD = 80,
+ VERY_GOOD = 90,
+ EXCELLENT = 95,
+ PERFECT = 100
+ };
+ int rssi_qual;
+ int tx_qual;
+ int beacon_qual;
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct iw_statistics *wstats;
+ u32 rssi, quality, tx_retries, missed_beacons, tx_failures;
+ u32 ord_len = sizeof(u32);
+
+ if (!priv)
+ return (struct iw_statistics *) NULL;
+
+ wstats = &priv->wstats;
+
+ /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
+ * ipw2100_wx_wireless_stats seems to be called before fw is
+ * initialized. STATUS_ASSOCIATED will only be set if the hw is up
+ * and associated; if not associcated, the values are all meaningless
+ * anyway, so set them all to NULL and INVALID */
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ wstats->miss.beacon = 0;
+ wstats->discard.retries = 0;
+ wstats->qual.qual = 0;
+ wstats->qual.level = 0;
+ wstats->qual.noise = 0;
+ wstats->qual.updated = 7;
+ wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
+ IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ return wstats;
+ }
+
+ if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
+ &missed_beacons, &ord_len))
+ goto fail_get_ordinal;
+
+ /* If we don't have a connection the quality and level is 0*/
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ wstats->qual.qual = 0;
+ wstats->qual.level = 0;
+ } else {
+ if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
+ &rssi, &ord_len))
+ goto fail_get_ordinal;
+ wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
+ if (rssi < 10)
+ rssi_qual = rssi * POOR / 10;
+ else if (rssi < 15)
+ rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
+ else if (rssi < 20)
+ rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
+ else if (rssi < 30)
+ rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
+ 10 + GOOD;
+ else
+ rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
+ 10 + VERY_GOOD;
+
+ if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
+ &tx_retries, &ord_len))
+ goto fail_get_ordinal;
+
+ if (tx_retries > 75)
+ tx_qual = (90 - tx_retries) * POOR / 15;
+ else if (tx_retries > 70)
+ tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
+ else if (tx_retries > 65)
+ tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
+ else if (tx_retries > 50)
+ tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
+ 15 + GOOD;
+ else
+ tx_qual = (50 - tx_retries) *
+ (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+
+ if (missed_beacons > 50)
+ beacon_qual = (60 - missed_beacons) * POOR / 10;
+ else if (missed_beacons > 40)
+ beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
+ 10 + POOR;
+ else if (missed_beacons > 32)
+ beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
+ 18 + FAIR;
+ else if (missed_beacons > 20)
+ beacon_qual = (32 - missed_beacons) *
+ (VERY_GOOD - GOOD) / 20 + GOOD;
+ else
+ beacon_qual = (20 - missed_beacons) *
+ (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
+
+ quality = min(beacon_qual, min(tx_qual, rssi_qual));
+
+#ifdef CONFIG_IPW_DEBUG
+ if (beacon_qual == quality)
+ IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
+ else if (tx_qual == quality)
+ IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
+ else if (quality != 100)
+ IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
+ else
+ IPW_DEBUG_WX("Quality not clamped.\n");
+#endif
+
+ wstats->qual.qual = quality;
+ wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
+ }
+
+ wstats->qual.noise = 0;
+ wstats->qual.updated = 7;
+ wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
+
+ /* FIXME: this is percent and not a # */
+ wstats->miss.beacon = missed_beacons;
+
+ if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
+ &tx_failures, &ord_len))
+ goto fail_get_ordinal;
+ wstats->discard.retries = tx_failures;
+
+ return wstats;
+
+ fail_get_ordinal:
+ IPW_DEBUG_WX("failed querying ordinals.\n");
+
+ return (struct iw_statistics *) NULL;
+}
+
+static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
+{
+ union iwreq_data wrqu;
+ int len = ETH_ALEN;
+
+ if (priv->status & STATUS_STOPPING)
+ return;
+
+ down(&priv->action_sem);
+
+ IPW_DEBUG_WX("enter\n");
+
+ up(&priv->action_sem);
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /* Fetch BSSID from the hardware */
+ if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
+ priv->status & STATUS_RF_KILL_MASK ||
+ ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
+ &priv->bssid, &len)) {
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ } else {
+ /* We now have the BSSID, so can finish setting to the full
+ * associated state */
+ memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
+ memcpy(&priv->ieee->bssid, priv->bssid, ETH_ALEN);
+ priv->status &= ~STATUS_ASSOCIATING;
+ priv->status |= STATUS_ASSOCIATED;
+ netif_carrier_on(priv->net_dev);
+ if (netif_queue_stopped(priv->net_dev)) {
+ IPW_DEBUG_INFO("Waking net queue.\n");
+ netif_wake_queue(priv->net_dev);
+ } else {
+ IPW_DEBUG_INFO("Starting net queue.\n");
+ netif_start_queue(priv->net_dev);
+ }
+ }
+
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ IPW_DEBUG_WX("Configuring ESSID\n");
+ down(&priv->action_sem);
+ /* This is a disassociation event, so kick the firmware to
+ * look for another AP */
+ if (priv->config & CFG_STATIC_ESSID)
+ ipw2100_set_essid(priv, priv->essid, priv->essid_len, 0);
+ else
+ ipw2100_set_essid(priv, NULL, 0, 0);
+ up(&priv->action_sem);
+ }
+
+ wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+#define IPW2100_FW_MAJOR_VERSION 1
+#define IPW2100_FW_MINOR_VERSION 3
+
+#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
+#define IPW2100_FW_MAJOR(x) (x & 0xff)
+
+#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
+ IPW2100_FW_MAJOR_VERSION)
+
+#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
+"." __stringify(IPW2100_FW_MINOR_VERSION)
+
+#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
+
+
+/*
+
+BINARY FIRMWARE HEADER FORMAT
+
+offset length desc
+0 2 version
+2 2 mode == 0:BSS,1:IBSS,2:MONITOR
+4 4 fw_len
+8 4 uc_len
+C fw_len firmware data
+12 + fw_len uc_len microcode data
+
+*/
+
+struct ipw2100_fw_header {
+ short version;
+ short mode;
+ unsigned int fw_size;
+ unsigned int uc_size;
+} __attribute__ ((packed));
+
+
+
+static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
+{
+ struct ipw2100_fw_header *h =
+ (struct ipw2100_fw_header *)fw->fw_entry->data;
+
+ if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
+ printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
+ "(detected version id of %u). "
+ "See Documentation/networking/README.ipw2100\n",
+ h->version);
+ return 1;
+ }
+
+ fw->version = h->version;
+ fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
+ fw->fw.size = h->fw_size;
+ fw->uc.data = fw->fw.data + h->fw_size;
+ fw->uc.size = h->uc_size;
+
+ return 0;
+}
+
+
+static int ipw2100_get_firmware(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw)
+{
+ char *fw_name;
+ int rc;
+
+ IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
+ priv->net_dev->name);
+
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ fw_name = IPW2100_FW_NAME("-i");
+ break;
+#ifdef CONFIG_IPW2100_MONITOR
+ case IW_MODE_MONITOR:
+ fw_name = IPW2100_FW_NAME("-p");
+ break;
+#endif
+ case IW_MODE_INFRA:
+ default:
+ fw_name = IPW2100_FW_NAME("");
+ break;
+ }
+
+ rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
+
+ if (rc < 0) {
+ printk(KERN_ERR DRV_NAME ": "
+ "%s: Firmware '%s' not available or load failed.\n",
+ priv->net_dev->name, fw_name);
+ return rc;
+ }
+ IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
+ fw->fw_entry->size);
+
+ ipw2100_mod_firmware_load(fw);
+
+ return 0;
+}
+
+static void ipw2100_release_firmware(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw)
+{
+ fw->version = 0;
+ if (fw->fw_entry)
+ release_firmware(fw->fw_entry);
+ fw->fw_entry = NULL;
+}
+
+
+static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
+ size_t max)
+{
+ char ver[MAX_FW_VERSION_LEN];
+ u32 len = MAX_FW_VERSION_LEN;
+ u32 tmp;
+ int i;
+ /* firmware version is an ascii string (max len of 14) */
+ if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM,
+ ver, &len))
+ return -EIO;
+ tmp = max;
+ if (len >= max)
+ len = max - 1;
+ for (i = 0; i < len; i++)
+ buf[i] = ver[i];
+ buf[i] = '\0';
+ return tmp;
+}
+
+static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
+ size_t max)
+{
+ u32 ver;
+ u32 len = sizeof(ver);
+ /* microcode version is a 32 bit integer */
+ if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION,
+ &ver, &len))
+ return -EIO;
+ return snprintf(buf, max, "%08X", ver);
+}
+
+/*
+ * On exit, the firmware will have been freed from the fw list
+ */
+static int ipw2100_fw_download(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw)
+{
+ /* firmware is constructed of N contiguous entries, each entry is
+ * structured as:
+ *
+ * offset sie desc
+ * 0 4 address to write to
+ * 4 2 length of data run
+ * 6 length data
+ */
+ unsigned int addr;
+ unsigned short len;
+
+ const unsigned char *firmware_data = fw->fw.data;
+ unsigned int firmware_data_left = fw->fw.size;
+
+ while (firmware_data_left > 0) {
+ addr = *(u32 *)(firmware_data);
+ firmware_data += 4;
+ firmware_data_left -= 4;
+
+ len = *(u16 *)(firmware_data);
+ firmware_data += 2;
+ firmware_data_left -= 2;
+
+ if (len > 32) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Invalid firmware run-length of %d bytes\n",
+ len);
+ return -EINVAL;
+ }
+
+ write_nic_memory(priv->net_dev, addr, len, firmware_data);
+ firmware_data += len;
+ firmware_data_left -= len;
+ }
+
+ return 0;
+}
+
+struct symbol_alive_response {
+ u8 cmd_id;
+ u8 seq_num;
+ u8 ucode_rev;
+ u8 eeprom_valid;
+ u16 valid_flags;
+ u8 IEEE_addr[6];
+ u16 flags;
+ u16 pcb_rev;
+ u16 clock_settle_time; // 1us LSB
+ u16 powerup_settle_time; // 1us LSB
+ u16 hop_settle_time; // 1us LSB
+ u8 date[3]; // month, day, year
+ u8 time[2]; // hours, minutes
+ u8 ucode_valid;
+};
+
+static int ipw2100_ucode_download(struct ipw2100_priv *priv,
+ struct ipw2100_fw *fw)
+{
+ struct net_device *dev = priv->net_dev;
+ const unsigned char *microcode_data = fw->uc.data;
+ unsigned int microcode_data_left = fw->uc.size;
+ void __iomem *reg = (void __iomem *)dev->base_addr;
+
+ struct symbol_alive_response response;
+ int i, j;
+ u8 data;
+
+ /* Symbol control */
+ write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
+ readl(reg);
+ write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
+ readl(reg);
+
+ /* HW config */
+ write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
+ readl(reg);
+ write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
+ readl(reg);
+
+ /* EN_CS_ACCESS bit to reset control store pointer */
+ write_nic_byte(dev, 0x210000, 0x40);
+ readl(reg);
+ write_nic_byte(dev, 0x210000, 0x0);
+ readl(reg);
+ write_nic_byte(dev, 0x210000, 0x40);
+ readl(reg);
+
+ /* copy microcode from buffer into Symbol */
+
+ while (microcode_data_left > 0) {
+ write_nic_byte(dev, 0x210010, *microcode_data++);
+ write_nic_byte(dev, 0x210010, *microcode_data++);
+ microcode_data_left -= 2;
+ }
+
+ /* EN_CS_ACCESS bit to reset the control store pointer */
+ write_nic_byte(dev, 0x210000, 0x0);
+ readl(reg);
+
+ /* Enable System (Reg 0)
+ * first enable causes garbage in RX FIFO */
+ write_nic_byte(dev, 0x210000, 0x0);
+ readl(reg);
+ write_nic_byte(dev, 0x210000, 0x80);
+ readl(reg);
+
+ /* Reset External Baseband Reg */
+ write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
+ readl(reg);
+ write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
+ readl(reg);
+
+ /* HW Config (Reg 5) */
+ write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
+ readl(reg);
+ write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
+ readl(reg);
+
+ /* Enable System (Reg 0)
+ * second enable should be OK */
+ write_nic_byte(dev, 0x210000, 0x00); // clear enable system
+ readl(reg);
+ write_nic_byte(dev, 0x210000, 0x80); // set enable system
+
+ /* check Symbol is enabled - upped this from 5 as it wasn't always
+ * catching the update */
+ for (i = 0; i < 10; i++) {
+ udelay(10);
+
+ /* check Dino is enabled bit */
+ read_nic_byte(dev, 0x210000, &data);
+ if (data & 0x1)
+ break;
+ }
+
+ if (i == 10) {
+ printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
+ dev->name);
+ return -EIO;
+ }
+
+ /* Get Symbol alive response */
+ for (i = 0; i < 30; i++) {
+ /* Read alive response structure */
+ for (j = 0;
+ j < (sizeof(struct symbol_alive_response) >> 1);
+ j++)
+ read_nic_word(dev, 0x210004,
+ ((u16 *)&response) + j);
+
+ if ((response.cmd_id == 1) &&
+ (response.ucode_valid == 0x1))
+ break;
+ udelay(10);
+ }
+
+ if (i == 30) {
+ printk(KERN_ERR DRV_NAME ": %s: No response from Symbol - hw not alive\n",
+ dev->name);
+ printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response));
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
new file mode 100644
index 0000000..2a3cdbd
--- /dev/null
+++ b/drivers/net/wireless/ipw2100.h
@@ -0,0 +1,1167 @@
+/******************************************************************************
+
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+#ifndef _IPW2100_H
+#define _IPW2100_H
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <asm/io.h>
+#include <linux/socket.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/version.h>
+#include <net/iw_handler.h> // new driver API
+
+#include <net/ieee80211.h>
+
+#include <linux/workqueue.h>
+
+struct ipw2100_priv;
+struct ipw2100_tx_packet;
+struct ipw2100_rx_packet;
+
+#define IPW_DL_UNINIT 0x80000000
+#define IPW_DL_NONE 0x00000000
+#define IPW_DL_ALL 0x7FFFFFFF
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IPW_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your
+ * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw2100/debug_level
+ *
+ * you simply need to add your entry to the ipw2100_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw2100 then you do not have
+ * CONFIG_IPW_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IPW_DL_ERROR (1<<0)
+#define IPW_DL_WARNING (1<<1)
+#define IPW_DL_INFO (1<<2)
+#define IPW_DL_WX (1<<3)
+#define IPW_DL_HC (1<<5)
+#define IPW_DL_STATE (1<<6)
+
+#define IPW_DL_NOTIF (1<<10)
+#define IPW_DL_SCAN (1<<11)
+#define IPW_DL_ASSOC (1<<12)
+#define IPW_DL_DROP (1<<13)
+
+#define IPW_DL_IOCTL (1<<14)
+#define IPW_DL_RF_KILL (1<<17)
+
+
+#define IPW_DL_MANAGE (1<<15)
+#define IPW_DL_FW (1<<16)
+
+#define IPW_DL_FRAG (1<<21)
+#define IPW_DL_WEP (1<<22)
+#define IPW_DL_TX (1<<23)
+#define IPW_DL_RX (1<<24)
+#define IPW_DL_ISR (1<<25)
+#define IPW_DL_IO (1<<26)
+#define IPW_DL_TRACE (1<<28)
+
+#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f)
+#define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f)
+#define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f)
+#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f)
+#define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f)
+#define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f)
+#define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f)
+#define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f)
+#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f)
+#define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f)
+#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f)
+#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f)
+#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f)
+#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f)
+#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f)
+#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f)
+#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f)
+#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+
+enum {
+ IPW_HW_STATE_DISABLED = 1,
+ IPW_HW_STATE_ENABLED = 0
+};
+
+struct ssid_context {
+ char ssid[IW_ESSID_MAX_SIZE + 1];
+ int ssid_len;
+ unsigned char bssid[ETH_ALEN];
+ int port_type;
+ int channel;
+
+};
+
+extern const char *port_type_str[];
+extern const char *band_str[];
+
+#define NUMBER_OF_BD_PER_COMMAND_PACKET 1
+#define NUMBER_OF_BD_PER_DATA_PACKET 2
+
+#define IPW_MAX_BDS 6
+#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2
+#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1
+
+#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \
+ (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET)
+
+struct bd_status {
+ union {
+ struct { u8 nlf:1, txType:2, intEnabled:1, reserved:4;} fields;
+ u8 field;
+ } info;
+} __attribute__ ((packed));
+
+struct ipw2100_bd {
+ u32 host_addr;
+ u32 buf_length;
+ struct bd_status status;
+ /* number of fragments for frame (should be set only for
+ * 1st TBD) */
+ u8 num_fragments;
+ u8 reserved[6];
+} __attribute__ ((packed));
+
+#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
+#define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd))
+
+#define IPW_BD_STATUS_TX_FRAME_802_3 0x00
+#define IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT 0x01
+#define IPW_BD_STATUS_TX_FRAME_COMMAND 0x02
+#define IPW_BD_STATUS_TX_FRAME_802_11 0x04
+#define IPW_BD_STATUS_TX_INTERRUPT_ENABLE 0x08
+
+struct ipw2100_bd_queue {
+ /* driver (virtual) pointer to queue */
+ struct ipw2100_bd *drv;
+
+ /* firmware (physical) pointer to queue */
+ dma_addr_t nic;
+
+ /* Length of phy memory allocated for BDs */
+ u32 size;
+
+ /* Number of BDs in queue (and in array) */
+ u32 entries;
+
+ /* Number of available BDs (invalid for NIC BDs) */
+ u32 available;
+
+ /* Offset of oldest used BD in array (next one to
+ * check for completion) */
+ u32 oldest;
+
+ /* Offset of next available (unused) BD */
+ u32 next;
+};
+
+#define RX_QUEUE_LENGTH 256
+#define TX_QUEUE_LENGTH 256
+#define HW_QUEUE_LENGTH 256
+
+#define TX_PENDED_QUEUE_LENGTH (TX_QUEUE_LENGTH / NUMBER_OF_BD_PER_DATA_PACKET)
+
+#define STATUS_TYPE_MASK 0x0000000f
+#define COMMAND_STATUS_VAL 0
+#define STATUS_CHANGE_VAL 1
+#define P80211_DATA_VAL 2
+#define P8023_DATA_VAL 3
+#define HOST_NOTIFICATION_VAL 4
+
+#define IPW2100_RSSI_TO_DBM (-98)
+
+struct ipw2100_status {
+ u32 frame_size;
+ u16 status_fields;
+ u8 flags;
+#define IPW_STATUS_FLAG_DECRYPTED (1<<0)
+#define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1)
+#define IPW_STATUS_FLAG_CRC_ERROR (1<<2)
+ u8 rssi;
+} __attribute__ ((packed));
+
+struct ipw2100_status_queue {
+ /* driver (virtual) pointer to queue */
+ struct ipw2100_status *drv;
+
+ /* firmware (physical) pointer to queue */
+ dma_addr_t nic;
+
+ /* Length of phy memory allocated for BDs */
+ u32 size;
+};
+
+#define HOST_COMMAND_PARAMS_REG_LEN 100
+#define CMD_STATUS_PARAMS_REG_LEN 3
+
+#define IPW_WPA_CAPABILITIES 0x1
+#define IPW_WPA_LISTENINTERVAL 0x2
+#define IPW_WPA_AP_ADDRESS 0x4
+
+#define IPW_MAX_VAR_IE_LEN ((HOST_COMMAND_PARAMS_REG_LEN - 4) * sizeof(u32))
+
+struct ipw2100_wpa_assoc_frame {
+ u16 fixed_ie_mask;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ u8 current_ap[ETH_ALEN];
+ } fixed_ies;
+ u32 var_ie_len;
+ u8 var_ie[IPW_MAX_VAR_IE_LEN];
+};
+
+#define IPW_BSS 1
+#define IPW_MONITOR 2
+#define IPW_IBSS 3
+
+/**
+ * @struct _tx_cmd - HWCommand
+ * @brief H/W command structure.
+ */
+struct ipw2100_cmd_header {
+ u32 host_command_reg;
+ u32 host_command_reg1;
+ u32 sequence;
+ u32 host_command_len_reg;
+ u32 host_command_params_reg[HOST_COMMAND_PARAMS_REG_LEN];
+ u32 cmd_status_reg;
+ u32 cmd_status_params_reg[CMD_STATUS_PARAMS_REG_LEN];
+ u32 rxq_base_ptr;
+ u32 rxq_next_ptr;
+ u32 rxq_host_ptr;
+ u32 txq_base_ptr;
+ u32 txq_next_ptr;
+ u32 txq_host_ptr;
+ u32 tx_status_reg;
+ u32 reserved;
+ u32 status_change_reg;
+ u32 reserved1[3];
+ u32 *ordinal1_ptr;
+ u32 *ordinal2_ptr;
+} __attribute__ ((packed));
+
+struct ipw2100_data_header {
+ u32 host_command_reg;
+ u32 host_command_reg1;
+ u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver
+ u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC
+ u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key
+ u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
+ u8 key[16];
+ u8 reserved[10]; // f/w reserved
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+ u16 fragment_size;
+} __attribute__ ((packed));
+
+/* Host command data structure */
+struct host_command {
+ u32 host_command; // COMMAND ID
+ u32 host_command1; // COMMAND ID
+ u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
+ u32 host_command_length; // LENGTH
+ u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
+} __attribute__ ((packed));
+
+
+typedef enum {
+ POWER_ON_RESET,
+ EXIT_POWER_DOWN_RESET,
+ SW_RESET,
+ EEPROM_RW,
+ SW_RE_INIT
+} ipw2100_reset_event;
+
+enum {
+ COMMAND = 0xCAFE,
+ DATA,
+ RX
+};
+
+
+struct ipw2100_tx_packet {
+ int type;
+ int index;
+ union {
+ struct { /* COMMAND */
+ struct ipw2100_cmd_header* cmd;
+ dma_addr_t cmd_phys;
+ } c_struct;
+ struct { /* DATA */
+ struct ipw2100_data_header* data;
+ dma_addr_t data_phys;
+ struct ieee80211_txb *txb;
+ } d_struct;
+ } info;
+ int jiffy_start;
+
+ struct list_head list;
+};
+
+
+struct ipw2100_rx_packet {
+ struct ipw2100_rx *rxp;
+ dma_addr_t dma_addr;
+ int jiffy_start;
+ struct sk_buff *skb;
+ struct list_head list;
+};
+
+#define FRAG_DISABLED (1<<31)
+#define RTS_DISABLED (1<<31)
+#define MAX_RTS_THRESHOLD 2304U
+#define MIN_RTS_THRESHOLD 1U
+#define DEFAULT_RTS_THRESHOLD 1000U
+
+#define DEFAULT_BEACON_INTERVAL 100U
+#define DEFAULT_SHORT_RETRY_LIMIT 7U
+#define DEFAULT_LONG_RETRY_LIMIT 4U
+
+struct ipw2100_ordinals {
+ u32 table1_addr;
+ u32 table2_addr;
+ u32 table1_size;
+ u32 table2_size;
+};
+
+/* Host Notification header */
+struct ipw2100_notification {
+ u32 hnhdr_subtype; /* type of host notification */
+ u32 hnhdr_size; /* size in bytes of data
+ or number of entries, if table.
+ Does NOT include header */
+} __attribute__ ((packed));
+
+#define MAX_KEY_SIZE 16
+#define MAX_KEYS 8
+
+#define IPW2100_WEP_ENABLE (1<<1)
+#define IPW2100_WEP_DROP_CLEAR (1<<2)
+
+#define IPW_NONE_CIPHER (1<<0)
+#define IPW_WEP40_CIPHER (1<<1)
+#define IPW_TKIP_CIPHER (1<<2)
+#define IPW_CCMP_CIPHER (1<<4)
+#define IPW_WEP104_CIPHER (1<<5)
+#define IPW_CKIP_CIPHER (1<<6)
+
+#define IPW_AUTH_OPEN 0
+#define IPW_AUTH_SHARED 1
+
+struct statistic {
+ int value;
+ int hi;
+ int lo;
+};
+
+#define INIT_STAT(x) do { \
+ (x)->value = (x)->hi = 0; \
+ (x)->lo = 0x7fffffff; \
+} while (0)
+#define SET_STAT(x,y) do { \
+ (x)->value = y; \
+ if ((x)->value > (x)->hi) (x)->hi = (x)->value; \
+ if ((x)->value < (x)->lo) (x)->lo = (x)->value; \
+} while (0)
+#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \
+while (0)
+#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \
+while (0)
+
+#define IPW2100_ERROR_QUEUE 5
+
+/* Power management code: enable or disable? */
+enum {
+#ifdef CONFIG_PM
+ IPW2100_PM_DISABLED = 0,
+ PM_STATE_SIZE = 16,
+#else
+ IPW2100_PM_DISABLED = 1,
+ PM_STATE_SIZE = 0,
+#endif
+};
+
+#define STATUS_POWERED (1<<0)
+#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */
+#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */
+#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */
+#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */
+#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */
+#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */
+#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */
+#define STATUS_INT_ENABLED (1<<11)
+#define STATUS_RF_KILL_HW (1<<12)
+#define STATUS_RF_KILL_SW (1<<13)
+#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
+#define STATUS_EXIT_PENDING (1<<14)
+
+#define STATUS_SCAN_PENDING (1<<23)
+#define STATUS_SCANNING (1<<24)
+#define STATUS_SCAN_ABORTING (1<<25)
+#define STATUS_SCAN_COMPLETE (1<<26)
+#define STATUS_WX_EVENT_PENDING (1<<27)
+#define STATUS_RESET_PENDING (1<<29)
+#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
+
+
+
+/* Internal NIC states */
+#define IPW_STATE_INITIALIZED (1<<0)
+#define IPW_STATE_COUNTRY_FOUND (1<<1)
+#define IPW_STATE_ASSOCIATED (1<<2)
+#define IPW_STATE_ASSN_LOST (1<<3)
+#define IPW_STATE_ASSN_CHANGED (1<<4)
+#define IPW_STATE_SCAN_COMPLETE (1<<5)
+#define IPW_STATE_ENTERED_PSP (1<<6)
+#define IPW_STATE_LEFT_PSP (1<<7)
+#define IPW_STATE_RF_KILL (1<<8)
+#define IPW_STATE_DISABLED (1<<9)
+#define IPW_STATE_POWER_DOWN (1<<10)
+#define IPW_STATE_SCANNING (1<<11)
+
+
+
+#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
+#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
+#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
+#define CFG_CUSTOM_MAC (1<<3)
+#define CFG_LONG_PREAMBLE (1<<4)
+#define CFG_ASSOCIATE (1<<6)
+#define CFG_FIXED_RATE (1<<7)
+#define CFG_ADHOC_CREATE (1<<8)
+#define CFG_C3_DISABLED (1<<9)
+#define CFG_PASSIVE_SCAN (1<<10)
+
+#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
+#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
+
+struct ipw2100_priv {
+
+ int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
+ int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
+
+ struct ieee80211_device *ieee;
+ unsigned long status;
+ unsigned long config;
+ unsigned long capability;
+
+ /* Statistics */
+ int resets;
+ int reset_backoff;
+
+ /* Context */
+ u8 essid[IW_ESSID_MAX_SIZE];
+ u8 essid_len;
+ u8 bssid[ETH_ALEN];
+ u8 channel;
+ int last_mode;
+ int cstate_limit;
+
+ unsigned long connect_start;
+ unsigned long last_reset;
+
+ u32 channel_mask;
+ u32 fatal_error;
+ u32 fatal_errors[IPW2100_ERROR_QUEUE];
+ u32 fatal_index;
+ int eeprom_version;
+ int firmware_version;
+ unsigned long hw_features;
+ int hangs;
+ u32 last_rtc;
+ int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
+ u8* snapshot[0x30];
+
+ u8 mandatory_bssid_mac[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
+
+ int power_mode;
+
+ /* WEP data */
+ struct ieee80211_security sec;
+ int messages_sent;
+
+
+ int short_retry_limit;
+ int long_retry_limit;
+
+ u32 rts_threshold;
+ u32 frag_threshold;
+
+ int in_isr;
+
+ u32 tx_rates;
+ int tx_power;
+ u32 beacon_interval;
+
+ char nick[IW_ESSID_MAX_SIZE + 1];
+
+ struct ipw2100_status_queue status_queue;
+
+ struct statistic txq_stat;
+ struct statistic rxq_stat;
+ struct ipw2100_bd_queue rx_queue;
+ struct ipw2100_bd_queue tx_queue;
+ struct ipw2100_rx_packet *rx_buffers;
+
+ struct statistic fw_pend_stat;
+ struct list_head fw_pend_list;
+
+ struct statistic msg_free_stat;
+ struct statistic msg_pend_stat;
+ struct list_head msg_free_list;
+ struct list_head msg_pend_list;
+ struct ipw2100_tx_packet *msg_buffers;
+
+ struct statistic tx_free_stat;
+ struct statistic tx_pend_stat;
+ struct list_head tx_free_list;
+ struct list_head tx_pend_list;
+ struct ipw2100_tx_packet *tx_buffers;
+
+ struct ipw2100_ordinals ordinals;
+
+ struct pci_dev *pci_dev;
+
+ struct proc_dir_entry *dir_dev;
+
+ struct net_device *net_dev;
+ struct iw_statistics wstats;
+
+ struct tasklet_struct irq_tasklet;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct reset_work;
+ struct work_struct security_work;
+ struct work_struct wx_event_work;
+ struct work_struct hang_check;
+ struct work_struct rf_kill;
+
+ u32 interrupts;
+ int tx_interrupts;
+ int rx_interrupts;
+ int inta_other;
+
+ spinlock_t low_lock;
+ struct semaphore action_sem;
+ struct semaphore adapter_sem;
+
+ wait_queue_head_t wait_command_queue;
+};
+
+
+/*********************************************************
+ * Host Command -> From Driver to FW
+ *********************************************************/
+
+/**
+ * Host command identifiers
+ */
+#define HOST_COMPLETE 2
+#define SYSTEM_CONFIG 6
+#define SSID 8
+#define MANDATORY_BSSID 9
+#define AUTHENTICATION_TYPE 10
+#define ADAPTER_ADDRESS 11
+#define PORT_TYPE 12
+#define INTERNATIONAL_MODE 13
+#define CHANNEL 14
+#define RTS_THRESHOLD 15
+#define FRAG_THRESHOLD 16
+#define POWER_MODE 17
+#define TX_RATES 18
+#define BASIC_TX_RATES 19
+#define WEP_KEY_INFO 20
+#define WEP_KEY_INDEX 25
+#define WEP_FLAGS 26
+#define ADD_MULTICAST 27
+#define CLEAR_ALL_MULTICAST 28
+#define BEACON_INTERVAL 29
+#define ATIM_WINDOW 30
+#define CLEAR_STATISTICS 31
+#define SEND 33
+#define TX_POWER_INDEX 36
+#define BROADCAST_SCAN 43
+#define CARD_DISABLE 44
+#define PREFERRED_BSSID 45
+#define SET_SCAN_OPTIONS 46
+#define SCAN_DWELL_TIME 47
+#define SWEEP_TABLE 48
+#define AP_OR_STATION_TABLE 49
+#define GROUP_ORDINALS 50
+#define SHORT_RETRY_LIMIT 51
+#define LONG_RETRY_LIMIT 52
+
+#define HOST_PRE_POWER_DOWN 58
+#define CARD_DISABLE_PHY_OFF 61
+#define MSDU_TX_RATES 62
+
+
+/* Rogue AP Detection */
+#define SET_STATION_STAT_BITS 64
+#define CLEAR_STATIONS_STAT_BITS 65
+#define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP
+#define SET_SECURITY_INFORMATION 67
+#define DISASSOCIATION_BSSID 68
+#define SET_WPA_IE 69
+
+
+
+/* system configuration bit mask: */
+#define IPW_CFG_MONITOR 0x00004
+#define IPW_CFG_PREAMBLE_AUTO 0x00010
+#define IPW_CFG_IBSS_AUTO_START 0x00020
+#define IPW_CFG_LOOPBACK 0x00100
+#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800
+#define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000
+#define IPW_CFG_802_1x_ENABLE 0x04000
+#define IPW_CFG_BSS_MASK 0x08000
+#define IPW_CFG_IBSS_MASK 0x10000
+
+#define IPW_SCAN_NOASSOCIATE (1<<0)
+#define IPW_SCAN_MIXED_CELL (1<<1)
+/* RESERVED (1<<2) */
+#define IPW_SCAN_PASSIVE (1<<3)
+
+#define IPW_NIC_FATAL_ERROR 0x2A7F0
+#define IPW_ERROR_ADDR(x) (x & 0x3FFFF)
+#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24)
+#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24)
+#define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24)
+#define IPW2100_ERR_FW_LOAD (0x12 << 24)
+
+#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200
+#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80
+
+#define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40)
+#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44)
+#define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48)
+#define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0)
+
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00)
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04)
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80)
+
+#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \
+ (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20)
+
+#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \
+ (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND)
+
+#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180)
+#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184)
+
+#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB)
+#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1
+#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2
+#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3
+#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4
+#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5
+#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16
+#define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24
+#define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25
+#define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30
+#define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB)
+
+#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001)
+#define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002)
+#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004)
+#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008)
+#define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080)
+#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100)
+#define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200)
+
+#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB)
+#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1
+#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2
+#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10
+#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9
+#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10
+#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29
+#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30
+#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB)
+
+#define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C
+#define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0
+#define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008
+#define IPW_BIT_GPIO_RF_KILL 0x00010000
+
+#define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1
+
+#define IPW_REG_DOMAIN_0_OFFSET 0x0000
+#define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND
+
+#define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008
+#define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C
+#define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010
+#define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014
+#define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018
+#define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C
+#define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020
+#define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024
+#define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030
+#define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188
+#define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C
+#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190
+
+#define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC
+
+#define IPW_INTERRUPT_MASK 0xC1010013
+
+#define IPW2100_CONTROL_REG 0x220000
+#define IPW2100_CONTROL_PHY_OFF 0x8
+
+#define IPW2100_COMMAND 0x00300004
+#define IPW2100_COMMAND_PHY_ON 0x0
+#define IPW2100_COMMAND_PHY_OFF 0x1
+
+/* in DEBUG_AREA, values of memory always 0xd55555d5 */
+#define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090
+#define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF
+#define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5
+
+#define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0
+
+#define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds
+#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds
+#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds
+
+// BD ring queue read/write difference
+#define IPW_BD_QUEUE_W_R_MIN_SPARE 2
+
+#define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80
+
+#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
+#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
+
+
+
+
+#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr)
+#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
+#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
+#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536
+#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60
+#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \
+ (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \
+ sizeof(struct ethhdr))
+
+#define IPW_802_11_FCS_LENGTH 4
+#define IPW_RX_NIC_BUFFER_LENGTH \
+ (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \
+ IPW_802_11_FCS_LENGTH)
+
+#define IPW_802_11_PAYLOAD_OFFSET \
+ (sizeof(struct ieee80211_hdr_3addr) + \
+ sizeof(struct ieee80211_snap_hdr))
+
+struct ipw2100_rx {
+ union {
+ unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
+ struct ieee80211_hdr header;
+ u32 status;
+ struct ipw2100_notification notification;
+ struct ipw2100_cmd_header command;
+ } rx_data;
+} __attribute__ ((packed));
+
+/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */
+#define TX_RATE_1_MBIT 0x0001
+#define TX_RATE_2_MBIT 0x0002
+#define TX_RATE_5_5_MBIT 0x0004
+#define TX_RATE_11_MBIT 0x0008
+#define TX_RATE_MASK 0x000F
+#define DEFAULT_TX_RATES 0x000F
+
+#define IPW_POWER_MODE_CAM 0x00 //(always on)
+#define IPW_POWER_INDEX_1 0x01
+#define IPW_POWER_INDEX_2 0x02
+#define IPW_POWER_INDEX_3 0x03
+#define IPW_POWER_INDEX_4 0x04
+#define IPW_POWER_INDEX_5 0x05
+#define IPW_POWER_AUTO 0x06
+#define IPW_POWER_MASK 0x0F
+#define IPW_POWER_ENABLED 0x10
+#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
+
+#define IPW_TX_POWER_AUTO 0
+#define IPW_TX_POWER_ENHANCED 1
+
+#define IPW_TX_POWER_DEFAULT 32
+#define IPW_TX_POWER_MIN 0
+#define IPW_TX_POWER_MAX 16
+#define IPW_TX_POWER_MIN_DBM (-12)
+#define IPW_TX_POWER_MAX_DBM 16
+
+#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan
+#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan
+
+#define REG_MIN_CHANNEL 0
+#define REG_MAX_CHANNEL 14
+
+#define REG_CHANNEL_MASK 0x00003FFF
+#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff
+
+#define DIVERSITY_EITHER 0 // Use both antennas
+#define DIVERSITY_ANTENNA_A 1 // Use antenna A
+#define DIVERSITY_ANTENNA_B 2 // Use antenna B
+
+
+#define HOST_COMMAND_WAIT 0
+#define HOST_COMMAND_NO_WAIT 1
+
+#define LOCK_NONE 0
+#define LOCK_DRIVER 1
+#define LOCK_FW 2
+
+#define TYPE_SWEEP_ORD 0x000D
+#define TYPE_IBSS_STTN_ORD 0x000E
+#define TYPE_BSS_AP_ORD 0x000F
+#define TYPE_RAW_BEACON_ENTRY 0x0010
+#define TYPE_CALIBRATION_DATA 0x0011
+#define TYPE_ROGUE_AP_DATA 0x0012
+#define TYPE_ASSOCIATION_REQUEST 0x0013
+#define TYPE_REASSOCIATION_REQUEST 0x0014
+
+
+#define HW_FEATURE_RFKILL (0x0001)
+#define RF_KILLSWITCH_OFF (1)
+#define RF_KILLSWITCH_ON (0)
+
+#define IPW_COMMAND_POOL_SIZE 40
+
+#define IPW_START_ORD_TAB_1 1
+#define IPW_START_ORD_TAB_2 1000
+
+#define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32)
+
+#define IS_ORDINAL_TABLE_ONE(mgr,id) \
+ ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size))
+#define IS_ORDINAL_TABLE_TWO(mgr,id) \
+ ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2)))
+
+#define BSS_ID_LENGTH 6
+
+// Fixed size data: Ordinal Table 1
+typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
+// Transmit statistics
+ IPW_ORD_STAT_TX_HOST_REQUESTS = 1,// # of requested Host Tx's (MSDU)
+ IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU)
+ IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU)
+
+ IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB
+ IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB
+ IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB
+ IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB
+ IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB
+
+ IPW_ORD_STAT_TX_NODIR_DATA1 = 13,// # of successful Non_Directed Tx's (MSDU) @ 1MB
+ IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB
+ IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB
+ IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB
+
+ IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's
+ IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS
+ IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS
+ IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK
+ IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's
+ IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's
+ IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's
+ IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's
+ IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted
+ IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted
+ IPW_ORD_STAT_TX_BEACON, // # of tx beacon
+ IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM
+ IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX
+ IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx
+ IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX
+
+ IPW_ORD_STAT_TX_TOTAL_BYTES = 41,// Total successful Tx data bytes
+ IPW_ORD_STAT_TX_RETRIES, // # of Tx retries
+ IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS
+ IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS
+ IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS
+ IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS
+
+ IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures
+ IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time
+ IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,// # of times max tries in a hop failed
+ IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup
+ IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted
+ IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed
+ IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames
+ IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent
+ IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks
+
+ // Receive statistics
+ IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host
+ IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets
+ IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB
+ IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB
+ IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB
+ IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB
+ IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB
+
+ IPW_ORD_STAT_RX_NODIR_DATA = 71,// # of nondirected packets
+ IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB
+ IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB
+ IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB
+ IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB
+
+ IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's
+ IPW_ORD_STAT_RX_POLL, //NS // # of poll rx
+ IPW_ORD_STAT_RX_RTS, // # of Rx RTS
+ IPW_ORD_STAT_RX_CTS, // # of Rx CTS
+ IPW_ORD_STAT_RX_ACK, // # of Rx ACK
+ IPW_ORD_STAT_RX_CFEND, // # of Rx CF End
+ IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack
+ IPW_ORD_STAT_RX_ASSN, // # of Association Rx's
+ IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's
+ IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's
+ IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's
+ IPW_ORD_STAT_RX_PROBE, // # of probe Rx's
+ IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's
+ IPW_ORD_STAT_RX_BEACON, // # of Rx beacon
+ IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM
+ IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx
+ IPW_ORD_STAT_RX_AUTH, // # of authentication Rx
+ IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx
+
+ IPW_ORD_STAT_RX_TOTAL_BYTES = 101,// Total rx data bytes received
+ IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error
+ IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB
+ IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB
+ IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB
+ IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB
+
+ IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
+ IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB
+ IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB
+ IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB
+ IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
+
+ IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db
+ IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db
+ IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db
+ IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol
+ IPW_ORD_SYS_BOOT_TIME, // # Boot time
+ IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer
+ IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late
+ IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop
+ IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment
+ IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment
+ IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame
+ IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame
+ IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused)
+ IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption
+
+// PSP Statistics
+ IPW_ORD_STAT_PSP_SUSPENSION = 137,// # of times adapter suspended
+ IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout
+ IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts
+ IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,// # of timeouts waiting for last broadcast/muticast pkt
+ IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received
+ IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received
+ IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID
+
+// Association and roaming
+ IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association
+ IPW_ORD_STAT_PERCENT_MISSED_BCNS,// current calculation of % missed beacons
+ IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries
+ IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated
+ // AP table entry. set to 0 if not associated
+ IPW_ORD_AVAILABLE_AP_CNT, // # of AP's decsribed in the AP table
+ IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs
+ IPW_ORD_STAT_AP_ASSNS, // # of associations
+ IPW_ORD_STAT_ASSN_FAIL, // # of association failures
+ IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail
+ IPW_ORD_STAT_FULL_SCANS, // # of full scans
+
+ IPW_ORD_CARD_DISABLED, // # Card Disabled
+ IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity
+ IPW_FILLER_40,
+ IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association
+ IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N
+ // hops or no prob_ responses in last 3 minutes
+ IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality
+ IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive
+ // load at the AP
+ IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below
+ // eligible group
+ IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling
+ IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap
+ IPW_FILLER_41,
+ IPW_FILLER_42,
+ IPW_FILLER_43,
+ IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed
+ IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed
+ IPW_ORD_STATION_TABLE_CNT, // # of entries in association table
+
+// Other statistics
+ IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI
+ IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word
+ IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word
+ IPW_ORD_SELF_TEST_STATUS, //NS //
+ IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP
+ IPW_ORD_POWER_MGMT_INDEX, //NS //
+ IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon
+ IPW_ORD_COUNTRY_CHANNELS, // channels suported by country
+// IPW_ORD_COUNTRY_CHANNELS:
+// For 11b the lower 2-byte are used for channels from 1-14
+// and the higher 2-byte are not used.
+ IPW_ORD_RESET_CNT, // # of adapter resets (warm)
+ IPW_ORD_BEACON_INTERVAL, // Beacon interval
+
+ IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version
+ IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled
+ IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed)
+ IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated
+ IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs
+ IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID
+
+ IPW_ORD_RTC_TIME = 190, // current RTC time
+ IPW_ORD_PORT_TYPE, // operating mode
+ IPW_ORD_CURRENT_TX_RATE, // current tx rate
+ IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates
+ IPW_ORD_ATIM_WINDOW, // current ATIM Window
+ IPW_ORD_BASIC_RATES, // bitmap of basic tx rates
+ IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates
+ IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates
+ IPW_ORD_CAPABILITIES, // Management frame capability field
+ IPW_ORD_AUTH_TYPE, // Type of authentication
+ IPW_ORD_RADIO_TYPE, // Adapter card platform type
+ IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used
+ IPW_ORD_INT_MODE, // International mode
+ IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold
+ IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM
+ IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM
+ IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 =
+ IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set
+
+ IPW_ORD_MAC_VERSION = 209, // MAC Version
+ IPW_ORD_MAC_REVISION, // MAC Revision
+ IPW_ORD_RADIO_VERSION, // Radio Version
+ IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP
+ IPW_ORD_UCODE_VERSION, // Ucode Version
+ IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State
+} ORDINALTABLE1;
+
+// ordinal table 2
+// Variable length data:
+#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001
+
+typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW
+ IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs
+ IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address
+ IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP
+ IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP
+ IPW_FILL_1, //NS //
+ IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code
+ IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String
+ IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans)
+ IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans)
+ IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log
+ IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log
+ IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures
+ IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011")
+ IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002")
+ IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP
+ IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes:
+ IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII
+ IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date
+ IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018,
+} ORDINALTABLE2; // NS - means Not Supported by FW
+
+#define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY // enable iwspy support
+#endif
+
+#define IPW_HOST_FW_SHARED_AREA0 0x0002f200
+#define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes
+
+#define IPW_HOST_FW_SHARED_AREA1 0x0002f610
+#define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes
+
+#define IPW_HOST_FW_SHARED_AREA2 0x0002fa00
+#define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes
+
+#define IPW_HOST_FW_SHARED_AREA3 0x0002fc00
+#define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes
+
+#define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80
+#define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes
+
+struct ipw2100_fw_chunk {
+ unsigned char *buf;
+ long len;
+ long pos;
+ struct list_head list;
+};
+
+struct ipw2100_fw_chunk_set {
+ const void *data;
+ unsigned long size;
+};
+
+struct ipw2100_fw {
+ int version;
+ struct ipw2100_fw_chunk_set fw;
+ struct ipw2100_fw_chunk_set uc;
+ const struct firmware *fw_entry;
+};
+
+#define MAX_FW_VERSION_LEN 14
+
+#endif /* _IPW2100_H */
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
new file mode 100644
index 0000000..b7f275c
--- /dev/null
+++ b/drivers/net/wireless/ipw2200.c
@@ -0,0 +1,7383 @@
+/******************************************************************************
+
+ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+
+ 802.11 status code portion of this file from ethereal-0.10.6:
+ Copyright 2000, Axis Communications AB
+ Ethereal - Network traffic analyzer
+ By Gerald Combs <gerald@ethereal.com>
+ Copyright 1998 Gerald Combs
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#include "ipw2200.h"
+
+#define IPW2200_VERSION "1.0.0"
+#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation"
+#define DRV_VERSION IPW2200_VERSION
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+static int channel = 0;
+static char *ifname;
+static int mode = 0;
+
+static u32 ipw_debug_level;
+static int associate = 1;
+static int auto_create = 1;
+static int disable = 0;
+static const char ipw_modes[] = {
+ 'a', 'b', 'g', '?'
+};
+
+static void ipw_rx(struct ipw_priv *priv);
+static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
+ struct clx2_tx_queue *txq, int qindex);
+static int ipw_queue_reset(struct ipw_priv *priv);
+
+static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
+ int len, int sync);
+
+static void ipw_tx_queue_free(struct ipw_priv *);
+
+static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
+static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
+static void ipw_rx_queue_replenish(void *);
+
+static int ipw_up(struct ipw_priv *);
+static void ipw_down(struct ipw_priv *);
+static int ipw_config(struct ipw_priv *);
+static int init_supported_rates(struct ipw_priv *priv,
+ struct ipw_supported_rates *prates);
+
+static u8 band_b_active_channel[MAX_B_CHANNELS] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0
+};
+static u8 band_a_active_channel[MAX_A_CHANNELS] = {
+ 36, 40, 44, 48, 149, 153, 157, 161, 165, 52, 56, 60, 64, 0
+};
+
+static int is_valid_channel(int mode_mask, int channel)
+{
+ int i;
+
+ if (!channel)
+ return 0;
+
+ if (mode_mask & IEEE_A)
+ for (i = 0; i < MAX_A_CHANNELS; i++)
+ if (band_a_active_channel[i] == channel)
+ return IEEE_A;
+
+ if (mode_mask & (IEEE_B | IEEE_G))
+ for (i = 0; i < MAX_B_CHANNELS; i++)
+ if (band_b_active_channel[i] == channel)
+ return mode_mask & (IEEE_B | IEEE_G);
+
+ return 0;
+}
+
+static char *snprint_line(char *buf, size_t count,
+ const u8 * data, u32 len, u32 ofs)
+{
+ int out, i, j, l;
+ char c;
+
+ out = snprintf(buf, count, "%08X", ofs);
+
+ for (l = 0, i = 0; i < 2; i++) {
+ out += snprintf(buf + out, count - out, " ");
+ for (j = 0; j < 8 && l < len; j++, l++)
+ out += snprintf(buf + out, count - out, "%02X ",
+ data[(i * 8 + j)]);
+ for (; j < 8; j++)
+ out += snprintf(buf + out, count - out, " ");
+ }
+
+ out += snprintf(buf + out, count - out, " ");
+ for (l = 0, i = 0; i < 2; i++) {
+ out += snprintf(buf + out, count - out, " ");
+ for (j = 0; j < 8 && l < len; j++, l++) {
+ c = data[(i * 8 + j)];
+ if (!isascii(c) || !isprint(c))
+ c = '.';
+
+ out += snprintf(buf + out, count - out, "%c", c);
+ }
+
+ for (; j < 8; j++)
+ out += snprintf(buf + out, count - out, " ");
+ }
+
+ return buf;
+}
+
+static void printk_buf(int level, const u8 * data, u32 len)
+{
+ char line[81];
+ u32 ofs = 0;
+ if (!(ipw_debug_level & level))
+ return;
+
+ while (len) {
+ printk(KERN_DEBUG "%s\n",
+ snprint_line(line, sizeof(line), &data[ofs],
+ min(len, 16U), ofs));
+ ofs += 16;
+ len -= min(len, 16U);
+ }
+}
+
+static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
+#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
+
+static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);
+#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)
+
+static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);
+static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c)
+{
+ IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__,
+ __LINE__, (u32) (b), (u32) (c));
+ _ipw_write_reg8(a, b, c);
+}
+
+static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);
+static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c)
+{
+ IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__,
+ __LINE__, (u32) (b), (u32) (c));
+ _ipw_write_reg16(a, b, c);
+}
+
+static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);
+static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
+{
+ IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__,
+ __LINE__, (u32) (b), (u32) (c));
+ _ipw_write_reg32(a, b, c);
+}
+
+#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
+#define ipw_write8(ipw, ofs, val) \
+ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
+ _ipw_write8(ipw, ofs, val)
+
+#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))
+#define ipw_write16(ipw, ofs, val) \
+ IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
+ _ipw_write16(ipw, ofs, val)
+
+#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))
+#define ipw_write32(ipw, ofs, val) \
+ IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
+ _ipw_write32(ipw, ofs, val)
+
+#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs))
+static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+{
+ IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs));
+ return _ipw_read8(ipw, ofs);
+}
+
+#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs)
+
+#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs))
+static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+{
+ IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs));
+ return _ipw_read16(ipw, ofs);
+}
+
+#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs)
+
+#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))
+static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+{
+ IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs));
+ return _ipw_read32(ipw, ofs);
+}
+
+#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
+
+static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
+#define ipw_read_indirect(a, b, c, d) \
+ IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
+ _ipw_read_indirect(a, b, c, d)
+
+static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
+ int num);
+#define ipw_write_indirect(a, b, c, d) \
+ IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
+ _ipw_write_indirect(a, b, c, d)
+
+/* indirect write s */
+static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
+{
+ IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
+ _ipw_write32(priv, CX2_INDIRECT_DATA, value);
+}
+
+static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
+{
+ IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+ _ipw_write8(priv, CX2_INDIRECT_DATA, value);
+ IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n",
+ (unsigned long)(priv->hw_base + CX2_INDIRECT_DATA), value);
+}
+
+static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
+{
+ IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+ _ipw_write16(priv, CX2_INDIRECT_DATA, value);
+}
+
+/* indirect read s */
+
+static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
+{
+ u32 word;
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+ IPW_DEBUG_IO(" reg = 0x%8X : \n", reg);
+ word = _ipw_read32(priv, CX2_INDIRECT_DATA);
+ return (word >> ((reg & 0x3) * 8)) & 0xff;
+}
+
+static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
+{
+ u32 value;
+
+ IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
+
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
+ value = _ipw_read32(priv, CX2_INDIRECT_DATA);
+ IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value);
+ return value;
+}
+
+/* iterative/auto-increment 32 bit reads and writes */
+static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
+ int num)
+{
+ u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+ u32 dif_len = addr - aligned_addr;
+ u32 aligned_len;
+ u32 i;
+
+ IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
+
+ /* Read the first nibble byte by byte */
+ if (unlikely(dif_len)) {
+ /* Start reading at aligned_addr + dif_len */
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+ for (i = dif_len; i < 4; i++, buf++)
+ *buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i);
+ num -= dif_len;
+ aligned_addr += 4;
+ }
+
+ /* Read DWs through autoinc register */
+ _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
+ aligned_len = num & CX2_INDIRECT_ADDR_MASK;
+ for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+ *(u32 *) buf = ipw_read32(priv, CX2_AUTOINC_DATA);
+
+ /* Copy the last nibble */
+ dif_len = num - aligned_len;
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+ for (i = 0; i < dif_len; i++, buf++)
+ *buf = ipw_read8(priv, CX2_INDIRECT_DATA + i);
+}
+
+static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
+ int num)
+{
+ u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+ u32 dif_len = addr - aligned_addr;
+ u32 aligned_len;
+ u32 i;
+
+ IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
+
+ /* Write the first nibble byte by byte */
+ if (unlikely(dif_len)) {
+ /* Start writing at aligned_addr + dif_len */
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+ for (i = dif_len; i < 4; i++, buf++)
+ _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
+ num -= dif_len;
+ aligned_addr += 4;
+ }
+
+ /* Write DWs through autoinc register */
+ _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
+ aligned_len = num & CX2_INDIRECT_ADDR_MASK;
+ for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
+ _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf);
+
+ /* Copy the last nibble */
+ dif_len = num - aligned_len;
+ _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
+ for (i = 0; i < dif_len; i++, buf++)
+ _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
+}
+
+static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
+ int num)
+{
+ memcpy_toio((priv->hw_base + addr), buf, num);
+}
+
+static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask)
+{
+ ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);
+}
+
+static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
+{
+ ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
+}
+
+static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+{
+ if (priv->status & STATUS_INT_ENABLED)
+ return;
+ priv->status |= STATUS_INT_ENABLED;
+ ipw_write32(priv, CX2_INTA_MASK_R, CX2_INTA_MASK_ALL);
+}
+
+static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+{
+ if (!(priv->status & STATUS_INT_ENABLED))
+ return;
+ priv->status &= ~STATUS_INT_ENABLED;
+ ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+}
+
+static char *ipw_error_desc(u32 val)
+{
+ switch (val) {
+ case IPW_FW_ERROR_OK:
+ return "ERROR_OK";
+ case IPW_FW_ERROR_FAIL:
+ return "ERROR_FAIL";
+ case IPW_FW_ERROR_MEMORY_UNDERFLOW:
+ return "MEMORY_UNDERFLOW";
+ case IPW_FW_ERROR_MEMORY_OVERFLOW:
+ return "MEMORY_OVERFLOW";
+ case IPW_FW_ERROR_BAD_PARAM:
+ return "ERROR_BAD_PARAM";
+ case IPW_FW_ERROR_BAD_CHECKSUM:
+ return "ERROR_BAD_CHECKSUM";
+ case IPW_FW_ERROR_NMI_INTERRUPT:
+ return "ERROR_NMI_INTERRUPT";
+ case IPW_FW_ERROR_BAD_DATABASE:
+ return "ERROR_BAD_DATABASE";
+ case IPW_FW_ERROR_ALLOC_FAIL:
+ return "ERROR_ALLOC_FAIL";
+ case IPW_FW_ERROR_DMA_UNDERRUN:
+ return "ERROR_DMA_UNDERRUN";
+ case IPW_FW_ERROR_DMA_STATUS:
+ return "ERROR_DMA_STATUS";
+ case IPW_FW_ERROR_DINOSTATUS_ERROR:
+ return "ERROR_DINOSTATUS_ERROR";
+ case IPW_FW_ERROR_EEPROMSTATUS_ERROR:
+ return "ERROR_EEPROMSTATUS_ERROR";
+ case IPW_FW_ERROR_SYSASSERT:
+ return "ERROR_SYSASSERT";
+ case IPW_FW_ERROR_FATAL_ERROR:
+ return "ERROR_FATALSTATUS_ERROR";
+ default:
+ return "UNKNOWNSTATUS_ERROR";
+ }
+}
+
+static void ipw_dump_nic_error_log(struct ipw_priv *priv)
+{
+ u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base;
+
+ base = ipw_read32(priv, IPWSTATUS_ERROR_LOG);
+ count = ipw_read_reg32(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IPW_ERROR("Start IPW Error Log Dump:\n");
+ IPW_ERROR("Status: 0x%08X, Config: %08X\n",
+ priv->status, priv->config);
+ }
+
+ for (i = ERROR_START_OFFSET;
+ i <= count * ERROR_ELEM_SIZE; i += ERROR_ELEM_SIZE) {
+ desc = ipw_read_reg32(priv, base + i);
+ time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
+ blink1 = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
+ blink2 = ipw_read_reg32(priv, base + i + 3 * sizeof(u32));
+ ilink1 = ipw_read_reg32(priv, base + i + 4 * sizeof(u32));
+ ilink2 = ipw_read_reg32(priv, base + i + 5 * sizeof(u32));
+ idata = ipw_read_reg32(priv, base + i + 6 * sizeof(u32));
+
+ IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ipw_error_desc(desc), time, blink1, blink2,
+ ilink1, ilink2, idata);
+ }
+}
+
+static void ipw_dump_nic_event_log(struct ipw_priv *priv)
+{
+ u32 ev, time, data, i, count, base;
+
+ base = ipw_read32(priv, IPW_EVENT_LOG);
+ count = ipw_read_reg32(priv, base);
+
+ if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE)
+ IPW_ERROR("Start IPW Event Log Dump:\n");
+
+ for (i = EVENT_START_OFFSET;
+ i <= count * EVENT_ELEM_SIZE; i += EVENT_ELEM_SIZE) {
+ ev = ipw_read_reg32(priv, base + i);
+ time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
+ data = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
+
+#ifdef CONFIG_IPW_DEBUG
+ IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev);
+#endif
+ }
+}
+
+static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
+{
+ u32 addr, field_info, field_len, field_count, total_len;
+
+ IPW_DEBUG_ORD("ordinal = %i\n", ord);
+
+ if (!priv || !val || !len) {
+ IPW_DEBUG_ORD("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ /* verify device ordinal tables have been initialized */
+ if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) {
+ IPW_DEBUG_ORD("Access ordinals before initialization\n");
+ return -EINVAL;
+ }
+
+ switch (IPW_ORD_TABLE_ID_MASK & ord) {
+ case IPW_ORD_TABLE_0_MASK:
+ /*
+ * TABLE 0: Direct access to a table of 32 bit values
+ *
+ * This is a very simple table with the data directly
+ * read from the table
+ */
+
+ /* remove the table id from the ordinal */
+ ord &= IPW_ORD_TABLE_VALUE_MASK;
+
+ /* boundary check */
+ if (ord > priv->table0_len) {
+ IPW_DEBUG_ORD("ordinal value (%i) longer then "
+ "max (%i)\n", ord, priv->table0_len);
+ return -EINVAL;
+ }
+
+ /* verify we have enough room to store the value */
+ if (*len < sizeof(u32)) {
+ IPW_DEBUG_ORD("ordinal buffer length too small, "
+ "need %zd\n", sizeof(u32));
+ return -EINVAL;
+ }
+
+ IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n",
+ ord, priv->table0_addr + (ord << 2));
+
+ *len = sizeof(u32);
+ ord <<= 2;
+ *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord);
+ break;
+
+ case IPW_ORD_TABLE_1_MASK:
+ /*
+ * TABLE 1: Indirect access to a table of 32 bit values
+ *
+ * This is a fairly large table of u32 values each
+ * representing starting addr for the data (which is
+ * also a u32)
+ */
+
+ /* remove the table id from the ordinal */
+ ord &= IPW_ORD_TABLE_VALUE_MASK;
+
+ /* boundary check */
+ if (ord > priv->table1_len) {
+ IPW_DEBUG_ORD("ordinal value too long\n");
+ return -EINVAL;
+ }
+
+ /* verify we have enough room to store the value */
+ if (*len < sizeof(u32)) {
+ IPW_DEBUG_ORD("ordinal buffer length too small, "
+ "need %zd\n", sizeof(u32));
+ return -EINVAL;
+ }
+
+ *((u32 *) val) =
+ ipw_read_reg32(priv, (priv->table1_addr + (ord << 2)));
+ *len = sizeof(u32);
+ break;
+
+ case IPW_ORD_TABLE_2_MASK:
+ /*
+ * TABLE 2: Indirect access to a table of variable sized values
+ *
+ * This table consist of six values, each containing
+ * - dword containing the starting offset of the data
+ * - dword containing the lengh in the first 16bits
+ * and the count in the second 16bits
+ */
+
+ /* remove the table id from the ordinal */
+ ord &= IPW_ORD_TABLE_VALUE_MASK;
+
+ /* boundary check */
+ if (ord > priv->table2_len) {
+ IPW_DEBUG_ORD("ordinal value too long\n");
+ return -EINVAL;
+ }
+
+ /* get the address of statistic */
+ addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3));
+
+ /* get the second DW of statistics ;
+ * two 16-bit words - first is length, second is count */
+ field_info =
+ ipw_read_reg32(priv,
+ priv->table2_addr + (ord << 3) +
+ sizeof(u32));
+
+ /* get each entry length */
+ field_len = *((u16 *) & field_info);
+
+ /* get number of entries */
+ field_count = *(((u16 *) & field_info) + 1);
+
+ /* abort if not enought memory */
+ total_len = field_len * field_count;
+ if (total_len > *len) {
+ *len = total_len;
+ return -EINVAL;
+ }
+
+ *len = total_len;
+ if (!total_len)
+ return 0;
+
+ IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, "
+ "field_info = 0x%08x\n",
+ addr, total_len, field_info);
+ ipw_read_indirect(priv, addr, val, total_len);
+ break;
+
+ default:
+ IPW_DEBUG_ORD("Invalid ordinal!\n");
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+static void ipw_init_ordinals(struct ipw_priv *priv)
+{
+ priv->table0_addr = IPW_ORDINALS_TABLE_LOWER;
+ priv->table0_len = ipw_read32(priv, priv->table0_addr);
+
+ IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n",
+ priv->table0_addr, priv->table0_len);
+
+ priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1);
+ priv->table1_len = ipw_read_reg32(priv, priv->table1_addr);
+
+ IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n",
+ priv->table1_addr, priv->table1_len);
+
+ priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2);
+ priv->table2_len = ipw_read_reg32(priv, priv->table2_addr);
+ priv->table2_len &= 0x0000ffff; /* use first two bytes */
+
+ IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n",
+ priv->table2_addr, priv->table2_len);
+
+}
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
+ * used for controling the debug level.
+ *
+ * See the level definitions in ipw for details.
+ */
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+ return sprintf(buf, "0x%08X\n", ipw_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ p++;
+ if (p[0] == 'x' || p[0] == 'X')
+ p++;
+ val = simple_strtoul(p, &p, 16);
+ } else
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ ipw_debug_level = val;
+
+ return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+static ssize_t show_status(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->config);
+}
+
+static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+
+static ssize_t show_nic_type(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw_priv *p = d->driver_data;
+ u8 type = p->eeprom[EEPROM_NIC_TYPE];
+
+ switch (type) {
+ case EEPROM_NIC_TYPE_STANDARD:
+ return sprintf(buf, "STANDARD\n");
+ case EEPROM_NIC_TYPE_DELL:
+ return sprintf(buf, "DELL\n");
+ case EEPROM_NIC_TYPE_FUJITSU:
+ return sprintf(buf, "FUJITSU\n");
+ case EEPROM_NIC_TYPE_IBM:
+ return sprintf(buf, "IBM\n");
+ case EEPROM_NIC_TYPE_HP:
+ return sprintf(buf, "HP\n");
+ }
+
+ return sprintf(buf, "UNKNOWN\n");
+}
+
+static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ ipw_dump_nic_error_log((struct ipw_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ ipw_dump_nic_event_log((struct ipw_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+static ssize_t show_ucode_version(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ u32 len = sizeof(u32), tmp = 0;
+ struct ipw_priv *p = d->driver_data;
+
+ if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len))
+ return 0;
+
+ return sprintf(buf, "0x%08x\n", tmp);
+}
+
+static DEVICE_ATTR(ucode_version, S_IWUSR | S_IRUGO, show_ucode_version, NULL);
+
+static ssize_t show_rtc(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ u32 len = sizeof(u32), tmp = 0;
+ struct ipw_priv *p = d->driver_data;
+
+ if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len))
+ return 0;
+
+ return sprintf(buf, "0x%08x\n", tmp);
+}
+
+static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL);
+
+/*
+ * Add a device attribute to view/control the delay between eeprom
+ * operations.
+ */
+static ssize_t show_eeprom_delay(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ int n = ((struct ipw_priv *)d->driver_data)->eeprom_delay;
+ return sprintf(buf, "%i\n", n);
+}
+static ssize_t store_eeprom_delay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *p = d->driver_data;
+ sscanf(buf, "%i", &p->eeprom_delay);
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO,
+ show_eeprom_delay, store_eeprom_delay);
+
+static ssize_t show_command_event_reg(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ u32 reg = 0;
+ struct ipw_priv *p = d->driver_data;
+
+ reg = ipw_read_reg32(p, CX2_INTERNAL_CMD_EVENT);
+ return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_command_event_reg(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 reg;
+ struct ipw_priv *p = d->driver_data;
+
+ sscanf(buf, "%x", ®);
+ ipw_write_reg32(p, CX2_INTERNAL_CMD_EVENT, reg);
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(command_event_reg, S_IWUSR | S_IRUGO,
+ show_command_event_reg, store_command_event_reg);
+
+static ssize_t show_mem_gpio_reg(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ u32 reg = 0;
+ struct ipw_priv *p = d->driver_data;
+
+ reg = ipw_read_reg32(p, 0x301100);
+ return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_mem_gpio_reg(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 reg;
+ struct ipw_priv *p = d->driver_data;
+
+ sscanf(buf, "%x", ®);
+ ipw_write_reg32(p, 0x301100, reg);
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO,
+ show_mem_gpio_reg, store_mem_gpio_reg);
+
+static ssize_t show_indirect_dword(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ u32 reg = 0;
+ struct ipw_priv *priv = d->driver_data;
+ if (priv->status & STATUS_INDIRECT_DWORD)
+ reg = ipw_read_reg32(priv, priv->indirect_dword);
+ else
+ reg = 0;
+
+ return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_indirect_dword(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = d->driver_data;
+
+ sscanf(buf, "%x", &priv->indirect_dword);
+ priv->status |= STATUS_INDIRECT_DWORD;
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(indirect_dword, S_IWUSR | S_IRUGO,
+ show_indirect_dword, store_indirect_dword);
+
+static ssize_t show_indirect_byte(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ u8 reg = 0;
+ struct ipw_priv *priv = d->driver_data;
+ if (priv->status & STATUS_INDIRECT_BYTE)
+ reg = ipw_read_reg8(priv, priv->indirect_byte);
+ else
+ reg = 0;
+
+ return sprintf(buf, "0x%02x\n", reg);
+}
+static ssize_t store_indirect_byte(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = d->driver_data;
+
+ sscanf(buf, "%x", &priv->indirect_byte);
+ priv->status |= STATUS_INDIRECT_BYTE;
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO,
+ show_indirect_byte, store_indirect_byte);
+
+static ssize_t show_direct_dword(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ u32 reg = 0;
+ struct ipw_priv *priv = d->driver_data;
+
+ if (priv->status & STATUS_DIRECT_DWORD)
+ reg = ipw_read32(priv, priv->direct_dword);
+ else
+ reg = 0;
+
+ return sprintf(buf, "0x%08x\n", reg);
+}
+static ssize_t store_direct_dword(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = d->driver_data;
+
+ sscanf(buf, "%x", &priv->direct_dword);
+ priv->status |= STATUS_DIRECT_DWORD;
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
+ show_direct_dword, store_direct_dword);
+
+static inline int rf_kill_active(struct ipw_priv *priv)
+{
+ if (0 == (ipw_read32(priv, 0x30) & 0x10000))
+ priv->status |= STATUS_RF_KILL_HW;
+ else
+ priv->status &= ~STATUS_RF_KILL_HW;
+
+ return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
+}
+
+static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ /* 0 - RF kill not enabled
+ 1 - SW based RF kill active (sysfs)
+ 2 - HW based RF kill active
+ 3 - Both HW and SW baed RF kill active */
+ struct ipw_priv *priv = d->driver_data;
+ int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
+ (rf_kill_active(priv) ? 0x2 : 0x0);
+ return sprintf(buf, "%i\n", val);
+}
+
+static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
+{
+ if ((disable_radio ? 1 : 0) ==
+ (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
+ return 0;
+
+ IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
+ disable_radio ? "OFF" : "ON");
+
+ if (disable_radio) {
+ priv->status |= STATUS_RF_KILL_SW;
+
+ if (priv->workqueue) {
+ cancel_delayed_work(&priv->request_scan);
+ }
+ wake_up_interruptible(&priv->wait_command_queue);
+ queue_work(priv->workqueue, &priv->down);
+ } else {
+ priv->status &= ~STATUS_RF_KILL_SW;
+ if (rf_kill_active(priv)) {
+ IPW_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by HW switch\n");
+ /* Make sure the RF_KILL check timer is running */
+ cancel_delayed_work(&priv->rf_kill);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ 2 * HZ);
+ } else
+ queue_work(priv->workqueue, &priv->up);
+ }
+
+ return 1;
+}
+
+static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = d->driver_data;
+
+ ipw_radio_kill_sw(priv, buf[0] == '1');
+
+ return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static void ipw_irq_tasklet(struct ipw_priv *priv)
+{
+ u32 inta, inta_mask, handled = 0;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ inta = ipw_read32(priv, CX2_INTA_RW);
+ inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
+ inta &= (CX2_INTA_MASK_ALL & inta_mask);
+
+ /* Add any cached INTA values that need to be handled */
+ inta |= priv->isr_inta;
+
+ /* handle all the justifications for the interrupt */
+ if (inta & CX2_INTA_BIT_RX_TRANSFER) {
+ ipw_rx(priv);
+ handled |= CX2_INTA_BIT_RX_TRANSFER;
+ }
+
+ if (inta & CX2_INTA_BIT_TX_CMD_QUEUE) {
+ IPW_DEBUG_HC("Command completed.\n");
+ rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
+ priv->status &= ~STATUS_HCMD_ACTIVE;
+ wake_up_interruptible(&priv->wait_command_queue);
+ handled |= CX2_INTA_BIT_TX_CMD_QUEUE;
+ }
+
+ if (inta & CX2_INTA_BIT_TX_QUEUE_1) {
+ IPW_DEBUG_TX("TX_QUEUE_1\n");
+ rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
+ handled |= CX2_INTA_BIT_TX_QUEUE_1;
+ }
+
+ if (inta & CX2_INTA_BIT_TX_QUEUE_2) {
+ IPW_DEBUG_TX("TX_QUEUE_2\n");
+ rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
+ handled |= CX2_INTA_BIT_TX_QUEUE_2;
+ }
+
+ if (inta & CX2_INTA_BIT_TX_QUEUE_3) {
+ IPW_DEBUG_TX("TX_QUEUE_3\n");
+ rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
+ handled |= CX2_INTA_BIT_TX_QUEUE_3;
+ }
+
+ if (inta & CX2_INTA_BIT_TX_QUEUE_4) {
+ IPW_DEBUG_TX("TX_QUEUE_4\n");
+ rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
+ handled |= CX2_INTA_BIT_TX_QUEUE_4;
+ }
+
+ if (inta & CX2_INTA_BIT_STATUS_CHANGE) {
+ IPW_WARNING("STATUS_CHANGE\n");
+ handled |= CX2_INTA_BIT_STATUS_CHANGE;
+ }
+
+ if (inta & CX2_INTA_BIT_BEACON_PERIOD_EXPIRED) {
+ IPW_WARNING("TX_PERIOD_EXPIRED\n");
+ handled |= CX2_INTA_BIT_BEACON_PERIOD_EXPIRED;
+ }
+
+ if (inta & CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
+ IPW_WARNING("HOST_CMD_DONE\n");
+ handled |= CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
+ }
+
+ if (inta & CX2_INTA_BIT_FW_INITIALIZATION_DONE) {
+ IPW_WARNING("FW_INITIALIZATION_DONE\n");
+ handled |= CX2_INTA_BIT_FW_INITIALIZATION_DONE;
+ }
+
+ if (inta & CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
+ IPW_WARNING("PHY_OFF_DONE\n");
+ handled |= CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
+ }
+
+ if (inta & CX2_INTA_BIT_RF_KILL_DONE) {
+ IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
+ priv->status |= STATUS_RF_KILL_HW;
+ wake_up_interruptible(&priv->wait_command_queue);
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+ cancel_delayed_work(&priv->request_scan);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
+ handled |= CX2_INTA_BIT_RF_KILL_DONE;
+ }
+
+ if (inta & CX2_INTA_BIT_FATAL_ERROR) {
+ IPW_ERROR("Firmware error detected. Restarting.\n");
+#ifdef CONFIG_IPW_DEBUG
+ if (ipw_debug_level & IPW_DL_FW_ERRORS) {
+ ipw_dump_nic_error_log(priv);
+ ipw_dump_nic_event_log(priv);
+ }
+#endif
+ queue_work(priv->workqueue, &priv->adapter_restart);
+ handled |= CX2_INTA_BIT_FATAL_ERROR;
+ }
+
+ if (inta & CX2_INTA_BIT_PARITY_ERROR) {
+ IPW_ERROR("Parity error\n");
+ handled |= CX2_INTA_BIT_PARITY_ERROR;
+ }
+
+ if (handled != inta) {
+ IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+ }
+
+ /* enable all interrupts */
+ ipw_enable_interrupts(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
+static char *get_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ IPW_CMD(HOST_COMPLETE);
+ IPW_CMD(POWER_DOWN);
+ IPW_CMD(SYSTEM_CONFIG);
+ IPW_CMD(MULTICAST_ADDRESS);
+ IPW_CMD(SSID);
+ IPW_CMD(ADAPTER_ADDRESS);
+ IPW_CMD(PORT_TYPE);
+ IPW_CMD(RTS_THRESHOLD);
+ IPW_CMD(FRAG_THRESHOLD);
+ IPW_CMD(POWER_MODE);
+ IPW_CMD(WEP_KEY);
+ IPW_CMD(TGI_TX_KEY);
+ IPW_CMD(SCAN_REQUEST);
+ IPW_CMD(SCAN_REQUEST_EXT);
+ IPW_CMD(ASSOCIATE);
+ IPW_CMD(SUPPORTED_RATES);
+ IPW_CMD(SCAN_ABORT);
+ IPW_CMD(TX_FLUSH);
+ IPW_CMD(QOS_PARAMETERS);
+ IPW_CMD(DINO_CONFIG);
+ IPW_CMD(RSN_CAPABILITIES);
+ IPW_CMD(RX_KEY);
+ IPW_CMD(CARD_DISABLE);
+ IPW_CMD(SEED_NUMBER);
+ IPW_CMD(TX_POWER);
+ IPW_CMD(COUNTRY_INFO);
+ IPW_CMD(AIRONET_INFO);
+ IPW_CMD(AP_TX_POWER);
+ IPW_CMD(CCKM_INFO);
+ IPW_CMD(CCX_VER_INFO);
+ IPW_CMD(SET_CALIBRATION);
+ IPW_CMD(SENSITIVITY_CALIB);
+ IPW_CMD(RETRY_LIMIT);
+ IPW_CMD(IPW_PRE_POWER_DOWN);
+ IPW_CMD(VAP_BEACON_TEMPLATE);
+ IPW_CMD(VAP_DTIM_PERIOD);
+ IPW_CMD(EXT_SUPPORTED_RATES);
+ IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT);
+ IPW_CMD(VAP_QUIET_INTERVALS);
+ IPW_CMD(VAP_CHANNEL_SWITCH);
+ IPW_CMD(VAP_MANDATORY_CHANNELS);
+ IPW_CMD(VAP_CELL_PWR_LIMIT);
+ IPW_CMD(VAP_CF_PARAM_SET);
+ IPW_CMD(VAP_SET_BEACONING_STATE);
+ IPW_CMD(MEASUREMENT);
+ IPW_CMD(POWER_CAPABILITY);
+ IPW_CMD(SUPPORTED_CHANNELS);
+ IPW_CMD(TPC_REPORT);
+ IPW_CMD(WME_INFO);
+ IPW_CMD(PRODUCTION_COMMAND);
+ default:
+ return "UNKNOWN";
+ }
+}
+#endif /* CONFIG_IPW_DEBUG */
+
+#define HOST_COMPLETE_TIMEOUT HZ
+static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
+{
+ int rc = 0;
+
+ if (priv->status & STATUS_HCMD_ACTIVE) {
+ IPW_ERROR("Already sending a command\n");
+ return -1;
+ }
+
+ priv->status |= STATUS_HCMD_ACTIVE;
+
+ IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
+ get_cmd_string(cmd->cmd), cmd->cmd, cmd->len);
+ printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
+
+ rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0);
+ if (rc)
+ return rc;
+
+ rc = wait_event_interruptible_timeout(priv->wait_command_queue,
+ !(priv->
+ status & STATUS_HCMD_ACTIVE),
+ HOST_COMPLETE_TIMEOUT);
+ if (rc == 0) {
+ IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
+ jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+ priv->status &= ~STATUS_HCMD_ACTIVE;
+ return -EIO;
+ }
+ if (priv->status & STATUS_RF_KILL_MASK) {
+ IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ipw_send_host_complete(struct ipw_priv *priv)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_HOST_COMPLETE,
+ .len = 0
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send HOST_COMPLETE command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_system_config(struct ipw_priv *priv,
+ struct ipw_sys_config *config)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SYSTEM_CONFIG,
+ .len = sizeof(*config)
+ };
+
+ if (!priv || !config) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, config, sizeof(*config));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SYSTEM_CONFIG command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SSID,
+ .len = min(len, IW_ESSID_MAX_SIZE)
+ };
+
+ if (!priv || !ssid) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, ssid, cmd.len);
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SSID command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_ADAPTER_ADDRESS,
+ .len = ETH_ALEN
+ };
+
+ if (!priv || !mac) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
+ priv->net_dev->name, MAC_ARG(mac));
+
+ memcpy(&cmd.param, mac, ETH_ALEN);
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send ADAPTER_ADDRESS command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ipw_adapter_restart(void *adapter)
+{
+ struct ipw_priv *priv = adapter;
+
+ if (priv->status & STATUS_RF_KILL_MASK)
+ return;
+
+ ipw_down(priv);
+ if (ipw_up(priv)) {
+ IPW_ERROR("Failed to up device\n");
+ return;
+ }
+}
+
+#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
+
+static void ipw_scan_check(void *data)
+{
+ struct ipw_priv *priv = data;
+ if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
+ IPW_DEBUG_SCAN("Scan completion watchdog resetting "
+ "adapter (%dms).\n",
+ IPW_SCAN_CHECK_WATCHDOG / 100);
+ ipw_adapter_restart(priv);
+ }
+}
+
+static int ipw_send_scan_request_ext(struct ipw_priv *priv,
+ struct ipw_scan_request_ext *request)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SCAN_REQUEST_EXT,
+ .len = sizeof(*request)
+ };
+
+ if (!priv || !request) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, request, sizeof(*request));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n");
+ return -1;
+ }
+
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IPW_SCAN_CHECK_WATCHDOG);
+ return 0;
+}
+
+static int ipw_send_scan_abort(struct ipw_priv *priv)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SCAN_ABORT,
+ .len = 0
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SCAN_ABORT command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SENSITIVITY_CALIB,
+ .len = sizeof(struct ipw_sensitivity_calib)
+ };
+ struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *)
+ &cmd.param;
+ calib->beacon_rssi_raw = sens;
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SENSITIVITY CALIB command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_associate(struct ipw_priv *priv,
+ struct ipw_associate *associate)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_ASSOCIATE,
+ .len = sizeof(*associate)
+ };
+
+ if (!priv || !associate) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, associate, sizeof(*associate));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send ASSOCIATE command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_supported_rates(struct ipw_priv *priv,
+ struct ipw_supported_rates *rates)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SUPPORTED_RATES,
+ .len = sizeof(*rates)
+ };
+
+ if (!priv || !rates) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, rates, sizeof(*rates));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SUPPORTED_RATES command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_set_random_seed(struct ipw_priv *priv)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_SEED_NUMBER,
+ .len = sizeof(u32)
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ get_random_bytes(&cmd.param, sizeof(u32));
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send SEED_NUMBER command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+#if 0
+static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_CARD_DISABLE,
+ .len = sizeof(u32)
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ *((u32 *) & cmd.param) = phy_off;
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send CARD_DISABLE command\n");
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_TX_POWER,
+ .len = sizeof(*power)
+ };
+
+ if (!priv || !power) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, power, sizeof(*power));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send TX_POWER command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
+{
+ struct ipw_rts_threshold rts_threshold = {
+ .rts_threshold = rts,
+ };
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_RTS_THRESHOLD,
+ .len = sizeof(rts_threshold)
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send RTS_THRESHOLD command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
+{
+ struct ipw_frag_threshold frag_threshold = {
+ .frag_threshold = frag,
+ };
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_FRAG_THRESHOLD,
+ .len = sizeof(frag_threshold)
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold));
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send FRAG_THRESHOLD command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_POWER_MODE,
+ .len = sizeof(u32)
+ };
+ u32 *param = (u32 *) (&cmd.param);
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
+ return -1;
+ }
+
+ /* If on battery, set to 3, if AC set to CAM, else user
+ * level */
+ switch (mode) {
+ case IPW_POWER_BATTERY:
+ *param = IPW_POWER_INDEX_3;
+ break;
+ case IPW_POWER_AC:
+ *param = IPW_POWER_MODE_CAM;
+ break;
+ default:
+ *param = mode;
+ break;
+ }
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send POWER_MODE command\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * The IPW device contains a Microwire compatible EEPROM that stores
+ * various data like the MAC address. Usually the firmware has exclusive
+ * access to the eeprom, but during device initialization (before the
+ * device driver has sent the HostComplete command to the firmware) the
+ * device driver has read access to the EEPROM by way of indirect addressing
+ * through a couple of memory mapped registers.
+ *
+ * The following is a simplified implementation for pulling data out of the
+ * the eeprom, along with some helper functions to find information in
+ * the per device private data's copy of the eeprom.
+ *
+ * NOTE: To better understand how these functions work (i.e what is a chip
+ * select and why do have to keep driving the eeprom clock?), read
+ * just about any data sheet for a Microwire compatible EEPROM.
+ */
+
+/* write a 32 bit value into the indirect accessor register */
+static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
+{
+ ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data);
+
+ /* the eeprom requires some time to complete the operation */
+ udelay(p->eeprom_delay);
+
+ return;
+}
+
+/* perform a chip select operation */
+static inline void eeprom_cs(struct ipw_priv *priv)
+{
+ eeprom_write_reg(priv, 0);
+ eeprom_write_reg(priv, EEPROM_BIT_CS);
+ eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
+ eeprom_write_reg(priv, EEPROM_BIT_CS);
+}
+
+/* perform a chip select operation */
+static inline void eeprom_disable_cs(struct ipw_priv *priv)
+{
+ eeprom_write_reg(priv, EEPROM_BIT_CS);
+ eeprom_write_reg(priv, 0);
+ eeprom_write_reg(priv, EEPROM_BIT_SK);
+}
+
+/* push a single bit down to the eeprom */
+static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit)
+{
+ int d = (bit ? EEPROM_BIT_DI : 0);
+ eeprom_write_reg(p, EEPROM_BIT_CS | d);
+ eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK);
+}
+
+/* push an opcode followed by an address down to the eeprom */
+static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr)
+{
+ int i;
+
+ eeprom_cs(priv);
+ eeprom_write_bit(priv, 1);
+ eeprom_write_bit(priv, op & 2);
+ eeprom_write_bit(priv, op & 1);
+ for (i = 7; i >= 0; i--) {
+ eeprom_write_bit(priv, addr & (1 << i));
+ }
+}
+
+/* pull 16 bits off the eeprom, one bit at a time */
+static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr)
+{
+ int i;
+ u16 r = 0;
+
+ /* Send READ Opcode */
+ eeprom_op(priv, EEPROM_CMD_READ, addr);
+
+ /* Send dummy bit */
+ eeprom_write_reg(priv, EEPROM_BIT_CS);
+
+ /* Read the byte off the eeprom one bit at a time */
+ for (i = 0; i < 16; i++) {
+ u32 data = 0;
+ eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
+ eeprom_write_reg(priv, EEPROM_BIT_CS);
+ data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS);
+ r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0);
+ }
+
+ /* Send another dummy bit */
+ eeprom_write_reg(priv, 0);
+ eeprom_disable_cs(priv);
+
+ return r;
+}
+
+/* helper function for pulling the mac address out of the private */
+/* data's copy of the eeprom data */
+static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
+{
+ u8 *ee = (u8 *) priv->eeprom;
+ memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6);
+}
+
+/*
+ * Either the device driver (i.e. the host) or the firmware can
+ * load eeprom data into the designated region in SRAM. If neither
+ * happens then the FW will shutdown with a fatal error.
+ *
+ * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE
+ * bit needs region of shared SRAM needs to be non-zero.
+ */
+static void ipw_eeprom_init_sram(struct ipw_priv *priv)
+{
+ int i;
+ u16 *eeprom = (u16 *) priv->eeprom;
+
+ IPW_DEBUG_TRACE(">>\n");
+
+ /* read entire contents of eeprom into private buffer */
+ for (i = 0; i < 128; i++)
+ eeprom[i] = eeprom_read_u16(priv, (u8) i);
+
+ /*
+ If the data looks correct, then copy it to our private
+ copy. Otherwise let the firmware know to perform the operation
+ on it's own
+ */
+ if ((priv->eeprom + EEPROM_VERSION) != 0) {
+ IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
+
+ /* write the eeprom data to sram */
+ for (i = 0; i < CX2_EEPROM_IMAGE_SIZE; i++)
+ ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
+
+ /* Do not load eeprom data on fatal error or suspend */
+ ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
+ } else {
+ IPW_DEBUG_INFO("Enabling FW initializationg of SRAM\n");
+
+ /* Load eeprom data on fatal error or suspend */
+ ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1);
+ }
+
+ IPW_DEBUG_TRACE("<<\n");
+}
+
+static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
+{
+ count >>= 2;
+ if (!count)
+ return;
+ _ipw_write32(priv, CX2_AUTOINC_ADDR, start);
+ while (count--)
+ _ipw_write32(priv, CX2_AUTOINC_DATA, 0);
+}
+
+static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
+{
+ ipw_zero_memory(priv, CX2_SHARED_SRAM_DMA_CONTROL,
+ CB_NUMBER_OF_ELEMENTS_SMALL *
+ sizeof(struct command_block));
+}
+
+static int ipw_fw_dma_enable(struct ipw_priv *priv)
+{ /* start dma engine but no transfers yet */
+
+ IPW_DEBUG_FW(">> : \n");
+
+ /* Start the dma */
+ ipw_fw_dma_reset_command_blocks(priv);
+
+ /* Write CB base address */
+ ipw_write_reg32(priv, CX2_DMA_I_CB_BASE, CX2_SHARED_SRAM_DMA_CONTROL);
+
+ IPW_DEBUG_FW("<< : \n");
+ return 0;
+}
+
+static void ipw_fw_dma_abort(struct ipw_priv *priv)
+{
+ u32 control = 0;
+
+ IPW_DEBUG_FW(">> :\n");
+
+ //set the Stop and Abort bit
+ control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
+ ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+ priv->sram_desc.last_cb_index = 0;
+
+ IPW_DEBUG_FW("<< \n");
+}
+
+static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
+ struct command_block *cb)
+{
+ u32 address =
+ CX2_SHARED_SRAM_DMA_CONTROL +
+ (sizeof(struct command_block) * index);
+ IPW_DEBUG_FW(">> :\n");
+
+ ipw_write_indirect(priv, address, (u8 *) cb,
+ (int)sizeof(struct command_block));
+
+ IPW_DEBUG_FW("<< :\n");
+ return 0;
+
+}
+
+static int ipw_fw_dma_kick(struct ipw_priv *priv)
+{
+ u32 control = 0;
+ u32 index = 0;
+
+ IPW_DEBUG_FW(">> :\n");
+
+ for (index = 0; index < priv->sram_desc.last_cb_index; index++)
+ ipw_fw_dma_write_command_block(priv, index,
+ &priv->sram_desc.cb_list[index]);
+
+ /* Enable the DMA in the CSR register */
+ ipw_clear_bit(priv, CX2_RESET_REG,
+ CX2_RESET_REG_MASTER_DISABLED |
+ CX2_RESET_REG_STOP_MASTER);
+
+ /* Set the Start bit. */
+ control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
+ ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+
+ IPW_DEBUG_FW("<< :\n");
+ return 0;
+}
+
+static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
+{
+ u32 address;
+ u32 register_value = 0;
+ u32 cb_fields_address = 0;
+
+ IPW_DEBUG_FW(">> :\n");
+ address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+ IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address);
+
+ /* Read the DMA Controlor register */
+ register_value = ipw_read_reg32(priv, CX2_DMA_I_DMA_CONTROL);
+ IPW_DEBUG_FW_INFO("CX2_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
+
+ /* Print the CB values */
+ cb_fields_address = address;
+ register_value = ipw_read_reg32(priv, cb_fields_address);
+ IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n", register_value);
+
+ cb_fields_address += sizeof(u32);
+ register_value = ipw_read_reg32(priv, cb_fields_address);
+ IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n", register_value);
+
+ cb_fields_address += sizeof(u32);
+ register_value = ipw_read_reg32(priv, cb_fields_address);
+ IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n",
+ register_value);
+
+ cb_fields_address += sizeof(u32);
+ register_value = ipw_read_reg32(priv, cb_fields_address);
+ IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n", register_value);
+
+ IPW_DEBUG_FW(">> :\n");
+}
+
+static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
+{
+ u32 current_cb_address = 0;
+ u32 current_cb_index = 0;
+
+ IPW_DEBUG_FW("<< :\n");
+ current_cb_address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+
+ current_cb_index = (current_cb_address - CX2_SHARED_SRAM_DMA_CONTROL) /
+ sizeof(struct command_block);
+
+ IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n",
+ current_cb_index, current_cb_address);
+
+ IPW_DEBUG_FW(">> :\n");
+ return current_cb_index;
+
+}
+
+static int ipw_fw_dma_add_command_block(struct ipw_priv *priv,
+ u32 src_address,
+ u32 dest_address,
+ u32 length,
+ int interrupt_enabled, int is_last)
+{
+
+ u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC |
+ CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG |
+ CB_DEST_SIZE_LONG;
+ struct command_block *cb;
+ u32 last_cb_element = 0;
+
+ IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n",
+ src_address, dest_address, length);
+
+ if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL)
+ return -1;
+
+ last_cb_element = priv->sram_desc.last_cb_index;
+ cb = &priv->sram_desc.cb_list[last_cb_element];
+ priv->sram_desc.last_cb_index++;
+
+ /* Calculate the new CB control word */
+ if (interrupt_enabled)
+ control |= CB_INT_ENABLED;
+
+ if (is_last)
+ control |= CB_LAST_VALID;
+
+ control |= length;
+
+ /* Calculate the CB Element's checksum value */
+ cb->status = control ^ src_address ^ dest_address;
+
+ /* Copy the Source and Destination addresses */
+ cb->dest_addr = dest_address;
+ cb->source_addr = src_address;
+
+ /* Copy the Control Word last */
+ cb->control = control;
+
+ return 0;
+}
+
+static int ipw_fw_dma_add_buffer(struct ipw_priv *priv,
+ u32 src_phys, u32 dest_address, u32 length)
+{
+ u32 bytes_left = length;
+ u32 src_offset = 0;
+ u32 dest_offset = 0;
+ int status = 0;
+ IPW_DEBUG_FW(">> \n");
+ IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n",
+ src_phys, dest_address, length);
+ while (bytes_left > CB_MAX_LENGTH) {
+ status = ipw_fw_dma_add_command_block(priv,
+ src_phys + src_offset,
+ dest_address +
+ dest_offset,
+ CB_MAX_LENGTH, 0, 0);
+ if (status) {
+ IPW_DEBUG_FW_INFO(": Failed\n");
+ return -1;
+ } else
+ IPW_DEBUG_FW_INFO(": Added new cb\n");
+
+ src_offset += CB_MAX_LENGTH;
+ dest_offset += CB_MAX_LENGTH;
+ bytes_left -= CB_MAX_LENGTH;
+ }
+
+ /* add the buffer tail */
+ if (bytes_left > 0) {
+ status =
+ ipw_fw_dma_add_command_block(priv, src_phys + src_offset,
+ dest_address + dest_offset,
+ bytes_left, 0, 0);
+ if (status) {
+ IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n");
+ return -1;
+ } else
+ IPW_DEBUG_FW_INFO
+ (": Adding new cb - the buffer tail\n");
+ }
+
+ IPW_DEBUG_FW("<< \n");
+ return 0;
+}
+
+static int ipw_fw_dma_wait(struct ipw_priv *priv)
+{
+ u32 current_index = 0;
+ u32 watchdog = 0;
+
+ IPW_DEBUG_FW(">> : \n");
+
+ current_index = ipw_fw_dma_command_block_index(priv);
+ IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n",
+ (int)priv->sram_desc.last_cb_index);
+
+ while (current_index < priv->sram_desc.last_cb_index) {
+ udelay(50);
+ current_index = ipw_fw_dma_command_block_index(priv);
+
+ watchdog++;
+
+ if (watchdog > 400) {
+ IPW_DEBUG_FW_INFO("Timeout\n");
+ ipw_fw_dma_dump_command_block(priv);
+ ipw_fw_dma_abort(priv);
+ return -1;
+ }
+ }
+
+ ipw_fw_dma_abort(priv);
+
+ /*Disable the DMA in the CSR register */
+ ipw_set_bit(priv, CX2_RESET_REG,
+ CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER);
+
+ IPW_DEBUG_FW("<< dmaWaitSync \n");
+ return 0;
+}
+
+static void ipw_remove_current_network(struct ipw_priv *priv)
+{
+ struct list_head *element, *safe;
+ struct ieee80211_network *network = NULL;
+ list_for_each_safe(element, safe, &priv->ieee->network_list) {
+ network = list_entry(element, struct ieee80211_network, list);
+ if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
+ list_del(element);
+ list_add_tail(&network->list,
+ &priv->ieee->network_free_list);
+ }
+ }
+}
+
+/**
+ * Check that card is still alive.
+ * Reads debug register from domain0.
+ * If card is present, pre-defined value should
+ * be found there.
+ *
+ * @param priv
+ * @return 1 if card is present, 0 otherwise
+ */
+static inline int ipw_alive(struct ipw_priv *priv)
+{
+ return ipw_read32(priv, 0x90) == 0xd55555d5;
+}
+
+static inline int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
+ int timeout)
+{
+ int i = 0;
+
+ do {
+ if ((ipw_read32(priv, addr) & mask) == mask)
+ return i;
+ mdelay(10);
+ i += 10;
+ } while (i < timeout);
+
+ return -ETIME;
+}
+
+/* These functions load the firmware and micro code for the operation of
+ * the ipw hardware. It assumes the buffer has all the bits for the
+ * image and the caller is handling the memory allocation and clean up.
+ */
+
+static int ipw_stop_master(struct ipw_priv *priv)
+{
+ int rc;
+
+ IPW_DEBUG_TRACE(">> \n");
+ /* stop master. typical delay - 0 */
+ ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+
+ rc = ipw_poll_bit(priv, CX2_RESET_REG,
+ CX2_RESET_REG_MASTER_DISABLED, 100);
+ if (rc < 0) {
+ IPW_ERROR("stop master failed in 10ms\n");
+ return -1;
+ }
+
+ IPW_DEBUG_INFO("stop master %dms\n", rc);
+
+ return rc;
+}
+
+static void ipw_arc_release(struct ipw_priv *priv)
+{
+ IPW_DEBUG_TRACE(">> \n");
+ mdelay(5);
+
+ ipw_clear_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+
+ /* no one knows timing, for safety add some delay */
+ mdelay(5);
+}
+
+struct fw_header {
+ u32 version;
+ u32 mode;
+};
+
+struct fw_chunk {
+ u32 address;
+ u32 length;
+};
+
+#define IPW_FW_MAJOR_VERSION 2
+#define IPW_FW_MINOR_VERSION 2
+
+#define IPW_FW_MINOR(x) ((x & 0xff) >> 8)
+#define IPW_FW_MAJOR(x) (x & 0xff)
+
+#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \
+ IPW_FW_MAJOR_VERSION)
+
+#define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \
+"." __stringify(IPW_FW_MINOR_VERSION) "-"
+
+#if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0
+#define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw"
+#else
+#define IPW_FW_NAME(x) "ipw2200_" x ".fw"
+#endif
+
+static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
+{
+ int rc = 0, i, addr;
+ u8 cr = 0;
+ u16 *image;
+
+ image = (u16 *) data;
+
+ IPW_DEBUG_TRACE(">> \n");
+
+ rc = ipw_stop_master(priv);
+
+ if (rc < 0)
+ return rc;
+
+// spin_lock_irqsave(&priv->lock, flags);
+
+ for (addr = CX2_SHARED_LOWER_BOUND;
+ addr < CX2_REGISTER_DOMAIN1_END; addr += 4) {
+ ipw_write32(priv, addr, 0);
+ }
+
+ /* no ucode (yet) */
+ memset(&priv->dino_alive, 0, sizeof(priv->dino_alive));
+ /* destroy DMA queues */
+ /* reset sequence */
+
+ ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_ON);
+ ipw_arc_release(priv);
+ ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_OFF);
+ mdelay(1);
+
+ /* reset PHY */
+ ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, CX2_BASEBAND_POWER_DOWN);
+ mdelay(1);
+
+ ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, 0);
+ mdelay(1);
+
+ /* enable ucode store */
+ ipw_write_reg8(priv, DINO_CONTROL_REG, 0x0);
+ ipw_write_reg8(priv, DINO_CONTROL_REG, DINO_ENABLE_CS);
+ mdelay(1);
+
+ /* write ucode */
+ /**
+ * @bug
+ * Do NOT set indirect address register once and then
+ * store data to indirect data register in the loop.
+ * It seems very reasonable, but in this case DINO do not
+ * accept ucode. It is essential to set address each time.
+ */
+ /* load new ipw uCode */
+ for (i = 0; i < len / 2; i++)
+ ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]);
+
+ /* enable DINO */
+ ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
+ ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
+
+ /* this is where the igx / win driver deveates from the VAP driver. */
+
+ /* wait for alive response */
+ for (i = 0; i < 100; i++) {
+ /* poll for incoming data */
+ cr = ipw_read_reg8(priv, CX2_BASEBAND_CONTROL_STATUS);
+ if (cr & DINO_RXFIFO_DATA)
+ break;
+ mdelay(1);
+ }
+
+ if (cr & DINO_RXFIFO_DATA) {
+ /* alive_command_responce size is NOT multiple of 4 */
+ u32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
+
+ for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
+ response_buffer[i] =
+ ipw_read_reg32(priv, CX2_BASEBAND_RX_FIFO_READ);
+ memcpy(&priv->dino_alive, response_buffer,
+ sizeof(priv->dino_alive));
+ if (priv->dino_alive.alive_command == 1
+ && priv->dino_alive.ucode_valid == 1) {
+ rc = 0;
+ IPW_DEBUG_INFO
+ ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) "
+ "of %02d/%02d/%02d %02d:%02d\n",
+ priv->dino_alive.software_revision,
+ priv->dino_alive.software_revision,
+ priv->dino_alive.device_identifier,
+ priv->dino_alive.device_identifier,
+ priv->dino_alive.time_stamp[0],
+ priv->dino_alive.time_stamp[1],
+ priv->dino_alive.time_stamp[2],
+ priv->dino_alive.time_stamp[3],
+ priv->dino_alive.time_stamp[4]);
+ } else {
+ IPW_DEBUG_INFO("Microcode is not alive\n");
+ rc = -EINVAL;
+ }
+ } else {
+ IPW_DEBUG_INFO("No alive response from DINO\n");
+ rc = -ETIME;
+ }
+
+ /* disable DINO, otherwise for some reason
+ firmware have problem getting alive resp. */
+ ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
+
+// spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
+{
+ int rc = -1;
+ int offset = 0;
+ struct fw_chunk *chunk;
+ dma_addr_t shared_phys;
+ u8 *shared_virt;
+
+ IPW_DEBUG_TRACE("<< : \n");
+ shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys);
+
+ if (!shared_virt)
+ return -ENOMEM;
+
+ memmove(shared_virt, data, len);
+
+ /* Start the Dma */
+ rc = ipw_fw_dma_enable(priv);
+
+ if (priv->sram_desc.last_cb_index > 0) {
+ /* the DMA is already ready this would be a bug. */
+ BUG();
+ goto out;
+ }
+
+ do {
+ chunk = (struct fw_chunk *)(data + offset);
+ offset += sizeof(struct fw_chunk);
+ /* build DMA packet and queue up for sending */
+ /* dma to chunk->address, the chunk->length bytes from data +
+ * offeset*/
+ /* Dma loading */
+ rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset,
+ chunk->address, chunk->length);
+ if (rc) {
+ IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
+ goto out;
+ }
+
+ offset += chunk->length;
+ } while (offset < len);
+
+ /* Run the DMA and wait for the answer */
+ rc = ipw_fw_dma_kick(priv);
+ if (rc) {
+ IPW_ERROR("dmaKick Failed\n");
+ goto out;
+ }
+
+ rc = ipw_fw_dma_wait(priv);
+ if (rc) {
+ IPW_ERROR("dmaWaitSync Failed\n");
+ goto out;
+ }
+ out:
+ pci_free_consistent(priv->pci_dev, len, shared_virt, shared_phys);
+ return rc;
+}
+
+/* stop nic */
+static int ipw_stop_nic(struct ipw_priv *priv)
+{
+ int rc = 0;
+
+ /* stop */
+ ipw_write32(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+
+ rc = ipw_poll_bit(priv, CX2_RESET_REG,
+ CX2_RESET_REG_MASTER_DISABLED, 500);
+ if (rc < 0) {
+ IPW_ERROR("wait for reg master disabled failed\n");
+ return rc;
+ }
+
+ ipw_set_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+
+ return rc;
+}
+
+static void ipw_start_nic(struct ipw_priv *priv)
+{
+ IPW_DEBUG_TRACE(">>\n");
+
+ /* prvHwStartNic release ARC */
+ ipw_clear_bit(priv, CX2_RESET_REG,
+ CX2_RESET_REG_MASTER_DISABLED |
+ CX2_RESET_REG_STOP_MASTER |
+ CBD_RESET_REG_PRINCETON_RESET);
+
+ /* enable power management */
+ ipw_set_bit(priv, CX2_GP_CNTRL_RW,
+ CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
+
+ IPW_DEBUG_TRACE("<<\n");
+}
+
+static int ipw_init_nic(struct ipw_priv *priv)
+{
+ int rc;
+
+ IPW_DEBUG_TRACE(">>\n");
+ /* reset */
+ /*prvHwInitNic */
+ /* set "initialization complete" bit to move adapter to D0 state */
+ ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+
+ /* low-level PLL activation */
+ ipw_write32(priv, CX2_READ_INT_REGISTER,
+ CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
+
+ /* wait for clock stabilization */
+ rc = ipw_poll_bit(priv, CX2_GP_CNTRL_RW,
+ CX2_GP_CNTRL_BIT_CLOCK_READY, 250);
+ if (rc < 0)
+ IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
+
+ /* assert SW reset */
+ ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_SW_RESET);
+
+ udelay(10);
+
+ /* set "initialization complete" bit to move adapter to D0 state */
+ ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+
+ IPW_DEBUG_TRACE(">>\n");
+ return 0;
+}
+
+/* Call this function from process context, it will sleep in request_firmware.
+ * Probe is an ok place to call this from.
+ */
+static int ipw_reset_nic(struct ipw_priv *priv)
+{
+ int rc = 0;
+
+ IPW_DEBUG_TRACE(">>\n");
+
+ rc = ipw_init_nic(priv);
+
+ /* Clear the 'host command active' bit... */
+ priv->status &= ~STATUS_HCMD_ACTIVE;
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ IPW_DEBUG_TRACE("<<\n");
+ return rc;
+}
+
+static int ipw_get_fw(struct ipw_priv *priv,
+ const struct firmware **fw, const char *name)
+{
+ struct fw_header *header;
+ int rc;
+
+ /* ask firmware_class module to get the boot firmware off disk */
+ rc = request_firmware(fw, name, &priv->pci_dev->dev);
+ if (rc < 0) {
+ IPW_ERROR("%s load failed: Reason %d\n", name, rc);
+ return rc;
+ }
+
+ header = (struct fw_header *)(*fw)->data;
+ if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) {
+ IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n",
+ name,
+ IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION);
+ return -EINVAL;
+ }
+
+ IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n",
+ name,
+ IPW_FW_MAJOR(header->version),
+ IPW_FW_MINOR(header->version),
+ (*fw)->size - sizeof(struct fw_header));
+ return 0;
+}
+
+#define CX2_RX_BUF_SIZE (3000)
+
+static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
+ struct ipw_rx_queue *rxq)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
+ CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->processed = RX_QUEUE_SIZE - 1;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+#ifdef CONFIG_PM
+static int fw_loaded = 0;
+static const struct firmware *bootfw = NULL;
+static const struct firmware *firmware = NULL;
+static const struct firmware *ucode = NULL;
+#endif
+
+static int ipw_load(struct ipw_priv *priv)
+{
+#ifndef CONFIG_PM
+ const struct firmware *bootfw = NULL;
+ const struct firmware *firmware = NULL;
+ const struct firmware *ucode = NULL;
+#endif
+ int rc = 0, retries = 3;
+
+#ifdef CONFIG_PM
+ if (!fw_loaded) {
+#endif
+ rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
+ if (rc)
+ goto error;
+
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ rc = ipw_get_fw(priv, &ucode,
+ IPW_FW_NAME("ibss_ucode"));
+ if (rc)
+ goto error;
+
+ rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss"));
+ break;
+
+#ifdef CONFIG_IPW_PROMISC
+ case IW_MODE_MONITOR:
+ rc = ipw_get_fw(priv, &ucode,
+ IPW_FW_NAME("ibss_ucode"));
+ if (rc)
+ goto error;
+
+ rc = ipw_get_fw(priv, &firmware,
+ IPW_FW_NAME("sniffer"));
+ break;
+#endif
+ case IW_MODE_INFRA:
+ rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("bss_ucode"));
+ if (rc)
+ goto error;
+
+ rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss"));
+ break;
+
+ default:
+ rc = -EINVAL;
+ }
+
+ if (rc)
+ goto error;
+
+#ifdef CONFIG_PM
+ fw_loaded = 1;
+ }
+#endif
+
+ if (!priv->rxq)
+ priv->rxq = ipw_rx_queue_alloc(priv);
+ else
+ ipw_rx_queue_reset(priv, priv->rxq);
+ if (!priv->rxq) {
+ IPW_ERROR("Unable to initialize Rx queue\n");
+ goto error;
+ }
+
+ retry:
+ /* Ensure interrupts are disabled */
+ ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+ priv->status &= ~STATUS_INT_ENABLED;
+
+ /* ack pending interrupts */
+ ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+
+ ipw_stop_nic(priv);
+
+ rc = ipw_reset_nic(priv);
+ if (rc) {
+ IPW_ERROR("Unable to reset NIC\n");
+ goto error;
+ }
+
+ ipw_zero_memory(priv, CX2_NIC_SRAM_LOWER_BOUND,
+ CX2_NIC_SRAM_UPPER_BOUND - CX2_NIC_SRAM_LOWER_BOUND);
+
+ /* DMA the initial boot firmware into the device */
+ rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
+ bootfw->size - sizeof(struct fw_header));
+ if (rc < 0) {
+ IPW_ERROR("Unable to load boot firmware\n");
+ goto error;
+ }
+
+ /* kick start the device */
+ ipw_start_nic(priv);
+
+ /* wait for the device to finish it's initial startup sequence */
+ rc = ipw_poll_bit(priv, CX2_INTA_RW,
+ CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+ if (rc < 0) {
+ IPW_ERROR("device failed to boot initial fw image\n");
+ goto error;
+ }
+ IPW_DEBUG_INFO("initial device response after %dms\n", rc);
+
+ /* ack fw init done interrupt */
+ ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+
+ /* DMA the ucode into the device */
+ rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
+ ucode->size - sizeof(struct fw_header));
+ if (rc < 0) {
+ IPW_ERROR("Unable to load ucode\n");
+ goto error;
+ }
+
+ /* stop nic */
+ ipw_stop_nic(priv);
+
+ /* DMA bss firmware into the device */
+ rc = ipw_load_firmware(priv, firmware->data +
+ sizeof(struct fw_header),
+ firmware->size - sizeof(struct fw_header));
+ if (rc < 0) {
+ IPW_ERROR("Unable to load firmware\n");
+ goto error;
+ }
+
+ ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
+
+ rc = ipw_queue_reset(priv);
+ if (rc) {
+ IPW_ERROR("Unable to initialize queues\n");
+ goto error;
+ }
+
+ /* Ensure interrupts are disabled */
+ ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+
+ /* kick start the device */
+ ipw_start_nic(priv);
+
+ if (ipw_read32(priv, CX2_INTA_RW) & CX2_INTA_BIT_PARITY_ERROR) {
+ if (retries > 0) {
+ IPW_WARNING("Parity error. Retrying init.\n");
+ retries--;
+ goto retry;
+ }
+
+ IPW_ERROR("TODO: Handle parity error -- schedule restart?\n");
+ rc = -EIO;
+ goto error;
+ }
+
+ /* wait for the device */
+ rc = ipw_poll_bit(priv, CX2_INTA_RW,
+ CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+ if (rc < 0) {
+ IPW_ERROR("device failed to start after 500ms\n");
+ goto error;
+ }
+ IPW_DEBUG_INFO("device response after %dms\n", rc);
+
+ /* ack fw init done interrupt */
+ ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+
+ /* read eeprom data and initialize the eeprom region of sram */
+ priv->eeprom_delay = 1;
+ ipw_eeprom_init_sram(priv);
+
+ /* enable interrupts */
+ ipw_enable_interrupts(priv);
+
+ /* Ensure our queue has valid packets */
+ ipw_rx_queue_replenish(priv);
+
+ ipw_write32(priv, CX2_RX_READ_INDEX, priv->rxq->read);
+
+ /* ack pending interrupts */
+ ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+
+#ifndef CONFIG_PM
+ release_firmware(bootfw);
+ release_firmware(ucode);
+ release_firmware(firmware);
+#endif
+ return 0;
+
+ error:
+ if (priv->rxq) {
+ ipw_rx_queue_free(priv, priv->rxq);
+ priv->rxq = NULL;
+ }
+ ipw_tx_queue_free(priv);
+ if (bootfw)
+ release_firmware(bootfw);
+ if (ucode)
+ release_firmware(ucode);
+ if (firmware)
+ release_firmware(firmware);
+#ifdef CONFIG_PM
+ fw_loaded = 0;
+ bootfw = ucode = firmware = NULL;
+#endif
+
+ return rc;
+}
+
+/**
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IPW operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ *
+ * The four transmit queues allow for performing quality of service (qos)
+ * transmissions as per the 802.11 protocol. Currently Linux does not
+ * provide a mechanism to the user for utilizing prioritized queues, so
+ * we only utilize the first data transmit queue (queue1).
+ */
+
+/**
+ * Driver allocates buffers of this size for Rx
+ */
+
+static inline int ipw_queue_space(const struct clx2_queue *q)
+{
+ int s = q->last_used - q->first_empty;
+ if (s <= 0)
+ s += q->n_bd;
+ s -= 2; /* keep some reserve to not confuse empty and full situations */
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+static inline int ipw_queue_inc_wrap(int index, int n_bd)
+{
+ return (++index == n_bd) ? 0 : index;
+}
+
+/**
+ * Initialize common DMA queue structure
+ *
+ * @param q queue to init
+ * @param count Number of BD's to allocate. Should be power of 2
+ * @param read_register Address for 'read' register
+ * (not offset within BAR, full address)
+ * @param write_register Address for 'write' register
+ * (not offset within BAR, full address)
+ * @param base_register Address for 'base' register
+ * (not offset within BAR, full address)
+ * @param size Address for 'size' register
+ * (not offset within BAR, full address)
+ */
+static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q,
+ int count, u32 read, u32 write, u32 base, u32 size)
+{
+ q->n_bd = count;
+
+ q->low_mark = q->n_bd / 4;
+ if (q->low_mark < 4)
+ q->low_mark = 4;
+
+ q->high_mark = q->n_bd / 8;
+ if (q->high_mark < 2)
+ q->high_mark = 2;
+
+ q->first_empty = q->last_used = 0;
+ q->reg_r = read;
+ q->reg_w = write;
+
+ ipw_write32(priv, base, q->dma_addr);
+ ipw_write32(priv, size, count);
+ ipw_write32(priv, read, 0);
+ ipw_write32(priv, write, 0);
+
+ _ipw_read32(priv, 0x90);
+}
+
+static int ipw_queue_tx_init(struct ipw_priv *priv,
+ struct clx2_tx_queue *q,
+ int count, u32 read, u32 write, u32 base, u32 size)
+{
+ struct pci_dev *dev = priv->pci_dev;
+
+ q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL);
+ if (!q->txb) {
+ IPW_ERROR("vmalloc for auxilary BD structures failed\n");
+ return -ENOMEM;
+ }
+
+ q->bd =
+ pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr);
+ if (!q->bd) {
+ IPW_ERROR("pci_alloc_consistent(%zd) failed\n",
+ sizeof(q->bd[0]) * count);
+ kfree(q->txb);
+ q->txb = NULL;
+ return -ENOMEM;
+ }
+
+ ipw_queue_init(priv, &q->q, count, read, write, base, size);
+ return 0;
+}
+
+/**
+ * Free one TFD, those at index [txq->q.last_used].
+ * Do NOT advance any indexes
+ *
+ * @param dev
+ * @param txq
+ */
+static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
+ struct clx2_tx_queue *txq)
+{
+ struct tfd_frame *bd = &txq->bd[txq->q.last_used];
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+
+ /* classify bd */
+ if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE)
+ /* nothing to cleanup after for host commands */
+ return;
+
+ /* sanity check */
+ if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) {
+ IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks);
+ /** @todo issue fatal error, it is quite serious situation */
+ return;
+ }
+
+ /* unmap chunks if any */
+ for (i = 0; i < bd->u.data.num_chunks; i++) {
+ pci_unmap_single(dev, bd->u.data.chunk_ptr[i],
+ bd->u.data.chunk_len[i], PCI_DMA_TODEVICE);
+ if (txq->txb[txq->q.last_used]) {
+ ieee80211_txb_free(txq->txb[txq->q.last_used]);
+ txq->txb[txq->q.last_used] = NULL;
+ }
+ }
+}
+
+/**
+ * Deallocate DMA queue.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ *
+ * @param dev
+ * @param q
+ */
+static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq)
+{
+ struct clx2_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+
+ if (q->n_bd == 0)
+ return;
+
+ /* first, empty all BD's */
+ for (; q->first_empty != q->last_used;
+ q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
+ ipw_queue_tx_free_tfd(priv, txq);
+ }
+
+ /* free buffers belonging to queue itself */
+ pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
+ q->dma_addr);
+ kfree(txq->txb);
+
+ /* 0 fill whole structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * Destroy all DMA queues and structures
+ *
+ * @param priv
+ */
+static void ipw_tx_queue_free(struct ipw_priv *priv)
+{
+ /* Tx CMD queue */
+ ipw_queue_tx_free(priv, &priv->txq_cmd);
+
+ /* Tx queues */
+ ipw_queue_tx_free(priv, &priv->txq[0]);
+ ipw_queue_tx_free(priv, &priv->txq[1]);
+ ipw_queue_tx_free(priv, &priv->txq[2]);
+ ipw_queue_tx_free(priv, &priv->txq[3]);
+}
+
+static void inline __maybe_wake_tx(struct ipw_priv *priv)
+{
+ if (netif_running(priv->net_dev)) {
+ switch (priv->port_type) {
+ case DCR_TYPE_MU_BSS:
+ case DCR_TYPE_MU_IBSS:
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ return;
+ }
+ }
+ netif_wake_queue(priv->net_dev);
+ }
+
+}
+
+static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
+{
+ /* First 3 bytes are manufacturer */
+ bssid[0] = priv->mac_addr[0];
+ bssid[1] = priv->mac_addr[1];
+ bssid[2] = priv->mac_addr[2];
+
+ /* Last bytes are random */
+ get_random_bytes(&bssid[3], ETH_ALEN - 3);
+
+ bssid[0] &= 0xfe; /* clear multicast bit */
+ bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */
+}
+
+static inline u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
+{
+ struct ipw_station_entry entry;
+ int i;
+
+ for (i = 0; i < priv->num_stations; i++) {
+ if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
+ /* Another node is active in network */
+ priv->missed_adhoc_beacons = 0;
+ if (!(priv->config & CFG_STATIC_CHANNEL))
+ /* when other nodes drop out, we drop out */
+ priv->config &= ~CFG_ADHOC_PERSIST;
+
+ return i;
+ }
+ }
+
+ if (i == MAX_STATIONS)
+ return IPW_INVALID_STATION;
+
+ IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid));
+
+ entry.reserved = 0;
+ entry.support_mode = 0;
+ memcpy(entry.mac_addr, bssid, ETH_ALEN);
+ memcpy(priv->stations[i], bssid, ETH_ALEN);
+ ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry),
+ &entry, sizeof(entry));
+ priv->num_stations++;
+
+ return i;
+}
+
+static inline u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
+{
+ int i;
+
+ for (i = 0; i < priv->num_stations; i++)
+ if (!memcmp(priv->stations[i], bssid, ETH_ALEN))
+ return i;
+
+ return IPW_INVALID_STATION;
+}
+
+static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
+{
+ int err;
+
+ if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) {
+ IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
+ return;
+ }
+
+ IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " "
+ "on channel %d.\n",
+ MAC_ARG(priv->assoc_request.bssid),
+ priv->assoc_request.channel);
+
+ priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
+ priv->status |= STATUS_DISASSOCIATING;
+
+ if (quiet)
+ priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
+ else
+ priv->assoc_request.assoc_type = HC_DISASSOCIATE;
+ err = ipw_send_associate(priv, &priv->assoc_request);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send [dis]associate command "
+ "failed.\n");
+ return;
+ }
+
+}
+
+static void ipw_disassociate(void *data)
+{
+ ipw_send_disassociate(data, 0);
+}
+
+static void notify_wx_assoc_event(struct ipw_priv *priv)
+{
+ union iwreq_data wrqu;
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ if (priv->status & STATUS_ASSOCIATED)
+ memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
+ else
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+struct ipw_status_code {
+ u16 status;
+ const char *reason;
+};
+
+static const struct ipw_status_code ipw_status_codes[] = {
+ {0x00, "Successful"},
+ {0x01, "Unspecified failure"},
+ {0x0A, "Cannot support all requested capabilities in the "
+ "Capability information field"},
+ {0x0B, "Reassociation denied due to inability to confirm that "
+ "association exists"},
+ {0x0C, "Association denied due to reason outside the scope of this "
+ "standard"},
+ {0x0D,
+ "Responding station does not support the specified authentication "
+ "algorithm"},
+ {0x0E,
+ "Received an Authentication frame with authentication sequence "
+ "transaction sequence number out of expected sequence"},
+ {0x0F, "Authentication rejected because of challenge failure"},
+ {0x10, "Authentication rejected due to timeout waiting for next "
+ "frame in sequence"},
+ {0x11, "Association denied because AP is unable to handle additional "
+ "associated stations"},
+ {0x12,
+ "Association denied due to requesting station not supporting all "
+ "of the datarates in the BSSBasicServiceSet Parameter"},
+ {0x13,
+ "Association denied due to requesting station not supporting "
+ "short preamble operation"},
+ {0x14,
+ "Association denied due to requesting station not supporting "
+ "PBCC encoding"},
+ {0x15,
+ "Association denied due to requesting station not supporting "
+ "channel agility"},
+ {0x19,
+ "Association denied due to requesting station not supporting "
+ "short slot operation"},
+ {0x1A,
+ "Association denied due to requesting station not supporting "
+ "DSSS-OFDM operation"},
+ {0x28, "Invalid Information Element"},
+ {0x29, "Group Cipher is not valid"},
+ {0x2A, "Pairwise Cipher is not valid"},
+ {0x2B, "AKMP is not valid"},
+ {0x2C, "Unsupported RSN IE version"},
+ {0x2D, "Invalid RSN IE Capabilities"},
+ {0x2E, "Cipher suite is rejected per security policy"},
+};
+
+#ifdef CONFIG_IPW_DEBUG
+static const char *ipw_get_status_code(u16 status)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
+ if (ipw_status_codes[i].status == status)
+ return ipw_status_codes[i].reason;
+ return "Unknown status value.";
+}
+#endif
+
+static void inline average_init(struct average *avg)
+{
+ memset(avg, 0, sizeof(*avg));
+}
+
+static void inline average_add(struct average *avg, s16 val)
+{
+ avg->sum -= avg->entries[avg->pos];
+ avg->sum += val;
+ avg->entries[avg->pos++] = val;
+ if (unlikely(avg->pos == AVG_ENTRIES)) {
+ avg->init = 1;
+ avg->pos = 0;
+ }
+}
+
+static s16 inline average_value(struct average *avg)
+{
+ if (!unlikely(avg->init)) {
+ if (avg->pos)
+ return avg->sum / avg->pos;
+ return 0;
+ }
+
+ return avg->sum / AVG_ENTRIES;
+}
+
+static void ipw_reset_stats(struct ipw_priv *priv)
+{
+ u32 len = sizeof(u32);
+
+ priv->quality = 0;
+
+ average_init(&priv->average_missed_beacons);
+ average_init(&priv->average_rssi);
+ average_init(&priv->average_noise);
+
+ priv->last_rate = 0;
+ priv->last_missed_beacons = 0;
+ priv->last_rx_packets = 0;
+ priv->last_tx_packets = 0;
+ priv->last_tx_failures = 0;
+
+ /* Firmware managed, reset only when NIC is restarted, so we have to
+ * normalize on the current value */
+ ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC,
+ &priv->last_rx_err, &len);
+ ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE,
+ &priv->last_tx_failures, &len);
+
+ /* Driver managed, reset with each association */
+ priv->missed_adhoc_beacons = 0;
+ priv->missed_beacons = 0;
+ priv->tx_packets = 0;
+ priv->rx_packets = 0;
+
+}
+
+static inline u32 ipw_get_max_rate(struct ipw_priv *priv)
+{
+ u32 i = 0x80000000;
+ u32 mask = priv->rates_mask;
+ /* If currently associated in B mode, restrict the maximum
+ * rate match to B rates */
+ if (priv->assoc_request.ieee_mode == IPW_B_MODE)
+ mask &= IEEE80211_CCK_RATES_MASK;
+
+ /* TODO: Verify that the rate is supported by the current rates
+ * list. */
+
+ while (i && !(mask & i))
+ i >>= 1;
+ switch (i) {
+ case IEEE80211_CCK_RATE_1MB_MASK: return 1000000;
+ case IEEE80211_CCK_RATE_2MB_MASK: return 2000000;
+ case IEEE80211_CCK_RATE_5MB_MASK: return 5500000;
+ case IEEE80211_OFDM_RATE_6MB_MASK: return 6000000;
+ case IEEE80211_OFDM_RATE_9MB_MASK: return 9000000;
+ case IEEE80211_CCK_RATE_11MB_MASK: return 11000000;
+ case IEEE80211_OFDM_RATE_12MB_MASK: return 12000000;
+ case IEEE80211_OFDM_RATE_18MB_MASK: return 18000000;
+ case IEEE80211_OFDM_RATE_24MB_MASK: return 24000000;
+ case IEEE80211_OFDM_RATE_36MB_MASK: return 36000000;
+ case IEEE80211_OFDM_RATE_48MB_MASK: return 48000000;
+ case IEEE80211_OFDM_RATE_54MB_MASK: return 54000000;
+ }
+
+ if (priv->ieee->mode == IEEE_B)
+ return 11000000;
+ else
+ return 54000000;
+}
+
+static u32 ipw_get_current_rate(struct ipw_priv *priv)
+{
+ u32 rate, len = sizeof(rate);
+ int err;
+
+ if (!(priv->status & STATUS_ASSOCIATED))
+ return 0;
+
+ if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) {
+ err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate,
+ &len);
+ if (err) {
+ IPW_DEBUG_INFO("failed querying ordinals.\n");
+ return 0;
+ }
+ } else
+ return ipw_get_max_rate(priv);
+
+ switch (rate) {
+ case IPW_TX_RATE_1MB: return 1000000;
+ case IPW_TX_RATE_2MB: return 2000000;
+ case IPW_TX_RATE_5MB: return 5500000;
+ case IPW_TX_RATE_6MB: return 6000000;
+ case IPW_TX_RATE_9MB: return 9000000;
+ case IPW_TX_RATE_11MB: return 11000000;
+ case IPW_TX_RATE_12MB: return 12000000;
+ case IPW_TX_RATE_18MB: return 18000000;
+ case IPW_TX_RATE_24MB: return 24000000;
+ case IPW_TX_RATE_36MB: return 36000000;
+ case IPW_TX_RATE_48MB: return 48000000;
+ case IPW_TX_RATE_54MB: return 54000000;
+ }
+
+ return 0;
+}
+
+#define PERFECT_RSSI (-50)
+#define WORST_RSSI (-85)
+#define IPW_STATS_INTERVAL (2 * HZ)
+static void ipw_gather_stats(struct ipw_priv *priv)
+{
+ u32 rx_err, rx_err_delta, rx_packets_delta;
+ u32 tx_failures, tx_failures_delta, tx_packets_delta;
+ u32 missed_beacons_percent, missed_beacons_delta;
+ u32 quality = 0;
+ u32 len = sizeof(u32);
+ s16 rssi;
+ u32 beacon_quality, signal_quality, tx_quality, rx_quality,
+ rate_quality;
+
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ priv->quality = 0;
+ return;
+ }
+
+ /* Update the statistics */
+ ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS,
+ &priv->missed_beacons, &len);
+ missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons;
+ priv->last_missed_beacons = priv->missed_beacons;
+ if (priv->assoc_request.beacon_interval) {
+ missed_beacons_percent = missed_beacons_delta *
+ (HZ * priv->assoc_request.beacon_interval) /
+ (IPW_STATS_INTERVAL * 10);
+ } else {
+ missed_beacons_percent = 0;
+ }
+ average_add(&priv->average_missed_beacons, missed_beacons_percent);
+
+ ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len);
+ rx_err_delta = rx_err - priv->last_rx_err;
+ priv->last_rx_err = rx_err;
+
+ ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len);
+ tx_failures_delta = tx_failures - priv->last_tx_failures;
+ priv->last_tx_failures = tx_failures;
+
+ rx_packets_delta = priv->rx_packets - priv->last_rx_packets;
+ priv->last_rx_packets = priv->rx_packets;
+
+ tx_packets_delta = priv->tx_packets - priv->last_tx_packets;
+ priv->last_tx_packets = priv->tx_packets;
+
+ /* Calculate quality based on the following:
+ *
+ * Missed beacon: 100% = 0, 0% = 70% missed
+ * Rate: 60% = 1Mbs, 100% = Max
+ * Rx and Tx errors represent a straight % of total Rx/Tx
+ * RSSI: 100% = > -50, 0% = < -80
+ * Rx errors: 100% = 0, 0% = 50% missed
+ *
+ * The lowest computed quality is used.
+ *
+ */
+#define BEACON_THRESHOLD 5
+ beacon_quality = 100 - missed_beacons_percent;
+ if (beacon_quality < BEACON_THRESHOLD)
+ beacon_quality = 0;
+ else
+ beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 /
+ (100 - BEACON_THRESHOLD);
+ IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n",
+ beacon_quality, missed_beacons_percent);
+
+ priv->last_rate = ipw_get_current_rate(priv);
+ rate_quality = priv->last_rate * 40 / priv->last_rate + 60;
+ IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
+ rate_quality, priv->last_rate / 1000000);
+
+ if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta)
+ rx_quality = 100 - (rx_err_delta * 100) /
+ (rx_packets_delta + rx_err_delta);
+ else
+ rx_quality = 100;
+ IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n",
+ rx_quality, rx_err_delta, rx_packets_delta);
+
+ if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta)
+ tx_quality = 100 - (tx_failures_delta * 100) /
+ (tx_packets_delta + tx_failures_delta);
+ else
+ tx_quality = 100;
+ IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n",
+ tx_quality, tx_failures_delta, tx_packets_delta);
+
+ rssi = average_value(&priv->average_rssi);
+ if (rssi > PERFECT_RSSI)
+ signal_quality = 100;
+ else if (rssi < WORST_RSSI)
+ signal_quality = 0;
+ else
+ signal_quality = (rssi - WORST_RSSI) * 100 /
+ (PERFECT_RSSI - WORST_RSSI);
+ IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
+ signal_quality, rssi);
+
+ quality = min(beacon_quality,
+ min(rate_quality,
+ min(tx_quality, min(rx_quality, signal_quality))));
+ if (quality == beacon_quality)
+ IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
+ quality);
+ if (quality == rate_quality)
+ IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n",
+ quality);
+ if (quality == tx_quality)
+ IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n",
+ quality);
+ if (quality == rx_quality)
+ IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n",
+ quality);
+ if (quality == signal_quality)
+ IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n",
+ quality);
+
+ priv->quality = quality;
+
+ queue_delayed_work(priv->workqueue, &priv->gather_stats,
+ IPW_STATS_INTERVAL);
+}
+
+/**
+ * Handle host notification packet.
+ * Called from interrupt routine
+ */
+static inline void ipw_rx_notification(struct ipw_priv *priv,
+ struct ipw_rx_notification *notif)
+{
+ IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
+
+ switch (notif->subtype) {
+ case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
+ struct notif_association *assoc = ¬if->u.assoc;
+
+ switch (assoc->state) {
+ case CMAS_ASSOCIATED:{
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "associated: '%s' " MAC_FMT
+ " \n",
+ escape_essid(priv->essid,
+ priv->essid_len),
+ MAC_ARG(priv->bssid));
+
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_INFRA:
+ memcpy(priv->ieee->bssid,
+ priv->bssid, ETH_ALEN);
+ break;
+
+ case IW_MODE_ADHOC:
+ memcpy(priv->ieee->bssid,
+ priv->bssid, ETH_ALEN);
+
+ /* clear out the station table */
+ priv->num_stations = 0;
+
+ IPW_DEBUG_ASSOC
+ ("queueing adhoc check\n");
+ queue_delayed_work(priv->
+ workqueue,
+ &priv->
+ adhoc_check,
+ priv->
+ assoc_request.
+ beacon_interval);
+ break;
+ }
+
+ priv->status &= ~STATUS_ASSOCIATING;
+ priv->status |= STATUS_ASSOCIATED;
+
+ netif_carrier_on(priv->net_dev);
+ if (netif_queue_stopped(priv->net_dev)) {
+ IPW_DEBUG_NOTIF
+ ("waking queue\n");
+ netif_wake_queue(priv->net_dev);
+ } else {
+ IPW_DEBUG_NOTIF
+ ("starting queue\n");
+ netif_start_queue(priv->
+ net_dev);
+ }
+
+ ipw_reset_stats(priv);
+ /* Ensure the rate is updated immediately */
+ priv->last_rate =
+ ipw_get_current_rate(priv);
+ schedule_work(&priv->gather_stats);
+ notify_wx_assoc_event(priv);
+
+/* queue_delayed_work(priv->workqueue,
+ &priv->request_scan,
+ SCAN_ASSOCIATED_INTERVAL);
+*/
+ break;
+ }
+
+ case CMAS_AUTHENTICATED:{
+ if (priv->
+ status & (STATUS_ASSOCIATED |
+ STATUS_AUTH)) {
+#ifdef CONFIG_IPW_DEBUG
+ struct notif_authenticate *auth
+ = ¬if->u.auth;
+ IPW_DEBUG(IPW_DL_NOTIF |
+ IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "deauthenticated: '%s' "
+ MAC_FMT
+ ": (0x%04X) - %s \n",
+ escape_essid(priv->
+ essid,
+ priv->
+ essid_len),
+ MAC_ARG(priv->bssid),
+ ntohs(auth->status),
+ ipw_get_status_code
+ (ntohs
+ (auth->status)));
+#endif
+
+ priv->status &=
+ ~(STATUS_ASSOCIATING |
+ STATUS_AUTH |
+ STATUS_ASSOCIATED);
+
+ netif_carrier_off(priv->
+ net_dev);
+ netif_stop_queue(priv->net_dev);
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+ notify_wx_assoc_event(priv);
+ break;
+ }
+
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "authenticated: '%s' " MAC_FMT
+ "\n",
+ escape_essid(priv->essid,
+ priv->essid_len),
+ MAC_ARG(priv->bssid));
+ break;
+ }
+
+ case CMAS_INIT:{
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "disassociated: '%s' " MAC_FMT
+ " \n",
+ escape_essid(priv->essid,
+ priv->essid_len),
+ MAC_ARG(priv->bssid));
+
+ priv->status &=
+ ~(STATUS_DISASSOCIATING |
+ STATUS_ASSOCIATING |
+ STATUS_ASSOCIATED | STATUS_AUTH);
+
+ netif_stop_queue(priv->net_dev);
+ if (!(priv->status & STATUS_ROAMING)) {
+ netif_carrier_off(priv->
+ net_dev);
+ notify_wx_assoc_event(priv);
+
+ /* Cancel any queued work ... */
+ cancel_delayed_work(&priv->
+ request_scan);
+ cancel_delayed_work(&priv->
+ adhoc_check);
+
+ /* Queue up another scan... */
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+
+ cancel_delayed_work(&priv->
+ gather_stats);
+ } else {
+ priv->status |= STATUS_ROAMING;
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+ }
+
+ ipw_reset_stats(priv);
+ break;
+ }
+
+ default:
+ IPW_ERROR("assoc: unknown (%d)\n",
+ assoc->state);
+ break;
+ }
+
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{
+ struct notif_authenticate *auth = ¬if->u.auth;
+ switch (auth->state) {
+ case CMAS_AUTHENTICATED:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+ "authenticated: '%s' " MAC_FMT " \n",
+ escape_essid(priv->essid,
+ priv->essid_len),
+ MAC_ARG(priv->bssid));
+ priv->status |= STATUS_AUTH;
+ break;
+
+ case CMAS_INIT:
+ if (priv->status & STATUS_AUTH) {
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "authentication failed (0x%04X): %s\n",
+ ntohs(auth->status),
+ ipw_get_status_code(ntohs
+ (auth->
+ status)));
+ }
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "deauthenticated: '%s' " MAC_FMT "\n",
+ escape_essid(priv->essid,
+ priv->essid_len),
+ MAC_ARG(priv->bssid));
+
+ priv->status &= ~(STATUS_ASSOCIATING |
+ STATUS_AUTH |
+ STATUS_ASSOCIATED);
+
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+ notify_wx_assoc_event(priv);
+ break;
+
+ case CMAS_TX_AUTH_SEQ_1:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUTH_SEQ_1\n");
+ break;
+ case CMAS_RX_AUTH_SEQ_2:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUTH_SEQ_2\n");
+ break;
+ case CMAS_AUTH_SEQ_1_PASS:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n");
+ break;
+ case CMAS_AUTH_SEQ_1_FAIL:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n");
+ break;
+ case CMAS_TX_AUTH_SEQ_3:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUTH_SEQ_3\n");
+ break;
+ case CMAS_RX_AUTH_SEQ_4:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n");
+ break;
+ case CMAS_AUTH_SEQ_2_PASS:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n");
+ break;
+ case CMAS_AUTH_SEQ_2_FAIL:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n");
+ break;
+ case CMAS_TX_ASSOC:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "TX_ASSOC\n");
+ break;
+ case CMAS_RX_ASSOC_RESP:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
+ break;
+ case CMAS_ASSOCIATED:
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
+ IPW_DL_ASSOC, "ASSOCIATED\n");
+ break;
+ default:
+ IPW_DEBUG_NOTIF("auth: failure - %d\n",
+ auth->state);
+ break;
+ }
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{
+ struct notif_channel_result *x =
+ ¬if->u.channel_result;
+
+ if (notif->size == sizeof(*x)) {
+ IPW_DEBUG_SCAN("Scan result for channel %d\n",
+ x->channel_num);
+ } else {
+ IPW_DEBUG_SCAN("Scan result of wrong size %d "
+ "(should be %zd)\n",
+ notif->size, sizeof(*x));
+ }
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
+ struct notif_scan_complete *x = ¬if->u.scan_complete;
+ if (notif->size == sizeof(*x)) {
+ IPW_DEBUG_SCAN
+ ("Scan completed: type %d, %d channels, "
+ "%d status\n", x->scan_type,
+ x->num_channels, x->status);
+ } else {
+ IPW_ERROR("Scan completed of wrong size %d "
+ "(should be %zd)\n",
+ notif->size, sizeof(*x));
+ }
+
+ priv->status &=
+ ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
+
+ cancel_delayed_work(&priv->scan_check);
+
+ if (!(priv->status & (STATUS_ASSOCIATED |
+ STATUS_ASSOCIATING |
+ STATUS_ROAMING |
+ STATUS_DISASSOCIATING)))
+ queue_work(priv->workqueue, &priv->associate);
+ else if (priv->status & STATUS_ROAMING) {
+ /* If a scan completed and we are in roam mode, then
+ * the scan that completed was the one requested as a
+ * result of entering roam... so, schedule the
+ * roam work */
+ queue_work(priv->workqueue, &priv->roam);
+ } else if (priv->status & STATUS_SCAN_PENDING)
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+
+ priv->ieee->scans++;
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
+ struct notif_frag_length *x = ¬if->u.frag_len;
+
+ if (notif->size == sizeof(*x)) {
+ IPW_ERROR("Frag length: %d\n", x->frag_length);
+ } else {
+ IPW_ERROR("Frag length of wrong size %d "
+ "(should be %zd)\n",
+ notif->size, sizeof(*x));
+ }
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
+ struct notif_link_deterioration *x =
+ ¬if->u.link_deterioration;
+ if (notif->size == sizeof(*x)) {
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+ "link deterioration: '%s' " MAC_FMT
+ " \n", escape_essid(priv->essid,
+ priv->essid_len),
+ MAC_ARG(priv->bssid));
+ memcpy(&priv->last_link_deterioration, x,
+ sizeof(*x));
+ } else {
+ IPW_ERROR("Link Deterioration of wrong size %d "
+ "(should be %zd)\n",
+ notif->size, sizeof(*x));
+ }
+ break;
+ }
+
+ case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
+ IPW_ERROR("Dino config\n");
+ if (priv->hcmd
+ && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) {
+ /* TODO: Do anything special? */
+ } else {
+ IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
+ }
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
+ struct notif_beacon_state *x = ¬if->u.beacon_state;
+ if (notif->size != sizeof(*x)) {
+ IPW_ERROR
+ ("Beacon state of wrong size %d (should "
+ "be %zd)\n", notif->size, sizeof(*x));
+ break;
+ }
+
+ if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) {
+ if (priv->status & STATUS_SCANNING) {
+ /* Stop scan to keep fw from getting
+ * stuck... */
+ queue_work(priv->workqueue,
+ &priv->abort_scan);
+ }
+
+ if (x->number > priv->missed_beacon_threshold &&
+ priv->status & STATUS_ASSOCIATED) {
+ IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+ IPW_DL_STATE,
+ "Missed beacon: %d - disassociate\n",
+ x->number);
+ queue_work(priv->workqueue,
+ &priv->disassociate);
+ } else if (x->number > priv->roaming_threshold) {
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+ "Missed beacon: %d - initiate "
+ "roaming\n", x->number);
+ queue_work(priv->workqueue,
+ &priv->roam);
+ } else {
+ IPW_DEBUG_NOTIF("Missed beacon: %d\n",
+ x->number);
+ }
+
+ priv->notif_missed_beacons = x->number;
+
+ }
+
+ break;
+ }
+
+ case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
+ struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key;
+ if (notif->size == sizeof(*x)) {
+ IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
+ "0x%02x station %d\n",
+ x->key_state, x->security_type,
+ x->station_index);
+ break;
+ }
+
+ IPW_ERROR
+ ("TGi Tx Key of wrong size %d (should be %zd)\n",
+ notif->size, sizeof(*x));
+ break;
+ }
+
+ case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
+ struct notif_calibration *x = ¬if->u.calibration;
+
+ if (notif->size == sizeof(*x)) {
+ memcpy(&priv->calib, x, sizeof(*x));
+ IPW_DEBUG_INFO("TODO: Calibration\n");
+ break;
+ }
+
+ IPW_ERROR
+ ("Calibration of wrong size %d (should be %zd)\n",
+ notif->size, sizeof(*x));
+ break;
+ }
+
+ case HOST_NOTIFICATION_NOISE_STATS:{
+ if (notif->size == sizeof(u32)) {
+ priv->last_noise =
+ (u8) (notif->u.noise.value & 0xff);
+ average_add(&priv->average_noise,
+ priv->last_noise);
+ break;
+ }
+
+ IPW_ERROR
+ ("Noise stat is wrong size %d (should be %zd)\n",
+ notif->size, sizeof(u32));
+ break;
+ }
+
+ default:
+ IPW_ERROR("Unknown notification: "
+ "subtype=%d,flags=0x%2x,size=%d\n",
+ notif->subtype, notif->flags, notif->size);
+ }
+}
+
+/**
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+static int ipw_queue_reset(struct ipw_priv *priv)
+{
+ int rc = 0;
+ /** @todo customize queue sizes */
+ int nTx = 64, nTxCmd = 8;
+ ipw_tx_queue_free(priv);
+ /* Tx CMD queue */
+ rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
+ CX2_TX_CMD_QUEUE_READ_INDEX,
+ CX2_TX_CMD_QUEUE_WRITE_INDEX,
+ CX2_TX_CMD_QUEUE_BD_BASE,
+ CX2_TX_CMD_QUEUE_BD_SIZE);
+ if (rc) {
+ IPW_ERROR("Tx Cmd queue init failed\n");
+ goto error;
+ }
+ /* Tx queue(s) */
+ rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
+ CX2_TX_QUEUE_0_READ_INDEX,
+ CX2_TX_QUEUE_0_WRITE_INDEX,
+ CX2_TX_QUEUE_0_BD_BASE, CX2_TX_QUEUE_0_BD_SIZE);
+ if (rc) {
+ IPW_ERROR("Tx 0 queue init failed\n");
+ goto error;
+ }
+ rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
+ CX2_TX_QUEUE_1_READ_INDEX,
+ CX2_TX_QUEUE_1_WRITE_INDEX,
+ CX2_TX_QUEUE_1_BD_BASE, CX2_TX_QUEUE_1_BD_SIZE);
+ if (rc) {
+ IPW_ERROR("Tx 1 queue init failed\n");
+ goto error;
+ }
+ rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
+ CX2_TX_QUEUE_2_READ_INDEX,
+ CX2_TX_QUEUE_2_WRITE_INDEX,
+ CX2_TX_QUEUE_2_BD_BASE, CX2_TX_QUEUE_2_BD_SIZE);
+ if (rc) {
+ IPW_ERROR("Tx 2 queue init failed\n");
+ goto error;
+ }
+ rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
+ CX2_TX_QUEUE_3_READ_INDEX,
+ CX2_TX_QUEUE_3_WRITE_INDEX,
+ CX2_TX_QUEUE_3_BD_BASE, CX2_TX_QUEUE_3_BD_SIZE);
+ if (rc) {
+ IPW_ERROR("Tx 3 queue init failed\n");
+ goto error;
+ }
+ /* statistics */
+ priv->rx_bufs_min = 0;
+ priv->rx_pend_max = 0;
+ return rc;
+
+ error:
+ ipw_tx_queue_free(priv);
+ return rc;
+}
+
+/**
+ * Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW adwances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ *
+ * @note Need to protect against garbage in 'R' index
+ * @param priv
+ * @param txq
+ * @param qindex
+ * @return Number of used entries remains in the queue
+ */
+static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
+ struct clx2_tx_queue *txq, int qindex)
+{
+ u32 hw_tail;
+ int used;
+ struct clx2_queue *q = &txq->q;
+
+ hw_tail = ipw_read32(priv, q->reg_r);
+ if (hw_tail >= q->n_bd) {
+ IPW_ERROR
+ ("Read index for DMA queue (%d) is out of range [0-%d)\n",
+ hw_tail, q->n_bd);
+ goto done;
+ }
+ for (; q->last_used != hw_tail;
+ q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
+ ipw_queue_tx_free_tfd(priv, txq);
+ priv->tx_packets++;
+ }
+ done:
+ if (ipw_queue_space(q) > q->low_mark && qindex >= 0) {
+ __maybe_wake_tx(priv);
+ }
+ used = q->first_empty - q->last_used;
+ if (used < 0)
+ used += q->n_bd;
+
+ return used;
+}
+
+static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
+ int len, int sync)
+{
+ struct clx2_tx_queue *txq = &priv->txq_cmd;
+ struct clx2_queue *q = &txq->q;
+ struct tfd_frame *tfd;
+
+ if (ipw_queue_space(q) < (sync ? 1 : 2)) {
+ IPW_ERROR("No space for Tx\n");
+ return -EBUSY;
+ }
+
+ tfd = &txq->bd[q->first_empty];
+ txq->txb[q->first_empty] = NULL;
+
+ memset(tfd, 0, sizeof(*tfd));
+ tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE;
+ tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
+ priv->hcmd_seq++;
+ tfd->u.cmd.index = hcmd;
+ tfd->u.cmd.length = len;
+ memcpy(tfd->u.cmd.payload, buf, len);
+ q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
+ ipw_write32(priv, q->reg_w, q->first_empty);
+ _ipw_read32(priv, 0x90);
+
+ return 0;
+}
+
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register CX2_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When
+ * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replensish the ipw->rxq->rx_free.
+ * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the
+ * ipw->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the ipw->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ
+ * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * ipw_rx_queue_alloc() Allocates rx_free
+ * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls
+ * ipw_rx_queue_restock
+ * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules ipw_rx_queue_replenish
+ *
+ * -- enable interrupts --
+ * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls ipw_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/*
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static void ipw_rx_queue_restock(struct ipw_priv *priv)
+{
+ struct ipw_rx_queue *rxq = priv->rxq;
+ struct list_head *element;
+ struct ipw_rx_mem_buffer *rxb;
+ unsigned long flags;
+ int write;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ write = rxq->write;
+ while ((rxq->write != rxq->processed) && (rxq->free_count)) {
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
+ list_del(element);
+
+ ipw_write32(priv, CX2_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
+ rxb->dma_addr);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ /* If the pre-allocated buffer pool is dropping low, schedule to
+ * refill it */
+ if (rxq->free_count <= RX_LOW_WATERMARK)
+ queue_work(priv->workqueue, &priv->rx_replenish);
+
+ /* If we've added more space for the firmware to place data, tell it */
+ if (write != rxq->write)
+ ipw_write32(priv, CX2_RX_WRITE_INDEX, rxq->write);
+}
+
+/*
+ * Move all used packet from rx_used to rx_free, allocating a new SKB for each.
+ * Also restock the Rx queue via ipw_rx_queue_restock.
+ *
+ * This is called as a scheduled work item (except for during intialization)
+ */
+static void ipw_rx_queue_replenish(void *data)
+{
+ struct ipw_priv *priv = data;
+ struct ipw_rx_queue *rxq = priv->rxq;
+ struct list_head *element;
+ struct ipw_rx_mem_buffer *rxb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ while (!list_empty(&rxq->rx_used)) {
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
+ rxb->skb = alloc_skb(CX2_RX_BUF_SIZE, GFP_ATOMIC);
+ if (!rxb->skb) {
+ printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
+ priv->net_dev->name);
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ break;
+ }
+ list_del(element);
+
+ rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ ipw_rx_queue_restock(priv);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq)
+{
+ int i;
+
+ if (!rxq)
+ return;
+
+ for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
+ CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ }
+
+ kfree(rxq);
+}
+
+static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
+{
+ struct ipw_rx_queue *rxq;
+ int i;
+
+ rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL);
+ memset(rxq, 0, sizeof(*rxq));
+ spin_lock_init(&rxq->lock);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->processed = RX_QUEUE_SIZE - 1;
+ rxq->free_count = 0;
+
+ return rxq;
+}
+
+static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
+{
+ rate &= ~IEEE80211_BASIC_RATE_MASK;
+ if (ieee_mode == IEEE_A) {
+ switch (rate) {
+ case IEEE80211_OFDM_RATE_6MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ?
+ 1 : 0;
+ case IEEE80211_OFDM_RATE_9MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ?
+ 1 : 0;
+ case IEEE80211_OFDM_RATE_12MB:
+ return priv->
+ rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_18MB:
+ return priv->
+ rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_24MB:
+ return priv->
+ rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_36MB:
+ return priv->
+ rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_48MB:
+ return priv->
+ rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_54MB:
+ return priv->
+ rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0;
+ default:
+ return 0;
+ }
+ }
+
+ /* B and G mixed */
+ switch (rate) {
+ case IEEE80211_CCK_RATE_1MB:
+ return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0;
+ case IEEE80211_CCK_RATE_2MB:
+ return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0;
+ case IEEE80211_CCK_RATE_5MB:
+ return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0;
+ case IEEE80211_CCK_RATE_11MB:
+ return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0;
+ }
+
+ /* If we are limited to B modulations, bail at this point */
+ if (ieee_mode == IEEE_B)
+ return 0;
+
+ /* G */
+ switch (rate) {
+ case IEEE80211_OFDM_RATE_6MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_9MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_12MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_18MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_24MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_36MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_48MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0;
+ case IEEE80211_OFDM_RATE_54MB:
+ return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0;
+ }
+
+ return 0;
+}
+
+static int ipw_compatible_rates(struct ipw_priv *priv,
+ const struct ieee80211_network *network,
+ struct ipw_supported_rates *rates)
+{
+ int num_rates, i;
+
+ memset(rates, 0, sizeof(*rates));
+ num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
+ rates->num_rates = 0;
+ for (i = 0; i < num_rates; i++) {
+ if (!ipw_is_rate_in_mask
+ (priv, network->mode, network->rates[i])) {
+ IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
+ network->rates[i], priv->rates_mask);
+ continue;
+ }
+
+ rates->supported_rates[rates->num_rates++] = network->rates[i];
+ }
+
+ num_rates =
+ min(network->rates_ex_len, (u8) (IPW_MAX_RATES - num_rates));
+ for (i = 0; i < num_rates; i++) {
+ if (!ipw_is_rate_in_mask
+ (priv, network->mode, network->rates_ex[i])) {
+ IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
+ network->rates_ex[i], priv->rates_mask);
+ continue;
+ }
+
+ rates->supported_rates[rates->num_rates++] =
+ network->rates_ex[i];
+ }
+
+ return rates->num_rates;
+}
+
+static inline void ipw_copy_rates(struct ipw_supported_rates *dest,
+ const struct ipw_supported_rates *src)
+{
+ u8 i;
+ for (i = 0; i < src->num_rates; i++)
+ dest->supported_rates[i] = src->supported_rates[i];
+ dest->num_rates = src->num_rates;
+}
+
+/* TODO: Look at sniffed packets in the air to determine if the basic rate
+ * mask should ever be used -- right now all callers to add the scan rates are
+ * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */
+static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates,
+ u8 modulation, u32 rate_mask)
+{
+ u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ?
+ IEEE80211_BASIC_RATE_MASK : 0;
+
+ if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+
+ if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+
+ if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK)
+ rates->supported_rates[rates->num_rates++] = basic_mask |
+ IEEE80211_CCK_RATE_5MB;
+
+ if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK)
+ rates->supported_rates[rates->num_rates++] = basic_mask |
+ IEEE80211_CCK_RATE_11MB;
+}
+
+static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates,
+ u8 modulation, u32 rate_mask)
+{
+ u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ?
+ IEEE80211_BASIC_RATE_MASK : 0;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK)
+ rates->supported_rates[rates->num_rates++] = basic_mask |
+ IEEE80211_OFDM_RATE_6MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_OFDM_RATE_9MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK)
+ rates->supported_rates[rates->num_rates++] = basic_mask |
+ IEEE80211_OFDM_RATE_12MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_OFDM_RATE_18MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK)
+ rates->supported_rates[rates->num_rates++] = basic_mask |
+ IEEE80211_OFDM_RATE_24MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_OFDM_RATE_36MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_OFDM_RATE_48MB;
+
+ if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK)
+ rates->supported_rates[rates->num_rates++] =
+ IEEE80211_OFDM_RATE_54MB;
+}
+
+struct ipw_network_match {
+ struct ieee80211_network *network;
+ struct ipw_supported_rates rates;
+};
+
+static int ipw_best_network(struct ipw_priv *priv,
+ struct ipw_network_match *match,
+ struct ieee80211_network *network, int roaming)
+{
+ struct ipw_supported_rates rates;
+
+ /* Verify that this network's capability is compatible with the
+ * current mode (AdHoc or Infrastructure) */
+ if ((priv->ieee->iw_mode == IW_MODE_INFRA &&
+ !(network->capability & WLAN_CAPABILITY_ESS)) ||
+ (priv->ieee->iw_mode == IW_MODE_ADHOC &&
+ !(network->capability & WLAN_CAPABILITY_IBSS))) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to "
+ "capability mismatch.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ /* If we do not have an ESSID for this AP, we can not associate with
+ * it */
+ if (network->flags & NETWORK_EMPTY_ESSID) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of hidden ESSID.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ if (unlikely(roaming)) {
+ /* If we are roaming, then ensure check if this is a valid
+ * network to try and roam to */
+ if ((network->ssid_len != match->network->ssid_len) ||
+ memcmp(network->ssid, match->network->ssid,
+ network->ssid_len)) {
+ IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded "
+ "because of non-network ESSID.\n",
+ escape_essid(network->ssid,
+ network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+ } else {
+ /* If an ESSID has been configured then compare the broadcast
+ * ESSID to ours */
+ if ((priv->config & CFG_STATIC_ESSID) &&
+ ((network->ssid_len != priv->essid_len) ||
+ memcmp(network->ssid, priv->essid,
+ min(network->ssid_len, priv->essid_len)))) {
+ char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ strncpy(escaped,
+ escape_essid(network->ssid, network->ssid_len),
+ sizeof(escaped));
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of ESSID mismatch: '%s'.\n",
+ escaped, MAC_ARG(network->bssid),
+ escape_essid(priv->essid,
+ priv->essid_len));
+ return 0;
+ }
+ }
+
+ /* If the old network rate is better than this one, don't bother
+ * testing everything else. */
+ if (match->network && match->network->stats.rssi > network->stats.rssi) {
+ char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ strncpy(escaped,
+ escape_essid(network->ssid, network->ssid_len),
+ sizeof(escaped));
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because "
+ "'%s (" MAC_FMT ")' has a stronger signal.\n",
+ escaped, MAC_ARG(network->bssid),
+ escape_essid(match->network->ssid,
+ match->network->ssid_len),
+ MAC_ARG(match->network->bssid));
+ return 0;
+ }
+
+ /* If this network has already had an association attempt within the
+ * last 3 seconds, do not try and associate again... */
+ if (network->last_associate &&
+ time_after(network->last_associate + (HZ * 5UL), jiffies)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of storming (%lu since last "
+ "assoc attempt).\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ (jiffies - network->last_associate) / HZ);
+ return 0;
+ }
+
+ /* Now go through and see if the requested network is valid... */
+ if (priv->ieee->scan_age != 0 &&
+ jiffies - network->last_scanned > priv->ieee->scan_age) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of age: %lums.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ (jiffies - network->last_scanned) / (HZ / 100));
+ return 0;
+ }
+
+ if ((priv->config & CFG_STATIC_CHANNEL) &&
+ (network->channel != priv->channel)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of channel mismatch: %d != %d.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ network->channel, priv->channel);
+ return 0;
+ }
+
+ /* Verify privacy compatability */
+ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
+ ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of privacy mismatch: %s != %s.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ priv->capability & CAP_PRIVACY_ON ? "on" :
+ "off",
+ network->capability &
+ WLAN_CAPABILITY_PRIVACY ? "on" : "off");
+ return 0;
+ }
+
+ if ((priv->config & CFG_STATIC_BSSID) &&
+ memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of BSSID mismatch: " MAC_FMT ".\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+ return 0;
+ }
+
+ /* Filter out any incompatible freq / mode combinations */
+ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of invalid frequency/mode "
+ "combination.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ ipw_compatible_rates(priv, network, &rates);
+ if (rates.num_rates == 0) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of no compatible rates.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ /* TODO: Perform any further minimal comparititive tests. We do not
+ * want to put too much policy logic here; intelligent scan selection
+ * should occur within a generic IEEE 802.11 user space tool. */
+
+ /* Set up 'new' AP to this network */
+ ipw_copy_rates(&match->rates, &rates);
+ match->network = network;
+
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+
+ return 1;
+}
+
+static void ipw_adhoc_create(struct ipw_priv *priv,
+ struct ieee80211_network *network)
+{
+ /*
+ * For the purposes of scanning, we can set our wireless mode
+ * to trigger scans across combinations of bands, but when it
+ * comes to creating a new ad-hoc network, we have tell the FW
+ * exactly which band to use.
+ *
+ * We also have the possibility of an invalid channel for the
+ * chossen band. Attempting to create a new ad-hoc network
+ * with an invalid channel for wireless mode will trigger a
+ * FW fatal error.
+ */
+ network->mode = is_valid_channel(priv->ieee->mode, priv->channel);
+ if (network->mode) {
+ network->channel = priv->channel;
+ } else {
+ IPW_WARNING("Overriding invalid channel\n");
+ if (priv->ieee->mode & IEEE_A) {
+ network->mode = IEEE_A;
+ priv->channel = band_a_active_channel[0];
+ } else if (priv->ieee->mode & IEEE_G) {
+ network->mode = IEEE_G;
+ priv->channel = band_b_active_channel[0];
+ } else {
+ network->mode = IEEE_B;
+ priv->channel = band_b_active_channel[0];
+ }
+ }
+
+ network->channel = priv->channel;
+ priv->config |= CFG_ADHOC_PERSIST;
+ ipw_create_bssid(priv, network->bssid);
+ network->ssid_len = priv->essid_len;
+ memcpy(network->ssid, priv->essid, priv->essid_len);
+ memset(&network->stats, 0, sizeof(network->stats));
+ network->capability = WLAN_CAPABILITY_IBSS;
+ if (priv->capability & CAP_PRIVACY_ON)
+ network->capability |= WLAN_CAPABILITY_PRIVACY;
+ network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
+ memcpy(network->rates, priv->rates.supported_rates, network->rates_len);
+ network->rates_ex_len = priv->rates.num_rates - network->rates_len;
+ memcpy(network->rates_ex,
+ &priv->rates.supported_rates[network->rates_len],
+ network->rates_ex_len);
+ network->last_scanned = 0;
+ network->flags = 0;
+ network->last_associate = 0;
+ network->time_stamp[0] = 0;
+ network->time_stamp[1] = 0;
+ network->beacon_interval = 100; /* Default */
+ network->listen_interval = 10; /* Default */
+ network->atim_window = 0; /* Default */
+#ifdef CONFIG_IEEE80211_WPA
+ network->wpa_ie_len = 0;
+ network->rsn_ie_len = 0;
+#endif /* CONFIG_IEEE80211_WPA */
+}
+
+static void ipw_send_wep_keys(struct ipw_priv *priv)
+{
+ struct ipw_wep_key *key;
+ int i;
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_WEP_KEY,
+ .len = sizeof(*key)
+ };
+
+ key = (struct ipw_wep_key *)&cmd.param;
+ key->cmd_id = DINO_CMD_WEP_KEY;
+ key->seq_num = 0;
+
+ for (i = 0; i < 4; i++) {
+ key->key_index = i;
+ if (!(priv->sec.flags & (1 << i))) {
+ key->key_size = 0;
+ } else {
+ key->key_size = priv->sec.key_sizes[i];
+ memcpy(key->key, priv->sec.keys[i], key->key_size);
+ }
+
+ if (ipw_send_cmd(priv, &cmd)) {
+ IPW_ERROR("failed to send WEP_KEY command\n");
+ return;
+ }
+ }
+}
+
+static void ipw_adhoc_check(void *data)
+{
+ struct ipw_priv *priv = data;
+
+ if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold &&
+ !(priv->config & CFG_ADHOC_PERSIST)) {
+ IPW_DEBUG_SCAN("Disassociating due to missed beacons\n");
+ ipw_remove_current_network(priv);
+ ipw_disassociate(priv);
+ return;
+ }
+
+ queue_delayed_work(priv->workqueue, &priv->adhoc_check,
+ priv->assoc_request.beacon_interval);
+}
+
+#ifdef CONFIG_IPW_DEBUG
+static void ipw_debug_config(struct ipw_priv *priv)
+{
+ IPW_DEBUG_INFO("Scan completed, no valid APs matched "
+ "[CFG 0x%08X]\n", priv->config);
+ if (priv->config & CFG_STATIC_CHANNEL)
+ IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel);
+ else
+ IPW_DEBUG_INFO("Channel unlocked.\n");
+ if (priv->config & CFG_STATIC_ESSID)
+ IPW_DEBUG_INFO("ESSID locked to '%s'\n",
+ escape_essid(priv->essid, priv->essid_len));
+ else
+ IPW_DEBUG_INFO("ESSID unlocked.\n");
+ if (priv->config & CFG_STATIC_BSSID)
+ IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel);
+ else
+ IPW_DEBUG_INFO("BSSID unlocked.\n");
+ if (priv->capability & CAP_PRIVACY_ON)
+ IPW_DEBUG_INFO("PRIVACY on\n");
+ else
+ IPW_DEBUG_INFO("PRIVACY off\n");
+ IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
+}
+#else
+#define ipw_debug_config(x) do {} while (0)
+#endif
+
+static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
+ struct ieee80211_network *network)
+{
+ /* TODO: Verify that this works... */
+ struct ipw_fixed_rate fr = {
+ .tx_rates = priv->rates_mask
+ };
+ u32 reg;
+ u16 mask = 0;
+
+ /* Identify 'current FW band' and match it with the fixed
+ * Tx rates */
+
+ switch (priv->ieee->freq_band) {
+ case IEEE80211_52GHZ_BAND: /* A only */
+ /* IEEE_A */
+ if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) {
+ /* Invalid fixed rate mask */
+ fr.tx_rates = 0;
+ break;
+ }
+
+ fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A;
+ break;
+
+ default: /* 2.4Ghz or Mixed */
+ /* IEEE_B */
+ if (network->mode == IEEE_B) {
+ if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) {
+ /* Invalid fixed rate mask */
+ fr.tx_rates = 0;
+ }
+ break;
+ }
+
+ /* IEEE_G */
+ if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK |
+ IEEE80211_OFDM_RATES_MASK)) {
+ /* Invalid fixed rate mask */
+ fr.tx_rates = 0;
+ break;
+ }
+
+ if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) {
+ mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1);
+ fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK;
+ }
+
+ if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) {
+ mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1);
+ fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK;
+ }
+
+ if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) {
+ mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1);
+ fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK;
+ }
+
+ fr.tx_rates |= mask;
+ break;
+ }
+
+ reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
+ ipw_write_reg32(priv, reg, *(u32 *) & fr);
+}
+
+static int ipw_associate_network(struct ipw_priv *priv,
+ struct ieee80211_network *network,
+ struct ipw_supported_rates *rates, int roaming)
+{
+ int err;
+
+ if (priv->config & CFG_FIXED_RATE)
+ ipw_set_fixed_rate(priv, network);
+
+ if (!(priv->config & CFG_STATIC_ESSID)) {
+ priv->essid_len = min(network->ssid_len,
+ (u8) IW_ESSID_MAX_SIZE);
+ memcpy(priv->essid, network->ssid, priv->essid_len);
+ }
+
+ network->last_associate = jiffies;
+
+ memset(&priv->assoc_request, 0, sizeof(priv->assoc_request));
+ priv->assoc_request.channel = network->channel;
+ if ((priv->capability & CAP_PRIVACY_ON) &&
+ (priv->capability & CAP_SHARED_KEY)) {
+ priv->assoc_request.auth_type = AUTH_SHARED_KEY;
+ priv->assoc_request.auth_key = priv->sec.active_key;
+ } else {
+ priv->assoc_request.auth_type = AUTH_OPEN;
+ priv->assoc_request.auth_key = 0;
+ }
+
+ if (priv->capability & CAP_PRIVACY_ON)
+ ipw_send_wep_keys(priv);
+
+ /*
+ * It is valid for our ieee device to support multiple modes, but
+ * when it comes to associating to a given network we have to choose
+ * just one mode.
+ */
+ if (network->mode & priv->ieee->mode & IEEE_A)
+ priv->assoc_request.ieee_mode = IPW_A_MODE;
+ else if (network->mode & priv->ieee->mode & IEEE_G)
+ priv->assoc_request.ieee_mode = IPW_G_MODE;
+ else if (network->mode & priv->ieee->mode & IEEE_B)
+ priv->assoc_request.ieee_mode = IPW_B_MODE;
+
+ IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
+ "802.11%c [%d], enc=%s%s%s%c%c\n",
+ roaming ? "Rea" : "A",
+ escape_essid(priv->essid, priv->essid_len),
+ network->channel,
+ ipw_modes[priv->assoc_request.ieee_mode],
+ rates->num_rates,
+ priv->capability & CAP_PRIVACY_ON ? "on " : "off",
+ priv->capability & CAP_PRIVACY_ON ?
+ (priv->capability & CAP_SHARED_KEY ? "(shared)" :
+ "(open)") : "",
+ priv->capability & CAP_PRIVACY_ON ? " key=" : "",
+ priv->capability & CAP_PRIVACY_ON ?
+ '1' + priv->sec.active_key : '.',
+ priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
+
+ priv->assoc_request.beacon_interval = network->beacon_interval;
+ if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
+ (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) {
+ priv->assoc_request.assoc_type = HC_IBSS_START;
+ priv->assoc_request.assoc_tsf_msw = 0;
+ priv->assoc_request.assoc_tsf_lsw = 0;
+ } else {
+ if (unlikely(roaming))
+ priv->assoc_request.assoc_type = HC_REASSOCIATE;
+ else
+ priv->assoc_request.assoc_type = HC_ASSOCIATE;
+ priv->assoc_request.assoc_tsf_msw = network->time_stamp[1];
+ priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0];
+ }
+
+ memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN);
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN);
+ priv->assoc_request.atim_window = network->atim_window;
+ } else {
+ memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN);
+ priv->assoc_request.atim_window = 0;
+ }
+
+ priv->assoc_request.capability = network->capability;
+ priv->assoc_request.listen_interval = network->listen_interval;
+
+ err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
+ return err;
+ }
+
+ rates->ieee_mode = priv->assoc_request.ieee_mode;
+ rates->purpose = IPW_RATE_CONNECT;
+ ipw_send_supported_rates(priv, rates);
+
+ if (priv->assoc_request.ieee_mode == IPW_G_MODE)
+ priv->sys_config.dot11g_auto_detection = 1;
+ else
+ priv->sys_config.dot11g_auto_detection = 0;
+ err = ipw_send_system_config(priv, &priv->sys_config);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
+ return err;
+ }
+
+ IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
+ err = ipw_set_sensitivity(priv, network->stats.rssi);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send associate command failed.\n");
+ return err;
+ }
+
+ /*
+ * If preemption is enabled, it is possible for the association
+ * to complete before we return from ipw_send_associate. Therefore
+ * we have to be sure and update our priviate data first.
+ */
+ priv->channel = network->channel;
+ memcpy(priv->bssid, network->bssid, ETH_ALEN);
+ priv->status |= STATUS_ASSOCIATING;
+ priv->status &= ~STATUS_SECURITY_UPDATED;
+
+ priv->assoc_network = network;
+
+ err = ipw_send_associate(priv, &priv->assoc_request);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send associate command failed.\n");
+ return err;
+ }
+
+ IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n",
+ escape_essid(priv->essid, priv->essid_len),
+ MAC_ARG(priv->bssid));
+
+ return 0;
+}
+
+static void ipw_roam(void *data)
+{
+ struct ipw_priv *priv = data;
+ struct ieee80211_network *network = NULL;
+ struct ipw_network_match match = {
+ .network = priv->assoc_network
+ };
+
+ /* The roaming process is as follows:
+ *
+ * 1. Missed beacon threshold triggers the roaming process by
+ * setting the status ROAM bit and requesting a scan.
+ * 2. When the scan completes, it schedules the ROAM work
+ * 3. The ROAM work looks at all of the known networks for one that
+ * is a better network than the currently associated. If none
+ * found, the ROAM process is over (ROAM bit cleared)
+ * 4. If a better network is found, a disassociation request is
+ * sent.
+ * 5. When the disassociation completes, the roam work is again
+ * scheduled. The second time through, the driver is no longer
+ * associated, and the newly selected network is sent an
+ * association request.
+ * 6. At this point ,the roaming process is complete and the ROAM
+ * status bit is cleared.
+ */
+
+ /* If we are no longer associated, and the roaming bit is no longer
+ * set, then we are not actively roaming, so just return */
+ if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING)))
+ return;
+
+ if (priv->status & STATUS_ASSOCIATED) {
+ /* First pass through ROAM process -- look for a better
+ * network */
+ u8 rssi = priv->assoc_network->stats.rssi;
+ priv->assoc_network->stats.rssi = -128;
+ list_for_each_entry(network, &priv->ieee->network_list, list) {
+ if (network != priv->assoc_network)
+ ipw_best_network(priv, &match, network, 1);
+ }
+ priv->assoc_network->stats.rssi = rssi;
+
+ if (match.network == priv->assoc_network) {
+ IPW_DEBUG_ASSOC("No better APs in this network to "
+ "roam to.\n");
+ priv->status &= ~STATUS_ROAMING;
+ ipw_debug_config(priv);
+ return;
+ }
+
+ ipw_send_disassociate(priv, 1);
+ priv->assoc_network = match.network;
+
+ return;
+ }
+
+ /* Second pass through ROAM process -- request association */
+ ipw_compatible_rates(priv, priv->assoc_network, &match.rates);
+ ipw_associate_network(priv, priv->assoc_network, &match.rates, 1);
+ priv->status &= ~STATUS_ROAMING;
+}
+
+static void ipw_associate(void *data)
+{
+ struct ipw_priv *priv = data;
+
+ struct ieee80211_network *network = NULL;
+ struct ipw_network_match match = {
+ .network = NULL
+ };
+ struct ipw_supported_rates *rates;
+ struct list_head *element;
+
+ if (!(priv->config & CFG_ASSOCIATE) &&
+ !(priv->config & (CFG_STATIC_ESSID |
+ CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) {
+ IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
+ return;
+ }
+
+ list_for_each_entry(network, &priv->ieee->network_list, list)
+ ipw_best_network(priv, &match, network, 0);
+
+ network = match.network;
+ rates = &match.rates;
+
+ if (network == NULL &&
+ priv->ieee->iw_mode == IW_MODE_ADHOC &&
+ priv->config & CFG_ADHOC_CREATE &&
+ priv->config & CFG_STATIC_ESSID &&
+ !list_empty(&priv->ieee->network_free_list)) {
+ element = priv->ieee->network_free_list.next;
+ network = list_entry(element, struct ieee80211_network, list);
+ ipw_adhoc_create(priv, network);
+ rates = &priv->rates;
+ list_del(element);
+ list_add_tail(&network->list, &priv->ieee->network_list);
+ }
+
+ /* If we reached the end of the list, then we don't have any valid
+ * matching APs */
+ if (!network) {
+ ipw_debug_config(priv);
+
+ queue_delayed_work(priv->workqueue, &priv->request_scan,
+ SCAN_INTERVAL);
+
+ return;
+ }
+
+ ipw_associate_network(priv, network, rates, 0);
+}
+
+static inline void ipw_handle_data_packet(struct ipw_priv *priv,
+ struct ipw_rx_mem_buffer *rxb,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
+
+ /* We received data from the HW, so stop the watchdog */
+ priv->net_dev->trans_start = jiffies;
+
+ /* We only process data packets if the
+ * interface is open */
+ if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) >
+ skb_tailroom(rxb->skb))) {
+ priv->ieee->stats.rx_errors++;
+ priv->wstats.discard.misc++;
+ IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
+ return;
+ } else if (unlikely(!netif_running(priv->net_dev))) {
+ priv->ieee->stats.rx_dropped++;
+ priv->wstats.discard.misc++;
+ IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+ return;
+ }
+
+ /* Advance skb->data to the start of the actual payload */
+ skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, pkt->u.frame.length);
+
+ IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+ if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
+ priv->ieee->stats.rx_errors++;
+ else /* ieee80211_rx succeeded, so it now owns the SKB */
+ rxb->skb = NULL;
+}
+
+/*
+ * Main entry function for recieving a packet with 80211 headers. This
+ * should be called when ever the FW has notified us that there is a new
+ * skb in the recieve queue.
+ */
+static void ipw_rx(struct ipw_priv *priv)
+{
+ struct ipw_rx_mem_buffer *rxb;
+ struct ipw_rx_packet *pkt;
+ struct ieee80211_hdr *header;
+ u32 r, w, i;
+ u8 network_packet;
+
+ r = ipw_read32(priv, CX2_RX_READ_INDEX);
+ w = ipw_read32(priv, CX2_RX_WRITE_INDEX);
+ i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;
+
+ while (i != r) {
+ rxb = priv->rxq->queue[i];
+#ifdef CONFIG_IPW_DEBUG
+ if (unlikely(rxb == NULL)) {
+ printk(KERN_CRIT "Queue not allocated!\n");
+ break;
+ }
+#endif
+ priv->rxq->queue[i] = NULL;
+
+ pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+ CX2_RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+
+ pkt = (struct ipw_rx_packet *)rxb->skb->data;
+ IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n",
+ pkt->header.message_type,
+ pkt->header.rx_seq_num, pkt->header.control_bits);
+
+ switch (pkt->header.message_type) {
+ case RX_FRAME_TYPE: /* 802.11 frame */ {
+ struct ieee80211_rx_stats stats = {
+ .rssi = pkt->u.frame.rssi_dbm -
+ IPW_RSSI_TO_DBM,
+ .signal = pkt->u.frame.signal,
+ .rate = pkt->u.frame.rate,
+ .mac_time = jiffies,
+ .received_channel =
+ pkt->u.frame.received_channel,
+ .freq =
+ (pkt->u.frame.
+ control & (1 << 0)) ?
+ IEEE80211_24GHZ_BAND :
+ IEEE80211_52GHZ_BAND,
+ .len = pkt->u.frame.length,
+ };
+
+ if (stats.rssi != 0)
+ stats.mask |= IEEE80211_STATMASK_RSSI;
+ if (stats.signal != 0)
+ stats.mask |= IEEE80211_STATMASK_SIGNAL;
+ if (stats.rate != 0)
+ stats.mask |= IEEE80211_STATMASK_RATE;
+
+ priv->rx_packets++;
+
+#ifdef CONFIG_IPW_PROMISC
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ ipw_handle_data_packet(priv, rxb,
+ &stats);
+ break;
+ }
+#endif
+
+ header =
+ (struct ieee80211_hdr *)(rxb->skb->data +
+ IPW_RX_FRAME_SIZE);
+ /* TODO: Check Ad-Hoc dest/source and make sure
+ * that we are actually parsing these packets
+ * correctly -- we should probably use the
+ * frame control of the packet and disregard
+ * the current iw_mode */
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ network_packet =
+ !memcmp(header->addr1,
+ priv->net_dev->dev_addr,
+ ETH_ALEN) ||
+ !memcmp(header->addr3,
+ priv->bssid, ETH_ALEN) ||
+ is_broadcast_ether_addr(header->
+ addr1)
+ || is_multicast_ether_addr(header->
+ addr1);
+ break;
+
+ case IW_MODE_INFRA:
+ default:
+ network_packet =
+ !memcmp(header->addr3,
+ priv->bssid, ETH_ALEN) ||
+ !memcmp(header->addr1,
+ priv->net_dev->dev_addr,
+ ETH_ALEN) ||
+ is_broadcast_ether_addr(header->
+ addr1)
+ || is_multicast_ether_addr(header->
+ addr1);
+ break;
+ }
+
+ if (network_packet && priv->assoc_network) {
+ priv->assoc_network->stats.rssi =
+ stats.rssi;
+ average_add(&priv->average_rssi,
+ stats.rssi);
+ priv->last_rx_rssi = stats.rssi;
+ }
+
+ IPW_DEBUG_RX("Frame: len=%u\n",
+ pkt->u.frame.length);
+
+ if (pkt->u.frame.length < frame_hdr_len(header)) {
+ IPW_DEBUG_DROP
+ ("Received packet is too small. "
+ "Dropping.\n");
+ priv->ieee->stats.rx_errors++;
+ priv->wstats.discard.misc++;
+ break;
+ }
+
+ switch (WLAN_FC_GET_TYPE(header->frame_ctl)) {
+ case IEEE80211_FTYPE_MGMT:
+ ieee80211_rx_mgt(priv->ieee, header,
+ &stats);
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC
+ &&
+ ((WLAN_FC_GET_STYPE
+ (header->frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP)
+ ||
+ (WLAN_FC_GET_STYPE
+ (header->frame_ctl) ==
+ IEEE80211_STYPE_BEACON))
+ && !memcmp(header->addr3,
+ priv->bssid, ETH_ALEN))
+ ipw_add_station(priv,
+ header->addr2);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+ break;
+
+ case IEEE80211_FTYPE_DATA:
+ if (network_packet)
+ ipw_handle_data_packet(priv,
+ rxb,
+ &stats);
+ else
+ IPW_DEBUG_DROP("Dropping: "
+ MAC_FMT ", "
+ MAC_FMT ", "
+ MAC_FMT "\n",
+ MAC_ARG(header->
+ addr1),
+ MAC_ARG(header->
+ addr2),
+ MAC_ARG(header->
+ addr3));
+ break;
+ }
+ break;
+ }
+
+ case RX_HOST_NOTIFICATION_TYPE:{
+ IPW_DEBUG_RX
+ ("Notification: subtype=%02X flags=%02X size=%d\n",
+ pkt->u.notification.subtype,
+ pkt->u.notification.flags,
+ pkt->u.notification.size);
+ ipw_rx_notification(priv, &pkt->u.notification);
+ break;
+ }
+
+ default:
+ IPW_DEBUG_RX("Bad Rx packet of type %d\n",
+ pkt->header.message_type);
+ break;
+ }
+
+ /* For now we just don't re-use anything. We can tweak this
+ * later to try and re-use notification packets and SKBs that
+ * fail to Rx correctly */
+ if (rxb->skb != NULL) {
+ dev_kfree_skb_any(rxb->skb);
+ rxb->skb = NULL;
+ }
+
+ pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+ CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &priv->rxq->rx_used);
+
+ i = (i + 1) % RX_QUEUE_SIZE;
+ }
+
+ /* Backtrack one entry */
+ priv->rxq->processed = (i ? i : RX_QUEUE_SIZE) - 1;
+
+ ipw_rx_queue_restock(priv);
+}
+
+static void ipw_abort_scan(struct ipw_priv *priv)
+{
+ int err;
+
+ if (priv->status & STATUS_SCAN_ABORTING) {
+ IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
+ return;
+ }
+ priv->status |= STATUS_SCAN_ABORTING;
+
+ err = ipw_send_scan_abort(priv);
+ if (err)
+ IPW_DEBUG_HC("Request to abort scan failed.\n");
+}
+
+static int ipw_request_scan(struct ipw_priv *priv)
+{
+ struct ipw_scan_request_ext scan;
+ int channel_index = 0;
+ int i, err, scan_type;
+
+ if (priv->status & STATUS_EXIT_PENDING) {
+ IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ return 0;
+ }
+
+ if (priv->status & STATUS_SCANNING) {
+ IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ ipw_abort_scan(priv);
+ return 0;
+ }
+
+ if (priv->status & STATUS_SCAN_ABORTING) {
+ IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ return 0;
+ }
+
+ if (priv->status & STATUS_RF_KILL_MASK) {
+ IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ return 0;
+ }
+
+ memset(&scan, 0, sizeof(scan));
+
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20;
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20;
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20;
+
+ scan.full_scan_index = ieee80211_get_scans(priv->ieee);
+ /* If we are roaming, then make this a directed scan for the current
+ * network. Otherwise, ensure that every other scan is a fast
+ * channel hop scan */
+ if ((priv->status & STATUS_ROAMING)
+ || (!(priv->status & STATUS_ASSOCIATED)
+ && (priv->config & CFG_STATIC_ESSID)
+ && (scan.full_scan_index % 2))) {
+ err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
+ return err;
+ }
+
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+ } else {
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
+ }
+
+ if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
+ int start = channel_index;
+ for (i = 0; i < MAX_A_CHANNELS; i++) {
+ if (band_a_active_channel[i] == 0)
+ break;
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ band_a_active_channel[i] == priv->channel)
+ continue;
+ channel_index++;
+ scan.channels_list[channel_index] =
+ band_a_active_channel[i];
+ ipw_set_scan_type(&scan, channel_index, scan_type);
+ }
+
+ if (start != channel_index) {
+ scan.channels_list[start] = (u8) (IPW_A_MODE << 6) |
+ (channel_index - start);
+ channel_index++;
+ }
+ }
+
+ if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
+ int start = channel_index;
+ for (i = 0; i < MAX_B_CHANNELS; i++) {
+ if (band_b_active_channel[i] == 0)
+ break;
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ band_b_active_channel[i] == priv->channel)
+ continue;
+ channel_index++;
+ scan.channels_list[channel_index] =
+ band_b_active_channel[i];
+ ipw_set_scan_type(&scan, channel_index, scan_type);
+ }
+
+ if (start != channel_index) {
+ scan.channels_list[start] = (u8) (IPW_B_MODE << 6) |
+ (channel_index - start);
+ }
+ }
+
+ err = ipw_send_scan_request_ext(priv, &scan);
+ if (err) {
+ IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+ return -EIO;
+ }
+
+ priv->status |= STATUS_SCANNING;
+ priv->status &= ~STATUS_SCAN_PENDING;
+
+ return 0;
+}
+
+/*
+ * This file defines the Wireless Extension handlers. It does not
+ * define any methods of hardware manipulation and relies on the
+ * functions defined in ipw_main to provide the HW interaction.
+ *
+ * The exception to this is the use of the ipw_get_ordinal()
+ * function used to poll the hardware vs. making unecessary calls.
+ *
+ */
+
+static int ipw_wx_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ if (!(priv->status & STATUS_ASSOCIATED))
+ strcpy(wrqu->name, "unassociated");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
+ ipw_modes[priv->assoc_request.ieee_mode]);
+ IPW_DEBUG_WX("Name: %s\n", wrqu->name);
+ return 0;
+}
+
+static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
+{
+ if (channel == 0) {
+ IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
+ priv->config &= ~CFG_STATIC_CHANNEL;
+ if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+ STATUS_ASSOCIATING))) {
+ IPW_DEBUG_ASSOC("Attempting to associate with new "
+ "parameters.\n");
+ ipw_associate(priv);
+ }
+
+ return 0;
+ }
+
+ priv->config |= CFG_STATIC_CHANNEL;
+
+ if (priv->channel == channel) {
+ IPW_DEBUG_INFO("Request to set channel to current value (%d)\n",
+ channel);
+ return 0;
+ }
+
+ IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
+ priv->channel = channel;
+
+ /* If we are currently associated, or trying to associate
+ * then see if this is a new channel (causing us to disassociate) */
+ if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ IPW_DEBUG_ASSOC("Disassociating due to channel change.\n");
+ ipw_disassociate(priv);
+ } else {
+ ipw_associate(priv);
+ }
+
+ return 0;
+}
+
+static int ipw_wx_set_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct iw_freq *fwrq = &wrqu->freq;
+
+ /* if setting by freq convert to channel */
+ if (fwrq->e == 1) {
+ if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
+ int f = fwrq->m / 100000;
+ int c = 0;
+
+ while ((c < REG_MAX_CHANNEL) &&
+ (f != ipw_frequencies[c]))
+ c++;
+
+ /* hack to fall through */
+ fwrq->e = 0;
+ fwrq->m = c + 1;
+ }
+ }
+
+ if (fwrq->e > 0 || fwrq->m > 1000)
+ return -EOPNOTSUPP;
+
+ IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+ return ipw_set_channel(priv, (u8) fwrq->m);
+
+ return 0;
+}
+
+static int ipw_wx_get_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ wrqu->freq.e = 0;
+
+ /* If we are associated, trying to associate, or have a statically
+ * configured CHANNEL then return that; otherwise return ANY */
+ if (priv->config & CFG_STATIC_CHANNEL ||
+ priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
+ wrqu->freq.m = priv->channel;
+ else
+ wrqu->freq.m = 0;
+
+ IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+ return 0;
+}
+
+static int ipw_wx_set_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int err = 0;
+
+ IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
+
+ if (wrqu->mode == priv->ieee->iw_mode)
+ return 0;
+
+ switch (wrqu->mode) {
+#ifdef CONFIG_IPW_PROMISC
+ case IW_MODE_MONITOR:
+#endif
+ case IW_MODE_ADHOC:
+ case IW_MODE_INFRA:
+ break;
+ case IW_MODE_AUTO:
+ wrqu->mode = IW_MODE_INFRA;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_IPW_PROMISC
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR)
+ priv->net_dev->type = ARPHRD_ETHER;
+
+ if (wrqu->mode == IW_MODE_MONITOR)
+ priv->net_dev->type = ARPHRD_IEEE80211;
+#endif /* CONFIG_IPW_PROMISC */
+
+#ifdef CONFIG_PM
+ /* Free the existing firmware and reset the fw_loaded
+ * flag so ipw_load() will bring in the new firmawre */
+ if (fw_loaded) {
+ fw_loaded = 0;
+ }
+
+ release_firmware(bootfw);
+ release_firmware(ucode);
+ release_firmware(firmware);
+ bootfw = ucode = firmware = NULL;
+#endif
+
+ priv->ieee->iw_mode = wrqu->mode;
+ ipw_adapter_restart(priv);
+
+ return err;
+}
+
+static int ipw_wx_get_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ wrqu->mode = priv->ieee->iw_mode;
+ IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
+
+ return 0;
+}
+
+#define DEFAULT_RTS_THRESHOLD 2304U
+#define MIN_RTS_THRESHOLD 1U
+#define MAX_RTS_THRESHOLD 2304U
+#define DEFAULT_BEACON_INTERVAL 100U
+#define DEFAULT_SHORT_RETRY_LIMIT 7U
+#define DEFAULT_LONG_RETRY_LIMIT 4U
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+ 350000,
+ 250000,
+ 75000,
+ 37000,
+ 25000,
+};
+
+static const s32 period_duration[] = {
+ 400000,
+ 700000,
+ 1000000,
+ 1000000,
+ 1000000
+};
+
+static int ipw_wx_get_range(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct iw_range *range = (struct iw_range *)extra;
+ u16 val;
+ int i;
+
+ wrqu->data.length = sizeof(*range);
+ memset(range, 0, sizeof(*range));
+
+ /* 54Mbs == ~27 Mb/s real (802.11g) */
+ range->throughput = 27 * 1000 * 1000;
+
+ range->max_qual.qual = 100;
+ /* TODO: Find real max RSSI and stick here */
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+ range->max_qual.updated = 7; /* Updated all three */
+
+ range->avg_qual.qual = 70;
+ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ range->avg_qual.level = 0; /* FIXME to real average level */
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = 7; /* Updated all three */
+
+ range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
+
+ for (i = 0; i < range->num_bitrates; i++)
+ range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) *
+ 500000;
+
+ range->max_rts = DEFAULT_RTS_THRESHOLD;
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = WEP_KEYS;
+
+ /* Set the Wireless Extension versions */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 16;
+
+ range->num_channels = FREQ_COUNT;
+
+ val = 0;
+ for (i = 0; i < FREQ_COUNT; i++) {
+ range->freq[val].i = i + 1;
+ range->freq[val].m = ipw_frequencies[i] * 100000;
+ range->freq[val].e = 1;
+ val++;
+
+ if (val == IW_MAX_FREQUENCIES)
+ break;
+ }
+ range->num_frequency = val;
+
+ IPW_DEBUG_WX("GET Range\n");
+ return 0;
+}
+
+static int ipw_wx_set_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ static const unsigned char any[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+ static const unsigned char off[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
+ !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+ /* we disable mandatory BSSID association */
+ IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
+ priv->config &= ~CFG_STATIC_BSSID;
+ if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+ STATUS_ASSOCIATING))) {
+ IPW_DEBUG_ASSOC("Attempting to associate with new "
+ "parameters.\n");
+ ipw_associate(priv);
+ }
+
+ return 0;
+ }
+
+ priv->config |= CFG_STATIC_BSSID;
+ if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+ IPW_DEBUG_WX("BSSID set to current BSSID.\n");
+ return 0;
+ }
+
+ IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n",
+ MAC_ARG(wrqu->ap_addr.sa_data));
+
+ memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
+
+ /* If we are currently associated, or trying to associate
+ * then see if this is a new BSSID (causing us to disassociate) */
+ if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n");
+ ipw_disassociate(priv);
+ } else {
+ ipw_associate(priv);
+ }
+
+ return 0;
+}
+
+static int ipw_wx_get_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ /* If we are associated, trying to associate, or have a statically
+ * configured BSSID then return that; otherwise return ANY */
+ if (priv->config & CFG_STATIC_BSSID ||
+ priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+ } else
+ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+ IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
+ MAC_ARG(wrqu->ap_addr.sa_data));
+ return 0;
+}
+
+static int ipw_wx_set_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ char *essid = ""; /* ANY */
+ int length = 0;
+
+ if (wrqu->essid.flags && wrqu->essid.length) {
+ length = wrqu->essid.length - 1;
+ essid = extra;
+ }
+ if (length == 0) {
+ IPW_DEBUG_WX("Setting ESSID to ANY\n");
+ priv->config &= ~CFG_STATIC_ESSID;
+ if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+ STATUS_ASSOCIATING))) {
+ IPW_DEBUG_ASSOC("Attempting to associate with new "
+ "parameters.\n");
+ ipw_associate(priv);
+ }
+
+ return 0;
+ }
+
+ length = min(length, IW_ESSID_MAX_SIZE);
+
+ priv->config |= CFG_STATIC_ESSID;
+
+ if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
+ IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+ return 0;
+ }
+
+ IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
+ length);
+
+ priv->essid_len = length;
+ memcpy(priv->essid, essid, priv->essid_len);
+
+ /* If we are currently associated, or trying to associate
+ * then see if this is a new ESSID (causing us to disassociate) */
+ if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n");
+ ipw_disassociate(priv);
+ } else {
+ ipw_associate(priv);
+ }
+
+ return 0;
+}
+
+static int ipw_wx_get_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ /* If we are associated, trying to associate, or have a statically
+ * configured ESSID then return that; otherwise return ANY */
+ if (priv->config & CFG_STATIC_ESSID ||
+ priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ IPW_DEBUG_WX("Getting essid: '%s'\n",
+ escape_essid(priv->essid, priv->essid_len));
+ memcpy(extra, priv->essid, priv->essid_len);
+ wrqu->essid.length = priv->essid_len;
+ wrqu->essid.flags = 1; /* active */
+ } else {
+ IPW_DEBUG_WX("Getting essid: ANY\n");
+ wrqu->essid.length = 0;
+ wrqu->essid.flags = 0; /* active */
+ }
+
+ return 0;
+}
+
+static int ipw_wx_set_nick(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
+ if (wrqu->data.length > IW_ESSID_MAX_SIZE)
+ return -E2BIG;
+
+ wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+ memset(priv->nick, 0, sizeof(priv->nick));
+ memcpy(priv->nick, extra, wrqu->data.length);
+ IPW_DEBUG_TRACE("<<\n");
+ return 0;
+
+}
+
+static int ipw_wx_get_nick(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ IPW_DEBUG_WX("Getting nick\n");
+ wrqu->data.length = strlen(priv->nick) + 1;
+ memcpy(extra, priv->nick, wrqu->data.length);
+ wrqu->data.flags = 1; /* active */
+ return 0;
+}
+
+static int ipw_wx_set_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
+ return -EOPNOTSUPP;
+}
+
+static int ipw_wx_get_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ wrqu->bitrate.value = priv->last_rate;
+
+ IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+ return 0;
+}
+
+static int ipw_wx_set_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ if (wrqu->rts.disabled)
+ priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+ else {
+ if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
+ wrqu->rts.value > MAX_RTS_THRESHOLD)
+ return -EINVAL;
+
+ priv->rts_threshold = wrqu->rts.value;
+ }
+
+ ipw_send_rts_threshold(priv, priv->rts_threshold);
+ IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
+ return 0;
+}
+
+static int ipw_wx_get_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ wrqu->rts.value = priv->rts_threshold;
+ wrqu->rts.fixed = 0; /* no auto select */
+ wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
+
+ IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
+ return 0;
+}
+
+static int ipw_wx_set_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_tx_power tx_power;
+ int i;
+
+ if (ipw_radio_kill_sw(priv, wrqu->power.disabled))
+ return -EINPROGRESS;
+
+ if (wrqu->power.flags != IW_TXPOW_DBM)
+ return -EINVAL;
+
+ if ((wrqu->power.value > 20) || (wrqu->power.value < -12))
+ return -EINVAL;
+
+ priv->tx_power = wrqu->power.value;
+
+ memset(&tx_power, 0, sizeof(tx_power));
+
+ /* configure device for 'G' band */
+ tx_power.ieee_mode = IPW_G_MODE;
+ tx_power.num_channels = 11;
+ for (i = 0; i < 11; i++) {
+ tx_power.channels_tx_power[i].channel_number = i + 1;
+ tx_power.channels_tx_power[i].tx_power = priv->tx_power;
+ }
+ if (ipw_send_tx_power(priv, &tx_power))
+ goto error;
+
+ /* configure device to also handle 'B' band */
+ tx_power.ieee_mode = IPW_B_MODE;
+ if (ipw_send_tx_power(priv, &tx_power))
+ goto error;
+
+ return 0;
+
+ error:
+ return -EIO;
+}
+
+static int ipw_wx_get_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ wrqu->power.value = priv->tx_power;
+ wrqu->power.fixed = 1;
+ wrqu->power.flags = IW_TXPOW_DBM;
+ wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
+
+ IPW_DEBUG_WX("GET TX Power -> %s %d \n",
+ wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value);
+
+ return 0;
+}
+
+static int ipw_wx_set_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ if (wrqu->frag.disabled)
+ priv->ieee->fts = DEFAULT_FTS;
+ else {
+ if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+ wrqu->frag.value > MAX_FRAG_THRESHOLD)
+ return -EINVAL;
+
+ priv->ieee->fts = wrqu->frag.value & ~0x1;
+ }
+
+ ipw_send_frag_threshold(priv, wrqu->frag.value);
+ IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
+ return 0;
+}
+
+static int ipw_wx_get_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ wrqu->frag.value = priv->ieee->fts;
+ wrqu->frag.fixed = 0; /* no auto select */
+ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
+
+ IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+
+ return 0;
+}
+
+static int ipw_wx_set_retry(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
+ return -EOPNOTSUPP;
+}
+
+static int ipw_wx_get_retry(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
+ return -EOPNOTSUPP;
+}
+
+static int ipw_wx_set_scan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ IPW_DEBUG_WX("Start scan\n");
+ if (ipw_request_scan(priv))
+ return -EIO;
+ return 0;
+}
+
+static int ipw_wx_get_scan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
+}
+
+static int ipw_wx_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw_wx_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
+}
+
+static int ipw_wx_set_power(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int err;
+
+ if (wrqu->power.disabled) {
+ priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
+ err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
+ if (err) {
+ IPW_DEBUG_WX("failed setting power mode.\n");
+ return err;
+ }
+
+ IPW_DEBUG_WX("SET Power Management Mode -> off\n");
+
+ return 0;
+ }
+
+ switch (wrqu->power.flags & IW_POWER_MODE) {
+ case IW_POWER_ON: /* If not specified */
+ case IW_POWER_MODE: /* If set all mask */
+ case IW_POWER_ALL_R: /* If explicitely state all */
+ break;
+ default: /* Otherwise we don't support it */
+ IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
+ wrqu->power.flags);
+ return -EOPNOTSUPP;
+ }
+
+ /* If the user hasn't specified a power management mode yet, default
+ * to BATTERY */
+ if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC)
+ priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
+ else
+ priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+ err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
+ if (err) {
+ IPW_DEBUG_WX("failed setting power mode.\n");
+ return err;
+ }
+
+ IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
+
+ return 0;
+}
+
+static int ipw_wx_get_power(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+ wrqu->power.disabled = 1;
+ } else {
+ wrqu->power.disabled = 0;
+ }
+
+ IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
+
+ return 0;
+}
+
+static int ipw_wx_set_powermode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int mode = *(int *)extra;
+ int err;
+
+ if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
+ mode = IPW_POWER_AC;
+ priv->power_mode = mode;
+ } else {
+ priv->power_mode = IPW_POWER_ENABLED | mode;
+ }
+
+ if (priv->power_mode != mode) {
+ err = ipw_send_power_mode(priv, mode);
+
+ if (err) {
+ IPW_DEBUG_WX("failed setting power mode.\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+#define MAX_WX_STRING 80
+static int ipw_wx_get_powermode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int level = IPW_POWER_LEVEL(priv->power_mode);
+ char *p = extra;
+
+ p += snprintf(p, MAX_WX_STRING, "Power save level: %d ", level);
+
+ switch (level) {
+ case IPW_POWER_AC:
+ p += snprintf(p, MAX_WX_STRING - (p - extra), "(AC)");
+ break;
+ case IPW_POWER_BATTERY:
+ p += snprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)");
+ break;
+ default:
+ p += snprintf(p, MAX_WX_STRING - (p - extra),
+ "(Timeout %dms, Period %dms)",
+ timeout_duration[level - 1] / 1000,
+ period_duration[level - 1] / 1000);
+ }
+
+ if (!(priv->power_mode & IPW_POWER_ENABLED))
+ p += snprintf(p, MAX_WX_STRING - (p - extra), " OFF");
+
+ wrqu->data.length = p - extra + 1;
+
+ return 0;
+}
+
+static int ipw_wx_set_wireless_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int mode = *(int *)extra;
+ u8 band = 0, modulation = 0;
+
+ if (mode == 0 || mode & ~IEEE_MODE_MASK) {
+ IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+ if (priv->adapter == IPW_2915ABG) {
+ priv->ieee->abg_ture = 1;
+ if (mode & IEEE_A) {
+ band |= IEEE80211_52GHZ_BAND;
+ modulation |= IEEE80211_OFDM_MODULATION;
+ } else
+ priv->ieee->abg_ture = 0;
+ } else {
+ if (mode & IEEE_A) {
+ IPW_WARNING("Attempt to set 2200BG into "
+ "802.11a mode\n");
+ return -EINVAL;
+ }
+
+ priv->ieee->abg_ture = 0;
+ }
+
+ if (mode & IEEE_B) {
+ band |= IEEE80211_24GHZ_BAND;
+ modulation |= IEEE80211_CCK_MODULATION;
+ } else
+ priv->ieee->abg_ture = 0;
+
+ if (mode & IEEE_G) {
+ band |= IEEE80211_24GHZ_BAND;
+ modulation |= IEEE80211_OFDM_MODULATION;
+ } else
+ priv->ieee->abg_ture = 0;
+
+ priv->ieee->mode = mode;
+ priv->ieee->freq_band = band;
+ priv->ieee->modulation = modulation;
+ init_supported_rates(priv, &priv->rates);
+
+ /* If we are currently associated, or trying to associate
+ * then see if this is a new configuration (causing us to
+ * disassociate) */
+ if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ /* The resulting association will trigger
+ * the new rates to be sent to the device */
+ IPW_DEBUG_ASSOC("Disassociating due to mode change.\n");
+ ipw_disassociate(priv);
+ } else
+ ipw_send_supported_rates(priv, &priv->rates);
+
+ IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
+ mode & IEEE_A ? 'a' : '.',
+ mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
+ return 0;
+}
+
+static int ipw_wx_get_wireless_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ switch (priv->ieee->freq_band) {
+ case IEEE80211_24GHZ_BAND:
+ switch (priv->ieee->modulation) {
+ case IEEE80211_CCK_MODULATION:
+ strncpy(extra, "802.11b (2)", MAX_WX_STRING);
+ break;
+ case IEEE80211_OFDM_MODULATION:
+ strncpy(extra, "802.11g (4)", MAX_WX_STRING);
+ break;
+ default:
+ strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
+ break;
+ }
+ break;
+
+ case IEEE80211_52GHZ_BAND:
+ strncpy(extra, "802.11a (1)", MAX_WX_STRING);
+ break;
+
+ default: /* Mixed Band */
+ switch (priv->ieee->modulation) {
+ case IEEE80211_CCK_MODULATION:
+ strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
+ break;
+ case IEEE80211_OFDM_MODULATION:
+ strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
+ break;
+ default:
+ strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
+ break;
+ }
+ break;
+ }
+
+ IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
+
+ wrqu->data.length = strlen(extra) + 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_IPW_PROMISC
+static int ipw_wx_set_promisc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int *parms = (int *)extra;
+ int enable = (parms[0] > 0);
+
+ IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]);
+ if (enable) {
+ if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+ priv->net_dev->type = ARPHRD_IEEE80211;
+ ipw_adapter_restart(priv);
+ }
+
+ ipw_set_channel(priv, parms[1]);
+ } else {
+ if (priv->ieee->iw_mode != IW_MODE_MONITOR)
+ return 0;
+ priv->net_dev->type = ARPHRD_ETHER;
+ ipw_adapter_restart(priv);
+ }
+ return 0;
+}
+
+static int ipw_wx_reset(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ IPW_DEBUG_WX("RESET\n");
+ ipw_adapter_restart(priv);
+ return 0;
+}
+#endif // CONFIG_IPW_PROMISC
+
+/* Rebase the WE IOCTLs to zero for the handler array */
+#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
+static iw_handler ipw_wx_handlers[] = {
+ IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
+ IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
+ IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
+ IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
+ IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode,
+ IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range,
+ IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap,
+ IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap,
+ IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan,
+ IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan,
+ IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid,
+ IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid,
+ IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick,
+ IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick,
+ IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate,
+ IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate,
+ IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts,
+ IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts,
+ IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag,
+ IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag,
+ IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow,
+ IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow,
+ IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry,
+ IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry,
+ IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode,
+ IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode,
+ IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power,
+ IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power,
+};
+
+#define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV
+#define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1
+#define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2
+#define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3
+#define IPW_PRIV_SET_PROMISC SIOCIWFIRSTPRIV+4
+#define IPW_PRIV_RESET SIOCIWFIRSTPRIV+5
+
+static struct iw_priv_args ipw_priv_args[] = {
+ {
+ .cmd = IPW_PRIV_SET_POWER,
+ .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ .name = "set_power"},
+ {
+ .cmd = IPW_PRIV_GET_POWER,
+ .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+ .name = "get_power"},
+ {
+ .cmd = IPW_PRIV_SET_MODE,
+ .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ .name = "set_mode"},
+ {
+ .cmd = IPW_PRIV_GET_MODE,
+ .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
+ .name = "get_mode"},
+#ifdef CONFIG_IPW_PROMISC
+ {
+ IPW_PRIV_SET_PROMISC,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
+ {
+ IPW_PRIV_RESET,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
+#endif /* CONFIG_IPW_PROMISC */
+};
+
+static iw_handler ipw_priv_handler[] = {
+ ipw_wx_set_powermode,
+ ipw_wx_get_powermode,
+ ipw_wx_set_wireless_mode,
+ ipw_wx_get_wireless_mode,
+#ifdef CONFIG_IPW_PROMISC
+ ipw_wx_set_promisc,
+ ipw_wx_reset,
+#endif
+};
+
+static struct iw_handler_def ipw_wx_handler_def = {
+ .standard = ipw_wx_handlers,
+ .num_standard = ARRAY_SIZE(ipw_wx_handlers),
+ .num_private = ARRAY_SIZE(ipw_priv_handler),
+ .num_private_args = ARRAY_SIZE(ipw_priv_args),
+ .private = ipw_priv_handler,
+ .private_args = ipw_priv_args,
+};
+
+/*
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
+ * Also called by SIOCGIWSTATS
+ */
+static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct iw_statistics *wstats;
+
+ wstats = &priv->wstats;
+
+ /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
+ * ipw2100_wx_wireless_stats seems to be called before fw is
+ * initialized. STATUS_ASSOCIATED will only be set if the hw is up
+ * and associated; if not associcated, the values are all meaningless
+ * anyway, so set them all to NULL and INVALID */
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ wstats->miss.beacon = 0;
+ wstats->discard.retries = 0;
+ wstats->qual.qual = 0;
+ wstats->qual.level = 0;
+ wstats->qual.noise = 0;
+ wstats->qual.updated = 7;
+ wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
+ IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ return wstats;
+ }
+
+ wstats->qual.qual = priv->quality;
+ wstats->qual.level = average_value(&priv->average_rssi);
+ wstats->qual.noise = average_value(&priv->average_noise);
+ wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
+ IW_QUAL_NOISE_UPDATED;
+
+ wstats->miss.beacon = average_value(&priv->average_missed_beacons);
+ wstats->discard.retries = priv->last_tx_failures;
+ wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable;
+
+/* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len))
+ goto fail_get_ordinal;
+ wstats->discard.retries += tx_retry; */
+
+ return wstats;
+}
+
+/* net device stuff */
+
+static inline void init_sys_config(struct ipw_sys_config *sys_config)
+{
+ memset(sys_config, 0, sizeof(struct ipw_sys_config));
+ sys_config->bt_coexistence = 1; /* We may need to look into prvStaBtConfig */
+ sys_config->answer_broadcast_ssid_probe = 0;
+ sys_config->accept_all_data_frames = 0;
+ sys_config->accept_non_directed_frames = 1;
+ sys_config->exclude_unicast_unencrypted = 0;
+ sys_config->disable_unicast_decryption = 1;
+ sys_config->exclude_multicast_unencrypted = 0;
+ sys_config->disable_multicast_decryption = 1;
+ sys_config->antenna_diversity = CFG_SYS_ANTENNA_BOTH;
+ sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */
+ sys_config->dot11g_auto_detection = 0;
+ sys_config->enable_cts_to_self = 0;
+ sys_config->bt_coexist_collision_thr = 0;
+ sys_config->pass_noise_stats_to_host = 1;
+}
+
+static int ipw_net_open(struct net_device *dev)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ IPW_DEBUG_INFO("dev->open\n");
+ /* we should be verifying the device is ready to be opened */
+ if (!(priv->status & STATUS_RF_KILL_MASK) &&
+ (priv->status & STATUS_ASSOCIATED))
+ netif_start_queue(dev);
+ return 0;
+}
+
+static int ipw_net_stop(struct net_device *dev)
+{
+ IPW_DEBUG_INFO("dev->close\n");
+ netif_stop_queue(dev);
+ return 0;
+}
+
+/*
+todo:
+
+modify to send one tfd per fragment instead of using chunking. otherwise
+we need to heavily modify the ieee80211_skb_to_txb.
+*/
+
+static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)
+ txb->fragments[0]->data;
+ int i = 0;
+ struct tfd_frame *tfd;
+ struct clx2_tx_queue *txq = &priv->txq[0];
+ struct clx2_queue *q = &txq->q;
+ u8 id, hdr_len, unicast;
+ u16 remaining_bytes;
+
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ hdr_len = IEEE80211_3ADDR_LEN;
+ unicast = !is_broadcast_ether_addr(hdr->addr1) &&
+ !is_multicast_ether_addr(hdr->addr1);
+ id = ipw_find_station(priv, hdr->addr1);
+ if (id == IPW_INVALID_STATION) {
+ id = ipw_add_station(priv, hdr->addr1);
+ if (id == IPW_INVALID_STATION) {
+ IPW_WARNING("Attempt to send data to "
+ "invalid cell: " MAC_FMT "\n",
+ MAC_ARG(hdr->addr1));
+ goto drop;
+ }
+ }
+ break;
+
+ case IW_MODE_INFRA:
+ default:
+ unicast = !is_broadcast_ether_addr(hdr->addr3) &&
+ !is_multicast_ether_addr(hdr->addr3);
+ hdr_len = IEEE80211_3ADDR_LEN;
+ id = 0;
+ break;
+ }
+
+ tfd = &txq->bd[q->first_empty];
+ txq->txb[q->first_empty] = txb;
+ memset(tfd, 0, sizeof(*tfd));
+ tfd->u.data.station_number = id;
+
+ tfd->control_flags.message_type = TX_FRAME_TYPE;
+ tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
+
+ tfd->u.data.cmd_id = DINO_CMD_TX;
+ tfd->u.data.len = txb->payload_size;
+ remaining_bytes = txb->payload_size;
+ if (unlikely(!unicast))
+ tfd->u.data.tx_flags = DCT_FLAG_NO_WEP;
+ else
+ tfd->u.data.tx_flags = DCT_FLAG_NO_WEP | DCT_FLAG_ACK_REQD;
+
+ if (priv->assoc_request.ieee_mode == IPW_B_MODE)
+ tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_CCK;
+ else
+ tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM;
+
+ if (priv->config & CFG_PREAMBLE)
+ tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL;
+
+ memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
+
+ /* payload */
+ tfd->u.data.num_chunks = min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags);
+ for (i = 0; i < tfd->u.data.num_chunks; i++) {
+ IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
+ i, tfd->u.data.num_chunks,
+ txb->fragments[i]->len - hdr_len);
+ printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len,
+ txb->fragments[i]->len - hdr_len);
+
+ tfd->u.data.chunk_ptr[i] =
+ pci_map_single(priv->pci_dev,
+ txb->fragments[i]->data + hdr_len,
+ txb->fragments[i]->len - hdr_len,
+ PCI_DMA_TODEVICE);
+ tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len;
+ }
+
+ if (i != txb->nr_frags) {
+ struct sk_buff *skb;
+ u16 remaining_bytes = 0;
+ int j;
+
+ for (j = i; j < txb->nr_frags; j++)
+ remaining_bytes += txb->fragments[j]->len - hdr_len;
+
+ printk(KERN_INFO "Trying to reallocate for %d bytes\n",
+ remaining_bytes);
+ skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
+ if (skb != NULL) {
+ tfd->u.data.chunk_len[i] = remaining_bytes;
+ for (j = i; j < txb->nr_frags; j++) {
+ int size = txb->fragments[j]->len - hdr_len;
+ printk(KERN_INFO "Adding frag %d %d...\n",
+ j, size);
+ memcpy(skb_put(skb, size),
+ txb->fragments[j]->data + hdr_len, size);
+ }
+ dev_kfree_skb_any(txb->fragments[i]);
+ txb->fragments[i] = skb;
+ tfd->u.data.chunk_ptr[i] =
+ pci_map_single(priv->pci_dev, skb->data,
+ tfd->u.data.chunk_len[i],
+ PCI_DMA_TODEVICE);
+ tfd->u.data.num_chunks++;
+ }
+ }
+
+ /* kick DMA */
+ q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
+ ipw_write32(priv, q->reg_w, q->first_empty);
+
+ if (ipw_queue_space(q) < q->high_mark)
+ netif_stop_queue(priv->net_dev);
+
+ return;
+
+ drop:
+ IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
+ ieee80211_txb_free(txb);
+}
+
+static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
+ struct net_device *dev)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ unsigned long flags;
+
+ IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!(priv->status & STATUS_ASSOCIATED)) {
+ IPW_DEBUG_INFO("Tx attempt while not associated.\n");
+ priv->ieee->stats.tx_carrier_errors++;
+ netif_stop_queue(dev);
+ goto fail_unlock;
+ }
+
+ ipw_tx_skb(priv, txb);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+
+ fail_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 1;
+}
+
+static struct net_device_stats *ipw_net_get_stats(struct net_device *dev)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ priv->ieee->stats.tx_packets = priv->tx_packets;
+ priv->ieee->stats.rx_packets = priv->rx_packets;
+ return &priv->ieee->stats;
+}
+
+static void ipw_net_set_multicast_list(struct net_device *dev)
+{
+
+}
+
+static int ipw_net_set_mac_address(struct net_device *dev, void *p)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct sockaddr *addr = p;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+ priv->config |= CFG_CUSTOM_MAC;
+ memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
+ printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
+ priv->net_dev->name, MAC_ARG(priv->mac_addr));
+ ipw_adapter_restart(priv);
+ return 0;
+}
+
+static void ipw_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct ipw_priv *p = ieee80211_priv(dev);
+ char vers[64];
+ char date[32];
+ u32 len;
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+
+ len = sizeof(vers);
+ ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len);
+ len = sizeof(date);
+ ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len);
+
+ snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
+ vers, date);
+ strcpy(info->bus_info, pci_name(p->pci_dev));
+ info->eedump_len = CX2_EEPROM_IMAGE_SIZE;
+}
+
+static u32 ipw_ethtool_get_link(struct net_device *dev)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ return (priv->status & STATUS_ASSOCIATED) != 0;
+}
+
+static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
+{
+ return CX2_EEPROM_IMAGE_SIZE;
+}
+
+static int ipw_ethtool_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+ struct ipw_priv *p = ieee80211_priv(dev);
+
+ if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+ return -EINVAL;
+
+ memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len);
+ return 0;
+}
+
+static int ipw_ethtool_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+ struct ipw_priv *p = ieee80211_priv(dev);
+ int i;
+
+ if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+ return -EINVAL;
+
+ memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len);
+ for (i = IPW_EEPROM_DATA;
+ i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++)
+ ipw_write8(p, i, p->eeprom[i]);
+
+ return 0;
+}
+
+static struct ethtool_ops ipw_ethtool_ops = {
+ .get_link = ipw_ethtool_get_link,
+ .get_drvinfo = ipw_ethtool_get_drvinfo,
+ .get_eeprom_len = ipw_ethtool_get_eeprom_len,
+ .get_eeprom = ipw_ethtool_get_eeprom,
+ .set_eeprom = ipw_ethtool_set_eeprom,
+};
+
+static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
+{
+ struct ipw_priv *priv = data;
+ u32 inta, inta_mask;
+
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ if (!(priv->status & STATUS_INT_ENABLED)) {
+ /* Shared IRQ */
+ goto none;
+ }
+
+ inta = ipw_read32(priv, CX2_INTA_RW);
+ inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
+
+ if (inta == 0xFFFFFFFF) {
+ /* Hardware disappeared */
+ IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n");
+ goto none;
+ }
+
+ if (!(inta & (CX2_INTA_MASK_ALL & inta_mask))) {
+ /* Shared interrupt */
+ goto none;
+ }
+
+ /* tell the device to stop sending interrupts */
+ ipw_disable_interrupts(priv);
+
+ /* ack current interrupts */
+ inta &= (CX2_INTA_MASK_ALL & inta_mask);
+ ipw_write32(priv, CX2_INTA_RW, inta);
+
+ /* Cache INTA value for our tasklet */
+ priv->isr_inta = inta;
+
+ tasklet_schedule(&priv->irq_tasklet);
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+ none:
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+}
+
+static void ipw_rf_kill(void *adapter)
+{
+ struct ipw_priv *priv = adapter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (rf_kill_active(priv)) {
+ IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
+ if (priv->workqueue)
+ queue_delayed_work(priv->workqueue,
+ &priv->rf_kill, 2 * HZ);
+ goto exit_unlock;
+ }
+
+ /* RF Kill is now disabled, so bring the device back up */
+
+ if (!(priv->status & STATUS_RF_KILL_MASK)) {
+ IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
+ "device\n");
+
+ /* we can not do an adapter restart while inside an irq lock */
+ queue_work(priv->workqueue, &priv->adapter_restart);
+ } else
+ IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
+ "enabled\n");
+
+ exit_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int ipw_setup_deferred_work(struct ipw_priv *priv)
+{
+ int ret = 0;
+
+ priv->workqueue = create_workqueue(DRV_NAME);
+ init_waitqueue_head(&priv->wait_command_queue);
+
+ INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv);
+ INIT_WORK(&priv->associate, ipw_associate, priv);
+ INIT_WORK(&priv->disassociate, ipw_disassociate, priv);
+ INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv);
+ INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv);
+ INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv);
+ INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv);
+ INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv);
+ INIT_WORK(&priv->request_scan,
+ (void (*)(void *))ipw_request_scan, priv);
+ INIT_WORK(&priv->gather_stats,
+ (void (*)(void *))ipw_gather_stats, priv);
+ INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv);
+ INIT_WORK(&priv->roam, ipw_roam, priv);
+ INIT_WORK(&priv->scan_check, ipw_scan_check, priv);
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ ipw_irq_tasklet, (unsigned long)priv);
+
+ return ret;
+}
+
+static void shim__set_security(struct net_device *dev,
+ struct ieee80211_security *sec)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (sec->flags & (1 << i)) {
+ priv->sec.key_sizes[i] = sec->key_sizes[i];
+ if (sec->key_sizes[i] == 0)
+ priv->sec.flags &= ~(1 << i);
+ else
+ memcpy(priv->sec.keys[i], sec->keys[i],
+ sec->key_sizes[i]);
+ priv->sec.flags |= (1 << i);
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+ }
+
+ if ((sec->flags & SEC_ACTIVE_KEY) &&
+ priv->sec.active_key != sec->active_key) {
+ if (sec->active_key <= 3) {
+ priv->sec.active_key = sec->active_key;
+ priv->sec.flags |= SEC_ACTIVE_KEY;
+ } else
+ priv->sec.flags &= ~SEC_ACTIVE_KEY;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+
+ if ((sec->flags & SEC_AUTH_MODE) &&
+ (priv->sec.auth_mode != sec->auth_mode)) {
+ priv->sec.auth_mode = sec->auth_mode;
+ priv->sec.flags |= SEC_AUTH_MODE;
+ if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
+ priv->capability |= CAP_SHARED_KEY;
+ else
+ priv->capability &= ~CAP_SHARED_KEY;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+
+ if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) {
+ priv->sec.flags |= SEC_ENABLED;
+ priv->sec.enabled = sec->enabled;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ if (sec->enabled)
+ priv->capability |= CAP_PRIVACY_ON;
+ else
+ priv->capability &= ~CAP_PRIVACY_ON;
+ }
+
+ if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) {
+ priv->sec.level = sec->level;
+ priv->sec.flags |= SEC_LEVEL;
+ priv->status |= STATUS_SECURITY_UPDATED;
+ }
+
+ /* To match current functionality of ipw2100 (which works well w/
+ * various supplicants, we don't force a disassociate if the
+ * privacy capability changes ... */
+#if 0
+ if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) &&
+ (((priv->assoc_request.capability &
+ WLAN_CAPABILITY_PRIVACY) && !sec->enabled) ||
+ (!(priv->assoc_request.capability &
+ WLAN_CAPABILITY_PRIVACY) && sec->enabled))) {
+ IPW_DEBUG_ASSOC("Disassociating due to capability "
+ "change.\n");
+ ipw_disassociate(priv);
+ }
+#endif
+}
+
+static int init_supported_rates(struct ipw_priv *priv,
+ struct ipw_supported_rates *rates)
+{
+ /* TODO: Mask out rates based on priv->rates_mask */
+
+ memset(rates, 0, sizeof(*rates));
+ /* configure supported rates */
+ switch (priv->ieee->freq_band) {
+ case IEEE80211_52GHZ_BAND:
+ rates->ieee_mode = IPW_A_MODE;
+ rates->purpose = IPW_RATE_CAPABILITIES;
+ ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION,
+ IEEE80211_OFDM_DEFAULT_RATES_MASK);
+ break;
+
+ default: /* Mixed or 2.4Ghz */
+ rates->ieee_mode = IPW_G_MODE;
+ rates->purpose = IPW_RATE_CAPABILITIES;
+ ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION,
+ IEEE80211_CCK_DEFAULT_RATES_MASK);
+ if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) {
+ ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION,
+ IEEE80211_OFDM_DEFAULT_RATES_MASK);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int ipw_config(struct ipw_priv *priv)
+{
+ int i;
+ struct ipw_tx_power tx_power;
+
+ memset(&priv->sys_config, 0, sizeof(priv->sys_config));
+ memset(&tx_power, 0, sizeof(tx_power));
+
+ /* This is only called from ipw_up, which resets/reloads the firmware
+ so, we don't need to first disable the card before we configure
+ it */
+
+ /* configure device for 'G' band */
+ tx_power.ieee_mode = IPW_G_MODE;
+ tx_power.num_channels = 11;
+ for (i = 0; i < 11; i++) {
+ tx_power.channels_tx_power[i].channel_number = i + 1;
+ tx_power.channels_tx_power[i].tx_power = priv->tx_power;
+ }
+ if (ipw_send_tx_power(priv, &tx_power))
+ goto error;
+
+ /* configure device to also handle 'B' band */
+ tx_power.ieee_mode = IPW_B_MODE;
+ if (ipw_send_tx_power(priv, &tx_power))
+ goto error;
+
+ /* initialize adapter address */
+ if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr))
+ goto error;
+
+ /* set basic system config settings */
+ init_sys_config(&priv->sys_config);
+ if (ipw_send_system_config(priv, &priv->sys_config))
+ goto error;
+
+ init_supported_rates(priv, &priv->rates);
+ if (ipw_send_supported_rates(priv, &priv->rates))
+ goto error;
+
+ /* Set request-to-send threshold */
+ if (priv->rts_threshold) {
+ if (ipw_send_rts_threshold(priv, priv->rts_threshold))
+ goto error;
+ }
+
+ if (ipw_set_random_seed(priv))
+ goto error;
+
+ /* final state transition to the RUN state */
+ if (ipw_send_host_complete(priv))
+ goto error;
+
+ /* If configured to try and auto-associate, kick off a scan */
+ if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv))
+ goto error;
+
+ return 0;
+
+ error:
+ return -EIO;
+}
+
+#define MAX_HW_RESTARTS 5
+static int ipw_up(struct ipw_priv *priv)
+{
+ int rc, i;
+
+ if (priv->status & STATUS_EXIT_PENDING)
+ return -EIO;
+
+ for (i = 0; i < MAX_HW_RESTARTS; i++) {
+ /* Load the microcode, firmware, and eeprom.
+ * Also start the clocks. */
+ rc = ipw_load(priv);
+ if (rc) {
+ IPW_ERROR("Unable to load firmware: 0x%08X\n", rc);
+ return rc;
+ }
+
+ ipw_init_ordinals(priv);
+ if (!(priv->config & CFG_CUSTOM_MAC))
+ eeprom_parse_mac(priv, priv->mac_addr);
+ memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
+
+ if (priv->status & STATUS_RF_KILL_MASK)
+ return 0;
+
+ rc = ipw_config(priv);
+ if (!rc) {
+ IPW_DEBUG_INFO("Configured device on count %i\n", i);
+ priv->notif_missed_beacons = 0;
+ netif_start_queue(priv->net_dev);
+ return 0;
+ } else {
+ IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n",
+ rc);
+ }
+
+ IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
+ i, MAX_HW_RESTARTS);
+
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ ipw_down(priv);
+ }
+
+ /* tried to restart and config the device for as long as our
+ * patience could withstand */
+ IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
+ return -EIO;
+}
+
+static void ipw_down(struct ipw_priv *priv)
+{
+ /* Attempt to disable the card */
+#if 0
+ ipw_send_card_disable(priv, 0);
+#endif
+
+ /* tell the device to stop sending interrupts */
+ ipw_disable_interrupts(priv);
+
+ /* Clear all bits but the RF Kill */
+ priv->status &= STATUS_RF_KILL_MASK;
+
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+
+ ipw_stop_nic(priv);
+}
+
+/* Called by register_netdev() */
+static int ipw_net_init(struct net_device *dev)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ if (priv->status & STATUS_RF_KILL_SW) {
+ IPW_WARNING("Radio disabled by module parameter.\n");
+ return 0;
+ } else if (rf_kill_active(priv)) {
+ IPW_WARNING("Radio Frequency Kill Switch is On:\n"
+ "Kill switch must be turned off for "
+ "wireless networking to work.\n");
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
+ return 0;
+ }
+
+ if (ipw_up(priv))
+ return -EIO;
+
+ return 0;
+}
+
+/* PCI driver stuff */
+static struct pci_device_id card_ids[] = {
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
+ {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 2225BG */
+ {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+ {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, card_ids);
+
+static struct attribute *ipw_sysfs_entries[] = {
+ &dev_attr_rf_kill.attr,
+ &dev_attr_direct_dword.attr,
+ &dev_attr_indirect_byte.attr,
+ &dev_attr_indirect_dword.attr,
+ &dev_attr_mem_gpio_reg.attr,
+ &dev_attr_command_event_reg.attr,
+ &dev_attr_nic_type.attr,
+ &dev_attr_status.attr,
+ &dev_attr_cfg.attr,
+ &dev_attr_dump_errors.attr,
+ &dev_attr_dump_events.attr,
+ &dev_attr_eeprom_delay.attr,
+ &dev_attr_ucode_version.attr,
+ &dev_attr_rtc.attr,
+ NULL
+};
+
+static struct attribute_group ipw_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = ipw_sysfs_entries,
+};
+
+static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = 0;
+ struct net_device *net_dev;
+ void __iomem *base;
+ u32 length, val;
+ struct ipw_priv *priv;
+ int band, modulation;
+
+ net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
+ if (net_dev == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ priv = ieee80211_priv(net_dev);
+ priv->ieee = netdev_priv(net_dev);
+ priv->net_dev = net_dev;
+ priv->pci_dev = pdev;
+#ifdef CONFIG_IPW_DEBUG
+ ipw_debug_level = debug;
+#endif
+ spin_lock_init(&priv->lock);
+
+ if (pci_enable_device(pdev)) {
+ err = -ENODEV;
+ goto out_free_ieee80211;
+ }
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+ goto out_pci_disable_device;
+ }
+
+ pci_set_drvdata(pdev, priv);
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto out_pci_disable_device;
+
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ length = pci_resource_len(pdev, 0);
+ priv->hw_len = length;
+
+ base = ioremap_nocache(pci_resource_start(pdev, 0), length);
+ if (!base) {
+ err = -ENODEV;
+ goto out_pci_release_regions;
+ }
+
+ priv->hw_base = base;
+ IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length);
+ IPW_DEBUG_INFO("pci_resource_base = %p\n", base);
+
+ err = ipw_setup_deferred_work(priv);
+ if (err) {
+ IPW_ERROR("Unable to setup deferred work\n");
+ goto out_iounmap;
+ }
+
+ /* Initialize module parameter values here */
+ if (ifname)
+ strncpy(net_dev->name, ifname, IFNAMSIZ);
+
+ if (associate)
+ priv->config |= CFG_ASSOCIATE;
+ else
+ IPW_DEBUG_INFO("Auto associate disabled.\n");
+
+ if (auto_create)
+ priv->config |= CFG_ADHOC_CREATE;
+ else
+ IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
+
+ if (disable) {
+ priv->status |= STATUS_RF_KILL_SW;
+ IPW_DEBUG_INFO("Radio disabled.\n");
+ }
+
+ if (channel != 0) {
+ priv->config |= CFG_STATIC_CHANNEL;
+ priv->channel = channel;
+ IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+ IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+ /* TODO: Validate that provided channel is in range */
+ }
+
+ switch (mode) {
+ case 1:
+ priv->ieee->iw_mode = IW_MODE_ADHOC;
+ break;
+#ifdef CONFIG_IPW_PROMISC
+ case 2:
+ priv->ieee->iw_mode = IW_MODE_MONITOR;
+ break;
+#endif
+ default:
+ case 0:
+ priv->ieee->iw_mode = IW_MODE_INFRA;
+ break;
+ }
+
+ if ((priv->pci_dev->device == 0x4223) ||
+ (priv->pci_dev->device == 0x4224)) {
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 2915ABG Network "
+ "Connection\n");
+ priv->ieee->abg_ture = 1;
+ band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
+ modulation = IEEE80211_OFDM_MODULATION |
+ IEEE80211_CCK_MODULATION;
+ priv->adapter = IPW_2915ABG;
+ priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
+ } else {
+ if (priv->pci_dev->device == 0x4221)
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 2225BG Network "
+ "Connection\n");
+ else
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 2200BG Network "
+ "Connection\n");
+
+ priv->ieee->abg_ture = 0;
+ band = IEEE80211_24GHZ_BAND;
+ modulation = IEEE80211_OFDM_MODULATION |
+ IEEE80211_CCK_MODULATION;
+ priv->adapter = IPW_2200BG;
+ priv->ieee->mode = IEEE_G | IEEE_B;
+ }
+
+ priv->ieee->freq_band = band;
+ priv->ieee->modulation = modulation;
+
+ priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
+
+ priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
+ priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
+
+ priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IPW_POWER_AC;
+ priv->tx_power = IPW_DEFAULT_TX_POWER;
+
+ err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv);
+ if (err) {
+ IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
+ goto out_destroy_workqueue;
+ }
+
+ SET_MODULE_OWNER(net_dev);
+ SET_NETDEV_DEV(net_dev, &pdev->dev);
+
+ priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
+ priv->ieee->set_security = shim__set_security;
+
+ net_dev->open = ipw_net_open;
+ net_dev->stop = ipw_net_stop;
+ net_dev->init = ipw_net_init;
+ net_dev->get_stats = ipw_net_get_stats;
+ net_dev->set_multicast_list = ipw_net_set_multicast_list;
+ net_dev->set_mac_address = ipw_net_set_mac_address;
+ net_dev->get_wireless_stats = ipw_get_wireless_stats;
+ net_dev->wireless_handlers = &ipw_wx_handler_def;
+ net_dev->ethtool_ops = &ipw_ethtool_ops;
+ net_dev->irq = pdev->irq;
+ net_dev->base_addr = (unsigned long)priv->hw_base;
+ net_dev->mem_start = pci_resource_start(pdev, 0);
+ net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1;
+
+ err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
+ if (err) {
+ IPW_ERROR("failed to create sysfs device attributes\n");
+ goto out_release_irq;
+ }
+
+ err = register_netdev(net_dev);
+ if (err) {
+ IPW_ERROR("failed to register network device\n");
+ goto out_remove_group;
+ }
+
+ return 0;
+
+ out_remove_group:
+ sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
+ out_release_irq:
+ free_irq(pdev->irq, priv);
+ out_destroy_workqueue:
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ out_iounmap:
+ iounmap(priv->hw_base);
+ out_pci_release_regions:
+ pci_release_regions(pdev);
+ out_pci_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ out_free_ieee80211:
+ free_ieee80211(priv->net_dev);
+ out:
+ return err;
+}
+
+static void ipw_pci_remove(struct pci_dev *pdev)
+{
+ struct ipw_priv *priv = pci_get_drvdata(pdev);
+ if (!priv)
+ return;
+
+ priv->status |= STATUS_EXIT_PENDING;
+
+ sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
+
+ ipw_down(priv);
+
+ unregister_netdev(priv->net_dev);
+
+ if (priv->rxq) {
+ ipw_rx_queue_free(priv, priv->rxq);
+ priv->rxq = NULL;
+ }
+ ipw_tx_queue_free(priv);
+
+ /* ipw_down will ensure that there is no more pending work
+ * in the workqueue's, so we can safely remove them now. */
+ if (priv->workqueue) {
+ cancel_delayed_work(&priv->adhoc_check);
+ cancel_delayed_work(&priv->gather_stats);
+ cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->rf_kill);
+ cancel_delayed_work(&priv->scan_check);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ }
+
+ free_irq(pdev->irq, priv);
+ iounmap(priv->hw_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ free_ieee80211(priv->net_dev);
+
+#ifdef CONFIG_PM
+ if (fw_loaded) {
+ release_firmware(bootfw);
+ release_firmware(ucode);
+ release_firmware(firmware);
+ fw_loaded = 0;
+ }
+#endif
+}
+
+#ifdef CONFIG_PM
+static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ipw_priv *priv = pci_get_drvdata(pdev);
+ struct net_device *dev = priv->net_dev;
+
+ printk(KERN_INFO "%s: Going into suspend...\n", dev->name);
+
+ /* Take down the device; powers it off, etc. */
+ ipw_down(priv);
+
+ /* Remove the PRESENT state of the device */
+ netif_device_detach(dev);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int ipw_pci_resume(struct pci_dev *pdev)
+{
+ struct ipw_priv *priv = pci_get_drvdata(pdev);
+ struct net_device *dev = priv->net_dev;
+ u32 val;
+
+ printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
+
+ pci_set_power_state(pdev, 0);
+ pci_enable_device(pdev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+ pci_restore_state(pdev, priv->pm_state);
+#else
+ pci_restore_state(pdev);
+#endif
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ /* Set the device back into the PRESENT state; this will also wake
+ * the queue of needed */
+ netif_device_attach(dev);
+
+ /* Bring the device back up */
+ queue_work(priv->workqueue, &priv->up);
+
+ return 0;
+}
+#endif
+
+/* driver initialization stuff */
+static struct pci_driver ipw_driver = {
+ .name = DRV_NAME,
+ .id_table = card_ids,
+ .probe = ipw_pci_probe,
+ .remove = __devexit_p(ipw_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = ipw_pci_suspend,
+ .resume = ipw_pci_resume,
+#endif
+};
+
+static int __init ipw_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+ ret = pci_module_init(&ipw_driver);
+ if (ret) {
+ IPW_ERROR("Unable to initialize PCI module\n");
+ return ret;
+ }
+
+ ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);
+ if (ret) {
+ IPW_ERROR("Unable to create driver sysfs file\n");
+ pci_unregister_driver(&ipw_driver);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void __exit ipw_exit(void)
+{
+ driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);
+ pci_unregister_driver(&ipw_driver);
+}
+
+module_param(disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+
+module_param(associate, int, 0444);
+MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+
+module_param(auto_create, int, 0444);
+MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
+
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+
+module_param(channel, int, 0444);
+MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
+
+module_param(ifname, charp, 0444);
+MODULE_PARM_DESC(ifname, "network device name (default eth%d)");
+
+#ifdef CONFIG_IPW_PROMISC
+module_param(mode, int, 0444);
+MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
+#else
+module_param(mode, int, 0444);
+MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
+#endif
+
+module_exit(ipw_exit);
+module_init(ipw_init);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
new file mode 100644
index 0000000..5b00882
--- /dev/null
+++ b/drivers/net/wireless/ipw2200.h
@@ -0,0 +1,1680 @@
+/******************************************************************************
+
+ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#ifndef __ipw2200_h__
+#define __ipw2200_h__
+
+#define WEXT_USECHANNELS 1
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+
+#include <net/ieee80211.h>
+
+#define DRV_NAME "ipw2200"
+
+#include <linux/workqueue.h>
+
+/* Authentication and Association States */
+enum connection_manager_assoc_states {
+ CMAS_INIT = 0,
+ CMAS_TX_AUTH_SEQ_1,
+ CMAS_RX_AUTH_SEQ_2,
+ CMAS_AUTH_SEQ_1_PASS,
+ CMAS_AUTH_SEQ_1_FAIL,
+ CMAS_TX_AUTH_SEQ_3,
+ CMAS_RX_AUTH_SEQ_4,
+ CMAS_AUTH_SEQ_2_PASS,
+ CMAS_AUTH_SEQ_2_FAIL,
+ CMAS_AUTHENTICATED,
+ CMAS_TX_ASSOC,
+ CMAS_RX_ASSOC_RESP,
+ CMAS_ASSOCIATED,
+ CMAS_LAST
+};
+
+#define IPW_WAIT (1<<0)
+#define IPW_QUIET (1<<1)
+#define IPW_ROAMING (1<<2)
+
+#define IPW_POWER_MODE_CAM 0x00 //(always on)
+#define IPW_POWER_INDEX_1 0x01
+#define IPW_POWER_INDEX_2 0x02
+#define IPW_POWER_INDEX_3 0x03
+#define IPW_POWER_INDEX_4 0x04
+#define IPW_POWER_INDEX_5 0x05
+#define IPW_POWER_AC 0x06
+#define IPW_POWER_BATTERY 0x07
+#define IPW_POWER_LIMIT 0x07
+#define IPW_POWER_MASK 0x0F
+#define IPW_POWER_ENABLED 0x10
+#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
+
+#define IPW_CMD_HOST_COMPLETE 2
+#define IPW_CMD_POWER_DOWN 4
+#define IPW_CMD_SYSTEM_CONFIG 6
+#define IPW_CMD_MULTICAST_ADDRESS 7
+#define IPW_CMD_SSID 8
+#define IPW_CMD_ADAPTER_ADDRESS 11
+#define IPW_CMD_PORT_TYPE 12
+#define IPW_CMD_RTS_THRESHOLD 15
+#define IPW_CMD_FRAG_THRESHOLD 16
+#define IPW_CMD_POWER_MODE 17
+#define IPW_CMD_WEP_KEY 18
+#define IPW_CMD_TGI_TX_KEY 19
+#define IPW_CMD_SCAN_REQUEST 20
+#define IPW_CMD_ASSOCIATE 21
+#define IPW_CMD_SUPPORTED_RATES 22
+#define IPW_CMD_SCAN_ABORT 23
+#define IPW_CMD_TX_FLUSH 24
+#define IPW_CMD_QOS_PARAMETERS 25
+#define IPW_CMD_SCAN_REQUEST_EXT 26
+#define IPW_CMD_DINO_CONFIG 30
+#define IPW_CMD_RSN_CAPABILITIES 31
+#define IPW_CMD_RX_KEY 32
+#define IPW_CMD_CARD_DISABLE 33
+#define IPW_CMD_SEED_NUMBER 34
+#define IPW_CMD_TX_POWER 35
+#define IPW_CMD_COUNTRY_INFO 36
+#define IPW_CMD_AIRONET_INFO 37
+#define IPW_CMD_AP_TX_POWER 38
+#define IPW_CMD_CCKM_INFO 39
+#define IPW_CMD_CCX_VER_INFO 40
+#define IPW_CMD_SET_CALIBRATION 41
+#define IPW_CMD_SENSITIVITY_CALIB 42
+#define IPW_CMD_RETRY_LIMIT 51
+#define IPW_CMD_IPW_PRE_POWER_DOWN 58
+#define IPW_CMD_VAP_BEACON_TEMPLATE 60
+#define IPW_CMD_VAP_DTIM_PERIOD 61
+#define IPW_CMD_EXT_SUPPORTED_RATES 62
+#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63
+#define IPW_CMD_VAP_QUIET_INTERVALS 64
+#define IPW_CMD_VAP_CHANNEL_SWITCH 65
+#define IPW_CMD_VAP_MANDATORY_CHANNELS 66
+#define IPW_CMD_VAP_CELL_PWR_LIMIT 67
+#define IPW_CMD_VAP_CF_PARAM_SET 68
+#define IPW_CMD_VAP_SET_BEACONING_STATE 69
+#define IPW_CMD_MEASUREMENT 80
+#define IPW_CMD_POWER_CAPABILITY 81
+#define IPW_CMD_SUPPORTED_CHANNELS 82
+#define IPW_CMD_TPC_REPORT 83
+#define IPW_CMD_WME_INFO 84
+#define IPW_CMD_PRODUCTION_COMMAND 85
+#define IPW_CMD_LINKSYS_EOU_INFO 90
+
+#define RFD_SIZE 4
+#define NUM_TFD_CHUNKS 6
+
+#define TX_QUEUE_SIZE 32
+#define RX_QUEUE_SIZE 32
+
+#define DINO_CMD_WEP_KEY 0x08
+#define DINO_CMD_TX 0x0B
+#define DCT_ANTENNA_A 0x01
+#define DCT_ANTENNA_B 0x02
+
+#define IPW_A_MODE 0
+#define IPW_B_MODE 1
+#define IPW_G_MODE 2
+
+/*
+ * TX Queue Flag Definitions
+ */
+
+/* abort attempt if mgmt frame is rx'd */
+#define DCT_FLAG_ABORT_MGMT 0x01
+
+/* require CTS */
+#define DCT_FLAG_CTS_REQUIRED 0x02
+
+/* use short preamble */
+#define DCT_FLAG_SHORT_PREMBL 0x04
+
+/* RTS/CTS first */
+#define DCT_FLAG_RTS_REQD 0x08
+
+/* dont calculate duration field */
+#define DCT_FLAG_DUR_SET 0x10
+
+/* even if MAC WEP set (allows pre-encrypt) */
+#define DCT_FLAG_NO_WEP 0x20
+
+/* overwrite TSF field */
+#define DCT_FLAG_TSF_REQD 0x40
+
+/* ACK rx is expected to follow */
+#define DCT_FLAG_ACK_REQD 0x80
+
+#define DCT_FLAG_EXT_MODE_CCK 0x01
+#define DCT_FLAG_EXT_MODE_OFDM 0x00
+
+#define TX_RX_TYPE_MASK 0xFF
+#define TX_FRAME_TYPE 0x00
+#define TX_HOST_COMMAND_TYPE 0x01
+#define RX_FRAME_TYPE 0x09
+#define RX_HOST_NOTIFICATION_TYPE 0x03
+#define RX_HOST_CMD_RESPONSE_TYPE 0x04
+#define RX_TX_FRAME_RESPONSE_TYPE 0x05
+#define TFD_NEED_IRQ_MASK 0x04
+
+#define HOST_CMD_DINO_CONFIG 30
+
+#define HOST_NOTIFICATION_STATUS_ASSOCIATED 10
+#define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11
+#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12
+#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13
+#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14
+#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15
+#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16
+#define HOST_NOTIFICATION_STATUS_BEACON_STATE 17
+#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18
+#define HOST_NOTIFICATION_TX_STATUS 19
+#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20
+#define HOST_NOTIFICATION_MEASUREMENT_STARTED 21
+#define HOST_NOTIFICATION_MEASUREMENT_ENDED 22
+#define HOST_NOTIFICATION_CHANNEL_SWITCHED 23
+#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24
+#define HOST_NOTIFICATION_NOISE_STATS 25
+#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30
+#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31
+
+#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1
+#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 24
+#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8
+#define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300
+
+#define MACADRR_BYTE_LEN 6
+
+#define DCR_TYPE_AP 0x01
+#define DCR_TYPE_WLAP 0x02
+#define DCR_TYPE_MU_ESS 0x03
+#define DCR_TYPE_MU_IBSS 0x04
+#define DCR_TYPE_MU_PIBSS 0x05
+#define DCR_TYPE_SNIFFER 0x06
+#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS
+
+/**
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct clx2_queue {
+ int n_bd; /**< number of BDs in this queue */
+ int first_empty; /**< 1-st empty entry (index) */
+ int last_used; /**< last used entry (index) */
+ u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */
+ u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */
+ dma_addr_t dma_addr; /**< physical addr for BD's */
+ int low_mark; /**< low watermark, resume queue if free space more than this */
+ int high_mark; /**< high watermark, stop queue if free space less than this */
+} __attribute__ ((packed));
+
+struct machdr32 {
+ u16 frame_ctl;
+ u16 duration; // watch out for endians!
+ u8 addr1[MACADRR_BYTE_LEN];
+ u8 addr2[MACADRR_BYTE_LEN];
+ u8 addr3[MACADRR_BYTE_LEN];
+ u16 seq_ctrl; // more endians!
+ u8 addr4[MACADRR_BYTE_LEN];
+ u16 qos_ctrl;
+} __attribute__ ((packed));
+
+struct machdr30 {
+ u16 frame_ctl;
+ u16 duration; // watch out for endians!
+ u8 addr1[MACADRR_BYTE_LEN];
+ u8 addr2[MACADRR_BYTE_LEN];
+ u8 addr3[MACADRR_BYTE_LEN];
+ u16 seq_ctrl; // more endians!
+ u8 addr4[MACADRR_BYTE_LEN];
+} __attribute__ ((packed));
+
+struct machdr26 {
+ u16 frame_ctl;
+ u16 duration; // watch out for endians!
+ u8 addr1[MACADRR_BYTE_LEN];
+ u8 addr2[MACADRR_BYTE_LEN];
+ u8 addr3[MACADRR_BYTE_LEN];
+ u16 seq_ctrl; // more endians!
+ u16 qos_ctrl;
+} __attribute__ ((packed));
+
+struct machdr24 {
+ u16 frame_ctl;
+ u16 duration; // watch out for endians!
+ u8 addr1[MACADRR_BYTE_LEN];
+ u8 addr2[MACADRR_BYTE_LEN];
+ u8 addr3[MACADRR_BYTE_LEN];
+ u16 seq_ctrl; // more endians!
+} __attribute__ ((packed));
+
+// TX TFD with 32 byte MAC Header
+struct tx_tfd_32 {
+ struct machdr32 mchdr; // 32
+ u32 uivplaceholder[2]; // 8
+} __attribute__ ((packed));
+
+// TX TFD with 30 byte MAC Header
+struct tx_tfd_30 {
+ struct machdr30 mchdr; // 30
+ u8 reserved[2]; // 2
+ u32 uivplaceholder[2]; // 8
+} __attribute__ ((packed));
+
+// tx tfd with 26 byte mac header
+struct tx_tfd_26 {
+ struct machdr26 mchdr; // 26
+ u8 reserved1[2]; // 2
+ u32 uivplaceholder[2]; // 8
+ u8 reserved2[4]; // 4
+} __attribute__ ((packed));
+
+// tx tfd with 24 byte mac header
+struct tx_tfd_24 {
+ struct machdr24 mchdr; // 24
+ u32 uivplaceholder[2]; // 8
+ u8 reserved[8]; // 8
+} __attribute__ ((packed));
+
+#define DCT_WEP_KEY_FIELD_LENGTH 16
+
+struct tfd_command {
+ u8 index;
+ u8 length;
+ u16 reserved;
+ u8 payload[0];
+} __attribute__ ((packed));
+
+struct tfd_data {
+ /* Header */
+ u32 work_area_ptr;
+ u8 station_number; /* 0 for BSS */
+ u8 reserved1;
+ u16 reserved2;
+
+ /* Tx Parameters */
+ u8 cmd_id;
+ u8 seq_num;
+ u16 len;
+ u8 priority;
+ u8 tx_flags;
+ u8 tx_flags_ext;
+ u8 key_index;
+ u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH];
+ u8 rate;
+ u8 antenna;
+ u16 next_packet_duration;
+ u16 next_frag_len;
+ u16 back_off_counter; //////txop;
+ u8 retrylimit;
+ u16 cwcurrent;
+ u8 reserved3;
+
+ /* 802.11 MAC Header */
+ union {
+ struct tx_tfd_24 tfd_24;
+ struct tx_tfd_26 tfd_26;
+ struct tx_tfd_30 tfd_30;
+ struct tx_tfd_32 tfd_32;
+ } tfd;
+
+ /* Payload DMA info */
+ u32 num_chunks;
+ u32 chunk_ptr[NUM_TFD_CHUNKS];
+ u16 chunk_len[NUM_TFD_CHUNKS];
+} __attribute__ ((packed));
+
+struct txrx_control_flags {
+ u8 message_type;
+ u8 rx_seq_num;
+ u8 control_bits;
+ u8 reserved;
+} __attribute__ ((packed));
+
+#define TFD_SIZE 128
+#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags))
+
+struct tfd_frame {
+ struct txrx_control_flags control_flags;
+ union {
+ struct tfd_data data;
+ struct tfd_command cmd;
+ u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
+ } u;
+} __attribute__ ((packed));
+
+typedef void destructor_func(const void *);
+
+/**
+ * Tx Queue for DMA. Queue consists of circular buffer of
+ * BD's and required locking structures.
+ */
+struct clx2_tx_queue {
+ struct clx2_queue q;
+ struct tfd_frame *bd;
+ struct ieee80211_txb **txb;
+};
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 32
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS (8)
+#define SUP_RATE_11B_MAX_NUM_CHANNELS (4)
+#define SUP_RATE_11G_MAX_NUM_CHANNELS (12)
+
+// Used for passing to driver number of successes and failures per rate
+struct rate_histogram {
+ union {
+ u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } success;
+ union {
+ u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+struct ipw_cmd_stats {
+ u8 cmd_id;
+ u8 seq_num;
+ u16 good_sfd;
+ u16 bad_plcp;
+ u16 wrong_bssid;
+ u16 valid_mpdu;
+ u16 bad_mac_header;
+ u16 reserved_frame_types;
+ u16 rx_ina;
+ u16 bad_crc32;
+ u16 invalid_cts;
+ u16 invalid_acks;
+ u16 long_distance_ina_fina;
+ u16 dsp_silence_unreachable;
+ u16 accumulated_rssi;
+ u16 rx_ovfl_frame_tossed;
+ u16 rssi_silence_threshold;
+ u16 rx_ovfl_frame_supplied;
+ u16 last_rx_frame_signal;
+ u16 last_rx_frame_noise;
+ u16 rx_autodetec_no_ofdm;
+ u16 rx_autodetec_no_barker;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct notif_channel_result {
+ u8 channel_num;
+ struct ipw_cmd_stats stats;
+ u8 uReserved;
+} __attribute__ ((packed));
+
+struct notif_scan_complete {
+ u8 scan_type;
+ u8 num_channels;
+ u8 status;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct notif_frag_length {
+ u16 frag_length;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct notif_beacon_state {
+ u32 state;
+ u32 number;
+} __attribute__ ((packed));
+
+struct notif_tgi_tx_key {
+ u8 key_state;
+ u8 security_type;
+ u8 station_index;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct notif_link_deterioration {
+ struct ipw_cmd_stats stats;
+ u8 rate;
+ u8 modulation;
+ struct rate_histogram histogram;
+ u8 reserved1;
+ u16 reserved2;
+} __attribute__ ((packed));
+
+struct notif_association {
+ u8 state;
+} __attribute__ ((packed));
+
+struct notif_authenticate {
+ u8 state;
+ struct machdr24 addr;
+ u16 status;
+} __attribute__ ((packed));
+
+struct notif_calibration {
+ u8 data[104];
+} __attribute__ ((packed));
+
+struct notif_noise {
+ u32 value;
+} __attribute__ ((packed));
+
+struct ipw_rx_notification {
+ u8 reserved[8];
+ u8 subtype;
+ u8 flags;
+ u16 size;
+ union {
+ struct notif_association assoc;
+ struct notif_authenticate auth;
+ struct notif_channel_result channel_result;
+ struct notif_scan_complete scan_complete;
+ struct notif_frag_length frag_len;
+ struct notif_beacon_state beacon_state;
+ struct notif_tgi_tx_key tgi_tx_key;
+ struct notif_link_deterioration link_deterioration;
+ struct notif_calibration calibration;
+ struct notif_noise noise;
+ u8 raw[0];
+ } u;
+} __attribute__ ((packed));
+
+struct ipw_rx_frame {
+ u32 reserved1;
+ u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER
+ u8 received_channel; // The channel that this frame was received on.
+ // Note that for .11b this does not have to be
+ // the same as the channel that it was sent.
+ // Filled by LMAC
+ u8 frameStatus;
+ u8 rate;
+ u8 rssi;
+ u8 agc;
+ u8 rssi_dbm;
+ u16 signal;
+ u16 noise;
+ u8 antennaAndPhy;
+ u8 control; // control bit should be on in bg
+ u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate
+ // is identical)
+ u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen
+ u16 length;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct ipw_rx_header {
+ u8 message_type;
+ u8 rx_seq_num;
+ u8 control_bits;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct ipw_rx_packet {
+ struct ipw_rx_header header;
+ union {
+ struct ipw_rx_frame frame;
+ struct ipw_rx_notification notification;
+ } u;
+} __attribute__ ((packed));
+
+#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
+#define IPW_RX_FRAME_SIZE sizeof(struct ipw_rx_header) + \
+ sizeof(struct ipw_rx_frame)
+
+struct ipw_rx_mem_buffer {
+ dma_addr_t dma_addr;
+ struct ipw_rx_buffer *rxb;
+ struct sk_buff *skb;
+ struct list_head list;
+}; /* Not transferred over network, so not __attribute__ ((packed)) */
+
+struct ipw_rx_queue {
+ struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+ struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+ u32 processed; /* Internal index to last handled Rx packet */
+ u32 read; /* Shared index to newest available Rx buffer */
+ u32 write; /* Shared index to oldest written Rx packet */
+ u32 free_count; /* Number of pre-allocated buffers in rx_free */
+ /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */
+ struct list_head rx_free; /* Own an SKBs */
+ struct list_head rx_used; /* No SKB allocated */
+ spinlock_t lock;
+}; /* Not transferred over network, so not __attribute__ ((packed)) */
+
+struct alive_command_responce {
+ u8 alive_command;
+ u8 sequence_number;
+ u16 software_revision;
+ u8 device_identifier;
+ u8 reserved1[5];
+ u16 reserved2;
+ u16 reserved3;
+ u16 clock_settle_time;
+ u16 powerup_settle_time;
+ u16 reserved4;
+ u8 time_stamp[5]; /* month, day, year, hours, minutes */
+ u8 ucode_valid;
+} __attribute__ ((packed));
+
+#define IPW_MAX_RATES 12
+
+struct ipw_rates {
+ u8 num_rates;
+ u8 rates[IPW_MAX_RATES];
+} __attribute__ ((packed));
+
+struct command_block {
+ unsigned int control;
+ u32 source_addr;
+ u32 dest_addr;
+ unsigned int status;
+} __attribute__ ((packed));
+
+#define CB_NUMBER_OF_ELEMENTS_SMALL 64
+struct fw_image_desc {
+ unsigned long last_cb_index;
+ unsigned long current_cb_index;
+ struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL];
+ void *v_addr;
+ unsigned long p_addr;
+ unsigned long len;
+};
+
+struct ipw_sys_config {
+ u8 bt_coexistence;
+ u8 reserved1;
+ u8 answer_broadcast_ssid_probe;
+ u8 accept_all_data_frames;
+ u8 accept_non_directed_frames;
+ u8 exclude_unicast_unencrypted;
+ u8 disable_unicast_decryption;
+ u8 exclude_multicast_unencrypted;
+ u8 disable_multicast_decryption;
+ u8 antenna_diversity;
+ u8 pass_crc_to_host;
+ u8 dot11g_auto_detection;
+ u8 enable_cts_to_self;
+ u8 enable_multicast_filtering;
+ u8 bt_coexist_collision_thr;
+ u8 reserved2;
+ u8 accept_all_mgmt_bcpr;
+ u8 accept_all_mgtm_frames;
+ u8 pass_noise_stats_to_host;
+ u8 reserved3;
+} __attribute__ ((packed));
+
+struct ipw_multicast_addr {
+ u8 num_of_multicast_addresses;
+ u8 reserved[3];
+ u8 mac1[6];
+ u8 mac2[6];
+ u8 mac3[6];
+ u8 mac4[6];
+} __attribute__ ((packed));
+
+struct ipw_wep_key {
+ u8 cmd_id;
+ u8 seq_num;
+ u8 key_index;
+ u8 key_size;
+ u8 key[16];
+} __attribute__ ((packed));
+
+struct ipw_tgi_tx_key {
+ u8 key_id;
+ u8 security_type;
+ u8 station_index;
+ u8 flags;
+ u8 key[16];
+ u32 tx_counter[2];
+} __attribute__ ((packed));
+
+#define IPW_SCAN_CHANNELS 54
+
+struct ipw_scan_request {
+ u8 scan_type;
+ u16 dwell_time;
+ u8 channels_list[IPW_SCAN_CHANNELS];
+ u8 channels_reserved[3];
+} __attribute__ ((packed));
+
+enum {
+ IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
+ IPW_SCAN_PASSIVE_FULL_DWELL_SCAN,
+ IPW_SCAN_ACTIVE_DIRECT_SCAN,
+ IPW_SCAN_ACTIVE_BROADCAST_SCAN,
+ IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN,
+ IPW_SCAN_TYPES
+};
+
+struct ipw_scan_request_ext {
+ u32 full_scan_index;
+ u8 channels_list[IPW_SCAN_CHANNELS];
+ u8 scan_type[IPW_SCAN_CHANNELS / 2];
+ u8 reserved;
+ u16 dwell_time[IPW_SCAN_TYPES];
+} __attribute__ ((packed));
+
+extern inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
+{
+ if (index % 2)
+ return scan->scan_type[index / 2] & 0x0F;
+ else
+ return (scan->scan_type[index / 2] & 0xF0) >> 4;
+}
+
+extern inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
+ u8 index, u8 scan_type)
+{
+ if (index % 2)
+ scan->scan_type[index / 2] =
+ (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F);
+ else
+ scan->scan_type[index / 2] =
+ (scan->scan_type[index / 2] & 0x0F) |
+ ((scan_type & 0x0F) << 4);
+}
+
+struct ipw_associate {
+ u8 channel;
+ u8 auth_type:4, auth_key:4;
+ u8 assoc_type;
+ u8 reserved;
+ u16 policy_support;
+ u8 preamble_length;
+ u8 ieee_mode;
+ u8 bssid[ETH_ALEN];
+ u32 assoc_tsf_msw;
+ u32 assoc_tsf_lsw;
+ u16 capability;
+ u16 listen_interval;
+ u16 beacon_interval;
+ u8 dest[ETH_ALEN];
+ u16 atim_window;
+ u8 smr;
+ u8 reserved1;
+ u16 reserved2;
+} __attribute__ ((packed));
+
+struct ipw_supported_rates {
+ u8 ieee_mode;
+ u8 num_rates;
+ u8 purpose;
+ u8 reserved;
+ u8 supported_rates[IPW_MAX_RATES];
+} __attribute__ ((packed));
+
+struct ipw_rts_threshold {
+ u16 rts_threshold;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_frag_threshold {
+ u16 frag_threshold;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_retry_limit {
+ u8 short_retry_limit;
+ u8 long_retry_limit;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_dino_config {
+ u32 dino_config_addr;
+ u16 dino_config_size;
+ u8 dino_response;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct ipw_aironet_info {
+ u8 id;
+ u8 length;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct ipw_rx_key {
+ u8 station_index;
+ u8 key_type;
+ u8 key_id;
+ u8 key_flag;
+ u8 key[16];
+ u8 station_address[6];
+ u8 key_index;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct ipw_country_channel_info {
+ u8 first_channel;
+ u8 no_channels;
+ s8 max_tx_power;
+} __attribute__ ((packed));
+
+struct ipw_country_info {
+ u8 id;
+ u8 length;
+ u8 country_str[3];
+ struct ipw_country_channel_info groups[7];
+} __attribute__ ((packed));
+
+struct ipw_channel_tx_power {
+ u8 channel_number;
+ s8 tx_power;
+} __attribute__ ((packed));
+
+#define SCAN_ASSOCIATED_INTERVAL (HZ)
+#define SCAN_INTERVAL (HZ / 10)
+#define MAX_A_CHANNELS 37
+#define MAX_B_CHANNELS 14
+
+struct ipw_tx_power {
+ u8 num_channels;
+ u8 ieee_mode;
+ struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
+} __attribute__ ((packed));
+
+struct ipw_qos_parameters {
+ u16 cw_min[4];
+ u16 cw_max[4];
+ u8 aifs[4];
+ u8 flag[4];
+ u16 tx_op_limit[4];
+} __attribute__ ((packed));
+
+struct ipw_rsn_capabilities {
+ u8 id;
+ u8 length;
+ u16 version;
+} __attribute__ ((packed));
+
+struct ipw_sensitivity_calib {
+ u16 beacon_rssi_raw;
+ u16 reserved;
+} __attribute__ ((packed));
+
+/**
+ * Host command structure.
+ *
+ * On input, the following fields should be filled:
+ * - cmd
+ * - len
+ * - status_len
+ * - param (if needed)
+ *
+ * On output,
+ * - \a status contains status;
+ * - \a param filled with status parameters.
+ */
+struct ipw_cmd {
+ u32 cmd; /**< Host command */
+ u32 status;/**< Status */
+ u32 status_len;
+ /**< How many 32 bit parameters in the status */
+ u32 len; /**< incoming parameters length, bytes */
+ /**
+ * command parameters.
+ * There should be enough space for incoming and
+ * outcoming parameters.
+ * Incoming parameters listed 1-st, followed by outcoming params.
+ * nParams=(len+3)/4+status_len
+ */
+ u32 param[0];
+} __attribute__ ((packed));
+
+#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */
+
+#define STATUS_INT_ENABLED (1<<1)
+#define STATUS_RF_KILL_HW (1<<2)
+#define STATUS_RF_KILL_SW (1<<3)
+#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
+
+#define STATUS_INIT (1<<5)
+#define STATUS_AUTH (1<<6)
+#define STATUS_ASSOCIATED (1<<7)
+#define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED)
+
+#define STATUS_ASSOCIATING (1<<8)
+#define STATUS_DISASSOCIATING (1<<9)
+#define STATUS_ROAMING (1<<10)
+#define STATUS_EXIT_PENDING (1<<11)
+#define STATUS_DISASSOC_PENDING (1<<12)
+#define STATUS_STATE_PENDING (1<<13)
+
+#define STATUS_SCAN_PENDING (1<<20)
+#define STATUS_SCANNING (1<<21)
+#define STATUS_SCAN_ABORTING (1<<22)
+
+#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */
+#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */
+#define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */
+
+#define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */
+
+#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
+#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
+#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
+#define CFG_CUSTOM_MAC (1<<3)
+#define CFG_PREAMBLE (1<<4)
+#define CFG_ADHOC_PERSIST (1<<5)
+#define CFG_ASSOCIATE (1<<6)
+#define CFG_FIXED_RATE (1<<7)
+#define CFG_ADHOC_CREATE (1<<8)
+
+#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
+#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
+
+#define MAX_STATIONS 32
+#define IPW_INVALID_STATION (0xff)
+
+struct ipw_station_entry {
+ u8 mac_addr[ETH_ALEN];
+ u8 reserved;
+ u8 support_mode;
+};
+
+#define AVG_ENTRIES 8
+struct average {
+ s16 entries[AVG_ENTRIES];
+ u8 pos;
+ u8 init;
+ s32 sum;
+};
+
+struct ipw_priv {
+ /* ieee device used by generic ieee processing code */
+ struct ieee80211_device *ieee;
+ struct ieee80211_security sec;
+
+ /* spinlock */
+ spinlock_t lock;
+
+ /* basic pci-network driver stuff */
+ struct pci_dev *pci_dev;
+ struct net_device *net_dev;
+
+ /* pci hardware address support */
+ void __iomem *hw_base;
+ unsigned long hw_len;
+
+ struct fw_image_desc sram_desc;
+
+ /* result of ucode download */
+ struct alive_command_responce dino_alive;
+
+ wait_queue_head_t wait_command_queue;
+ wait_queue_head_t wait_state;
+
+ /* Rx and Tx DMA processing queues */
+ struct ipw_rx_queue *rxq;
+ struct clx2_tx_queue txq_cmd;
+ struct clx2_tx_queue txq[4];
+ u32 status;
+ u32 config;
+ u32 capability;
+
+ u8 last_rx_rssi;
+ u8 last_noise;
+ struct average average_missed_beacons;
+ struct average average_rssi;
+ struct average average_noise;
+ u32 port_type;
+ int rx_bufs_min; /**< minimum number of bufs in Rx queue */
+ int rx_pend_max; /**< maximum pending buffers for one IRQ */
+ u32 hcmd_seq; /**< sequence number for hcmd */
+ u32 missed_beacon_threshold;
+ u32 roaming_threshold;
+
+ struct ipw_associate assoc_request;
+ struct ieee80211_network *assoc_network;
+
+ unsigned long ts_scan_abort;
+ struct ipw_supported_rates rates;
+ struct ipw_rates phy[3]; /**< PHY restrictions, per band */
+ struct ipw_rates supp; /**< software defined */
+ struct ipw_rates extended; /**< use for corresp. IE, AP only */
+
+ struct notif_link_deterioration last_link_deterioration; /** for statistics */
+ struct ipw_cmd *hcmd; /**< host command currently executed */
+
+ wait_queue_head_t hcmd_wq; /**< host command waits for execution */
+ u32 tsf_bcn[2]; /**< TSF from latest beacon */
+
+ struct notif_calibration calib; /**< last calibration */
+
+ /* ordinal interface with firmware */
+ u32 table0_addr;
+ u32 table0_len;
+ u32 table1_addr;
+ u32 table1_len;
+ u32 table2_addr;
+ u32 table2_len;
+
+ /* context information */
+ u8 essid[IW_ESSID_MAX_SIZE];
+ u8 essid_len;
+ u8 nick[IW_ESSID_MAX_SIZE];
+ u16 rates_mask;
+ u8 channel;
+ struct ipw_sys_config sys_config;
+ u32 power_mode;
+ u8 bssid[ETH_ALEN];
+ u16 rts_threshold;
+ u8 mac_addr[ETH_ALEN];
+ u8 num_stations;
+ u8 stations[MAX_STATIONS][ETH_ALEN];
+
+ u32 notif_missed_beacons;
+
+ /* Statistics and counters normalized with each association */
+ u32 last_missed_beacons;
+ u32 last_tx_packets;
+ u32 last_rx_packets;
+ u32 last_tx_failures;
+ u32 last_rx_err;
+ u32 last_rate;
+
+ u32 missed_adhoc_beacons;
+ u32 missed_beacons;
+ u32 rx_packets;
+ u32 tx_packets;
+ u32 quality;
+
+ /* eeprom */
+ u8 eeprom[0x100]; /* 256 bytes of eeprom */
+ int eeprom_delay;
+
+ struct iw_statistics wstats;
+
+ struct workqueue_struct *workqueue;
+
+ struct work_struct adhoc_check;
+ struct work_struct associate;
+ struct work_struct disassociate;
+ struct work_struct rx_replenish;
+ struct work_struct request_scan;
+ struct work_struct adapter_restart;
+ struct work_struct rf_kill;
+ struct work_struct up;
+ struct work_struct down;
+ struct work_struct gather_stats;
+ struct work_struct abort_scan;
+ struct work_struct roam;
+ struct work_struct scan_check;
+
+ struct tasklet_struct irq_tasklet;
+
+#define IPW_2200BG 1
+#define IPW_2915ABG 2
+ u8 adapter;
+
+#define IPW_DEFAULT_TX_POWER 0x14
+ u8 tx_power;
+
+#ifdef CONFIG_PM
+ u32 pm_state[16];
+#endif
+
+ /* network state */
+
+ /* Used to pass the current INTA value from ISR to Tasklet */
+ u32 isr_inta;
+
+ /* debugging info */
+ u32 indirect_dword;
+ u32 direct_dword;
+ u32 indirect_byte;
+}; /*ipw_priv */
+
+/* debug macros */
+
+#ifdef CONFIG_IPW_DEBUG
+#define IPW_DEBUG(level, fmt, args...) \
+do { if (ipw_debug_level & (level)) \
+ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+#define IPW_DEBUG(level, fmt, args...) do {} while (0)
+#endif /* CONFIG_IPW_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IPW_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IPW_xxxx_DEBUG() macro definition for your
+ * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IPW_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IPW_DL_ERROR (1<<0)
+#define IPW_DL_WARNING (1<<1)
+#define IPW_DL_INFO (1<<2)
+#define IPW_DL_WX (1<<3)
+#define IPW_DL_HOST_COMMAND (1<<5)
+#define IPW_DL_STATE (1<<6)
+
+#define IPW_DL_NOTIF (1<<10)
+#define IPW_DL_SCAN (1<<11)
+#define IPW_DL_ASSOC (1<<12)
+#define IPW_DL_DROP (1<<13)
+#define IPW_DL_IOCTL (1<<14)
+
+#define IPW_DL_MANAGE (1<<15)
+#define IPW_DL_FW (1<<16)
+#define IPW_DL_RF_KILL (1<<17)
+#define IPW_DL_FW_ERRORS (1<<18)
+
+#define IPW_DL_ORD (1<<20)
+
+#define IPW_DL_FRAG (1<<21)
+#define IPW_DL_WEP (1<<22)
+#define IPW_DL_TX (1<<23)
+#define IPW_DL_RX (1<<24)
+#define IPW_DL_ISR (1<<25)
+#define IPW_DL_FW_INFO (1<<26)
+#define IPW_DL_IO (1<<27)
+#define IPW_DL_TRACE (1<<28)
+
+#define IPW_DL_STATS (1<<29)
+
+#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a)
+
+#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a)
+#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a)
+#define IPW_DEBUG_STATUS(f, a...) IPW_DEBUG(IPW_DL_STATUS, f, ## a)
+#define IPW_DEBUG_TRACE(f, a...) IPW_DEBUG(IPW_DL_TRACE, f, ## a)
+#define IPW_DEBUG_RX(f, a...) IPW_DEBUG(IPW_DL_RX, f, ## a)
+#define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a)
+#define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a)
+#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
+#define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a)
+#define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
+#define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a)
+#define IPW_DEBUG_FW(f, a...) IPW_DEBUG(IPW_DL_FW, f, ## a)
+#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
+#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
+#define IPW_DEBUG_IO(f, a...) IPW_DEBUG(IPW_DL_IO, f, ## a)
+#define IPW_DEBUG_ORD(f, a...) IPW_DEBUG(IPW_DL_ORD, f, ## a)
+#define IPW_DEBUG_FW_INFO(f, a...) IPW_DEBUG(IPW_DL_FW_INFO, f, ## a)
+#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
+#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
+#define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a)
+
+#include <linux/ctype.h>
+
+/*
+* Register bit definitions
+*/
+
+/* Dino control registers bits */
+
+#define DINO_ENABLE_SYSTEM 0x80
+#define DINO_ENABLE_CS 0x40
+#define DINO_RXFIFO_DATA 0x01
+#define DINO_CONTROL_REG 0x00200000
+
+#define CX2_INTA_RW 0x00000008
+#define CX2_INTA_MASK_R 0x0000000C
+#define CX2_INDIRECT_ADDR 0x00000010
+#define CX2_INDIRECT_DATA 0x00000014
+#define CX2_AUTOINC_ADDR 0x00000018
+#define CX2_AUTOINC_DATA 0x0000001C
+#define CX2_RESET_REG 0x00000020
+#define CX2_GP_CNTRL_RW 0x00000024
+
+#define CX2_READ_INT_REGISTER 0xFF4
+
+#define CX2_GP_CNTRL_BIT_INIT_DONE 0x00000004
+
+#define CX2_REGISTER_DOMAIN1_END 0x00001000
+#define CX2_SRAM_READ_INT_REGISTER 0x00000ff4
+
+#define CX2_SHARED_LOWER_BOUND 0x00000200
+#define CX2_INTERRUPT_AREA_LOWER_BOUND 0x00000f80
+
+#define CX2_NIC_SRAM_LOWER_BOUND 0x00000000
+#define CX2_NIC_SRAM_UPPER_BOUND 0x00030000
+
+#define CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
+#define CX2_GP_CNTRL_BIT_CLOCK_READY 0x00000001
+#define CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
+
+/*
+ * RESET Register Bit Indexes
+ */
+#define CBD_RESET_REG_PRINCETON_RESET 0x00000001 /* Bit 0 (LSB) */
+#define CX2_RESET_REG_SW_RESET 0x00000080 /* Bit 7 */
+#define CX2_RESET_REG_MASTER_DISABLED 0x00000100 /* Bit 8 */
+#define CX2_RESET_REG_STOP_MASTER 0x00000200 /* Bit 9 */
+#define CX2_ARC_KESHET_CONFIG 0x08000000 /* Bit 27 */
+#define CX2_START_STANDBY 0x00000004 /* Bit 2 */
+
+#define CX2_CSR_CIS_UPPER_BOUND 0x00000200
+#define CX2_DOMAIN_0_END 0x1000
+#define CLX_MEM_BAR_SIZE 0x1000
+
+#define CX2_BASEBAND_CONTROL_STATUS 0X00200000
+#define CX2_BASEBAND_TX_FIFO_WRITE 0X00200004
+#define CX2_BASEBAND_RX_FIFO_READ 0X00200004
+#define CX2_BASEBAND_CONTROL_STORE 0X00200010
+
+#define CX2_INTERNAL_CMD_EVENT 0X00300004
+#define CX2_BASEBAND_POWER_DOWN 0x00000001
+
+#define CX2_MEM_HALT_AND_RESET 0x003000e0
+
+/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
+#define CX2_BIT_HALT_RESET_ON 0x80000000
+#define CX2_BIT_HALT_RESET_OFF 0x00000000
+
+#define CB_LAST_VALID 0x20000000
+#define CB_INT_ENABLED 0x40000000
+#define CB_VALID 0x80000000
+#define CB_SRC_LE 0x08000000
+#define CB_DEST_LE 0x04000000
+#define CB_SRC_AUTOINC 0x00800000
+#define CB_SRC_IO_GATED 0x00400000
+#define CB_DEST_AUTOINC 0x00080000
+#define CB_SRC_SIZE_LONG 0x00200000
+#define CB_DEST_SIZE_LONG 0x00020000
+
+/* DMA DEFINES */
+
+#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000
+#define DMA_CB_STOP_AND_ABORT 0x00000C00
+#define DMA_CB_START 0x00000100
+
+#define CX2_SHARED_SRAM_SIZE 0x00030000
+#define CX2_SHARED_SRAM_DMA_CONTROL 0x00027000
+#define CB_MAX_LENGTH 0x1FFF
+
+#define CX2_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
+#define CX2_EEPROM_IMAGE_SIZE 0x100
+
+/* DMA defs */
+#define CX2_DMA_I_CURRENT_CB 0x003000D0
+#define CX2_DMA_O_CURRENT_CB 0x003000D4
+#define CX2_DMA_I_DMA_CONTROL 0x003000A4
+#define CX2_DMA_I_CB_BASE 0x003000A0
+
+#define CX2_TX_CMD_QUEUE_BD_BASE (0x00000200)
+#define CX2_TX_CMD_QUEUE_BD_SIZE (0x00000204)
+#define CX2_TX_QUEUE_0_BD_BASE (0x00000208)
+#define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C)
+#define CX2_TX_QUEUE_1_BD_BASE (0x00000210)
+#define CX2_TX_QUEUE_1_BD_SIZE (0x00000214)
+#define CX2_TX_QUEUE_2_BD_BASE (0x00000218)
+#define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C)
+#define CX2_TX_QUEUE_3_BD_BASE (0x00000220)
+#define CX2_TX_QUEUE_3_BD_SIZE (0x00000224)
+#define CX2_RX_BD_BASE (0x00000240)
+#define CX2_RX_BD_SIZE (0x00000244)
+#define CX2_RFDS_TABLE_LOWER (0x00000500)
+
+#define CX2_TX_CMD_QUEUE_READ_INDEX (0x00000280)
+#define CX2_TX_QUEUE_0_READ_INDEX (0x00000284)
+#define CX2_TX_QUEUE_1_READ_INDEX (0x00000288)
+#define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C)
+#define CX2_TX_QUEUE_3_READ_INDEX (0x00000290)
+#define CX2_RX_READ_INDEX (0x000002A0)
+
+#define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80)
+#define CX2_TX_QUEUE_0_WRITE_INDEX (0x00000F84)
+#define CX2_TX_QUEUE_1_WRITE_INDEX (0x00000F88)
+#define CX2_TX_QUEUE_2_WRITE_INDEX (0x00000F8C)
+#define CX2_TX_QUEUE_3_WRITE_INDEX (0x00000F90)
+#define CX2_RX_WRITE_INDEX (0x00000FA0)
+
+/*
+ * EEPROM Related Definitions
+ */
+
+#define IPW_EEPROM_DATA_SRAM_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x814)
+#define IPW_EEPROM_DATA_SRAM_SIZE (CX2_SHARED_LOWER_BOUND + 0x818)
+#define IPW_EEPROM_LOAD_DISABLE (CX2_SHARED_LOWER_BOUND + 0x81C)
+#define IPW_EEPROM_DATA (CX2_SHARED_LOWER_BOUND + 0x820)
+#define IPW_EEPROM_UPPER_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x9E0)
+
+#define IPW_STATION_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0xA0C)
+#define IPW_STATION_TABLE_UPPER (CX2_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_REQUEST_ATIM (CX2_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_ATIM_SENT (CX2_SHARED_LOWER_BOUND + 0xB10)
+#define IPW_WHO_IS_AWAKE (CX2_SHARED_LOWER_BOUND + 0xB14)
+#define IPW_DURING_ATIM_WINDOW (CX2_SHARED_LOWER_BOUND + 0xB18)
+
+#define MSB 1
+#define LSB 0
+#define WORD_TO_BYTE(_word) ((_word) * sizeof(u16))
+
+#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \
+ ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) )
+
+/* EEPROM access by BYTE */
+#define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */
+#define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */
+#define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */
+#define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */
+#define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */
+#define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */
+#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */
+#define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */
+#define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */
+#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */
+
+/* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/
+#define EEPROM_NIC_TYPE_STANDARD 0
+#define EEPROM_NIC_TYPE_DELL 1
+#define EEPROM_NIC_TYPE_FUJITSU 2
+#define EEPROM_NIC_TYPE_IBM 3
+#define EEPROM_NIC_TYPE_HP 4
+
+#define FW_MEM_REG_LOWER_BOUND 0x00300000
+#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40)
+
+#define EEPROM_BIT_SK (1<<0)
+#define EEPROM_BIT_CS (1<<1)
+#define EEPROM_BIT_DI (1<<2)
+#define EEPROM_BIT_DO (1<<4)
+
+#define EEPROM_CMD_READ 0x2
+
+/* Interrupts masks */
+#define CX2_INTA_NONE 0x00000000
+
+#define CX2_INTA_BIT_RX_TRANSFER 0x00000002
+#define CX2_INTA_BIT_STATUS_CHANGE 0x00000010
+#define CX2_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020
+
+//Inta Bits for CF
+#define CX2_INTA_BIT_TX_CMD_QUEUE 0x00000800
+#define CX2_INTA_BIT_TX_QUEUE_1 0x00001000
+#define CX2_INTA_BIT_TX_QUEUE_2 0x00002000
+#define CX2_INTA_BIT_TX_QUEUE_3 0x00004000
+#define CX2_INTA_BIT_TX_QUEUE_4 0x00008000
+
+#define CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000
+
+#define CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000
+#define CX2_INTA_BIT_POWER_DOWN 0x00200000
+
+#define CX2_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000
+#define CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000
+#define CX2_INTA_BIT_RF_KILL_DONE 0x04000000
+#define CX2_INTA_BIT_FATAL_ERROR 0x40000000
+#define CX2_INTA_BIT_PARITY_ERROR 0x80000000
+
+/* Interrupts enabled at init time. */
+#define CX2_INTA_MASK_ALL \
+ (CX2_INTA_BIT_TX_QUEUE_1 | \
+ CX2_INTA_BIT_TX_QUEUE_2 | \
+ CX2_INTA_BIT_TX_QUEUE_3 | \
+ CX2_INTA_BIT_TX_QUEUE_4 | \
+ CX2_INTA_BIT_TX_CMD_QUEUE | \
+ CX2_INTA_BIT_RX_TRANSFER | \
+ CX2_INTA_BIT_FATAL_ERROR | \
+ CX2_INTA_BIT_PARITY_ERROR | \
+ CX2_INTA_BIT_STATUS_CHANGE | \
+ CX2_INTA_BIT_FW_INITIALIZATION_DONE | \
+ CX2_INTA_BIT_BEACON_PERIOD_EXPIRED | \
+ CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
+ CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN | \
+ CX2_INTA_BIT_POWER_DOWN | \
+ CX2_INTA_BIT_RF_KILL_DONE )
+
+#define IPWSTATUS_ERROR_LOG (CX2_SHARED_LOWER_BOUND + 0x410)
+#define IPW_EVENT_LOG (CX2_SHARED_LOWER_BOUND + 0x414)
+
+/* FW event log definitions */
+#define EVENT_ELEM_SIZE (3 * sizeof(u32))
+#define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16))
+
+/* FW error log definitions */
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+
+enum {
+ IPW_FW_ERROR_OK = 0,
+ IPW_FW_ERROR_FAIL,
+ IPW_FW_ERROR_MEMORY_UNDERFLOW,
+ IPW_FW_ERROR_MEMORY_OVERFLOW,
+ IPW_FW_ERROR_BAD_PARAM,
+ IPW_FW_ERROR_BAD_CHECKSUM,
+ IPW_FW_ERROR_NMI_INTERRUPT,
+ IPW_FW_ERROR_BAD_DATABASE,
+ IPW_FW_ERROR_ALLOC_FAIL,
+ IPW_FW_ERROR_DMA_UNDERRUN,
+ IPW_FW_ERROR_DMA_STATUS,
+ IPW_FW_ERROR_DINOSTATUS_ERROR,
+ IPW_FW_ERROR_EEPROMSTATUS_ERROR,
+ IPW_FW_ERROR_SYSASSERT,
+ IPW_FW_ERROR_FATAL_ERROR
+};
+
+#define AUTH_OPEN 0
+#define AUTH_SHARED_KEY 1
+#define AUTH_IGNORE 3
+
+#define HC_ASSOCIATE 0
+#define HC_REASSOCIATE 1
+#define HC_DISASSOCIATE 2
+#define HC_IBSS_START 3
+#define HC_IBSS_RECONF 4
+#define HC_DISASSOC_QUIET 5
+
+#define IPW_RATE_CAPABILITIES 1
+#define IPW_RATE_CONNECT 0
+
+/*
+ * Rate values and masks
+ */
+#define IPW_TX_RATE_1MB 0x0A
+#define IPW_TX_RATE_2MB 0x14
+#define IPW_TX_RATE_5MB 0x37
+#define IPW_TX_RATE_6MB 0x0D
+#define IPW_TX_RATE_9MB 0x0F
+#define IPW_TX_RATE_11MB 0x6E
+#define IPW_TX_RATE_12MB 0x05
+#define IPW_TX_RATE_18MB 0x07
+#define IPW_TX_RATE_24MB 0x09
+#define IPW_TX_RATE_36MB 0x0B
+#define IPW_TX_RATE_48MB 0x01
+#define IPW_TX_RATE_54MB 0x03
+
+#define IPW_ORD_TABLE_ID_MASK 0x0000FF00
+#define IPW_ORD_TABLE_VALUE_MASK 0x000000FF
+
+#define IPW_ORD_TABLE_0_MASK 0x0000F000
+#define IPW_ORD_TABLE_1_MASK 0x0000F100
+#define IPW_ORD_TABLE_2_MASK 0x0000F200
+#define IPW_ORD_TABLE_3_MASK 0x0000F300
+#define IPW_ORD_TABLE_4_MASK 0x0000F400
+#define IPW_ORD_TABLE_5_MASK 0x0000F500
+#define IPW_ORD_TABLE_6_MASK 0x0000F600
+#define IPW_ORD_TABLE_7_MASK 0x0000F700
+
+/*
+ * Table 0 Entries (all entries are 32 bits)
+ */
+enum {
+ IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1,
+ IPW_ORD_STAT_FRAG_TRESHOLD,
+ IPW_ORD_STAT_RTS_THRESHOLD,
+ IPW_ORD_STAT_TX_HOST_REQUESTS,
+ IPW_ORD_STAT_TX_HOST_COMPLETE,
+ IPW_ORD_STAT_TX_DIR_DATA,
+ IPW_ORD_STAT_TX_DIR_DATA_B_1,
+ IPW_ORD_STAT_TX_DIR_DATA_B_2,
+ IPW_ORD_STAT_TX_DIR_DATA_B_5_5,
+ IPW_ORD_STAT_TX_DIR_DATA_B_11,
+ /* Hole */
+
+ IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19,
+ IPW_ORD_STAT_TX_DIR_DATA_G_2,
+ IPW_ORD_STAT_TX_DIR_DATA_G_5_5,
+ IPW_ORD_STAT_TX_DIR_DATA_G_6,
+ IPW_ORD_STAT_TX_DIR_DATA_G_9,
+ IPW_ORD_STAT_TX_DIR_DATA_G_11,
+ IPW_ORD_STAT_TX_DIR_DATA_G_12,
+ IPW_ORD_STAT_TX_DIR_DATA_G_18,
+ IPW_ORD_STAT_TX_DIR_DATA_G_24,
+ IPW_ORD_STAT_TX_DIR_DATA_G_36,
+ IPW_ORD_STAT_TX_DIR_DATA_G_48,
+ IPW_ORD_STAT_TX_DIR_DATA_G_54,
+ IPW_ORD_STAT_TX_NON_DIR_DATA,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_B_1,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_B_2,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_B_11,
+ /* Hole */
+
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_2,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_6,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_9,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_11,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_12,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_18,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_24,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_36,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_48,
+ IPW_ORD_STAT_TX_NON_DIR_DATA_G_54,
+ IPW_ORD_STAT_TX_RETRY,
+ IPW_ORD_STAT_TX_FAILURE,
+ IPW_ORD_STAT_RX_ERR_CRC,
+ IPW_ORD_STAT_RX_ERR_ICV,
+ IPW_ORD_STAT_RX_NO_BUFFER,
+ IPW_ORD_STAT_FULL_SCANS,
+ IPW_ORD_STAT_PARTIAL_SCANS,
+ IPW_ORD_STAT_TGH_ABORTED_SCANS,
+ IPW_ORD_STAT_TX_TOTAL_BYTES,
+ IPW_ORD_STAT_CURR_RSSI_RAW,
+ IPW_ORD_STAT_RX_BEACON,
+ IPW_ORD_STAT_MISSED_BEACONS,
+ IPW_ORD_TABLE_0_LAST
+};
+
+#define IPW_RSSI_TO_DBM 112
+
+/* Table 1 Entries
+ */
+enum {
+ IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1,
+};
+
+/*
+ * Table 2 Entries
+ *
+ * FW_VERSION: 16 byte string
+ * FW_DATE: 16 byte string (only 14 bytes used)
+ * UCODE_VERSION: 4 byte version code
+ * UCODE_DATE: 5 bytes code code
+ * ADDAPTER_MAC: 6 byte MAC address
+ * RTC: 4 byte clock
+ */
+enum {
+ IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1,
+ IPW_ORD_STAT_FW_DATE,
+ IPW_ORD_STAT_UCODE_VERSION,
+ IPW_ORD_STAT_UCODE_DATE,
+ IPW_ORD_STAT_ADAPTER_MAC,
+ IPW_ORD_STAT_RTC,
+ IPW_ORD_TABLE_2_LAST
+};
+
+/* Table 3 */
+enum {
+ IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0,
+ IPW_ORD_STAT_TX_PACKET_FAILURE,
+ IPW_ORD_STAT_TX_PACKET_SUCCESS,
+ IPW_ORD_STAT_TX_PACKET_ABORTED,
+ IPW_ORD_TABLE_3_LAST
+};
+
+/* Table 4 */
+enum {
+ IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK
+};
+
+/* Table 5 */
+enum {
+ IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK,
+ IPW_ORD_STAT_AP_ASSNS,
+ IPW_ORD_STAT_ROAM,
+ IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS,
+ IPW_ORD_STAT_ROAM_CAUSE_UNASSOC,
+ IPW_ORD_STAT_ROAM_CAUSE_RSSI,
+ IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY,
+ IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE,
+ IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX,
+ IPW_ORD_STAT_LINK_UP,
+ IPW_ORD_STAT_LINK_DOWN,
+ IPW_ORD_ANTENNA_DIVERSITY,
+ IPW_ORD_CURR_FREQ,
+ IPW_ORD_TABLE_5_LAST
+};
+
+/* Table 6 */
+enum {
+ IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK,
+ IPW_ORD_CURR_BSSID,
+ IPW_ORD_CURR_SSID,
+ IPW_ORD_TABLE_6_LAST
+};
+
+/* Table 7 */
+enum {
+ IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK,
+ IPW_ORD_STAT_PERCENT_TX_RETRIES,
+ IPW_ORD_STAT_PERCENT_LINK_QUALITY,
+ IPW_ORD_STAT_CURR_RSSI_DBM,
+ IPW_ORD_TABLE_7_LAST
+};
+
+#define IPW_ORDINALS_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0x500)
+#define IPW_ORDINALS_TABLE_0 (CX2_SHARED_LOWER_BOUND + 0x180)
+#define IPW_ORDINALS_TABLE_1 (CX2_SHARED_LOWER_BOUND + 0x184)
+#define IPW_ORDINALS_TABLE_2 (CX2_SHARED_LOWER_BOUND + 0x188)
+#define IPW_MEM_FIXED_OVERRIDE (CX2_SHARED_LOWER_BOUND + 0x41C)
+
+struct ipw_fixed_rate {
+ u16 tx_rates;
+ u16 reserved;
+} __attribute__ ((packed));
+
+#define CX2_INDIRECT_ADDR_MASK (~0x3ul)
+
+struct host_cmd {
+ u8 cmd;
+ u8 len;
+ u16 reserved;
+ u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
+} __attribute__ ((packed));
+
+#define CFG_BT_COEXISTENCE_MIN 0x00
+#define CFG_BT_COEXISTENCE_DEFER 0x02
+#define CFG_BT_COEXISTENCE_KILL 0x04
+#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08
+#define CFG_BT_COEXISTENCE_OOB 0x10
+#define CFG_BT_COEXISTENCE_MAX 0xFF
+#define CFG_BT_COEXISTENCE_DEF 0x80 /* read Bt from EEPROM */
+
+#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x0
+#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x1
+#define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN
+
+#define CFG_SYS_ANTENNA_BOTH 0x000
+#define CFG_SYS_ANTENNA_A 0x001
+#define CFG_SYS_ANTENNA_B 0x003
+
+/*
+ * The definitions below were lifted off the ipw2100 driver, which only
+ * supports 'b' mode, so I'm sure these are not exactly correct.
+ *
+ * Somebody fix these!!
+ */
+#define REG_MIN_CHANNEL 0
+#define REG_MAX_CHANNEL 14
+
+#define REG_CHANNEL_MASK 0x00003FFF
+#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff
+
+static const long ipw_frequencies[] = {
+ 2412, 2417, 2422, 2427,
+ 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467,
+ 2472, 2484
+};
+
+#define FREQ_COUNT ARRAY_SIZE(ipw_frequencies)
+
+#define IPW_MAX_CONFIG_RETRIES 10
+
+static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr)
+{
+ u32 retval;
+ u16 fc;
+
+ retval = sizeof(struct ieee80211_hdr);
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ /*
+ * Function ToDS FromDS
+ * IBSS 0 0
+ * To AP 1 0
+ * From AP 0 1
+ * WDS (bridge) 1 1
+ *
+ * Only WDS frames use Address4 among them. --YZ
+ */
+ if (!(fc & IEEE80211_FCTL_TODS) || !(fc & IEEE80211_FCTL_FROMDS))
+ retval -= ETH_ALEN;
+
+ return retval;
+}
+
+#endif /* __ipw2200_h__ */
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 5f507c4..ca6c03c 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -471,12 +471,12 @@
dev->get_stats = &netwave_get_stats;
dev->set_multicast_list = &set_multicast_list;
/* wireless extensions */
-#ifdef WIRELESS_EXT
+#if WIRELESS_EXT <= 16
dev->get_wireless_stats = &netwave_get_wireless_stats;
+#endif /* WIRELESS_EXT <= 16 */
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def;
#endif /* WIRELESS_EXT > 12 */
-#endif /* WIRELESS_EXT */
dev->do_ioctl = &netwave_ioctl;
dev->tx_timeout = &netwave_watchdog;
@@ -839,6 +839,9 @@
.standard = (iw_handler *) netwave_handler,
.private = (iw_handler *) netwave_private_handler,
.private_args = (struct iw_priv_args *) netwave_private_args,
+#if WIRELESS_EXT > 16
+ .get_wireless_stats = netwave_get_wireless_stats,
+#endif /* WIRELESS_EXT > 16 */
};
#endif /* WIRELESS_EXT > 12 */
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 9c2d07c..8de49fe 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -94,6 +94,8 @@
#include <net/iw_handler.h>
#include <net/ieee80211.h>
+#include <net/ieee80211.h>
+
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -101,7 +103,6 @@
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
-#include "ieee802_11.h"
/********************************************************************/
/* Module information */
@@ -150,7 +151,7 @@
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
#define ORINOCO_MIN_MTU 256
-#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
#define SYMBOL_MAX_VER_LEN (14)
#define USER_BAP 0
@@ -442,7 +443,7 @@
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
return -EINVAL;
- if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) >
+ if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
(priv->nicbuf_size - ETH_HLEN) )
return -EINVAL;
@@ -918,7 +919,7 @@
data. */
return;
}
- if (length > IEEE802_11_DATA_LEN) {
+ if (length > IEEE80211_DATA_LEN) {
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
dev->name, length);
stats->rx_length_errors++;
@@ -1052,8 +1053,9 @@
u16 channel;
} __attribute__ ((packed)) req;
const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
- struct prism2_scan_apinfo *atom;
+ struct prism2_scan_apinfo *atom = NULL;
int offset = 4;
+ int found = 0;
u8 *buf;
u16 len;
@@ -1088,15 +1090,18 @@
* we were requested to join */
for (; offset + atom_len <= len; offset += atom_len) {
atom = (struct prism2_scan_apinfo *) (buf + offset);
- if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
- goto found;
+ if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+ found = 1;
+ break;
+ }
}
- DEBUG(1, "%s: Requested AP not found in scan results\n",
- dev->name);
- goto out;
+ if (! found) {
+ DEBUG(1, "%s: Requested AP not found in scan results\n",
+ dev->name);
+ goto out;
+ }
- found:
memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
req.channel = atom->channel; /* both are little-endian */
err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
@@ -1283,8 +1288,10 @@
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
- if (err)
+ if (err) {
+ kfree(buf);
break;
+ }
#ifdef ORINOCO_DEBUG
{
@@ -2272,7 +2279,7 @@
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
- priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
+ priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
/* Initialize the firmware */
err = orinoco_reinit_firmware(dev);
@@ -4020,7 +4027,8 @@
}
/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
+ * format that the Wireless Tools will understand - Jean II
+ * Return message length or -errno for fatal errors */
static inline int orinoco_translate_scan(struct net_device *dev,
char *buffer,
char *scan,
@@ -4060,13 +4068,19 @@
break;
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
- if (priv->has_hostscan)
- atom_len = scan[0] + (scan[1] << 8);
- else
+ if (priv->has_hostscan) {
+ atom_len = le16_to_cpup((u16 *)scan);
+ /* Sanity check for atom_len */
+ if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+ printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
+ dev->name, atom_len);
+ return -EIO;
+ }
+ } else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
default:
- return 0;
+ return -EOPNOTSUPP;
}
/* Check that we got an whole number of atoms */
@@ -4074,7 +4088,7 @@
printk(KERN_ERR "%s: Unexpected scan data length %d, "
"atom_len %d, offset %d\n", dev->name, scan_len,
atom_len, offset);
- return 0;
+ return -EIO;
}
/* Read the entries one by one */
@@ -4209,33 +4223,41 @@
/* We have some results to push back to user space */
/* Translate to WE format */
- srq->length = orinoco_translate_scan(dev, extra,
- priv->scan_result,
- priv->scan_len);
+ int ret = orinoco_translate_scan(dev, extra,
+ priv->scan_result,
+ priv->scan_len);
- /* Return flags */
- srq->flags = (__u16) priv->scan_mode;
+ if (ret < 0) {
+ err = ret;
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+ } else {
+ srq->length = ret;
- /* Results are here, so scan no longer in progress */
- priv->scan_inprogress = 0;
+ /* Return flags */
+ srq->flags = (__u16) priv->scan_mode;
- /* In any case, Scan results will be cleaned up in the
- * reset function and when exiting the driver.
- * The person triggering the scanning may never come to
- * pick the results, so we need to do it in those places.
- * Jean II */
+ /* In any case, Scan results will be cleaned up in the
+ * reset function and when exiting the driver.
+ * The person triggering the scanning may never come to
+ * pick the results, so we need to do it in those places.
+ * Jean II */
#ifdef SCAN_SINGLE_READ
- /* If you enable this option, only one client (the first
- * one) will be able to read the result (and only one
- * time). If there is multiple concurent clients that
- * want to read scan results, this behavior is not
- * advisable - Jean II */
- kfree(priv->scan_result);
- priv->scan_result = NULL;
+ /* If you enable this option, only one client (the first
+ * one) will be able to read the result (and only one
+ * time). If there is multiple concurent clients that
+ * want to read scan results, this behavior is not
+ * advisable - Jean II */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
#endif /* SCAN_SINGLE_READ */
- /* Here, if too much time has elapsed since last scan,
- * we may want to clean up scan results... - Jean II */
+ /* Here, if too much time has elapsed since last scan,
+ * we may want to clean up scan results... - Jean II */
+ }
+
+ /* Scan is no longer in progress */
+ priv->scan_inprogress = 0;
}
orinoco_unlock(priv, &flags);
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 1cc1492..d1fb1ba 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -604,7 +604,6 @@
static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
new file mode 100644
index 0000000..86fa58e
--- /dev/null
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -0,0 +1,324 @@
+/* orinoco_nortel.c
+ *
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter.
+ *
+ * Copyright (C) 2002 Tobias Hoffmann
+ * (C) 2003 Christoph Jungegger <disdos@traum404.de>
+ *
+ * Some of this code is borrowed from orinoco_plx.c
+ * Copyright (C) 2001 Daniel Barlow
+ * Some of this code is borrowed from orinoco_pci.c
+ * Copyright (C) 2001 Jean Tourrilhes
+ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
+ * has been copied from it. linux-wlan-ng-0.1.10 is originally :
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#define DRIVER_NAME "orinoco_nortel"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/config.h>
+
+#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>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/fcntl.h>
+
+#include <pcmcia/cisreg.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
+#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+
+
+/* Nortel specific data */
+struct nortel_pci_card {
+ unsigned long iobase1;
+ unsigned long iobase2;
+};
+
+/*
+ * Do a soft reset of the PCI card using the Configuration Option Register
+ * We need this to get going...
+ * This is the part of the code that is strongly inspired from wlan-ng
+ *
+ * Note bis : Don't try to access HERMES_CMD during the reset phase.
+ * It just won't work !
+ */
+static int nortel_pci_cor_reset(struct orinoco_private *priv)
+{
+ struct nortel_pci_card *card = priv->card;
+
+ /* Assert the reset until the card notice */
+ outw_p(8, card->iobase1 + 2);
+ inw(card->iobase2 + COR_OFFSET);
+ outw_p(0x80, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+
+ /* Give time for the card to recover from this hard effort */
+ outw_p(0, card->iobase2 + COR_OFFSET);
+ outw_p(0, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+
+ /* set COR as usual */
+ outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+
+ outw_p(0x228, card->iobase1 + 2);
+
+ return 0;
+}
+
+int nortel_pci_hw_init(struct nortel_pci_card *card)
+{
+ int i;
+ u32 reg;
+
+ /* setup bridge */
+ if (inw(card->iobase1) & 1) {
+ printk(KERN_ERR PFX "brg1 answer1 wrong\n");
+ return -EBUSY;
+ }
+ outw_p(0x118, card->iobase1 + 2);
+ outw_p(0x108, card->iobase1 + 2);
+ mdelay(30);
+ outw_p(0x8, card->iobase1 + 2);
+ for (i = 0; i < 30; i++) {
+ mdelay(30);
+ if (inw(card->iobase1) & 0x10) {
+ break;
+ }
+ }
+ if (i == 30) {
+ printk(KERN_ERR PFX "brg1 timed out\n");
+ return -EBUSY;
+ }
+ if (inw(card->iobase2 + 0xe0) & 1) {
+ printk(KERN_ERR PFX "brg2 answer1 wrong\n");
+ return -EBUSY;
+ }
+ if (inw(card->iobase2 + 0xe2) & 1) {
+ printk(KERN_ERR PFX "brg2 answer2 wrong\n");
+ return -EBUSY;
+ }
+ if (inw(card->iobase2 + 0xe4) & 1) {
+ printk(KERN_ERR PFX "brg2 answer3 wrong\n");
+ return -EBUSY;
+ }
+
+ /* set the PCMCIA COR-Register */
+ outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+ reg = inw(card->iobase2 + COR_OFFSET);
+ if (reg != COR_VALUE) {
+ printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
+ reg);
+ return -EBUSY;
+ }
+
+ /* set leds */
+ outw_p(1, card->iobase1 + 10);
+ return 0;
+}
+
+static int nortel_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int err;
+ struct orinoco_private *priv;
+ struct nortel_pci_card *card;
+ struct net_device *dev;
+ void __iomem *iomem;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRIVER_NAME);
+ if (err != 0) {
+ printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+ goto fail_resources;
+ }
+
+ iomem = pci_iomap(pdev, 3, 0);
+ if (!iomem) {
+ err = -ENOMEM;
+ goto fail_map_io;
+ }
+
+ /* Allocate network device */
+ dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset);
+ if (!dev) {
+ printk(KERN_ERR PFX "Cannot allocate network device\n");
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ priv = netdev_priv(dev);
+ card = priv->card;
+ card->iobase1 = pci_resource_start(pdev, 0);
+ card->iobase2 = pci_resource_start(pdev, 1);
+ dev->base_addr = pci_resource_start(pdev, 2);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING);
+
+ printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, "
+ "io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr);
+
+ err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ dev->name, dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+ err = -EBUSY;
+ goto fail_irq;
+ }
+ dev->irq = pdev->irq;
+
+ err = nortel_pci_hw_init(card);
+ if (err) {
+ printk(KERN_ERR PFX "Hardware initialization failed\n");
+ goto fail;
+ }
+
+ err = nortel_pci_cor_reset(priv);
+ if (err) {
+ printk(KERN_ERR PFX "Initial reset failed\n");
+ goto fail;
+ }
+
+
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register network device\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ return 0;
+
+ fail:
+ free_irq(pdev->irq, dev);
+
+ fail_irq:
+ pci_set_drvdata(pdev, NULL);
+ free_orinocodev(dev);
+
+ fail_alloc:
+ pci_iounmap(pdev, iomem);
+
+ fail_map_io:
+ pci_release_regions(pdev);
+
+ fail_resources:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void __devexit nortel_pci_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct nortel_pci_card *card = priv->card;
+
+ /* clear leds */
+ outw_p(0, card->iobase1 + 10);
+
+ unregister_netdev(dev);
+ free_irq(dev->irq, dev);
+ pci_set_drvdata(pdev, NULL);
+ free_orinocodev(dev);
+ pci_iounmap(pdev, priv->hw.iobase);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+
+static struct pci_device_id nortel_pci_id_table[] = {
+ /* Nortel emobility PCI */
+ {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
+ {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, nortel_pci_id_table);
+
+static struct pci_driver nortel_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = nortel_pci_id_table,
+ .probe = nortel_pci_init_one,
+ .remove = __devexit_p(nortel_pci_remove_one),
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+ " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
+MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
+MODULE_DESCRIPTION
+ ("Driver for wireless LAN cards using the Nortel PCI bridge");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init nortel_pci_init(void)
+{
+ printk(KERN_DEBUG "%s\n", version);
+ return pci_module_init(&nortel_pci_driver);
+}
+
+static void __exit nortel_pci_exit(void)
+{
+ pci_unregister_driver(&nortel_pci_driver);
+ ssleep(1);
+}
+
+module_init(nortel_pci_init);
+module_exit(nortel_pci_exit);
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 7a6f52e..42e0343 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -301,8 +301,6 @@
unsigned long flags;
int err;
- printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n",
- dev->name, state);
err = orinoco_lock(priv, &flags);
if (err) {
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 0f29a9c..9a8790e 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2727,6 +2727,9 @@
.standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args,
+#if WIRELESS_EXT > 16
+ .get_wireless_stats = prism54_get_wireless_stats,
+#endif /* WIRELESS_EXT > 16 */
#if WIRELESS_EXT == 16
.spy_offset = offsetof(islpci_private, spy_data),
#endif /* WIRELESS_EXT == 16 */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index efab07e..6f13d4a 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -815,7 +815,6 @@
ndev->open = &islpci_open;
ndev->stop = &islpci_close;
ndev->get_stats = &islpci_statistics;
- ndev->get_wireless_stats = &prism54_get_wireless_stats;
ndev->do_ioctl = &prism54_ioctl;
ndev->wireless_handlers =
(struct iw_handler_def *) &prism54_handler_def;
@@ -844,6 +843,8 @@
/* Add pointers to enable iwspy support. */
priv->wireless_data.spy_data = &priv->spy_data;
ndev->wireless_data = &priv->wireless_data;
+#else /* WIRELESS_EXT > 16 */
+ ndev->get_wireless_stats = &prism54_get_wireless_stats;
#endif /* WIRELESS_EXT > 16 */
/* save the start and end address of the PCI memory area */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index c17391d..dc040ca 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -267,8 +267,6 @@
islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
BUG_ON(!priv);
- printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
- ndev->name, state);
pci_save_state(pdev);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 0e0ba61..e9c5ea0 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -53,6 +53,7 @@
#include <pcmcia/ds.h>
#include <pcmcia/mem_op.h>
+#include <net/ieee80211.h>
#include <linux/wireless.h>
#include <asm/io.h>
@@ -64,7 +65,6 @@
#define WIRELESS_SPY /* Enable spying addresses */
/* Definitions we need for spy */
typedef struct iw_statistics iw_stats;
-typedef struct iw_quality iw_qual;
typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */
#include "rayctl.h"
@@ -101,7 +101,6 @@
static int ray_dev_config(struct net_device *dev, struct ifmap *map);
static struct net_device_stats *ray_get_stats(struct net_device *dev);
static int ray_dev_init(struct net_device *dev);
-static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static struct ethtool_ops netdev_ethtool_ops;
@@ -114,9 +113,8 @@
static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type,
unsigned char *data);
static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
-#if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */
static iw_stats * ray_get_wireless_stats(struct net_device * dev);
-#endif /* WIRELESS_EXT > 7 */
+static const struct iw_handler_def ray_handler_def;
/***** Prototypes for raylink functions **************************************/
static int asc_to_int(char a);
@@ -373,11 +371,12 @@
dev->hard_start_xmit = &ray_dev_start_xmit;
dev->set_config = &ray_dev_config;
dev->get_stats = &ray_get_stats;
- dev->do_ioctl = &ray_dev_ioctl;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-#if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */
- dev->get_wireless_stats = ray_get_wireless_stats;
-#endif
+ dev->wireless_handlers = &ray_handler_def;
+#ifdef WIRELESS_SPY
+ local->wireless_data.spy_data = &local->spy_data;
+ dev->wireless_data = &local->wireless_data;
+#endif /* WIRELESS_SPY */
dev->set_multicast_list = &set_multicast_list;
@@ -1201,436 +1200,420 @@
/*====================================================================*/
-static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get protocol name
+ */
+static int ray_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ char *cwrq,
+ char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
- dev_link_t *link = local->finder;
- int err = 0;
-#if WIRELESS_EXT > 7
- struct iwreq *wrq = (struct iwreq *) ifr;
-#endif /* WIRELESS_EXT > 7 */
-#ifdef WIRELESS_SPY
- struct sockaddr address[IW_MAX_SPY];
-#endif /* WIRELESS_SPY */
+ strcpy(cwrq, "IEEE 802.11-FH");
+ return 0;
+}
- if (!(link->state & DEV_PRESENT)) {
- DEBUG(2,"ray_dev_ioctl - device not present\n");
- return -1;
- }
- DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd);
- /* Validate the command */
- switch (cmd)
- {
-#if WIRELESS_EXT > 7
- /* --------------- WIRELESS EXTENSIONS --------------- */
- /* Get name */
- case SIOCGIWNAME:
- strcpy(wrq->u.name, "IEEE 802.11-FH");
- break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set frequency
+ */
+static int ray_set_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *fwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+ int err = -EINPROGRESS; /* Call commit handler */
- /* Get frequency/channel */
- case SIOCGIWFREQ:
- wrq->u.freq.m = local->sparm.b5.a_hop_pattern;
- wrq->u.freq.e = 0;
- break;
+ /* Reject if card is already initialised */
+ if(local->card_status != CARD_AWAITING_PARAM)
+ return -EBUSY;
- /* Set frequency/channel */
- case SIOCSIWFREQ:
- /* Reject if card is already initialised */
- if(local->card_status != CARD_AWAITING_PARAM)
- {
- err = -EBUSY;
- break;
- }
-
- /* Setting by channel number */
- if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0))
- err = -EOPNOTSUPP;
- else
- local->sparm.b5.a_hop_pattern = wrq->u.freq.m;
- break;
-
- /* Get current network name (ESSID) */
- case SIOCGIWESSID:
- if (wrq->u.data.pointer)
- {
- char essid[IW_ESSID_MAX_SIZE + 1];
- /* Get the essid that was set */
- memcpy(essid, local->sparm.b5.a_current_ess_id,
- IW_ESSID_MAX_SIZE);
- essid[IW_ESSID_MAX_SIZE] = '\0';
-
- /* Push it out ! */
- wrq->u.data.length = strlen(essid) + 1;
- wrq->u.data.flags = 1; /* active */
- if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)))
- err = -EFAULT;
- }
- break;
-
- /* Set desired network name (ESSID) */
- case SIOCSIWESSID:
- /* Reject if card is already initialised */
- if(local->card_status != CARD_AWAITING_PARAM)
- {
- err = -EBUSY;
- break;
- }
-
- if (wrq->u.data.pointer)
- {
- char card_essid[IW_ESSID_MAX_SIZE + 1];
-
- /* Check if we asked for `any' */
- if(wrq->u.data.flags == 0)
- {
- /* Corey : can you do that ? */
+ /* Setting by channel number */
+ if ((fwrq->m > USA_HOP_MOD) || (fwrq->e > 0))
err = -EOPNOTSUPP;
- }
- else
- {
+ else
+ local->sparm.b5.a_hop_pattern = fwrq->m;
+
+ return err;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get frequency
+ */
+static int ray_get_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *fwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+ fwrq->m = local->sparm.b5.a_hop_pattern;
+ fwrq->e = 0;
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set ESSID
+ */
+static int ray_set_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+ /* Reject if card is already initialised */
+ if(local->card_status != CARD_AWAITING_PARAM)
+ return -EBUSY;
+
+ /* Check if we asked for `any' */
+ if(dwrq->flags == 0) {
+ /* Corey : can you do that ? */
+ return -EOPNOTSUPP;
+ } else {
/* Check the size of the string */
- if(wrq->u.data.length >
- IW_ESSID_MAX_SIZE + 1)
- {
- err = -E2BIG;
- break;
+ if(dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ return -E2BIG;
}
- if (copy_from_user(card_essid,
- wrq->u.data.pointer,
- wrq->u.data.length)) {
- err = -EFAULT;
- break;
- }
- card_essid[IW_ESSID_MAX_SIZE] = '\0';
/* Set the ESSID in the card */
- memcpy(local->sparm.b5.a_current_ess_id, card_essid,
- IW_ESSID_MAX_SIZE);
- }
+ memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
+ memcpy(local->sparm.b5.a_current_ess_id, extra, dwrq->length);
}
- break;
- /* Get current Access Point (BSSID in our case) */
- case SIOCGIWAP:
- memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN);
- wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
- break;
+ return -EINPROGRESS; /* Call commit handler */
+}
- /* Get the current bit-rate */
- case SIOCGIWRATE:
- if(local->net_default_tx_rate == 3)
- wrq->u.bitrate.value = 2000000; /* Hum... */
- else
- wrq->u.bitrate.value = local->net_default_tx_rate * 500000;
- wrq->u.bitrate.fixed = 0; /* We are in auto mode */
- break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get ESSID
+ */
+static int ray_get_essid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
- /* Set the desired bit-rate */
- case SIOCSIWRATE:
- /* Check if rate is in range */
- if((wrq->u.bitrate.value != 1000000) &&
- (wrq->u.bitrate.value != 2000000))
- {
- err = -EINVAL;
- break;
- }
- /* Hack for 1.5 Mb/s instead of 2 Mb/s */
- if((local->fw_ver == 0x55) && /* Please check */
- (wrq->u.bitrate.value == 2000000))
- local->net_default_tx_rate = 3;
- else
- local->net_default_tx_rate = wrq->u.bitrate.value/500000;
- break;
+ /* Get the essid that was set */
+ memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+ extra[IW_ESSID_MAX_SIZE] = '\0';
- /* Get the current RTS threshold */
- case SIOCGIWRTS:
- wrq->u.rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
- + local->sparm.b5.a_rts_threshold[1];
-#if WIRELESS_EXT > 8
- wrq->u.rts.disabled = (wrq->u.rts.value == 32767);
-#endif /* WIRELESS_EXT > 8 */
- wrq->u.rts.fixed = 1;
- break;
+ /* Push it out ! */
+ dwrq->length = strlen(extra) + 1;
+ dwrq->flags = 1; /* active */
- /* Set the desired RTS threshold */
- case SIOCSIWRTS:
- {
- int rthr = wrq->u.rts.value;
+ return 0;
+}
- /* Reject if card is already initialised */
- if(local->card_status != CARD_AWAITING_PARAM)
- {
- err = -EBUSY;
- break;
- }
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get AP address
+ */
+static int ray_get_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *awrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+ memcpy(awrq->sa_data, local->bss_id, ETH_ALEN);
+ awrq->sa_family = ARPHRD_ETHER;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Bit-Rate
+ */
+static int ray_set_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+ /* Reject if card is already initialised */
+ if(local->card_status != CARD_AWAITING_PARAM)
+ return -EBUSY;
+
+ /* Check if rate is in range */
+ if((vwrq->value != 1000000) && (vwrq->value != 2000000))
+ return -EINVAL;
+
+ /* Hack for 1.5 Mb/s instead of 2 Mb/s */
+ if((local->fw_ver == 0x55) && /* Please check */
+ (vwrq->value == 2000000))
+ local->net_default_tx_rate = 3;
+ else
+ local->net_default_tx_rate = vwrq->value/500000;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Bit-Rate
+ */
+static int ray_get_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+ if(local->net_default_tx_rate == 3)
+ vwrq->value = 2000000; /* Hum... */
+ else
+ vwrq->value = local->net_default_tx_rate * 500000;
+ vwrq->fixed = 0; /* We are in auto mode */
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set RTS threshold
+ */
+static int ray_set_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+ int rthr = vwrq->value;
+
+ /* Reject if card is already initialised */
+ if(local->card_status != CARD_AWAITING_PARAM)
+ return -EBUSY;
/* if(wrq->u.rts.fixed == 0) we should complain */
-#if WIRELESS_EXT > 8
- if(wrq->u.rts.disabled)
- rthr = 32767;
- else
-#endif /* WIRELESS_EXT > 8 */
- if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
- {
- err = -EINVAL;
- break;
- }
+ if(vwrq->disabled)
+ rthr = 32767;
+ else {
+ if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
+ return -EINVAL;
+ }
local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
- }
- break;
- /* Get the current fragmentation threshold */
- case SIOCGIWFRAG:
- wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
- + local->sparm.b5.a_frag_threshold[1];
-#if WIRELESS_EXT > 8
- wrq->u.frag.disabled = (wrq->u.frag.value == 32767);
-#endif /* WIRELESS_EXT > 8 */
- wrq->u.frag.fixed = 1;
- break;
+ return -EINPROGRESS; /* Call commit handler */
+}
- /* Set the desired fragmentation threshold */
- case SIOCSIWFRAG:
- {
- int fthr = wrq->u.frag.value;
- /* Reject if card is already initialised */
- if(local->card_status != CARD_AWAITING_PARAM)
- {
- err = -EBUSY;
- break;
- }
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get RTS threshold
+ */
+static int ray_get_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+ vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
+ + local->sparm.b5.a_rts_threshold[1];
+ vwrq->disabled = (vwrq->value == 32767);
+ vwrq->fixed = 1;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Fragmentation threshold
+ */
+static int ray_set_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+ int fthr = vwrq->value;
+
+ /* Reject if card is already initialised */
+ if(local->card_status != CARD_AWAITING_PARAM)
+ return -EBUSY;
/* if(wrq->u.frag.fixed == 0) should complain */
-#if WIRELESS_EXT > 8
- if(wrq->u.frag.disabled)
- fthr = 32767;
- else
-#endif /* WIRELESS_EXT > 8 */
- if((fthr < 256) || (fthr > 2347)) /* To check out ! */
- {
- err = -EINVAL;
- break;
- }
+ if(vwrq->disabled)
+ fthr = 32767;
+ else {
+ if((fthr < 256) || (fthr > 2347)) /* To check out ! */
+ return -EINVAL;
+ }
local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
- }
- break;
-#endif /* WIRELESS_EXT > 7 */
-#if WIRELESS_EXT > 8
+ return -EINPROGRESS; /* Call commit handler */
+}
- /* Get the current mode of operation */
- case SIOCGIWMODE:
- if(local->sparm.b5.a_network_type)
- wrq->u.mode = IW_MODE_INFRA;
- else
- wrq->u.mode = IW_MODE_ADHOC;
- break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Fragmentation threshold
+ */
+static int ray_get_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
- /* Set the current mode of operation */
- case SIOCSIWMODE:
- {
+ vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
+ + local->sparm.b5.a_frag_threshold[1];
+ vwrq->disabled = (vwrq->value == 32767);
+ vwrq->fixed = 1;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set Mode of Operation
+ */
+static int ray_set_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *uwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
+ int err = -EINPROGRESS; /* Call commit handler */
char card_mode = 1;
-
- /* Reject if card is already initialised */
- if(local->card_status != CARD_AWAITING_PARAM)
- {
- err = -EBUSY;
- break;
- }
- switch (wrq->u.mode)
+ /* Reject if card is already initialised */
+ if(local->card_status != CARD_AWAITING_PARAM)
+ return -EBUSY;
+
+ switch (*uwrq)
{
case IW_MODE_ADHOC:
- card_mode = 0;
- // Fall through
+ card_mode = 0;
+ // Fall through
case IW_MODE_INFRA:
- local->sparm.b5.a_network_type = card_mode;
- break;
+ local->sparm.b5.a_network_type = card_mode;
+ break;
default:
- err = -EINVAL;
+ err = -EINVAL;
}
- }
- break;
-#endif /* WIRELESS_EXT > 8 */
-#if WIRELESS_EXT > 7
- /* ------------------ IWSPY SUPPORT ------------------ */
- /* Define the range (variations) of above parameters */
- case SIOCGIWRANGE:
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- struct iw_range range;
- memset((char *) &range, 0, sizeof(struct iw_range));
+ return err;
+}
- /* Set the length (very important for backward compatibility) */
- wrq->u.data.length = sizeof(struct iw_range);
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get Mode of Operation
+ */
+static int ray_get_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *uwrq,
+ char *extra)
+{
+ ray_dev_t *local = (ray_dev_t *)dev->priv;
-#if WIRELESS_EXT > 10
- /* Set the Wireless Extension versions */
- range.we_version_compiled = WIRELESS_EXT;
- range.we_version_source = 9;
-#endif /* WIRELESS_EXT > 10 */
+ if(local->sparm.b5.a_network_type)
+ *uwrq = IW_MODE_INFRA;
+ else
+ *uwrq = IW_MODE_ADHOC;
- /* Set information in the range struct */
- range.throughput = 1.1 * 1000 * 1000; /* Put the right number here */
- range.num_channels = hop_pattern_length[(int)country];
- range.num_frequency = 0;
- range.max_qual.qual = 0;
- range.max_qual.level = 255; /* What's the correct value ? */
- range.max_qual.noise = 255; /* Idem */
- range.num_bitrates = 2;
- range.bitrate[0] = 1000000; /* 1 Mb/s */
- range.bitrate[1] = 2000000; /* 2 Mb/s */
+ return 0;
+}
- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, &range,
- sizeof(struct iw_range)))
- err = -EFAULT;
- }
- break;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get range info
+ */
+static int ray_get_range(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ struct iw_range *range = (struct iw_range *) extra;
-#ifdef WIRELESS_SPY
- /* Set addresses to spy */
- case SIOCSIWSPY:
- /* Check the number of addresses */
- if(wrq->u.data.length > IW_MAX_SPY)
- {
- err = -E2BIG;
- break;
- }
- local->spy_number = wrq->u.data.length;
+ memset((char *) range, 0, sizeof(struct iw_range));
- /* If there is some addresses to copy */
- if(local->spy_number > 0)
- {
- int i;
+ /* Set the length (very important for backward compatibility) */
+ dwrq->length = sizeof(struct iw_range);
- /* Copy addresses to the driver */
- if(copy_from_user(address, wrq->u.data.pointer,
- sizeof(struct sockaddr) * local->spy_number))
- {
- err = -EFAULT;
- break;
- }
+ /* Set the Wireless Extension versions */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 9;
- /* Copy addresses to the lp structure */
- for(i = 0; i < local->spy_number; i++)
- memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN);
+ /* Set information in the range struct */
+ range->throughput = 1.1 * 1000 * 1000; /* Put the right number here */
+ range->num_channels = hop_pattern_length[(int)country];
+ range->num_frequency = 0;
+ range->max_qual.qual = 0;
+ range->max_qual.level = 255; /* What's the correct value ? */
+ range->max_qual.noise = 255; /* Idem */
+ range->num_bitrates = 2;
+ range->bitrate[0] = 1000000; /* 1 Mb/s */
+ range->bitrate[1] = 2000000; /* 2 Mb/s */
+ return 0;
+}
- /* Reset structure... */
- memset(local->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : set framing mode
+ */
+static int ray_set_framing(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ translate = *(extra); /* Set framing mode */
-#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
- for(i = 0; i < local->spy_number; i++)
- printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
- local->spy_address[i][0],
- local->spy_address[i][1],
- local->spy_address[i][2],
- local->spy_address[i][3],
- local->spy_address[i][4],
- local->spy_address[i][5]);
-#endif /* DEBUG_IOCTL_INFO */
- }
- break;
+ return 0;
+}
- /* Get the spy list and spy stats */
- case SIOCGIWSPY:
- /* Set the number of addresses */
- wrq->u.data.length = local->spy_number;
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get framing mode
+ */
+static int ray_get_framing(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ *(extra) = translate;
- /* If the user want to have the addresses back... */
- if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
- {
- int i;
+ return 0;
+}
- /* Copy addresses from the lp structure */
- for(i = 0; i < local->spy_number; i++)
- {
- memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN);
- address[i].sa_family = ARPHRD_ETHER;
- }
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Private Handler : get country
+ */
+static int ray_get_country(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ *(extra) = country;
- /* Copy addresses to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, address,
- sizeof(struct sockaddr) * local->spy_number))
- {
- err = -EFAULT;
- break;
- }
+ return 0;
+}
- /* Copy stats to the user buffer (just after) */
- if(copy_to_user(wrq->u.data.pointer +
- (sizeof(struct sockaddr) * local->spy_number),
- local->spy_stat, sizeof(iw_qual) * local->spy_number))
- {
- err = -EFAULT;
- break;
- }
+/*------------------------------------------------------------------*/
+/*
+ * Commit handler : called after a bunch of SET operations
+ */
+static int ray_commit(struct net_device *dev,
+ struct iw_request_info *info, /* NULL */
+ void *zwrq, /* NULL */
+ char *extra) /* NULL */
+{
+ return 0;
+}
- /* Reset updated flags */
- for(i = 0; i < local->spy_number; i++)
- local->spy_stat[i].updated = 0x0;
- } /* if(pointer != NULL) */
-
- break;
-#endif /* WIRELESS_SPY */
-
- /* ------------------ PRIVATE IOCTL ------------------ */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
-#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */
-#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */
- case SIOCSIPFRAMING:
- if(!capable(CAP_NET_ADMIN)) /* For private IOCTLs, we need to check permissions */
- {
- err = -EPERM;
- break;
- }
- translate = *(wrq->u.name); /* Set framing mode */
- break;
- case SIOCGIPFRAMING:
- *(wrq->u.name) = translate;
- break;
- case SIOCGIPCOUNTRY:
- *(wrq->u.name) = country;
- break;
- case SIOCGIWPRIV:
- /* Export our "private" intercace */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- struct iw_priv_args priv[] =
- { /* cmd, set_args, get_args, name */
- { SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
- { SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
- { SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
- };
- /* Set the number of ioctl available */
- wrq->u.data.length = 3;
- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
- sizeof(priv)))
- err = -EFAULT;
- }
- break;
-#endif /* WIRELESS_EXT > 7 */
-
-
- default:
- DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd);
- err = -EOPNOTSUPP;
- }
- return err;
-} /* end ray_dev_ioctl */
-/*===========================================================================*/
-#if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */
+/*------------------------------------------------------------------*/
+/*
+ * Stats handler : return Wireless Stats
+ */
static iw_stats * ray_get_wireless_stats(struct net_device * dev)
{
ray_dev_t * local = (ray_dev_t *) dev->priv;
@@ -1642,13 +1625,13 @@
local->wstats.status = local->card_status;
#ifdef WIRELESS_SPY
- if((local->spy_number > 0) && (local->sparm.b5.a_network_type == 0))
+ if((local->spy_data.spy_number > 0) && (local->sparm.b5.a_network_type == 0))
{
/* Get it from the first node in spy list */
- local->wstats.qual.qual = local->spy_stat[0].qual;
- local->wstats.qual.level = local->spy_stat[0].level;
- local->wstats.qual.noise = local->spy_stat[0].noise;
- local->wstats.qual.updated = local->spy_stat[0].updated;
+ local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
+ local->wstats.qual.level = local->spy_data.spy_stat[0].level;
+ local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
+ local->wstats.qual.updated = local->spy_data.spy_stat[0].updated;
}
#endif /* WIRELESS_SPY */
@@ -1659,7 +1642,65 @@
return &local->wstats;
} /* end ray_get_wireless_stats */
-#endif /* WIRELESS_EXT > 7 */
+
+/*------------------------------------------------------------------*/
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const iw_handler ray_handler[] = {
+ [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) ray_commit,
+ [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) ray_get_name,
+ [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) ray_set_freq,
+ [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) ray_get_freq,
+ [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) ray_set_mode,
+ [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) ray_get_mode,
+ [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) ray_get_range,
+#ifdef WIRELESS_SPY
+ [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_set_spy,
+ [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_get_spy,
+ [SIOCSIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_set_thrspy,
+ [SIOCGIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_get_thrspy,
+#endif /* WIRELESS_SPY */
+ [SIOCGIWAP -SIOCIWFIRST] (iw_handler) ray_get_wap,
+ [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) ray_set_essid,
+ [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) ray_get_essid,
+ [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) ray_set_rate,
+ [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) ray_get_rate,
+ [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) ray_set_rts,
+ [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) ray_get_rts,
+ [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) ray_set_frag,
+ [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) ray_get_frag,
+};
+
+#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
+#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */
+#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */
+
+static const iw_handler ray_private_handler[] = {
+ [0] (iw_handler) ray_set_framing,
+ [1] (iw_handler) ray_get_framing,
+ [3] (iw_handler) ray_get_country,
+};
+
+static const struct iw_priv_args ray_private_args[] = {
+/* cmd, set_args, get_args, name */
+{ SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
+{ SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
+{ SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
+};
+
+static const struct iw_handler_def ray_handler_def =
+{
+ .num_standard = sizeof(ray_handler)/sizeof(iw_handler),
+ .num_private = sizeof(ray_private_handler)/sizeof(iw_handler),
+ .num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args),
+ .standard = ray_handler,
+ .private = ray_private_handler,
+ .private_args = ray_private_args,
+ .get_wireless_stats = ray_get_wireless_stats,
+};
+
/*===========================================================================*/
static int ray_open(struct net_device *dev)
{
@@ -2392,20 +2433,15 @@
/*local->wstats.qual.noise = none ? */
local->wstats.qual.updated = 0x2;
}
- /* Now, for the addresses in the spy list */
+ /* Now, update the spy stuff */
{
- int i;
- /* Look all addresses */
- for(i = 0; i < local->spy_number; i++)
- /* If match */
- if(!memcmp(linksrcaddr, local->spy_address[i], ETH_ALEN))
- {
- /* Update statistics */
- /*local->spy_stat[i].qual = none ? */
- local->spy_stat[i].level = siglev;
- /*local->spy_stat[i].noise = none ? */
- local->spy_stat[i].updated = 0x2;
- }
+ struct iw_quality wstats;
+ wstats.level = siglev;
+ /* wstats.noise = none ? */
+ /* wstats.qual = none ? */
+ wstats.updated = 0x2;
+ /* Update spy records */
+ wireless_spy_update(dev, linksrcaddr, &wstats);
}
#endif /* WIRELESS_SPY */
} /* end rx_data */
diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h
index c77afa1..42660fe 100644
--- a/drivers/net/wireless/ray_cs.h
+++ b/drivers/net/wireless/ray_cs.h
@@ -63,13 +63,10 @@
UCHAR last_rsl;
int beacon_rxed;
struct beacon_rx last_bcn;
-#ifdef WIRELESS_EXT
iw_stats wstats; /* Wireless specific stats */
-#endif
#ifdef WIRELESS_SPY
- int spy_number; /* Number of addresses to spy */
- mac_addr spy_address[IW_MAX_SPY + 1]; /* The addresses to spy */
- iw_qual spy_stat[IW_MAX_SPY + 1]; /* Statistics gathered */
+ struct iw_spy_data spy_data;
+ struct iw_public_data wireless_data;
#endif /* WIRELESS_SPY */
} ray_dev_t;
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
new file mode 100644
index 0000000..39c6cdf
--- /dev/null
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -0,0 +1,1120 @@
+/*
+ * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
+ * Symbol Wireless Networker LA4100, CompactFlash cards by Socket
+ * Communications and Intel PRO/Wireless 2011B.
+ *
+ * The driver implements Symbol firmware download. The rest is handled
+ * in hermes.c and orinoco.c.
+ *
+ * Utilities for downloading the Symbol firmware are available at
+ * http://sourceforge.net/projects/orinoco/
+ *
+ * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
+ * Portions based on orinoco_cs.c:
+ * Copyright (C) David Gibson, Linuxcare Australia
+ * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
+ * Copyright (C) Symbol Technologies.
+ *
+ * See copyright notice in file orinoco.c.
+ */
+
+#define DRIVER_NAME "spectrum_cs"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/config.h>
+#ifdef __IN_PCMCIA_PACKAGE__
+#include <pcmcia/k_compat.h>
+#endif /* __IN_PCMCIA_PACKAGE__ */
+
+#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>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "orinoco.h"
+
+/*
+ * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into
+ * the driver. Use get_symbol_fw script to generate spectrum_fw.h and
+ * copy it to the same directory as spectrum_cs.c.
+ *
+ * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the
+ * runtime using hotplug. Use the same get_symbol_fw script to generate
+ * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the
+ * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and
+ * make sure that you have hotplug installed and enabled in the kernel.
+ */
+/* #define SPECTRUM_FW_INCLUDED 1 */
+
+#ifdef SPECTRUM_FW_INCLUDED
+/* Header with the firmware */
+#include "spectrum_fw.h"
+#else /* !SPECTRUM_FW_INCLUDED */
+#include <linux/firmware.h>
+static unsigned char *primsym;
+static unsigned char *secsym;
+static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
+static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
+#endif /* !SPECTRUM_FW_INCLUDED */
+
+/********************************************************************/
+/* Module stuff */
+/********************************************************************/
+
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
+MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Module parameters */
+
+/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+static int ignore_cis_vcc; /* = 0 */
+module_param(ignore_cis_vcc, int, 0);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
+
+/********************************************************************/
+/* Magic constants */
+/********************************************************************/
+
+/*
+ * The dev_info variable is the "key" that is used to match up this
+ * device driver with appropriate cards, through the card
+ * configuration database.
+ */
+static dev_info_t dev_info = DRIVER_NAME;
+
+/********************************************************************/
+/* Data structures */
+/********************************************************************/
+
+/* PCMCIA specific device information (goes in the card field of
+ * struct orinoco_private */
+struct orinoco_pccard {
+ dev_link_t link;
+ dev_node_t node;
+};
+
+/*
+ * A linked list of "instances" of the device. Each actual PCMCIA
+ * card corresponds to one device instance, and is described by one
+ * dev_link_t structure (defined in ds.h).
+ */
+static dev_link_t *dev_list; /* = NULL */
+
+/********************************************************************/
+/* Function prototypes */
+/********************************************************************/
+
+/* device methods */
+static int spectrum_cs_hard_reset(struct orinoco_private *priv);
+
+/* PCMCIA gumpf */
+static void spectrum_cs_config(dev_link_t * link);
+static void spectrum_cs_release(dev_link_t * link);
+static int spectrum_cs_event(event_t event, int priority,
+ event_callback_args_t * args);
+
+static dev_link_t *spectrum_cs_attach(void);
+static void spectrum_cs_detach(dev_link_t *);
+
+/********************************************************************/
+/* Firmware downloader */
+/********************************************************************/
+
+/* Position of PDA in the adapter memory */
+#define EEPROM_ADDR 0x3000
+#define EEPROM_LEN 0x200
+#define PDA_OFFSET 0x100
+
+#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET)
+#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2)
+
+/* Constants for the CISREG_CCSR register */
+#define HCR_RUN 0x07 /* run firmware after reset */
+#define HCR_IDLE 0x0E /* don't run firmware after reset */
+#define HCR_MEM16 0x10 /* memory width bit, should be preserved */
+
+/*
+ * AUX port access. To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register. Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* End markers */
+#define PDI_END 0x00000000 /* End of PDA */
+#define BLOCK_END 0xFFFFFFFF /* Last image block */
+#define TEXT_END 0x1A /* End of text header */
+
+/*
+ * The following structures have little-endian fields denoted by
+ * the leading underscore. Don't access them directly - use inline
+ * functions defined below.
+ */
+
+/*
+ * The binary image to be downloaded consists of series of data blocks.
+ * Each block has the following structure.
+ */
+struct dblock {
+ u32 _addr; /* adapter address where to write the block */
+ u16 _len; /* length of the data only, in bytes */
+ char data[0]; /* data to be written */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data References are located in in the image after the last data
+ * block. They refer to areas in the adapter memory where the plug data
+ * items with matching ID should be written.
+ */
+struct pdr {
+ u32 _id; /* record ID */
+ u32 _addr; /* adapter address where to write the data */
+ u32 _len; /* expected length of the data, in bytes */
+ char next[0]; /* next PDR starts here */
+} __attribute__ ((packed));
+
+
+/*
+ * Plug Data Items are located in the EEPROM read from the adapter by
+ * primary firmware. They refer to the device-specific data that should
+ * be plugged into the secondary firmware.
+ */
+struct pdi {
+ u16 _len; /* length of ID and data, in words */
+ u16 _id; /* record ID */
+ char data[0]; /* plug data */
+} __attribute__ ((packed));;
+
+
+/* Functions for access to little-endian data */
+static inline u32
+dblock_addr(const struct dblock *blk)
+{
+ return le32_to_cpu(blk->_addr);
+}
+
+static inline u32
+dblock_len(const struct dblock *blk)
+{
+ return le16_to_cpu(blk->_len);
+}
+
+static inline u32
+pdr_id(const struct pdr *pdr)
+{
+ return le32_to_cpu(pdr->_id);
+}
+
+static inline u32
+pdr_addr(const struct pdr *pdr)
+{
+ return le32_to_cpu(pdr->_addr);
+}
+
+static inline u32
+pdr_len(const struct pdr *pdr)
+{
+ return le32_to_cpu(pdr->_len);
+}
+
+static inline u32
+pdi_id(const struct pdi *pdi)
+{
+ return le16_to_cpu(pdi->_id);
+}
+
+/* Return length of the data only, in bytes */
+static inline u32
+pdi_len(const struct pdi *pdi)
+{
+ return 2 * (le16_to_cpu(pdi->_len) - 1);
+}
+
+
+/* Set address of the auxiliary port */
+static inline void
+spectrum_aux_setaddr(hermes_t *hw, u32 addr)
+{
+ hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+ hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+
+/* Open access to the auxiliary port */
+static int
+spectrum_aux_open(hermes_t *hw)
+{
+ int i;
+
+ /* Already open? */
+ if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
+ return 0;
+
+ hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+ hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+ hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+ hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
+
+ for (i = 0; i < 20; i++) {
+ udelay(10);
+ if (hermes_read_reg(hw, HERMES_CONTROL) ==
+ HERMES_AUX_ENABLED)
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+
+#define CS_CHECK(fn, ret) \
+ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+/*
+ * Reset the card using configuration registers COR and CCSR.
+ * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
+ */
+static int
+spectrum_reset(dev_link_t *link, int idle)
+{
+ int last_ret, last_fn;
+ conf_reg_t reg;
+ u_int save_cor;
+
+ /* Doing it if hardware is gone is guaranteed crash */
+ if (!(link->state & DEV_CONFIG))
+ return -ENODEV;
+
+ /* Save original COR value */
+ reg.Function = 0;
+ reg.Action = CS_READ;
+ reg.Offset = CISREG_COR;
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ save_cor = reg.Value;
+
+ /* Soft-Reset card */
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ reg.Value = (save_cor | COR_SOFT_RESET);
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ udelay(1000);
+
+ /* Read CCSR */
+ reg.Action = CS_READ;
+ reg.Offset = CISREG_CCSR;
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+
+ /*
+ * Start or stop the firmware. Memory width bit should be
+ * preserved from the value we've just read.
+ */
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_CCSR;
+ reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ udelay(1000);
+
+ /* Restore original COR configuration index */
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ reg.Value = (save_cor & ~COR_SOFT_RESET);
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ udelay(1000);
+ return 0;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ return -ENODEV;
+}
+
+
+/*
+ * Scan PDR for the record with the specified RECORD_ID.
+ * If it's not found, return NULL.
+ */
+static struct pdr *
+spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
+{
+ struct pdr *pdr = first_pdr;
+
+ while (pdr_id(pdr) != PDI_END) {
+ /*
+ * PDR area is currently not terminated by PDI_END.
+ * It's followed by CRC records, which have the type
+ * field where PDR has length. The type can be 0 or 1.
+ */
+ if (pdr_len(pdr) < 2)
+ return NULL;
+
+ /* If the record ID matches, we are done */
+ if (pdr_id(pdr) == record_id)
+ return pdr;
+
+ pdr = (struct pdr *) pdr->next;
+ }
+ return NULL;
+}
+
+
+/* Process one Plug Data Item - find corresponding PDR and plug it */
+static int
+spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
+{
+ struct pdr *pdr;
+
+ /* Find the PDI corresponding to this PDR */
+ pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
+
+ /* No match is found, safe to ignore */
+ if (!pdr)
+ return 0;
+
+ /* Lengths of the data in PDI and PDR must match */
+ if (pdi_len(pdi) != pdr_len(pdr))
+ return -EINVAL;
+
+ /* do the actual plugging */
+ spectrum_aux_setaddr(hw, pdr_addr(pdr));
+ hermes_write_words(hw, HERMES_AUXDATA, pdi->data,
+ pdi_len(pdi) / 2);
+
+ return 0;
+}
+
+
+/* Read PDA from the adapter */
+static int
+spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len)
+{
+ int ret;
+ int pda_size;
+
+ /* Issue command to read EEPROM */
+ ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+ if (ret)
+ return ret;
+
+ /* Open auxiliary port */
+ ret = spectrum_aux_open(hw);
+ if (ret)
+ return ret;
+
+ /* read PDA from EEPROM */
+ spectrum_aux_setaddr(hw, PDA_ADDR);
+ hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
+
+ /* Check PDA length */
+ pda_size = le16_to_cpu(pda[0]);
+ if (pda_size > pda_len)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+/* Parse PDA and write the records into the adapter */
+static int
+spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
+ u16 *pda)
+{
+ int ret;
+ struct pdi *pdi;
+ struct pdr *first_pdr;
+ const struct dblock *blk = first_block;
+
+ /* Skip all blocks to locate Plug Data References */
+ while (dblock_addr(blk) != BLOCK_END)
+ blk = (struct dblock *) &blk->data[dblock_len(blk)];
+
+ first_pdr = (struct pdr *) blk;
+
+ /* Go through every PDI and plug them into the adapter */
+ pdi = (struct pdi *) (pda + 2);
+ while (pdi_id(pdi) != PDI_END) {
+ ret = spectrum_plug_pdi(hw, first_pdr, pdi);
+ if (ret)
+ return ret;
+
+ /* Increment to the next PDI */
+ pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
+ }
+ return 0;
+}
+
+
+/* Load firmware blocks into the adapter */
+static int
+spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
+{
+ const struct dblock *blk;
+ u32 blkaddr;
+ u32 blklen;
+
+ blk = first_block;
+ blkaddr = dblock_addr(blk);
+ blklen = dblock_len(blk);
+
+ while (dblock_addr(blk) != BLOCK_END) {
+ spectrum_aux_setaddr(hw, blkaddr);
+ hermes_write_words(hw, HERMES_AUXDATA, blk->data,
+ blklen / 2);
+
+ blk = (struct dblock *) &blk->data[blklen];
+ blkaddr = dblock_addr(blk);
+ blklen = dblock_len(blk);
+ }
+ return 0;
+}
+
+
+/*
+ * Process a firmware image - stop the card, load the firmware, reset
+ * the card and make sure it responds. For the secondary firmware take
+ * care of the PDA - read it and then write it on top of the firmware.
+ */
+static int
+spectrum_dl_image(hermes_t *hw, dev_link_t *link,
+ const unsigned char *image)
+{
+ int ret;
+ const unsigned char *ptr;
+ const struct dblock *first_block;
+
+ /* Plug Data Area (PDA) */
+ u16 pda[PDA_WORDS];
+
+ /* Binary block begins after the 0x1A marker */
+ ptr = image;
+ while (*ptr++ != TEXT_END);
+ first_block = (const struct dblock *) ptr;
+
+ /* Read the PDA */
+ if (image != primsym) {
+ ret = spectrum_read_pda(hw, pda, sizeof(pda));
+ if (ret)
+ return ret;
+ }
+
+ /* Stop the firmware, so that it can be safely rewritten */
+ ret = spectrum_reset(link, 1);
+ if (ret)
+ return ret;
+
+ /* Program the adapter with new firmware */
+ ret = spectrum_load_blocks(hw, first_block);
+ if (ret)
+ return ret;
+
+ /* Write the PDA to the adapter */
+ if (image != primsym) {
+ ret = spectrum_apply_pda(hw, first_block, pda);
+ if (ret)
+ return ret;
+ }
+
+ /* Run the firmware */
+ ret = spectrum_reset(link, 0);
+ if (ret)
+ return ret;
+
+ /* Reset hermes chip and make sure it responds */
+ ret = hermes_init(hw);
+
+ /* hermes_reset() should return 0 with the secondary firmware */
+ if (image != primsym && ret != 0)
+ return -ENODEV;
+
+ /* And this should work with any firmware */
+ if (!hermes_present(hw))
+ return -ENODEV;
+
+ return 0;
+}
+
+
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+spectrum_dl_firmware(hermes_t *hw, dev_link_t *link)
+{
+ int ret;
+ client_handle_t handle = link->handle;
+
+#ifndef SPECTRUM_FW_INCLUDED
+ const struct firmware *fw_entry;
+
+ if (request_firmware(&fw_entry, primary_fw_name,
+ &handle_to_dev(handle)) == 0) {
+ primsym = fw_entry->data;
+ } else {
+ printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+ primary_fw_name);
+ return -ENOENT;
+ }
+
+ if (request_firmware(&fw_entry, secondary_fw_name,
+ &handle_to_dev(handle)) == 0) {
+ secsym = fw_entry->data;
+ } else {
+ printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+ secondary_fw_name);
+ return -ENOENT;
+ }
+#endif
+
+ /* Load primary firmware */
+ ret = spectrum_dl_image(hw, link, primsym);
+ if (ret) {
+ printk(KERN_ERR PFX "Primary firmware download failed\n");
+ return ret;
+ }
+
+ /* Load secondary firmware */
+ ret = spectrum_dl_image(hw, link, secsym);
+
+ if (ret) {
+ printk(KERN_ERR PFX "Secondary firmware download failed\n");
+ }
+
+ return ret;
+}
+
+/********************************************************************/
+/* Device methods */
+/********************************************************************/
+
+static int
+spectrum_cs_hard_reset(struct orinoco_private *priv)
+{
+ struct orinoco_pccard *card = priv->card;
+ dev_link_t *link = &card->link;
+ int err;
+
+ if (!hermes_present(&priv->hw)) {
+ /* The firmware needs to be reloaded */
+ if (spectrum_dl_firmware(&priv->hw, &card->link) != 0) {
+ printk(KERN_ERR PFX "Firmware download failed\n");
+ err = -ENODEV;
+ }
+ } else {
+ /* Soft reset using COR and HCR */
+ spectrum_reset(link, 0);
+ }
+
+ return 0;
+}
+
+/********************************************************************/
+/* PCMCIA stuff */
+/********************************************************************/
+
+/*
+ * This creates an "instance" of the driver, allocating local data
+ * structures for one device. The device is registered with Card
+ * Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a card
+ * insertion event. */
+static dev_link_t *
+spectrum_cs_attach(void)
+{
+ struct net_device *dev;
+ struct orinoco_private *priv;
+ struct orinoco_pccard *card;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret;
+
+ dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
+ if (! dev)
+ return NULL;
+ priv = netdev_priv(dev);
+ card = priv->card;
+
+ /* Link both structures together */
+ link = &card->link;
+ link->priv = dev;
+
+ /* Interrupt setup */
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Handler = orinoco_interrupt;
+ link->irq.Instance = dev;
+
+ /* General socket configuration defaults can go here. In this
+ * client, we assume very little, and rely on the CIS for
+ * almost everything. In most clients, many details (i.e.,
+ * number, sizes, and attributes of IO windows) are fixed by
+ * the nature of the device, and can be hard-wired here. */
+ link->conf.Attributes = 0;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Register with Card Services */
+ /* FIXME: need a lock? */
+ link->next = dev_list;
+ dev_list = link;
+
+ client_reg.dev_info = &dev_info;
+ client_reg.Version = 0x0210; /* FIXME: what does this mean? */
+ client_reg.event_callback_args.client_data = link;
+
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ spectrum_cs_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* spectrum_cs_attach */
+
+/*
+ * This deletes a driver "instance". The device is de-registered with
+ * Card Services. If it has been released, all local data structures
+ * are freed. Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void spectrum_cs_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+ struct net_device *dev = link->priv;
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link)
+ break;
+
+ BUG_ON(*linkp == NULL);
+
+ if (link->state & DEV_CONFIG)
+ spectrum_cs_release(link);
+
+ /* Break the link with Card Services */
+ if (link->handle)
+ pcmcia_deregister_client(link->handle);
+
+ /* Unlink device structure, and free it */
+ *linkp = link->next;
+ DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev);
+ if (link->dev) {
+ DEBUG(0, PFX "About to unregister net device %p\n",
+ dev);
+ unregister_netdev(dev);
+ }
+ free_orinocodev(dev);
+} /* spectrum_cs_detach */
+
+/*
+ * spectrum_cs_config() is scheduled to run after a CARD_INSERTION
+ * event is received, to configure the PCMCIA socket, and to make the
+ * device available to the system.
+ */
+
+static void
+spectrum_cs_config(dev_link_t *link)
+{
+ struct net_device *dev = link->priv;
+ client_handle_t handle = link->handle;
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_pccard *card = priv->card;
+ hermes_t *hw = &priv->hw;
+ int last_fn, last_ret;
+ u_char buf[64];
+ config_info_t conf;
+ cisinfo_t info;
+ tuple_t tuple;
+ cisparse_t parse;
+ void __iomem *mem;
+
+ CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info));
+
+ /*
+ * This reads the card's CONFIG tuple to find its
+ * configuration registers.
+ */
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ /* Look up the current Vcc */
+ CS_CHECK(GetConfigurationInfo,
+ pcmcia_get_configuration_info(handle, &conf));
+ link->conf.Vcc = conf.Vcc;
+
+ /*
+ * In this loop, we scan the CIS for configuration table
+ * entries, each of which describes a valid card
+ * configuration, including voltage, IO window, memory window,
+ * and interrupt settings.
+ *
+ * We make no assumptions about the card to be configured: we
+ * use just the information available in the CIS. In an ideal
+ * world, this would work for any PCMCIA card, but it requires
+ * a complete and accurate CIS. In practice, a driver usually
+ * "knows" most of these things without consulting the CIS,
+ * and most client drivers will only use the CIS to fill in
+ * implementation-defined details.
+ */
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ while (1) {
+ cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+ cistpl_cftable_entry_t dflt = { .index = 0 };
+
+ if ( (pcmcia_get_tuple_data(handle, &tuple) != 0)
+ || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0))
+ goto next_entry;
+
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ dflt = *cfg;
+ if (cfg->index == 0)
+ goto next_entry;
+ link->conf.ConfigIndex = cfg->index;
+
+ /* Does this card need audio output? */
+ if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+ link->conf.Attributes |= CONF_ENABLE_SPKR;
+ link->conf.Status = CCSR_AUDIO_ENA;
+ }
+
+ /* Use power settings for Vcc and Vpp if present */
+ /* Note that the CIS values need to be rescaled */
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+ DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+ if (!ignore_cis_vcc)
+ goto next_entry;
+ }
+ } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
+ DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+ if(!ignore_cis_vcc)
+ goto next_entry;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ /* Do we need to allocate an interrupt? */
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+ /* IO window settings */
+ link->io.NumPorts1 = link->io.NumPorts2 = 0;
+ if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+ cistpl_io_t *io =
+ (cfg->io.nwin) ? &cfg->io : &dflt.io;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(io->flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 =
+ IO_DATA_PATH_WIDTH_16;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 =
+ IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines =
+ io->flags & CISTPL_IO_LINES_MASK;
+ link->io.BasePort1 = io->win[0].base;
+ link->io.NumPorts1 = io->win[0].len;
+ if (io->nwin > 1) {
+ link->io.Attributes2 =
+ link->io.Attributes1;
+ link->io.BasePort2 = io->win[1].base;
+ link->io.NumPorts2 = io->win[1].len;
+ }
+
+ /* This reserves IO space but doesn't actually enable it */
+ if (pcmcia_request_io(link->handle, &link->io) != 0)
+ goto next_entry;
+ }
+
+
+ /* If we got this far, we're cool! */
+
+ break;
+
+ next_entry:
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ last_ret = pcmcia_get_next_tuple(handle, &tuple);
+ if (last_ret == CS_NO_MORE_ITEMS) {
+ printk(KERN_ERR PFX "GetNextTuple(): No matching "
+ "CIS configuration. Maybe you need the "
+ "ignore_cis_vcc=1 parameter.\n");
+ goto cs_failed;
+ }
+ }
+
+ /*
+ * Allocate an interrupt line. Note that this does not assign
+ * a handler to the interrupt, unless the 'Handler' member of
+ * the irq structure is initialized.
+ */
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+
+ /* We initialize the hermes structure before completing PCMCIA
+ * configuration just in case the interrupt handler gets
+ * called. */
+ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+ if (!mem)
+ goto cs_failed;
+
+ hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+
+ /*
+ * This actually configures the PCMCIA socket -- setting up
+ * the I/O windows and the interrupt mapping, and putting the
+ * card and host interface into "Memory and IO" mode.
+ */
+ CS_CHECK(RequestConfiguration,
+ pcmcia_request_configuration(link->handle, &link->conf));
+
+ /* Ok, we have the configuration, prepare to register the netdev */
+ dev->base_addr = link->io.BasePort1;
+ dev->irq = link->irq.AssignedIRQ;
+ SET_MODULE_OWNER(dev);
+ card->node.major = card->node.minor = 0;
+
+ /* Reset card and download firmware */
+ if (spectrum_cs_hard_reset(priv) != 0) {
+ goto failed;
+ }
+
+ SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+ /* Tell the stack we exist */
+ if (register_netdev(dev) != 0) {
+ printk(KERN_ERR PFX "register_netdev() failed\n");
+ goto failed;
+ }
+
+ /* At this point, the dev_node_t structure(s) needs to be
+ * initialized and arranged in a linked list at link->dev. */
+ strcpy(card->node.dev_name, dev->name);
+ link->dev = &card->node; /* link->dev being non-NULL is also
+ used to indicate that the
+ net_device has been registered */
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ /* Finally, report what we've done */
+ printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
+ dev->name, link->conf.ConfigIndex,
+ link->conf.Vcc / 10, link->conf.Vcc % 10);
+ if (link->conf.Vpp1)
+ printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+ link->conf.Vpp1 % 10);
+ printk(", irq %d", link->irq.AssignedIRQ);
+ if (link->io.NumPorts1)
+ printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ link->io.BasePort1 + link->io.NumPorts1 - 1);
+ if (link->io.NumPorts2)
+ printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ link->io.BasePort2 + link->io.NumPorts2 - 1);
+ printk("\n");
+
+ return;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+
+ failed:
+ spectrum_cs_release(link);
+} /* spectrum_cs_config */
+
+/*
+ * After a card is removed, spectrum_cs_release() will unregister the
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+spectrum_cs_release(dev_link_t *link)
+{
+ struct net_device *dev = link->priv;
+ struct orinoco_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ /* We're committed to taking the device away now, so mark the
+ * hardware as unavailable */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Don't bother checking to see if these succeed or not */
+ pcmcia_release_configuration(link->handle);
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ if (link->irq.AssignedIRQ)
+ pcmcia_release_irq(link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+ if (priv->hw.iobase)
+ ioport_unmap(priv->hw.iobase);
+} /* spectrum_cs_release */
+
+/*
+ * The card status event handler. Mostly, this schedules other stuff
+ * to run after an event is received.
+ */
+static int
+spectrum_cs_event(event_t event, int priority,
+ event_callback_args_t * args)
+{
+ dev_link_t *link = args->client_data;
+ struct net_device *dev = link->priv;
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = 0;
+ unsigned long flags;
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ break;
+
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ spectrum_cs_config(link);
+ break;
+
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ /* Mark the device as stopped, to block IO until later */
+ if (link->state & DEV_CONFIG) {
+ /* This is probably racy, but I can't think of
+ a better way, short of rewriting the PCMCIA
+ layer to not suck :-( */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ err = __orinoco_down(dev);
+ if (err)
+ printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
+ dev->name,
+ event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
+ err);
+
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ pcmcia_release_configuration(link->handle);
+ }
+ break;
+
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ /* FIXME: should we double check that this is
+ * the same card as we had before */
+ pcmcia_request_configuration(link->handle, &link->conf);
+ netif_device_attach(dev);
+ priv->hw_unavailable--;
+ schedule_work(&priv->reset_work);
+ }
+ break;
+ }
+
+ return err;
+} /* spectrum_cs_event */
+
+/********************************************************************/
+/* Module initialization */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+ " (Pavel Roskin <proski@gnu.org>,"
+ " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
+
+static struct pcmcia_device_id spectrum_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */
+ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
+ PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
+
+static struct pcmcia_driver orinoco_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRIVER_NAME,
+ },
+ .attach = spectrum_cs_attach,
+ .event = spectrum_cs_event,
+ .detach = spectrum_cs_detach,
+ .id_table = spectrum_cs_ids,
+};
+
+static int __init
+init_spectrum_cs(void)
+{
+ printk(KERN_DEBUG "%s\n", version);
+
+ return pcmcia_register_driver(&orinoco_driver);
+}
+
+static void __exit
+exit_spectrum_cs(void)
+{
+ pcmcia_unregister_driver(&orinoco_driver);
+ BUG_ON(dev_list != NULL);
+}
+
+module_init(init_spectrum_cs);
+module_exit(exit_spectrum_cs);
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 6c42b57..4b0acae 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -209,7 +209,7 @@
NoStructure = 0, /* Really old firmware */
StructuredMessages = 1, /* Parsable AT response msgs */
ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */
-} FirmwareLevel;
+};
struct strip {
int magic;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index f6130a5..183c473 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -59,6 +59,12 @@
/* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */
#include "wavelan_cs.p.h" /* Private header */
+#ifdef WAVELAN_ROAMING
+static void wl_cell_expiry(unsigned long data);
+static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp);
+static void wv_nwid_filter(unsigned char mode, net_local *lp);
+#endif /* WAVELAN_ROAMING */
+
/************************* MISC SUBROUTINES **************************/
/*
* Subroutines which won't fit in one of the following category
@@ -500,9 +506,9 @@
#ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */
-unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
+static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00};
-void wv_roam_init(struct net_device *dev)
+static void wv_roam_init(struct net_device *dev)
{
net_local *lp= netdev_priv(dev);
@@ -531,7 +537,7 @@
printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name);
}
-void wv_roam_cleanup(struct net_device *dev)
+static void wv_roam_cleanup(struct net_device *dev)
{
wavepoint_history *ptr,*old_ptr;
net_local *lp= netdev_priv(dev);
@@ -550,7 +556,7 @@
}
/* Enable/Disable NWID promiscuous mode on a given device */
-void wv_nwid_filter(unsigned char mode, net_local *lp)
+static void wv_nwid_filter(unsigned char mode, net_local *lp)
{
mm_t m;
unsigned long flags;
@@ -575,7 +581,7 @@
}
/* Find a record in the WavePoint table matching a given NWID */
-wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
+static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
{
wavepoint_history *ptr=lp->wavepoint_table.head;
@@ -588,7 +594,7 @@
}
/* Create a new wavepoint table entry */
-wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
+static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
{
wavepoint_history *new_wavepoint;
@@ -624,7 +630,7 @@
}
/* Remove a wavepoint entry from WavePoint table */
-void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
+static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
{
if(wavepoint==NULL)
return;
@@ -646,7 +652,7 @@
}
/* Timer callback function - checks WavePoint table for stale entries */
-void wl_cell_expiry(unsigned long data)
+static void wl_cell_expiry(unsigned long data)
{
net_local *lp=(net_local *)data;
wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point;
@@ -686,7 +692,7 @@
}
/* Update SNR history of a wavepoint */
-void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)
+static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)
{
int i=0,num_missed=0,ptr=0;
int average_fast=0,average_slow=0;
@@ -723,7 +729,7 @@
}
/* Perform a handover to a new WavePoint */
-void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
+static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
{
kio_addr_t base = lp->dev->base_addr;
mm_t m;
diff --git a/drivers/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h
index 29cff6d..fabc63e 100644
--- a/drivers/net/wireless/wavelan_cs.h
+++ b/drivers/net/wireless/wavelan_cs.h
@@ -62,7 +62,7 @@
* like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this
* part to accommodate your hardware...
*/
-const unsigned char MAC_ADDRESSES[][3] =
+static const unsigned char MAC_ADDRESSES[][3] =
{
{ 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */
{ 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */
@@ -79,14 +79,14 @@
* (as read in the offset register of the dac area).
* Used to map channel numbers used by `wfreqsel' to frequencies
*/
-const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
+static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
0xD0, 0xF0, 0xF8, 0x150 };
/* Frequencies of the 1.0 modem (fixed frequencies).
* Use to map the PSA `subband' to a frequency
* Note : all frequencies apart from the first one need to be multiplied by 10
*/
-const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
/*************************** PC INTERFACE ****************************/
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 677ff71..01d882b 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -647,23 +647,6 @@
void __iomem *mem;
};
-/**************************** PROTOTYPES ****************************/
-
-#ifdef WAVELAN_ROAMING
-/* ---------------------- ROAMING SUBROUTINES -----------------------*/
-
-wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp);
-wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp);
-void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp);
-void wl_cell_expiry(unsigned long data);
-wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp);
-void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq);
-void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp);
-void wv_nwid_filter(unsigned char mode, net_local *lp);
-void wv_roam_init(struct net_device *dev);
-void wv_roam_cleanup(struct net_device *dev);
-#endif /* WAVELAN_ROAMING */
-
/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
static inline u_char /* data */
hasr_read(u_long); /* Read the host interface : base address */
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 8636d93..7fcbe58 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -2,7 +2,7 @@
#define __WL3501_H__
#include <linux/spinlock.h>
-#include "ieee802_11.h"
+#include <net/ieee80211.h>
/* define for WLA 2.0 */
#define WL3501_BLKSZ 256
@@ -548,7 +548,7 @@
struct wl3501_80211_tx_hdr {
struct wl3501_80211_tx_plcp_hdr pclp_hdr;
- struct ieee802_11_hdr mac_hdr;
+ struct ieee80211_hdr mac_hdr;
} __attribute__ ((packed));
/*
@@ -609,6 +609,7 @@
struct net_device_stats stats;
struct iw_statistics wstats;
struct iw_spy_data spy_data;
+ struct iw_public_data wireless_data;
struct dev_node_t node;
};
#endif
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index dd90212..3f8c27f 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -296,7 +296,8 @@
*
* Move 'size' bytes from PC to card. (Shouldn't be interrupted)
*/
-void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size)
+static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src,
+ int size)
{
/* switch to SRAM Page 0 */
wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 :
@@ -317,8 +318,8 @@
*
* Move 'size' bytes from card to PC. (Shouldn't be interrupted)
*/
-void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
- int size)
+static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
+ int size)
{
/* switch to SRAM Page 0 */
wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 :
@@ -1438,14 +1439,14 @@
goto out;
}
-struct net_device_stats *wl3501_get_stats(struct net_device *dev)
+static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
{
struct wl3501_card *this = dev->priv;
return &this->stats;
}
-struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
+static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
{
struct wl3501_card *this = dev->priv;
struct iw_statistics *wstats = &this->wstats;
@@ -1943,7 +1944,7 @@
static const struct iw_handler_def wl3501_handler_def = {
.num_standard = sizeof(wl3501_handler) / sizeof(iw_handler),
.standard = (iw_handler *)wl3501_handler,
- .spy_offset = offsetof(struct wl3501_card, spy_data),
+ .get_wireless_stats = wl3501_get_wireless_stats,
};
/**
@@ -1960,6 +1961,7 @@
client_reg_t client_reg;
dev_link_t *link;
struct net_device *dev;
+ struct wl3501_card *this;
int ret;
/* Initialize the dev_link_t structure */
@@ -1994,7 +1996,9 @@
dev->tx_timeout = wl3501_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
dev->get_stats = wl3501_get_stats;
- dev->get_wireless_stats = wl3501_get_wireless_stats;
+ this = dev->priv;
+ this->wireless_data.spy_data = &this->spy_data;
+ dev->wireless_data = &this->wireless_data;
dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def;
SET_ETHTOOL_OPS(dev, &ops);
netif_stop_queue(dev);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 4598c6a..97f7231 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2739,6 +2739,7 @@
syba_2p_epp,
syba_1p_ecp,
titan_010l,
+ titan_1284p1,
titan_1284p2,
avlab_1p,
avlab_2p,
@@ -2811,6 +2812,7 @@
/* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
/* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } },
/* titan_010l */ { 1, { { 3, -1 }, } },
+ /* titan_1284p1 */ { 1, { { 0, 1 }, } },
/* titan_1284p2 */ { 2, { { 0, 1 }, { 2, 3 }, } },
/* avlab_1p */ { 1, { { 0, 1}, } },
/* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} },
@@ -2884,6 +2886,7 @@
PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
+ { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 },
{ 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
{ 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 2b85aa3..532f73b 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -91,6 +91,7 @@
{
struct msi_desc *entry;
struct msg_address address;
+ unsigned int irq = vector;
entry = (struct msi_desc *)msi_desc[vector];
if (!entry || !entry->dev)
@@ -112,6 +113,7 @@
entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
address.lo_address.value);
+ set_native_irq_info(irq, cpu_mask);
break;
}
case PCI_CAP_ID_MSIX:
@@ -125,22 +127,13 @@
MSI_TARGET_CPU_SHIFT);
entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
writel(address.lo_address.value, entry->mask_base + offset);
+ set_native_irq_info(irq, cpu_mask);
break;
}
default:
break;
}
}
-
-#ifdef CONFIG_IRQBALANCE
-static inline void move_msi(int vector)
-{
- if (!cpus_empty(pending_irq_balance_cpumask[vector])) {
- set_msi_affinity(vector, pending_irq_balance_cpumask[vector]);
- cpus_clear(pending_irq_balance_cpumask[vector]);
- }
-}
-#endif /* CONFIG_IRQBALANCE */
#endif /* CONFIG_SMP */
static void mask_MSI_irq(unsigned int vector)
@@ -191,13 +184,13 @@
static void end_msi_irq_wo_maskbit(unsigned int vector)
{
- move_msi(vector);
+ move_native_irq(vector);
ack_APIC_irq();
}
static void end_msi_irq_w_maskbit(unsigned int vector)
{
- move_msi(vector);
+ move_native_irq(vector);
unmask_MSI_irq(vector);
ack_APIC_irq();
}
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 390f185..402136a 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -19,7 +19,6 @@
#define NR_HP_RESERVED_VECTORS 20
extern int vector_irq[NR_VECTORS];
-extern cpumask_t pending_irq_balance_cpumask[NR_IRQS];
extern void (*interrupt[NR_IRQS])(void);
extern int pci_vector_resources(int last, int nr_released);
@@ -29,10 +28,6 @@
#define set_msi_irq_affinity NULL
#endif
-#ifndef CONFIG_IRQBALANCE
-static inline void move_msi(int vector) {}
-#endif
-
/*
* MSI-X Address Register
*/
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1b34fc5..c62d2f0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -333,13 +333,17 @@
if (platform_pci_choose_state) {
ret = platform_pci_choose_state(dev, state);
if (ret >= 0)
- state = ret;
+ state.event = ret;
}
- switch (state) {
- case 0: return PCI_D0;
- case 3: return PCI_D3hot;
+
+ switch (state.event) {
+ case PM_EVENT_ON:
+ return PCI_D0;
+ case PM_EVENT_FREEZE:
+ case PM_EVENT_SUSPEND:
+ return PCI_D3hot;
default:
- printk("They asked me for state %d\n", state);
+ printk("They asked me for state %d\n", state.event);
BUG();
}
return PCI_D0;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index bb36bb6..140354a 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -422,6 +422,25 @@
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
/*
+ * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
+ * This leads to doubled level interrupt rates.
+ * Set this bit to get rid of cycle wastage.
+ * Otherwise uncritical.
+ */
+static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
+{
+ u8 misc_control2;
+#define BYPASS_APIC_DEASSERT 8
+
+ pci_read_config_byte(dev, 0x5B, &misc_control2);
+ if (!(misc_control2 & BYPASS_APIC_DEASSERT)) {
+ printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n");
+ pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT);
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert);
+
+/*
* The AMD io apic can hang the box when an apic irq is masked.
* We check all revs >= B0 (yet not in the pre production!) as the bug
* is currently marked NoFix
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 713c78f..49bd217 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -21,13 +21,21 @@
* between the ROM and other resources, so enabling it may disable access
* to MMIO registers or other card memory.
*/
-static void pci_enable_rom(struct pci_dev *pdev)
+static int pci_enable_rom(struct pci_dev *pdev)
{
+ struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
+ struct pci_bus_region region;
u32 rom_addr;
+ if (!res->flags)
+ return -1;
+
+ pcibios_resource_to_bus(pdev, ®ion, res);
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
- rom_addr |= PCI_ROM_ADDRESS_ENABLE;
+ rom_addr &= ~PCI_ROM_ADDRESS_MASK;
+ rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
+ return 0;
}
/**
@@ -71,19 +79,21 @@
} else {
if (res->flags & IORESOURCE_ROM_COPY) {
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE);
+ return (void __iomem *)pci_resource_start(pdev,
+ PCI_ROM_RESOURCE);
} else {
/* assign the ROM an address if it doesn't have one */
- if (res->parent == NULL)
- pci_assign_resource(pdev, PCI_ROM_RESOURCE);
-
+ if (res->parent == NULL &&
+ pci_assign_resource(pdev,PCI_ROM_RESOURCE))
+ return NULL;
start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
if (*size == 0)
return NULL;
/* Enable ROM space decodes */
- pci_enable_rom(pdev);
+ if (pci_enable_rom(pdev))
+ return NULL;
}
}
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 3e23cd4..325c992 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -246,7 +246,7 @@
driver_unregister(&pxa2xx_pcmcia_driver);
}
-module_init(pxa2xx_pcmcia_init);
+fs_initcall(pxa2xx_pcmcia_init);
module_exit(pxa2xx_pcmcia_exit);
MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>");
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 5309734..bbe69b0 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -196,7 +196,7 @@
platform_device_unregister(mst_pcmcia_device);
}
-module_init(mst_pcmcia_init);
+fs_initcall(mst_pcmcia_init);
module_exit(mst_pcmcia_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index 42efe21..a1178a6 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -20,27 +20,18 @@
#include <asm/hardware.h>
#include <asm/irq.h>
-
#include <asm/hardware/scoop.h>
-#include <asm/arch/corgi.h>
#include <asm/arch/pxa-regs.h>
#include "soc_common.h"
#define NO_KEEP_VS 0x0001
-static unsigned char keep_vs;
-static unsigned char keep_rd;
-
-static struct pcmcia_irqs irqs[] = {
- { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"},
-};
-
-static void sharpsl_pcmcia_init_reset(void)
+static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
{
- reset_scoop(&corgiscoop_device.dev);
- keep_vs = NO_KEEP_VS;
- keep_rd = 0;
+ reset_scoop(scoopdev->dev);
+ scoopdev->keep_vs = NO_KEEP_VS;
+ scoopdev->keep_rd = 0;
}
static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -71,29 +62,35 @@
pxa_gpio_mode(GPIO57_nIOIS16_MD);
/* Register interrupts */
- ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+ if (scoop_devs[skt->nr].cd_irq >= 0) {
+ struct pcmcia_irqs cd_irq;
- if (ret) {
- printk(KERN_ERR "Request for Compact Flash IRQ failed\n");
- return ret;
+ cd_irq.sock = skt->nr;
+ cd_irq.irq = scoop_devs[skt->nr].cd_irq;
+ cd_irq.str = scoop_devs[skt->nr].cd_irq_str;
+ ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
+
+ if (ret) {
+ printk(KERN_ERR "Request for Compact Flash IRQ failed\n");
+ return ret;
+ }
}
- /* Enable interrupt */
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0);
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101);
- keep_vs = NO_KEEP_VS;
-
- skt->irq = CORGI_IRQ_GPIO_CF_IRQ;
+ skt->irq = scoop_devs[skt->nr].irq;
return 0;
}
static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
- soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+ if (scoop_devs[skt->nr].cd_irq >= 0) {
+ struct pcmcia_irqs cd_irq;
- /* CF_BUS_OFF */
- sharpsl_pcmcia_init_reset();
+ cd_irq.sock = skt->nr;
+ cd_irq.irq = scoop_devs[skt->nr].cd_irq;
+ cd_irq.str = scoop_devs[skt->nr].cd_irq_str;
+ soc_pcmcia_free_irqs(skt, &cd_irq, 1);
+ }
}
@@ -101,31 +98,32 @@
struct pcmcia_state *state)
{
unsigned short cpr, csr;
+ struct device *scoop = scoop_devs[skt->nr].dev;
- cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR);
+ cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR);
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF);
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000);
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000);
- csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR);
+ write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
+ write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
+ write_scoop_reg(scoop, SCOOP_IRM, 0x0000);
+ csr = read_scoop_reg(scoop, SCOOP_CSR);
if (csr & 0x0004) {
/* card eject */
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
- keep_vs = NO_KEEP_VS;
+ write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+ scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
}
- else if (!(keep_vs & NO_KEEP_VS)) {
+ else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) {
/* keep vs1,vs2 */
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
- csr |= keep_vs;
+ write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+ csr |= scoop_devs[skt->nr].keep_vs;
}
else if (cpr & 0x0003) {
/* power on */
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
- keep_vs = (csr & 0x00C0);
+ write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+ scoop_devs[skt->nr].keep_vs = (csr & 0x00C0);
}
else {
/* card detect */
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002);
+ write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
}
state->detect = (csr & 0x0004) ? 0 : 1;
@@ -147,6 +145,7 @@
const socket_state_t *state)
{
unsigned long flags;
+ struct device *scoop = scoop_devs[skt->nr].dev;
unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
@@ -166,10 +165,10 @@
local_irq_save(flags);
- nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010;
- ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083;
- nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080;
- nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E;
+ nmcr = (mcr = read_scoop_reg(scoop, SCOOP_MCR)) & ~0x0010;
+ ncpr = (cpr = read_scoop_reg(scoop, SCOOP_CPR)) & ~0x0083;
+ nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
+ nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
ncpr |= (state->Vcc == 33) ? 0x0001 :
(state->Vcc == 50) ? 0x0002 : 0;
@@ -184,22 +183,22 @@
((skt->status&SS_WRPROT) ? 0x0008 : 0);
if (!(ncpr & 0x0003)) {
- keep_rd = 0;
- } else if (!keep_rd) {
+ scoop_devs[skt->nr].keep_rd = 0;
+ } else if (!scoop_devs[skt->nr].keep_rd) {
if (nccr & 0x0080)
- keep_rd = 1;
+ scoop_devs[skt->nr].keep_rd = 1;
else
nccr |= 0x0080;
}
if (mcr != nmcr)
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr);
+ write_scoop_reg(scoop, SCOOP_MCR, nmcr);
if (cpr != ncpr)
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr);
+ write_scoop_reg(scoop, SCOOP_CPR, ncpr);
if (ccr != nccr)
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr);
+ write_scoop_reg(scoop, SCOOP_CCR, nccr);
if (imr != nimr)
- write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr);
+ write_scoop_reg(scoop, SCOOP_IMR, nimr);
local_irq_restore(flags);
@@ -208,10 +207,18 @@
static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
{
+ sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+
+ /* Enable interrupt */
+ write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0);
+ write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101);
+ scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
}
static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
+ /* CF_BUS_OFF */
+ sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
}
static struct pcmcia_low_level sharpsl_pcmcia_ops = {
@@ -223,7 +230,7 @@
.socket_init = sharpsl_pcmcia_socket_init,
.socket_suspend = sharpsl_pcmcia_socket_suspend,
.first = 0,
- .nr = 1,
+ .nr = 0,
};
static struct platform_device *sharpsl_pcmcia_device;
@@ -232,12 +239,15 @@
{
int ret;
+ sharpsl_pcmcia_ops.nr=scoop_num;
sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL);
if (!sharpsl_pcmcia_device)
return -ENOMEM;
+
memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device));
sharpsl_pcmcia_device->name = "pxa2xx-pcmcia";
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
+ sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev;
ret = platform_device_register(sharpsl_pcmcia_device);
if (ret)
@@ -257,7 +267,7 @@
platform_device_unregister(sharpsl_pcmcia_device);
}
-module_init(sharpsl_pcmcia_init);
+fs_initcall(sharpsl_pcmcia_init);
module_exit(sharpsl_pcmcia_exit);
MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index e98bb3d..d4ed508 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -126,5 +126,5 @@
MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
MODULE_LICENSE("Dual MPL/GPL");
-module_init(sa11x0_pcmcia_init);
+fs_initcall(sa11x0_pcmcia_init);
module_exit(sa11x0_pcmcia_exit);
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index b441f43..bb90a14 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -189,7 +189,7 @@
sa1111_driver_unregister(&pcmcia_driver);
}
-module_init(sa1111_drv_pcmcia_init);
+fs_initcall(sa1111_drv_pcmcia_init);
module_exit(sa1111_drv_pcmcia_exit);
MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index db04ffb..59c5d96 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -189,7 +189,7 @@
{
return 0;
}
-module_init(sa11xx_pcmcia_init);
+fs_initcall(sa11xx_pcmcia_init);
static void __exit sa11xx_pcmcia_exit(void) {}
diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h
index be420bb..edccfa5 100644
--- a/drivers/pcmcia/topic.h
+++ b/drivers/pcmcia/topic.h
@@ -101,6 +101,8 @@
#define TOPIC97_AVS_AUDIO_CONTROL 0x02
#define TOPIC97_AVS_VIDEO_CONTROL 0x01
+#define TOPIC_EXCA_IF_CONTROL 0x3e /* 8 bit */
+#define TOPIC_EXCA_IFC_33V_ENA 0x01
static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff)
{
@@ -137,4 +139,19 @@
return 0;
}
+
+static int topic95_override(struct yenta_socket *socket)
+{
+ u8 fctrl;
+
+ /* enable 3.3V support for 16bit cards */
+ fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL);
+ exca_writeb(socket, TOPIC_EXCA_IF_CONTROL, fctrl | TOPIC_EXCA_IFC_33V_ENA);
+
+ /* tell yenta to use exca registers to power 16bit cards */
+ socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF;
+
+ return 0;
+}
+
#endif /* _LINUX_TOPIC_H */
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 62fd705..0347a29 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -184,22 +184,52 @@
return 0;
}
-static int yenta_Vcc_power(u32 control)
+static void yenta_get_power(struct yenta_socket *socket, socket_state_t *state)
{
- switch (control & CB_SC_VCC_MASK) {
- case CB_SC_VCC_5V: return 50;
- case CB_SC_VCC_3V: return 33;
- default: return 0;
- }
-}
+ if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+ (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+ u8 reg, vcc, vpp;
-static int yenta_Vpp_power(u32 control)
-{
- switch (control & CB_SC_VPP_MASK) {
- case CB_SC_VPP_12V: return 120;
- case CB_SC_VPP_5V: return 50;
- case CB_SC_VPP_3V: return 33;
- default: return 0;
+ reg = exca_readb(socket, I365_POWER);
+ vcc = reg & I365_VCC_MASK;
+ vpp = reg & I365_VPP1_MASK;
+ state->Vcc = state->Vpp = 0;
+
+ if (socket->flags & YENTA_16BIT_POWER_DF) {
+ if (vcc == I365_VCC_3V)
+ state->Vcc = 33;
+ if (vcc == I365_VCC_5V)
+ state->Vcc = 50;
+ if (vpp == I365_VPP1_5V)
+ state->Vpp = state->Vcc;
+ if (vpp == I365_VPP1_12V)
+ state->Vpp = 120;
+ } else {
+ if (reg & I365_VCC_5V) {
+ state->Vcc = 50;
+ if (vpp == I365_VPP1_5V)
+ state->Vpp = 50;
+ if (vpp == I365_VPP1_12V)
+ state->Vpp = 120;
+ }
+ }
+ } else {
+ u32 control;
+
+ control = cb_readl(socket, CB_SOCKET_CONTROL);
+
+ switch (control & CB_SC_VCC_MASK) {
+ case CB_SC_VCC_5V: state->Vcc = 50; break;
+ case CB_SC_VCC_3V: state->Vcc = 33; break;
+ default: state->Vcc = 0;
+ }
+
+ switch (control & CB_SC_VPP_MASK) {
+ case CB_SC_VPP_12V: state->Vpp = 120; break;
+ case CB_SC_VPP_5V: state->Vpp = 50; break;
+ case CB_SC_VPP_3V: state->Vpp = 33; break;
+ default: state->Vpp = 0;
+ }
}
}
@@ -211,8 +241,7 @@
control = cb_readl(socket, CB_SOCKET_CONTROL);
- state->Vcc = yenta_Vcc_power(control);
- state->Vpp = yenta_Vpp_power(control);
+ yenta_get_power(socket, state);
state->io_irq = socket->io_irq;
if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
@@ -246,19 +275,54 @@
static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
{
- u32 reg = 0; /* CB_SC_STPCLK? */
- switch (state->Vcc) {
- case 33: reg = CB_SC_VCC_3V; break;
- case 50: reg = CB_SC_VCC_5V; break;
- default: reg = 0; break;
+ /* some birdges require to use the ExCA registers to power 16bit cards */
+ if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+ (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+ u8 reg, old;
+ reg = old = exca_readb(socket, I365_POWER);
+ reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK);
+
+ /* i82365SL-DF style */
+ if (socket->flags & YENTA_16BIT_POWER_DF) {
+ switch (state->Vcc) {
+ case 33: reg |= I365_VCC_3V; break;
+ case 50: reg |= I365_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 33:
+ case 50: reg |= I365_VPP1_5V; break;
+ case 120: reg |= I365_VPP1_12V; break;
+ }
+ } else {
+ /* i82365SL-B style */
+ switch (state->Vcc) {
+ case 50: reg |= I365_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+ case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+ }
+ }
+
+ if (reg != old)
+ exca_writeb(socket, I365_POWER, reg);
+ } else {
+ u32 reg = 0; /* CB_SC_STPCLK? */
+ switch (state->Vcc) {
+ case 33: reg = CB_SC_VCC_3V; break;
+ case 50: reg = CB_SC_VCC_5V; break;
+ default: reg = 0; break;
+ }
+ switch (state->Vpp) {
+ case 33: reg |= CB_SC_VPP_3V; break;
+ case 50: reg |= CB_SC_VPP_5V; break;
+ case 120: reg |= CB_SC_VPP_12V; break;
+ }
+ if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
+ cb_writel(socket, CB_SOCKET_CONTROL, reg);
}
- switch (state->Vpp) {
- case 33: reg |= CB_SC_VPP_3V; break;
- case 50: reg |= CB_SC_VPP_5V; break;
- case 120: reg |= CB_SC_VPP_12V; break;
- }
- if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
- cb_writel(socket, CB_SOCKET_CONTROL, reg);
}
static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
@@ -751,6 +815,7 @@
CARDBUS_TYPE_TI12XX,
CARDBUS_TYPE_TI1250,
CARDBUS_TYPE_RICOH,
+ CARDBUS_TYPE_TOPIC95,
CARDBUS_TYPE_TOPIC97,
CARDBUS_TYPE_O2MICRO,
};
@@ -789,6 +854,9 @@
.save_state = ricoh_save_state,
.restore_state = ricoh_restore_state,
},
+ [CARDBUS_TYPE_TOPIC95] = {
+ .override = topic95_override,
+ },
[CARDBUS_TYPE_TOPIC97] = {
.override = topic97_override,
},
@@ -1196,6 +1264,7 @@
CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH),
CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH),
+ CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95),
CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
diff --git a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h
index 4e637ee..4e75e9e 100644
--- a/drivers/pcmcia/yenta_socket.h
+++ b/drivers/pcmcia/yenta_socket.h
@@ -95,6 +95,12 @@
*/
#define CB_MEM_PAGE(map) (0x40 + (map))
+
+/* control how 16bit cards are powered */
+#define YENTA_16BIT_POWER_EXCA 0x00000001
+#define YENTA_16BIT_POWER_DF 0x00000002
+
+
struct yenta_socket;
struct cardbus_type {
@@ -113,6 +119,8 @@
struct pcmcia_socket socket;
struct cardbus_type *type;
+ u32 flags;
+
/* for PCI interrupt probing */
unsigned int probe_status;
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index 6e5229e9..e95ed67 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -8,13 +8,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 1d037c2..33da25f 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -11,13 +11,6 @@
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 82c5edd..beedd86 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -142,17 +142,6 @@
isapnp_write_byte(idx+1, val);
}
-static void *isapnp_alloc(long size)
-{
- void *result;
-
- result = kmalloc(size, GFP_KERNEL);
- if (!result)
- return NULL;
- memset(result, 0, size);
- return result;
-}
-
static void isapnp_key(void)
{
unsigned char code = 0x6a, msb;
@@ -406,7 +395,7 @@
struct pnp_id * id;
if (!dev)
return;
- id = isapnp_alloc(sizeof(struct pnp_id));
+ id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!id)
return;
sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -430,7 +419,7 @@
struct pnp_dev *dev;
isapnp_peek(tmp, size);
- dev = isapnp_alloc(sizeof(struct pnp_dev));
+ dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev)
return NULL;
dev->number = number;
@@ -461,7 +450,7 @@
unsigned long bits;
isapnp_peek(tmp, size);
- irq = isapnp_alloc(sizeof(struct pnp_irq));
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
bits = (tmp[1] << 8) | tmp[0];
@@ -485,7 +474,7 @@
struct pnp_dma *dma;
isapnp_peek(tmp, size);
- dma = isapnp_alloc(sizeof(struct pnp_dma));
+ dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = tmp[0];
@@ -505,7 +494,7 @@
struct pnp_port *port;
isapnp_peek(tmp, size);
- port = isapnp_alloc(sizeof(struct pnp_port));
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = (tmp[2] << 8) | tmp[1];
@@ -528,7 +517,7 @@
struct pnp_port *port;
isapnp_peek(tmp, size);
- port = isapnp_alloc(sizeof(struct pnp_port));
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = (tmp[1] << 8) | tmp[0];
@@ -550,7 +539,7 @@
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = isapnp_alloc(sizeof(struct pnp_mem));
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
@@ -573,7 +562,7 @@
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = isapnp_alloc(sizeof(struct pnp_mem));
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -595,7 +584,7 @@
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = isapnp_alloc(sizeof(struct pnp_mem));
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -838,7 +827,7 @@
static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device)
{
- struct pnp_id * id = isapnp_alloc(sizeof(struct pnp_id));
+ struct pnp_id * id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!id)
return;
sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -874,7 +863,7 @@
header[4], header[5], header[6], header[7], header[8]);
printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
#endif
- if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL)
+ if ((card = kcalloc(1, sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
continue;
card->number = csn;
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 6c510c1..94442ff 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -11,13 +11,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 8655dd2..1a8915e 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/config.h>
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <acpi/acpi_bus.h>
@@ -41,14 +42,6 @@
return (!acpi_match_ids(dev, excluded_id_list));
}
-void *pnpacpi_kmalloc(size_t size, int f)
-{
- void *p = kmalloc(size, f);
- if (p)
- memset(p, 0, size);
- return p;
-}
-
/*
* Compatible Device IDs
*/
@@ -143,7 +136,7 @@
return 0;
pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
- dev = pnpacpi_kmalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev) {
pnp_err("Out of memory");
return -ENOMEM;
@@ -173,7 +166,7 @@
dev->number = num;
/* set the initial values for the PnP device */
- dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
goto err;
pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
@@ -205,8 +198,7 @@
for (i = 0; i < cid_list->count; i++) {
if (!ispnpidacpi(cid_list->id[i].value))
continue;
- dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id),
- GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
continue;
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
index 76f907e..f28e2ed 100644
--- a/drivers/pnp/pnpacpi/pnpacpi.h
+++ b/drivers/pnp/pnpacpi/pnpacpi.h
@@ -5,7 +5,6 @@
#include <linux/acpi.h>
#include <linux/pnp.h>
-void *pnpacpi_kmalloc(size_t size, int f);
acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 75575f6..675b76a 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -244,7 +244,7 @@
if (p->number_of_channels == 0)
return;
- dma = pnpacpi_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
@@ -300,7 +300,7 @@
if (p->number_of_interrupts == 0)
return;
- irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
@@ -321,7 +321,7 @@
if (p->number_of_interrupts == 0)
return;
- irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
@@ -342,7 +342,7 @@
if (io->range_length == 0)
return;
- port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = io->min_base_address;
@@ -363,7 +363,7 @@
if (io->range_length == 0)
return;
- port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = io->base_address;
@@ -382,7 +382,7 @@
if (p->range_length == 0)
return;
- mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = p->min_base_address;
@@ -405,7 +405,7 @@
if (p->range_length == 0)
return;
- mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = p->min_base_address;
@@ -428,7 +428,7 @@
if (p->range_length == 0)
return;
- mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = p->range_base_address;
@@ -612,7 +612,7 @@
if (!res_cnt)
return -EINVAL;
buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
- buffer->pointer = pnpacpi_kmalloc(buffer->length - 1, GFP_KERNEL);
+ buffer->pointer = kcalloc(1, buffer->length - 1, GFP_KERNEL);
if (!buffer->pointer)
return -ENOMEM;
pnp_dbg("Res cnt %d", res_cnt);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 778a324..f49674f 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -86,16 +86,6 @@
struct pnp_dev_node_info node_info;
-void *pnpbios_kmalloc(size_t size, int f)
-{
- void *p = kmalloc( size, f );
- if ( p == NULL )
- printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
- else
- memset(p, 0, size);
- return p;
-}
-
/*
*
* DOCKING FUNCTIONS
@@ -121,10 +111,10 @@
if (!current->fs->root) {
return -EAGAIN;
}
- if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = (char **) kcalloc (20, sizeof (char *), GFP_KERNEL))) {
return -ENOMEM;
}
- if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
+ if (!(buf = kcalloc (1, 256, GFP_KERNEL))) {
kfree (envp);
return -ENOMEM;
}
@@ -231,7 +221,7 @@
if(!pnpbios_is_dynamic(dev))
return -EPERM;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -254,7 +244,7 @@
if (!pnpbios_is_dynamic(dev))
return -EPERM;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -305,7 +295,7 @@
if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
return -EPERM;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
@@ -347,7 +337,7 @@
}
/* set the initial values for the PnP device */
- dev_id = pnpbios_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
return -1;
pnpid32_to_pnpid(node->eisa_id,id);
@@ -385,7 +375,7 @@
struct pnp_bios_node *node;
struct pnp_dev *dev;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return;
@@ -402,7 +392,7 @@
break;
}
nodes_got++;
- dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
+ dev = kcalloc(1, sizeof (struct pnp_dev), GFP_KERNEL);
if (!dev)
break;
if(insert_device(dev,node)<0)
diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h
index 01896e7..d8cb2fd 100644
--- a/drivers/pnp/pnpbios/pnpbios.h
+++ b/drivers/pnp/pnpbios/pnpbios.h
@@ -26,7 +26,6 @@
extern int pnp_bios_present(void);
extern int pnpbios_dont_use_current_config;
-extern void *pnpbios_kmalloc(size_t size, int f);
extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node);
extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 6bb8e19..5a3dfc9 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -87,7 +87,7 @@
return -EFBIG;
}
- tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+ tmpbuf = kcalloc(1, escd.escd_size, GFP_KERNEL);
if (!tmpbuf) return -ENOMEM;
if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
@@ -133,7 +133,7 @@
if (pos >= 0xff)
return 0;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
for (nodenum=pos; nodenum<0xff; ) {
@@ -168,7 +168,7 @@
u8 nodenum = (long)data;
int len;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
kfree(node);
@@ -188,7 +188,7 @@
u8 nodenum = (long)data;
int ret = count;
- node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index e305bb1..b0ca65b 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -247,7 +247,7 @@
pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = ((p[5] << 8) | p[4]) << 8;
@@ -263,7 +263,7 @@
pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -279,7 +279,7 @@
pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -296,7 +296,7 @@
struct pnp_irq * irq;
unsigned long bits;
- irq = pnpbios_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
bits = (p[2] << 8) | p[1];
@@ -313,7 +313,7 @@
pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_dma * dma;
- dma = pnpbios_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = p[1];
@@ -326,7 +326,7 @@
pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
- port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = (p[3] << 8) | p[2];
@@ -342,7 +342,7 @@
pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
- port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+ port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = (p[2] << 8) | p[1];
@@ -530,7 +530,7 @@
case SMALL_TAG_COMPATDEVID: /* compatible ID */
if (len != 4)
goto len_err;
- dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
+ dev_id = kcalloc(1, sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id)
return NULL;
memset(dev_id, 0, sizeof(struct pnp_id));
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 596a02d..8936b0c 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -16,13 +16,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index b952aec..61fe998 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -8,13 +8,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/ctype.h>
-
-#ifdef CONFIG_PNP_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pnp.h>
#include "base.h"
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index dc1c89d..6e7d7b0 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -49,7 +49,7 @@
config DASD_DIAG
tristate "Support for DIAG access to Disks"
- depends on DASD && ARCH_S390X = 'n'
+ depends on DASD && ( ARCH_S390X = 'n' || EXPERIMENTAL)
help
Select this option if you want to use Diagnose250 command to access
Disks under VM. If you are not running under VM or unsure what it is,
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index d5f5398..8fc891a 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.165 $
+ * $Revision: 1.167 $
*/
#include <linux/config.h>
@@ -1131,17 +1131,13 @@
request_queue_t *queue;
struct request *req;
struct dasd_ccw_req *cqr;
- int nr_queued, feature_ro;
+ int nr_queued;
queue = device->request_queue;
/* No queue ? Then there is nothing to do. */
if (queue == NULL)
return;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0) /* no devmap */
- return;
-
/*
* We requeue request from the block device queue to the ccw
* queue only in two states. In state DASD_STATE_READY the
@@ -1162,7 +1158,8 @@
nr_queued < DASD_CHANQ_MAX_SIZE) {
req = elv_next_request(queue);
- if (feature_ro && rq_data_dir(req) == WRITE) {
+ if (device->features & DASD_FEATURE_READONLY &&
+ rq_data_dir(req) == WRITE) {
DBF_DEV_EVENT(DBF_ERR, device,
"Rejecting write request %p",
req);
@@ -1814,17 +1811,13 @@
{
struct dasd_device *device;
- int feature_diag, rc;
+ int rc;
device = dasd_create_device(cdev);
if (IS_ERR(device))
return PTR_ERR(device);
- feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG);
- if (feature_diag < 0)
- return feature_diag;
-
- if (feature_diag) {
+ if (device->features & DASD_FEATURE_USEDIAG) {
if (!dasd_diag_discipline_pointer) {
printk (KERN_WARNING
"dasd_generic couldn't online device %s "
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index d948566..bda896d 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -11,7 +11,7 @@
* functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context.
*
- * $Revision: 1.40 $
+ * $Revision: 1.43 $
*/
#include <linux/config.h>
@@ -513,6 +513,7 @@
if (!devmap->device) {
devmap->device = device;
device->devindex = devmap->devindex;
+ device->features = devmap->features;
get_device(&cdev->dev);
device->cdev = cdev;
rc = 0;
@@ -643,6 +644,8 @@
devmap->features |= DASD_FEATURE_READONLY;
else
devmap->features &= ~DASD_FEATURE_READONLY;
+ if (devmap->device)
+ devmap->device->features = devmap->features;
if (devmap->device && devmap->device->gdp)
set_disk_ro(devmap->device->gdp, ro_flag);
spin_unlock(&dasd_devmap_lock);
@@ -758,7 +761,8 @@
devmap->features |= feature;
else
devmap->features &= ~feature;
-
+ if (devmap->device)
+ devmap->device->features = devmap->features;
spin_unlock(&dasd_devmap_lock);
return 0;
}
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 1276998..7478423 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -6,17 +6,18 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.42 $
+ * $Revision: 1.49 $
*/
#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/hdreg.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <asm/dasd.h>
#include <asm/debug.h>
@@ -28,58 +29,89 @@
#include "dasd_int.h"
#include "dasd_diag.h"
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif /* PRINTK_HEADER */
#define PRINTK_HEADER "dasd(diag):"
MODULE_LICENSE("GPL");
+/* The maximum number of blocks per request (max_blocks) is dependent on the
+ * amount of storage that is available in the static I/O buffer for each
+ * device. Currently each device gets 2 pages. We want to fit two requests
+ * into the available memory so that we can immediately start the next if one
+ * finishes. */
+#define DIAG_MAX_BLOCKS (((2 * PAGE_SIZE - sizeof(struct dasd_ccw_req) - \
+ sizeof(struct dasd_diag_req)) / \
+ sizeof(struct dasd_diag_bio)) / 2)
+#define DIAG_MAX_RETRIES 32
+#define DIAG_TIMEOUT 50 * HZ
+
struct dasd_discipline dasd_diag_discipline;
struct dasd_diag_private {
struct dasd_diag_characteristics rdc_data;
struct dasd_diag_rw_io iob;
struct dasd_diag_init_io iib;
- unsigned int pt_block;
+ blocknum_t pt_block;
};
struct dasd_diag_req {
- int block_count;
+ unsigned int block_count;
struct dasd_diag_bio bio[0];
};
+static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
+
+/* Perform DIAG250 call with block I/O parameter list iob (input and output)
+ * and function code cmd.
+ * In case of an exception return 3. Otherwise return result of bitwise OR of
+ * resulting condition code and DIAG return code. */
static __inline__ int
dia250(void *iob, int cmd)
{
+ typedef struct {
+ char _[max(sizeof (struct dasd_diag_init_io),
+ sizeof (struct dasd_diag_rw_io))];
+ } addr_type;
int rc;
- __asm__ __volatile__(" lhi %0,3\n"
- " lr 0,%2\n"
- " diag 0,%1,0x250\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- " or %0,1\n"
- "1:\n"
-#ifndef CONFIG_ARCH_S390X
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous\n"
+ __asm__ __volatile__(
+#ifdef CONFIG_ARCH_S390X
+ " lghi %0,3\n"
+ " lgr 0,%3\n"
+ " diag 0,%2,0x250\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ " or %0,1\n"
+ "1:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 0b,1b\n"
+ ".previous\n"
#else
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous\n"
+ " lhi %0,3\n"
+ " lr 0,%3\n"
+ " diag 0,%2,0x250\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ " or %0,1\n"
+ "1:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,1b\n"
+ ".previous\n"
#endif
- : "=&d" (rc)
- : "d" (cmd), "d" ((void *) __pa(iob))
- : "0", "1", "cc");
+ : "=&d" (rc), "=m" (*(addr_type *) iob)
+ : "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
+ : "0", "1", "cc");
return rc;
}
+/* Initialize block I/O to DIAG device using the specified blocksize and
+ * block offset. On success, return zero and set end_block to contain the
+ * number of blocks on the device minus the specified offset. Return non-zero
+ * otherwise. */
static __inline__ int
-mdsk_init_io(struct dasd_device * device, int blocksize, int offset, int size)
+mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
+ blocknum_t offset, blocknum_t *end_block)
{
struct dasd_diag_private *private;
struct dasd_diag_init_io *iib;
@@ -92,14 +124,18 @@
iib->dev_nr = _ccw_device_get_device_number(device->cdev);
iib->block_size = blocksize;
iib->offset = offset;
- iib->start_block = 0;
- iib->end_block = size;
+ iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
rc = dia250(iib, INIT_BIO);
- return rc & 3;
+ if ((rc & 3) == 0 && end_block)
+ *end_block = iib->end_block;
+
+ return rc;
}
+/* Remove block I/O environment for device. Return zero on success, non-zero
+ * otherwise. */
static __inline__ int
mdsk_term_io(struct dasd_device * device)
{
@@ -112,9 +148,25 @@
memset(iib, 0, sizeof (struct dasd_diag_init_io));
iib->dev_nr = _ccw_device_get_device_number(device->cdev);
rc = dia250(iib, TERM_BIO);
- return rc & 3;
+ return rc;
}
+/* Error recovery for failed DIAG requests - try to reestablish the DIAG
+ * environment. */
+static void
+dasd_diag_erp(struct dasd_device *device)
+{
+ int rc;
+
+ mdsk_term_io(device);
+ rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+ if (rc)
+ DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
+ "rc=%d", rc);
+}
+
+/* Start a given request at the device. Return zero on success, non-zero
+ * otherwise. */
static int
dasd_start_diag(struct dasd_ccw_req * cqr)
{
@@ -124,32 +176,66 @@
int rc;
device = cqr->device;
+ if (cqr->retries < 0) {
+ DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
+ "- no retry left)", cqr);
+ cqr->status = DASD_CQR_FAILED;
+ return -EIO;
+ }
private = (struct dasd_diag_private *) device->private;
dreq = (struct dasd_diag_req *) cqr->data;
private->iob.dev_nr = _ccw_device_get_device_number(device->cdev);
private->iob.key = 0;
- private->iob.flags = 2; /* do asynchronous io */
+ private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
private->iob.block_count = dreq->block_count;
- private->iob.interrupt_params = (u32)(addr_t) cqr;
+ private->iob.interrupt_params = (addr_t) cqr;
private->iob.bio_list = __pa(dreq->bio);
+ private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
cqr->startclk = get_clock();
+ cqr->starttime = jiffies;
+ cqr->retries--;
rc = dia250(&private->iob, RW_BIO);
- if (rc > 8) {
- DEV_MESSAGE(KERN_WARNING, device, "dia250 returned CC %d", rc);
- cqr->status = DASD_CQR_ERROR;
- } else if (rc == 0) {
+ switch (rc) {
+ case 0: /* Synchronous I/O finished successfully */
+ cqr->stopclk = get_clock();
cqr->status = DASD_CQR_DONE;
- dasd_schedule_bh(device);
- } else {
+ /* Indicate to calling function that only a dasd_schedule_bh()
+ and no timer is needed */
+ rc = -EACCES;
+ break;
+ case 8: /* Asynchronous I/O was started */
cqr->status = DASD_CQR_IN_IO;
rc = 0;
+ break;
+ default: /* Error condition */
+ cqr->status = DASD_CQR_QUEUED;
+ DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc);
+ dasd_diag_erp(device);
+ rc = -EIO;
+ break;
}
return rc;
}
+/* Terminate given request at the device. */
+static int
+dasd_diag_term_IO(struct dasd_ccw_req * cqr)
+{
+ struct dasd_device *device;
+
+ device = cqr->device;
+ mdsk_term_io(device);
+ mdsk_init_io(device, device->bp_block, 0, NULL);
+ cqr->status = DASD_CQR_CLEAR;
+ cqr->stopclk = get_clock();
+ dasd_schedule_bh(device);
+ return 0;
+}
+
+/* Handle external interruption. */
static void
dasd_ext_handler(struct pt_regs *regs, __u16 code)
{
@@ -157,25 +243,27 @@
struct dasd_device *device;
unsigned long long expires;
unsigned long flags;
- char status;
- int ip;
+ u8 int_code, status;
+ addr_t ip;
+ int rc;
- /*
- * Get the external interruption subcode. VM stores
- * this in the 'cpu address' field associated with
- * the external interrupt. For diag 250 the subcode
- * needs to be 3.
- */
- if ((S390_lowcore.cpu_addr & 0xff00) != 0x0300)
+ int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
+ status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
+ switch (int_code) {
+ case DASD_DIAG_CODE_31BIT:
+ ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
+ break;
+ case DASD_DIAG_CODE_64BIT:
+ ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
+ break;
+ default:
return;
- status = *((char *) &S390_lowcore.ext_params + 5);
- ip = S390_lowcore.ext_params;
-
+ }
if (!ip) { /* no intparm: unsolicited interrupt */
MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
return;
}
- cqr = (struct dasd_ccw_req *)(addr_t) ip;
+ cqr = (struct dasd_ccw_req *) ip;
device = (struct dasd_device *) cqr->device;
if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
DEV_MESSAGE(KERN_WARNING, device,
@@ -188,6 +276,15 @@
/* get irq lock to modify request queue */
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ /* Check for a pending clear operation */
+ if (cqr->status == DASD_CQR_CLEAR) {
+ cqr->status = DASD_CQR_QUEUED;
+ dasd_clear_timer(device);
+ dasd_schedule_bh(device);
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ return;
+ }
+
cqr->stopclk = get_clock();
expires = 0;
@@ -198,16 +295,22 @@
next = list_entry(device->ccw_queue.next,
struct dasd_ccw_req, list);
if (next->status == DASD_CQR_QUEUED) {
- if (dasd_start_diag(next) == 0)
+ rc = dasd_start_diag(next);
+ if (rc == 0)
expires = next->expires;
- else
+ else if (rc != -EACCES)
DEV_MESSAGE(KERN_WARNING, device, "%s",
"Interrupt fastpath "
"failed!");
}
}
- } else
- cqr->status = DASD_CQR_FAILED;
+ } else {
+ cqr->status = DASD_CQR_QUEUED;
+ DEV_MESSAGE(KERN_WARNING, device, "interrupt status for "
+ "request %p was %d (%d retries left)", cqr, status,
+ cqr->retries);
+ dasd_diag_erp(device);
+ }
if (expires != 0)
dasd_set_timer(device, expires);
@@ -218,14 +321,17 @@
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
}
+/* Check whether device can be controlled by DIAG discipline. Return zero on
+ * success, non-zero otherwise. */
static int
dasd_diag_check_device(struct dasd_device *device)
{
struct dasd_diag_private *private;
struct dasd_diag_characteristics *rdc_data;
struct dasd_diag_bio bio;
- long *label;
- int sb, bsize;
+ struct dasd_diag_cms_label *label;
+ blocknum_t end_block;
+ unsigned int sb, bsize;
int rc;
private = (struct dasd_diag_private *) device->private;
@@ -244,8 +350,11 @@
rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);
rc = diag210((struct diag210 *) rdc_data);
- if (rc)
+ if (rc) {
+ DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device "
+ "information (rc=%d)", rc);
return -ENOTSUPP;
+ }
/* Figure out position of label block */
switch (private->rdc_data.vdev_class) {
@@ -256,6 +365,8 @@
private->pt_block = 2;
break;
default:
+ DEV_MESSAGE(KERN_WARNING, device, "unsupported device class "
+ "(class=%d)", private->rdc_data.vdev_class);
return -ENOTSUPP;
}
@@ -269,15 +380,17 @@
mdsk_term_io(device);
/* figure out blocksize of device */
- label = (long *) get_zeroed_page(GFP_KERNEL);
+ label = (struct dasd_diag_cms_label *) get_zeroed_page(GFP_KERNEL);
if (label == NULL) {
DEV_MESSAGE(KERN_WARNING, device, "%s",
"No memory to allocate initialization request");
return -ENOMEM;
}
+ rc = 0;
+ end_block = 0;
/* try all sizes - needed for ECKD devices */
for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
- mdsk_init_io(device, bsize, 0, 64);
+ mdsk_init_io(device, bsize, 0, &end_block);
memset(&bio, 0, sizeof (struct dasd_diag_bio));
bio.type = MDSK_READ_REQ;
bio.block_number = private->pt_block + 1;
@@ -289,37 +402,45 @@
private->iob.block_count = 1;
private->iob.interrupt_params = 0;
private->iob.bio_list = __pa(&bio);
- if (dia250(&private->iob, RW_BIO) == 0)
+ private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
+ rc = dia250(&private->iob, RW_BIO);
+ if (rc == 0 || rc == 3)
break;
mdsk_term_io(device);
}
- if (bsize <= PAGE_SIZE && label[0] == 0xc3d4e2f1) {
- /* get formatted blocksize from label block */
- bsize = (int) label[3];
- device->blocks = label[7];
+ if (rc == 3) {
+ DEV_MESSAGE(KERN_WARNING, device, "%s", "DIAG call failed");
+ rc = -EOPNOTSUPP;
+ } else if (rc != 0) {
+ DEV_MESSAGE(KERN_WARNING, device, "device access failed "
+ "(rc=%d)", rc);
+ rc = -EIO;
+ } else {
+ if (memcmp(label->label_id, DASD_DIAG_CMS1,
+ sizeof(DASD_DIAG_CMS1)) == 0) {
+ /* get formatted blocksize from label block */
+ bsize = (unsigned int) label->block_size;
+ device->blocks = (unsigned long) label->block_count;
+ } else
+ device->blocks = end_block;
device->bp_block = bsize;
device->s2b_shift = 0; /* bits to shift 512 to get a block */
for (sb = 512; sb < bsize; sb = sb << 1)
device->s2b_shift++;
DEV_MESSAGE(KERN_INFO, device,
- "capacity (%dkB blks): %ldkB",
- (device->bp_block >> 10),
- (device->blocks << device->s2b_shift) >> 1);
+ "(%ld B/blk): %ldkB",
+ (unsigned long) device->bp_block,
+ (unsigned long) (device->blocks <<
+ device->s2b_shift) >> 1);
rc = 0;
- } else {
- if (bsize > PAGE_SIZE)
- DEV_MESSAGE(KERN_WARNING, device, "%s",
- "DIAG access failed");
- else
- DEV_MESSAGE(KERN_WARNING, device, "%s",
- "volume is not CMS formatted");
- rc = -EMEDIUMTYPE;
}
free_page((long) label);
return rc;
}
+/* Fill in virtual disk geometry for device. Return zero on success, non-zero
+ * otherwise. */
static int
dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
{
@@ -349,6 +470,8 @@
return dasd_default_erp_postaction;
}
+/* Create DASD request from block device request. Return pointer to new
+ * request on success, ERR_PTR otherwise. */
static struct dasd_ccw_req *
dasd_diag_build_cp(struct dasd_device * device, struct request *req)
{
@@ -358,9 +481,9 @@
struct bio *bio;
struct bio_vec *bv;
char *dst;
- int count, datasize;
+ unsigned int count, datasize;
sector_t recid, first_rec, last_rec;
- unsigned blksize, off;
+ unsigned int blksize, off;
unsigned char rw_cmd;
int i;
@@ -413,13 +536,16 @@
}
}
}
+ cqr->retries = DIAG_MAX_RETRIES;
cqr->buildclk = get_clock();
cqr->device = device;
- cqr->expires = 50 * HZ; /* 50 seconds */
+ cqr->expires = DIAG_TIMEOUT;
cqr->status = DASD_CQR_FILLED;
return cqr;
}
+/* Release DASD request. Return non-zero if request was successful, zero
+ * otherwise. */
static int
dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
@@ -430,6 +556,7 @@
return status;
}
+/* Fill in IOCTL data for device. */
static int
dasd_diag_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
@@ -437,7 +564,7 @@
struct dasd_diag_private *private;
private = (struct dasd_diag_private *) device->private;
- info->label_block = private->pt_block;
+ info->label_block = (unsigned int) private->pt_block;
info->FBA_layout = 1;
info->format = DASD_FORMAT_LDL;
info->characteristics_size = sizeof (struct dasd_diag_characteristics);
@@ -456,26 +583,15 @@
"dump sense not available for DIAG data");
}
-/*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). dasd diag is only relevant for 31 bit.
- * The struct dasd_ccw_req has 96 bytes, the struct dasd_diag_req has
- * 8 bytes and the struct dasd_diag_bio for each block has 16 bytes.
- * That makes:
- * (8192 - 96 - 8) / 16 = 505.5 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 252.75 blocks
- * for one request. Give a little safety and the result is 240.
- */
struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",
- .max_blocks = 240,
+ .max_blocks = DIAG_MAX_BLOCKS,
.check_device = dasd_diag_check_device,
.fill_geometry = dasd_diag_fill_geometry,
.start_IO = dasd_start_diag,
+ .term_IO = dasd_diag_term_IO,
.examine_error = dasd_diag_examine_error,
.erp_action = dasd_diag_erp_action,
.erp_postaction = dasd_diag_erp_postaction,
@@ -493,7 +609,7 @@
"Machine is not VM: %s "
"discipline not initializing",
dasd_diag_discipline.name);
- return -EINVAL;
+ return -ENODEV;
}
ASCEBC(dasd_diag_discipline.ebcname, 4);
@@ -506,13 +622,6 @@
static void __exit
dasd_diag_cleanup(void)
{
- if (!MACHINE_IS_VM) {
- MESSAGE_LOG(KERN_INFO,
- "Machine is not VM: %s "
- "discipline not cleaned",
- dasd_diag_discipline.name);
- return;
- }
unregister_external_interrupt(0x2603, dasd_ext_handler);
ctl_clear_bit(0, 9);
dasd_diag_discipline_pointer = NULL;
@@ -520,22 +629,3 @@
module_init(dasd_diag_init);
module_exit(dasd_diag_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h
index a0c38e3..b26eb28 100644
--- a/drivers/s390/block/dasd_diag.h
+++ b/drivers/s390/block/dasd_diag.h
@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.6 $
+ * $Revision: 1.7 $
*/
#define MDSK_WRITE_REQ 0x01
@@ -19,6 +19,18 @@
#define DEV_CLASS_FBA 0x01
#define DEV_CLASS_ECKD 0x04
+#define DASD_DIAG_LC_INT_CODE 132
+#define DASD_DIAG_LC_INT_STATUS 133
+#define DASD_DIAG_LC_INT_PARM_31BIT 128
+#define DASD_DIAG_LC_INT_PARM_64BIT 4536
+#define DASD_DIAG_CODE_31BIT 0x03
+#define DASD_DIAG_CODE_64BIT 0x07
+
+#define DASD_DIAG_RWFLAG_ASYNC 0x02
+#define DASD_DIAG_RWFLAG_NOCACHE 0x01
+
+#define DASD_DIAG_FLAGA_FORMAT_64BIT 0x80
+
struct dasd_diag_characteristics {
u16 dev_nr;
u16 rdc_len;
@@ -32,35 +44,106 @@
u8 rdev_features;
} __attribute__ ((packed, aligned(4)));
+struct dasd_diag_cms_label {
+ u8 label_id[4];
+ u8 vol_id[6];
+ u16 version_id;
+ u32 block_size;
+ u32 origin_ptr;
+ u32 usable_count;
+ u32 formatted_count;
+ u32 block_count;
+ u32 used_count;
+ u32 fst_size;
+ u32 fst_count;
+ u8 format_date[6];
+ u8 reserved1[2];
+ u32 disk_offset;
+ u32 map_block;
+ u32 hblk_disp;
+ u32 user_disp;
+ u8 reserved2[4];
+ u8 segment_name[8];
+} __attribute__ ((packed));
+
+#ifdef CONFIG_ARCH_S390X
+#define DASD_DIAG_FLAGA_DEFAULT DASD_DIAG_FLAGA_FORMAT_64BIT
+
+typedef u64 blocknum_t;
+typedef s64 sblocknum_t;
+
+struct dasd_diag_bio {
+ u8 type;
+ u8 status;
+ u8 spare1[2];
+ u32 alet;
+ blocknum_t block_number;
+ u64 buffer;
+} __attribute__ ((packed, aligned(8)));
+
+struct dasd_diag_init_io {
+ u16 dev_nr;
+ u8 flaga;
+ u8 spare1[21];
+ u32 block_size;
+ u8 spare2[4];
+ blocknum_t offset;
+ sblocknum_t start_block;
+ blocknum_t end_block;
+ u8 spare3[8];
+} __attribute__ ((packed, aligned(8)));
+
+struct dasd_diag_rw_io {
+ u16 dev_nr;
+ u8 flaga;
+ u8 spare1[21];
+ u8 key;
+ u8 flags;
+ u8 spare2[2];
+ u32 block_count;
+ u32 alet;
+ u8 spare3[4];
+ u64 interrupt_params;
+ u64 bio_list;
+ u8 spare4[8];
+} __attribute__ ((packed, aligned(8)));
+#else /* CONFIG_ARCH_S390X */
+#define DASD_DIAG_FLAGA_DEFAULT 0x0
+
+typedef u32 blocknum_t;
+typedef s32 sblocknum_t;
+
struct dasd_diag_bio {
u8 type;
u8 status;
u16 spare1;
- u32 block_number;
+ blocknum_t block_number;
u32 alet;
u32 buffer;
} __attribute__ ((packed, aligned(8)));
struct dasd_diag_init_io {
u16 dev_nr;
- u16 spare1[11];
+ u8 flaga;
+ u8 spare1[21];
u32 block_size;
- u32 offset;
- u32 start_block;
- u32 end_block;
- u32 spare2[6];
+ blocknum_t offset;
+ sblocknum_t start_block;
+ blocknum_t end_block;
+ u8 spare2[24];
} __attribute__ ((packed, aligned(8)));
struct dasd_diag_rw_io {
u16 dev_nr;
- u16 spare1[11];
+ u8 flaga;
+ u8 spare1[21];
u8 key;
u8 flags;
- u16 spare2;
+ u8 spare2[2];
u32 block_count;
u32 alet;
u32 bio_list;
u32 interrupt_params;
- u32 spare3[5];
+ u8 spare3[20];
} __attribute__ ((packed, aligned(8)));
-
+#endif /* CONFIG_ARCH_S390X */
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 96c4934..a601c9a 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -9,7 +9,7 @@
*
* gendisk related functions for the dasd driver.
*
- * $Revision: 1.50 $
+ * $Revision: 1.51 $
*/
#include <linux/config.h>
@@ -31,16 +31,12 @@
dasd_gendisk_alloc(struct dasd_device *device)
{
struct gendisk *gdp;
- int len, feature_ro;
+ int len;
/* Make sure the minor for this device exists. */
if (device->devindex >= DASD_PER_MAJOR)
return -EBUSY;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0)
- return feature_ro;
-
gdp = alloc_disk(1 << DASD_PARTN_BITS);
if (!gdp)
return -ENOMEM;
@@ -75,7 +71,7 @@
sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
- if (feature_ro)
+ if (device->features & DASD_FEATURE_READONLY)
set_disk_ro(gdp, 1);
gdp->private_data = device;
gdp->queue = device->request_queue;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a9f38b2..9fab04f 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.64 $
+ * $Revision: 1.65 $
*/
#ifndef DASD_INT_H
@@ -286,6 +286,7 @@
unsigned int bp_block; /* bytes per block */
unsigned int s2b_shift; /* log2 (bp_block/512) */
unsigned long flags; /* per device flags */
+ unsigned short features; /* copy of devmap-features (read-only!) */
/* Device discipline stuff. */
struct dasd_discipline *discipline;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 980c555..789595b 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.45 $
+ * $Revision: 1.47 $
*
* i/o controls for the dasd driver.
*/
@@ -296,7 +296,6 @@
{
struct dasd_device *device;
struct format_data_t fdata;
- int feature_ro;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -308,10 +307,7 @@
if (device == NULL)
return -ENODEV;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0)
- return feature_ro;
- if (feature_ro)
+ if (device->features & DASD_FEATURE_READONLY)
return -EROFS;
if (copy_from_user(&fdata, (void __user *) args,
sizeof (struct format_data_t)))
@@ -384,7 +380,7 @@
struct dasd_device *device;
struct dasd_information2_t *dasd_info;
unsigned long flags;
- int rc, feature_ro;
+ int rc;
struct ccw_device *cdev;
device = bdev->bd_disk->private_data;
@@ -394,10 +390,6 @@
if (!device->discipline->fill_info)
return -EINVAL;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0)
- return feature_ro;
-
dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
if (dasd_info == NULL)
return -ENOMEM;
@@ -427,7 +419,8 @@
(dasd_check_blocksize(device->bp_block)))
dasd_info->format = DASD_FORMAT_NONE;
- dasd_info->features |= feature_ro;
+ dasd_info->features |=
+ ((device->features & DASD_FEATURE_READONLY) != 0);
if (device->discipline)
memcpy(dasd_info->type, device->discipline->name, 4);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 43c34f8..fff9020 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -9,7 +9,7 @@
*
* /proc interface for the dasd driver.
*
- * $Revision: 1.32 $
+ * $Revision: 1.33 $
*/
#include <linux/config.h>
@@ -55,7 +55,6 @@
{
struct dasd_device *device;
char *substr;
- int feature;
device = dasd_device_from_devindex((unsigned long) v - 1);
if (IS_ERR(device))
@@ -79,10 +78,7 @@
else
seq_printf(m, " is ????????");
/* Print devices features. */
- feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature < 0)
- return 0;
- substr = feature ? "(ro)" : " ";
+ substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
seq_printf(m, "%4s: ", substr);
/* Print device status information. */
switch ((device != NULL) ? device->state : -1) {
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index d5eefea..328d9cb 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -632,12 +632,9 @@
raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
- if (rc) {
+ if (rc)
/* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
- if (rc == -EOPNOTSUPP && MACHINE_IS_VM)
- return __raw3270_size_device_vm(rp);
return rc;
- }
/* Wait for attention interrupt. */
#ifdef CONFIG_TN3270_CONSOLE
@@ -695,7 +692,10 @@
down(&raw3270_init_sem);
rp->view = &raw3270_init_view;
raw3270_init_view.dev = rp;
- rc = __raw3270_size_device(rp);
+ if (MACHINE_IS_VM)
+ rc = __raw3270_size_device_vm(rp);
+ else
+ rc = __raw3270_size_device(rp);
raw3270_init_view.dev = 0;
rp->view = 0;
up(&raw3270_init_sem);
@@ -710,6 +710,12 @@
rp->model = 4;
if (rp->rows == 27 && rp->cols == 132)
rp->model = 5;
+ } else {
+ /* Couldn't detect size. Use default model 2. */
+ rp->model = 2;
+ rp->rows = 24;
+ rp->cols = 80;
+ return 0;
}
return rc;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ea813bd..185bc73 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls
- * $Revision: 1.134 $
+ * $Revision: 1.135 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -815,8 +815,9 @@
struct tpi_info ti;
if (tpi(&ti)) {
- tsch(schid, (struct irb *)__LC_IRB);
- return 0;
+ tsch(ti.irq, (struct irb *)__LC_IRB);
+ if (ti.irq == schid)
+ return 0;
}
udelay(100);
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index ee7a05e..fbe4202 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <asm/ccwdev.h>
-#include <asm/qdio.h>
+#include <asm/cio.h>
#include "cio.h"
#include "cio_debug.h"
@@ -21,7 +21,6 @@
#include "device.h"
#include "chsc.h"
#include "ioasm.h"
-#include "qdio.h"
int
device_is_online(struct subchannel *sch)
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 02d01a0..ad3fe5a 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/device_ops.c
*
- * $Revision: 1.56 $
+ * $Revision: 1.57 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -19,14 +19,12 @@
#include <asm/ccwdev.h>
#include <asm/idals.h>
-#include <asm/qdio.h>
#include "cio.h"
#include "cio_debug.h"
#include "css.h"
#include "chsc.h"
#include "device.h"
-#include "qdio.h"
int
ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index c874607..45480a2 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -21,7 +21,7 @@
* Some S390 specific IO instructions as inline
*/
-extern __inline__ int stsch(int irq, volatile struct schib *addr)
+static inline int stsch(int irq, volatile struct schib *addr)
{
int ccode;
@@ -36,7 +36,7 @@
return ccode;
}
-extern __inline__ int msch(int irq, volatile struct schib *addr)
+static inline int msch(int irq, volatile struct schib *addr)
{
int ccode;
@@ -51,7 +51,7 @@
return ccode;
}
-extern __inline__ int msch_err(int irq, volatile struct schib *addr)
+static inline int msch_err(int irq, volatile struct schib *addr)
{
int ccode;
@@ -79,7 +79,7 @@
return ccode;
}
-extern __inline__ int tsch(int irq, volatile struct irb *addr)
+static inline int tsch(int irq, volatile struct irb *addr)
{
int ccode;
@@ -94,7 +94,7 @@
return ccode;
}
-extern __inline__ int tpi( volatile struct tpi_info *addr)
+static inline int tpi( volatile struct tpi_info *addr)
{
int ccode;
@@ -108,7 +108,7 @@
return ccode;
}
-extern __inline__ int ssch(int irq, volatile struct orb *addr)
+static inline int ssch(int irq, volatile struct orb *addr)
{
int ccode;
@@ -123,7 +123,7 @@
return ccode;
}
-extern __inline__ int rsch(int irq)
+static inline int rsch(int irq)
{
int ccode;
@@ -138,7 +138,7 @@
return ccode;
}
-extern __inline__ int csch(int irq)
+static inline int csch(int irq)
{
int ccode;
@@ -153,7 +153,7 @@
return ccode;
}
-extern __inline__ int hsch(int irq)
+static inline int hsch(int irq)
{
int ccode;
@@ -168,7 +168,7 @@
return ccode;
}
-extern __inline__ int xsch(int irq)
+static inline int xsch(int irq)
{
int ccode;
@@ -183,7 +183,7 @@
return ccode;
}
-extern __inline__ int chsc(void *chsc_area)
+static inline int chsc(void *chsc_area)
{
int cc;
@@ -198,7 +198,7 @@
return cc;
}
-extern __inline__ int iac( void)
+static inline int iac( void)
{
int ccode;
@@ -210,7 +210,7 @@
return ccode;
}
-extern __inline__ int rchp(int chpid)
+static inline int rchp(int chpid)
{
int ccode;
diff --git a/drivers/s390/crypto/z90common.h b/drivers/s390/crypto/z90common.h
index bcabac7..e319e78 100644
--- a/drivers/s390/crypto/z90common.h
+++ b/drivers/s390/crypto/z90common.h
@@ -27,7 +27,7 @@
#ifndef _Z90COMMON_H_
#define _Z90COMMON_H_
-#define VERSION_Z90COMMON_H "$Revision: 1.16 $"
+#define VERSION_Z90COMMON_H "$Revision: 1.17 $"
#define RESPBUFFSIZE 256
@@ -164,5 +164,4 @@
#define UMIN(a,b) ((a) < (b) ? (a) : (b))
#define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
-
#endif
diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c
index beb6a5e..c215e08 100644
--- a/drivers/s390/crypto/z90hardware.c
+++ b/drivers/s390/crypto/z90hardware.c
@@ -32,7 +32,7 @@
#include "z90crypt.h"
#include "z90common.h"
-#define VERSION_Z90HARDWARE_C "$Revision: 1.33 $"
+#define VERSION_Z90HARDWARE_C "$Revision: 1.34 $"
char z90hardware_version[] __initdata =
"z90hardware.o (" VERSION_Z90HARDWARE_C "/"
@@ -283,48 +283,6 @@
struct CPRB CPRB;
};
-union request_msg {
- union type4_msg t4msg;
- struct type6_msg t6msg;
-};
-
-struct request_msg_ext {
- int q_nr;
- unsigned char *psmid;
- union request_msg reqMsg;
-};
-
-struct type82_hdr {
- unsigned char reserved1;
- unsigned char type;
- unsigned char reserved2[2];
- unsigned char reply_code;
- unsigned char reserved3[3];
-};
-
-#define TYPE82_RSP_CODE 0x82
-
-#define REPLY_ERROR_MACHINE_FAILURE 0x10
-#define REPLY_ERROR_PREEMPT_FAILURE 0x12
-#define REPLY_ERROR_CHECKPT_FAILURE 0x14
-#define REPLY_ERROR_MESSAGE_TYPE 0x20
-#define REPLY_ERROR_INVALID_COMM_CD 0x21
-#define REPLY_ERROR_INVALID_MSG_LEN 0x23
-#define REPLY_ERROR_RESERVD_FIELD 0x24
-#define REPLY_ERROR_FORMAT_FIELD 0x29
-#define REPLY_ERROR_INVALID_COMMAND 0x30
-#define REPLY_ERROR_MALFORMED_MSG 0x40
-#define REPLY_ERROR_RESERVED_FIELDO 0x50
-#define REPLY_ERROR_WORD_ALIGNMENT 0x60
-#define REPLY_ERROR_MESSAGE_LENGTH 0x80
-#define REPLY_ERROR_OPERAND_INVALID 0x82
-#define REPLY_ERROR_OPERAND_SIZE 0x84
-#define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85
-#define REPLY_ERROR_RESERVED_FIELD 0x88
-#define REPLY_ERROR_TRANSPORT_FAIL 0x90
-#define REPLY_ERROR_PACKET_TRUNCATED 0xA0
-#define REPLY_ERROR_ZERO_BUFFER_LEN 0xB0
-
struct type86_hdr {
unsigned char reserved1;
unsigned char type;
@@ -338,7 +296,7 @@
#define TYPE86_FMT2 0x02
struct type86_fmt2_msg {
- struct type86_hdr hdr;
+ struct type86_hdr header;
unsigned char reserved[4];
unsigned char apfs[4];
unsigned int count1;
@@ -538,6 +496,8 @@
{'M','R','P',' ',' ',' ',' ',' '}
};
+static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+
struct T6_keyBlock_hdrX {
unsigned short blen;
unsigned short ulen;
@@ -688,9 +648,38 @@
#define RESPONSE_CPRB_SIZE 0x000006B8
#define RESPONSE_CPRBX_SIZE 0x00000724
-#define CALLER_HEADER 12
+struct error_hdr {
+ unsigned char reserved1;
+ unsigned char type;
+ unsigned char reserved2[2];
+ unsigned char reply_code;
+ unsigned char reserved3[3];
+};
-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+#define TYPE82_RSP_CODE 0x82
+
+#define REP82_ERROR_MACHINE_FAILURE 0x10
+#define REP82_ERROR_PREEMPT_FAILURE 0x12
+#define REP82_ERROR_CHECKPT_FAILURE 0x14
+#define REP82_ERROR_MESSAGE_TYPE 0x20
+#define REP82_ERROR_INVALID_COMM_CD 0x21
+#define REP82_ERROR_INVALID_MSG_LEN 0x23
+#define REP82_ERROR_RESERVD_FIELD 0x24
+#define REP82_ERROR_FORMAT_FIELD 0x29
+#define REP82_ERROR_INVALID_COMMAND 0x30
+#define REP82_ERROR_MALFORMED_MSG 0x40
+#define REP82_ERROR_RESERVED_FIELDO 0x50
+#define REP82_ERROR_WORD_ALIGNMENT 0x60
+#define REP82_ERROR_MESSAGE_LENGTH 0x80
+#define REP82_ERROR_OPERAND_INVALID 0x82
+#define REP82_ERROR_OPERAND_SIZE 0x84
+#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REP82_ERROR_RESERVED_FIELD 0x88
+#define REP82_ERROR_TRANSPORT_FAIL 0x90
+#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
+
+#define CALLER_HEADER 12
static inline int
testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
@@ -1212,9 +1201,9 @@
struct ap_status_word stat_word;
enum devstat stat;
int ccode;
+ u32 *q_nr_p = (u32 *)msg_ext;
- ((struct request_msg_ext *) msg_ext)->q_nr =
- (dev_nr << SKIP_BITL) + cdx;
+ *q_nr_p = (dev_nr << SKIP_BITL) + cdx;
PDEBUG("msg_len passed to sen: %d\n", msg_len);
PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
@@ -2104,7 +2093,7 @@
int *respbufflen_p, unsigned char *resp_buff)
{
struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
- struct type82_hdr *t82h_p = (struct type82_hdr *) response;
+ struct error_hdr *errh_p = (struct error_hdr *) response;
struct type84_hdr *t84h_p = (struct type84_hdr *) response;
struct type86_fmt2_msg *t86m_p = (struct type86_fmt2_msg *) response;
int reply_code, service_rc, service_rs, src_l;
@@ -2117,12 +2106,13 @@
service_rc = 0;
service_rs = 0;
src_l = 0;
- switch (t82h_p->type) {
+ switch (errh_p->type) {
case TYPE82_RSP_CODE:
- reply_code = t82h_p->reply_code;
- src_p = (unsigned char *)t82h_p;
- PRINTK("Hardware error: Type 82 Message Header: "
+ reply_code = errh_p->reply_code;
+ src_p = (unsigned char *)errh_p;
+ PRINTK("Hardware error: Type %02X Message Header: "
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ errh_p->type,
src_p[0], src_p[1], src_p[2], src_p[3],
src_p[4], src_p[5], src_p[6], src_p[7]);
break;
@@ -2131,7 +2121,7 @@
src_p = response + (int)t84h_p->len - src_l;
break;
case TYPE86_RSP_CODE:
- reply_code = t86m_p->hdr.reply_code;
+ reply_code = t86m_p->header.reply_code;
if (reply_code != 0)
break;
cprb_p = (struct CPRB *)
@@ -2143,6 +2133,9 @@
le2toI(cprb_p->ccp_rscode, &service_rs);
if ((service_rc == 8) && (service_rs == 66))
PDEBUG("Bad block format on PCICC\n");
+ else if ((service_rc == 8) && (service_rs == 65))
+ PDEBUG("Probably an even modulus on "
+ "PCICC\n");
else if ((service_rc == 8) && (service_rs == 770)) {
PDEBUG("Invalid key length on PCICC\n");
unset_ext_bitlens();
@@ -2155,7 +2148,7 @@
return REC_USE_PCICA;
}
else
- PRINTK("service rc/rs: %d/%d\n",
+ PRINTK("service rc/rs (PCICC): %d/%d\n",
service_rc, service_rs);
return REC_OPERAND_INV;
}
@@ -2169,7 +2162,10 @@
if (service_rc != 0) {
service_rs = (int) cprbx_p->ccp_rscode;
if ((service_rc == 8) && (service_rs == 66))
- PDEBUG("Bad block format on PCXICC\n");
+ PDEBUG("Bad block format on PCIXCC\n");
+ else if ((service_rc == 8) && (service_rs == 65))
+ PDEBUG("Probably an even modulus on "
+ "PCIXCC\n");
else if ((service_rc == 8) && (service_rs == 770)) {
PDEBUG("Invalid key length on PCIXCC\n");
unset_ext_bitlens();
@@ -2182,7 +2178,7 @@
return REC_USE_PCICA;
}
else
- PRINTK("service rc/rs: %d/%d\n",
+ PRINTK("service rc/rs (PCIXCC): %d/%d\n",
service_rc, service_rs);
return REC_OPERAND_INV;
}
@@ -2195,20 +2191,25 @@
}
break;
default:
+ src_p = (unsigned char *)errh_p;
+ PRINTK("Unrecognized Message Header: "
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ src_p[0], src_p[1], src_p[2], src_p[3],
+ src_p[4], src_p[5], src_p[6], src_p[7]);
return REC_BAD_MESSAGE;
}
if (reply_code)
switch (reply_code) {
- case REPLY_ERROR_OPERAND_INVALID:
+ case REP82_ERROR_OPERAND_INVALID:
return REC_OPERAND_INV;
- case REPLY_ERROR_OPERAND_SIZE:
+ case REP82_ERROR_OPERAND_SIZE:
return REC_OPERAND_SIZE;
- case REPLY_ERROR_EVEN_MOD_IN_OPND:
+ case REP82_ERROR_EVEN_MOD_IN_OPND:
return REC_EVEN_MOD;
- case REPLY_ERROR_MESSAGE_TYPE:
+ case REP82_ERROR_MESSAGE_TYPE:
return WRONG_DEVICE_TYPE;
- case REPLY_ERROR_TRANSPORT_FAIL:
+ case REP82_ERROR_TRANSPORT_FAIL:
PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
t86m_p->apfs[0], t86m_p->apfs[1],
t86m_p->apfs[2], t86m_p->apfs[3]);
@@ -2229,7 +2230,7 @@
PDEBUG("Length returned = %d\n", src_l);
tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
memcpy(tgt_p, src_p, src_l);
- if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
+ if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
return REC_INVALID_PAD;
diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
index 9ec29bb..6aeef3b 100644
--- a/drivers/s390/crypto/z90main.c
+++ b/drivers/s390/crypto/z90main.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/interrupt.h> // for tasklets
#include <linux/ioctl32.h>
+#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kobject_uevent.h>
@@ -39,19 +40,8 @@
#include <linux/version.h>
#include "z90crypt.h"
#include "z90common.h"
-#ifndef Z90CRYPT_USE_HOTPLUG
-#include <linux/miscdevice.h>
-#endif
-#define VERSION_CODE(vers, rel, seq) (((vers)<<16) | ((rel)<<8) | (seq))
-#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) /* version < 2.4 */
-# error "This kernel is too old: not supported"
-#endif
-#if LINUX_VERSION_CODE > VERSION_CODE(2,7,0) /* version > 2.6 */
-# error "This kernel is too recent: not supported by this file"
-#endif
-
-#define VERSION_Z90MAIN_C "$Revision: 1.57 $"
+#define VERSION_Z90MAIN_C "$Revision: 1.62 $"
static char z90main_version[] __initdata =
"z90main.o (" VERSION_Z90MAIN_C "/"
@@ -63,21 +53,12 @@
* Defaults that may be modified.
*/
-#ifndef Z90CRYPT_USE_HOTPLUG
/**
* You can specify a different minor at compile time.
*/
#ifndef Z90CRYPT_MINOR
#define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR
#endif
-#else
-/**
- * You can specify a different major at compile time.
- */
-#ifndef Z90CRYPT_MAJOR
-#define Z90CRYPT_MAJOR 0
-#endif
-#endif
/**
* You can specify a different domain at compile time or on the insmod
@@ -97,7 +78,7 @@
* older than CLEANUPTIME seconds in the past.
*/
#ifndef CLEANUPTIME
-#define CLEANUPTIME 20
+#define CLEANUPTIME 15
#endif
/**
@@ -298,6 +279,10 @@
* it contains the request; at READ, the response. The function
* send_to_crypto_device converts the request to device-dependent
* form and use the caller's OPEN-allocated buffer for the response.
+ *
+ * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
+ * because that points to it, see the discussion in z90hardware.c.
+ * Search for "extended request message block".
*/
struct caller {
int caller_buf_l; // length of original request
@@ -398,24 +383,9 @@
unsigned long, void *);
/**
- * Hotplug support
- */
-
-#ifdef Z90CRYPT_USE_HOTPLUG
-#define Z90CRYPT_HOTPLUG_ADD 1
-#define Z90CRYPT_HOTPLUG_REMOVE 2
-
-static void z90crypt_hotplug_event(int, int, int);
-#endif
-
-/**
* Storage allocated at initialization and used throughout the life of
* this insmod
*/
-#ifdef Z90CRYPT_USE_HOTPLUG
-static int z90crypt_major = Z90CRYPT_MAJOR;
-#endif
-
static int domain = DOMAIN_INDEX;
static struct z90crypt z90crypt;
static int quiesce_z90crypt;
@@ -444,14 +414,12 @@
.release = z90crypt_release
};
-#ifndef Z90CRYPT_USE_HOTPLUG
static struct miscdevice z90crypt_misc_device = {
.minor = Z90CRYPT_MINOR,
.name = DEV_NAME,
.fops = &z90crypt_fops,
.devfs_name = DEV_NAME
};
-#endif
/**
* Documentation values.
@@ -603,7 +571,6 @@
return -EINVAL;
}
-#ifndef Z90CRYPT_USE_HOTPLUG
/* Register as misc device with given minor (or get a dynamic one). */
result = misc_register(&z90crypt_misc_device);
if (result < 0) {
@@ -611,18 +578,6 @@
z90crypt_misc_device.minor, result);
return result;
}
-#else
- /* Register the major (or get a dynamic one). */
- result = register_chrdev(z90crypt_major, REG_NAME, &z90crypt_fops);
- if (result < 0) {
- PRINTKW("register_chrdev (major %d) failed with %d.\n",
- z90crypt_major, result);
- return result;
- }
-
- if (z90crypt_major == 0)
- z90crypt_major = result;
-#endif
PDEBUG("Registered " DEV_NAME " with result %d\n", result);
@@ -645,11 +600,6 @@
} else
PRINTK("No devices at startup\n");
-#ifdef Z90CRYPT_USE_HOTPLUG
- /* generate hotplug event for device node generation */
- z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_ADD);
-#endif
-
/* Initialize globals. */
spin_lock_init(&queuespinlock);
@@ -701,17 +651,10 @@
return 0; // success
init_module_cleanup:
-#ifndef Z90CRYPT_USE_HOTPLUG
if ((nresult = misc_deregister(&z90crypt_misc_device)))
PRINTK("misc_deregister failed with %d.\n", nresult);
else
PDEBUG("misc_deregister successful.\n");
-#else
- if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
- PRINTK("unregister_chrdev failed with %d.\n", nresult);
- else
- PDEBUG("unregister_chrdev successful.\n");
-#endif
return result; // failure
}
@@ -728,19 +671,10 @@
remove_proc_entry("driver/z90crypt", 0);
-#ifndef Z90CRYPT_USE_HOTPLUG
if ((nresult = misc_deregister(&z90crypt_misc_device)))
PRINTK("misc_deregister failed with %d.\n", nresult);
else
PDEBUG("misc_deregister successful.\n");
-#else
- z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_REMOVE);
-
- if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
- PRINTK("unregister_chrdev failed with %d.\n", nresult);
- else
- PDEBUG("unregister_chrdev successful.\n");
-#endif
/* Remove the tasks */
tasklet_kill(&reader_tasklet);
@@ -748,6 +682,9 @@
del_timer(&config_timer);
del_timer(&cleanup_timer);
+ if (z90_device_work)
+ destroy_workqueue(z90_device_work);
+
destroy_z90crypt();
PRINTKN("Unloaded.\n");
@@ -766,8 +703,6 @@
* z90crypt_status_write
* disable_card
* enable_card
- * scan_char
- * scan_string
*
* Helper functions:
* z90crypt_rsa
@@ -1057,9 +992,10 @@
* The MCL must be applied and the newer bitlengths enabled for these to work.
*
* Card Type Old limit New limit
+ * PCICA ??-2048 same (the lower limit is less than 128 bit...)
* PCICC 512-1024 512-2048
- * PCIXCC_MCL2 512-2048 no change (applying this MCL == card is MCL3+)
- * PCIXCC_MCL3 512-2048 128-2048
+ * PCIXCC_MCL2 512-2048 ----- (applying any GA LIC will make an MCL3 card)
+ * PCIXCC_MCL3 ----- 128-2048
* CEX2C 512-2048 128-2048
*
* ext_bitlens (extended bitlengths) is a global, since you should not apply an
@@ -1104,7 +1040,7 @@
if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail) {
/**
* bitlength is a factor, PCICA is the most capable, even with
- * the new MCL.
+ * the new MCL for PCIXCC.
*/
if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
(!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
@@ -2144,73 +2080,15 @@
z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
}
-static inline int
-scan_char(unsigned char *bf, unsigned int len,
- unsigned int *offs, unsigned int *p_eof, unsigned char c)
-{
- unsigned int i, found;
-
- found = 0;
- for (i = 0; i < len; i++) {
- if (bf[i] == c) {
- found = 1;
- break;
- }
- if (bf[i] == '\0') {
- *p_eof = 1;
- break;
- }
- if (bf[i] == '\n') {
- break;
- }
- }
- *offs = i+1;
- return found;
-}
-
-static inline int
-scan_string(unsigned char *bf, unsigned int len,
- unsigned int *offs, unsigned int *p_eof, unsigned char *s)
-{
- unsigned int temp_len, temp_offs, found, eof;
-
- temp_len = temp_offs = found = eof = 0;
- while (!eof && !found) {
- found = scan_char(bf+temp_len, len-temp_len,
- &temp_offs, &eof, *s);
-
- temp_len += temp_offs;
- if (eof) {
- found = 0;
- break;
- }
-
- if (found) {
- if (len >= temp_offs+strlen(s)) {
- found = !strncmp(bf+temp_len-1, s, strlen(s));
- if (found) {
- *offs = temp_len+strlen(s)-1;
- break;
- }
- } else {
- found = 0;
- *p_eof = 1;
- break;
- }
- }
- }
- return found;
-}
-
static int
z90crypt_status_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
- int i, j, len, offs, found, eof;
- unsigned char *lbuf;
+ int j, eol;
+ unsigned char *lbuf, *ptr;
unsigned int local_count;
-#define LBUFSIZE 600
+#define LBUFSIZE 1200
lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
if (!lbuf) {
PRINTK("kmalloc failed!\n");
@@ -2227,49 +2105,46 @@
return -EFAULT;
}
- lbuf[local_count-1] = '\0';
+ lbuf[local_count] = '\0';
- len = 0;
- eof = 0;
- found = 0;
- while (!eof) {
- found = scan_string(lbuf+len, local_count-len, &offs, &eof,
- "Online devices");
- len += offs;
- if (found == 1)
- break;
- }
-
- if (eof) {
+ ptr = strstr(lbuf, "Online devices");
+ if (ptr == 0) {
+ PRINTK("Unable to parse data (missing \"Online devices\")\n");
kfree(lbuf);
return count;
}
- if (found)
- found = scan_char(lbuf+len, local_count-len, &offs, &eof, '\n');
+ ptr = strstr(ptr, "\n");
+ if (ptr == 0) {
+ PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
+ kfree(lbuf);
+ return count;
+ }
+ ptr++;
- if (!found || eof) {
+ if (strstr(ptr, "Waiting work element counts") == NULL) {
+ PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
kfree(lbuf);
return count;
}
- len += offs;
j = 0;
- for (i = 0; i < 80; i++) {
- switch (*(lbuf+len+i)) {
+ eol = 0;
+ while ((j < 64) && (*ptr != '\0')) {
+ switch (*ptr) {
case '\t':
case ' ':
break;
case '\n':
default:
- eof = 1;
+ eol = 1;
break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
+ case '0': // no device
+ case '1': // PCICA
+ case '2': // PCICC
+ case '3': // PCIXCC_MCL2
+ case '4': // PCIXCC_MCL3
+ case '5': // CEX2C
j++;
break;
case 'd':
@@ -2283,8 +2158,9 @@
j++;
break;
}
- if (eof)
+ if (eol)
break;
+ ptr++;
}
kfree(lbuf);
@@ -3479,45 +3355,5 @@
return rv;
}
-#ifdef Z90CRYPT_USE_HOTPLUG
-static void
-z90crypt_hotplug_event(int dev_major, int dev_minor, int action)
-{
-#ifdef CONFIG_HOTPLUG
- char *argv[3];
- char *envp[6];
- char major[20];
- char minor[20];
-
- sprintf(major, "MAJOR=%d", dev_major);
- sprintf(minor, "MINOR=%d", dev_minor);
-
- argv[0] = hotplug_path;
- argv[1] = "z90crypt";
- argv[2] = 0;
-
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- switch (action) {
- case Z90CRYPT_HOTPLUG_ADD:
- envp[2] = "ACTION=add";
- break;
- case Z90CRYPT_HOTPLUG_REMOVE:
- envp[2] = "ACTION=remove";
- break;
- default:
- BUG();
- break;
- }
- envp[3] = major;
- envp[4] = minor;
- envp[5] = 0;
-
- call_usermodehelper(argv[0], argv, envp, 0);
-#endif
-}
-#endif
-
module_init(z90crypt_init_module);
module_exit(z90crypt_cleanup_module);
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 24c0af4..3092473 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -2,9 +2,9 @@
* drivers/s390/net/claw.c
* ESCON CLAW network driver
*
- * $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $
+ * $Revision: 1.38 $ $Date: 2005/08/29 09:47:04 $
*
- * Linux fo zSeries version
+ * Linux for zSeries version
* Copyright (C) 2002,2005 IBM Corporation
* Author(s) Original code written by:
* Kazuo Iimura (iimura@jp.ibm.com)
@@ -431,12 +431,12 @@
if (!skb_queue_empty(&p_ch->collect_queue)) {
/* some data */
held_skb = skb_dequeue(&p_ch->collect_queue);
- if (p_env->packing != DO_PACKED)
- return held_skb;
if (held_skb)
- atomic_dec(&held_skb->users);
+ dev_kfree_skb_any(held_skb);
else
return NULL;
+ if (p_env->packing != DO_PACKED)
+ return held_skb;
/* get a new SKB we will pack at least one */
new_skb = dev_alloc_skb(p_env->write_size);
if (new_skb == NULL) {
@@ -455,7 +455,7 @@
privptr->stats.tx_packets++;
so_far += held_skb->len;
pkt_cnt++;
- dev_kfree_skb_irq(held_skb);
+ dev_kfree_skb_any(held_skb);
held_skb = skb_dequeue(&p_ch->collect_queue);
if (held_skb)
atomic_dec(&held_skb->users);
@@ -1092,7 +1092,7 @@
}
}
if (privptr->pk_skb != NULL) {
- dev_kfree_skb(privptr->pk_skb);
+ dev_kfree_skb_any(privptr->pk_skb);
privptr->pk_skb = NULL;
}
if(privptr->buffs_alloc != 1) {
@@ -2016,7 +2016,7 @@
p_buf=(struct ccwbk*)privptr->p_end_ccw;
dumpit((char *)p_buf, sizeof(struct endccw));
#endif
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
if (linkid==0) {
lock=LOCK_NO;
}
@@ -4061,7 +4061,7 @@
while ((skb = skb_dequeue(q))) {
atomic_dec(&skb->users);
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb_any(skb);
}
}
@@ -4410,7 +4410,7 @@
#else
"compiled into kernel "
#endif
- " $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $ \n");
+ " $Revision: 1.38 $ $Date: 2005/08/29 09:47:04 $ \n");
#ifdef FUNCTRACE
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 5bb255e..4191fd9 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -240,7 +240,7 @@
* Floating point control register can't be restored.
* Task will be terminated.
*/
- asm volatile ("lfpc 0(%0)" : : "a" (&zero));
+ asm volatile ("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
kill_task = 1;
}
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index a41778a..3a81529 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -69,11 +69,40 @@
If you say Y here, you will be able to boot from your JavaStation's
Flash memory.
-# XXX Why don't we do "source drivers/char/Config.in" somewhere?
-# no shit
-config RTC
- tristate "PC-style Real Time Clock Support"
- depends on PCI && EXPERIMENTAL && SPARC32
+config BBC_I2C
+ tristate "UltraSPARC-III bootbus i2c controller driver"
+ depends on PCI && SPARC64
+ help
+ The BBC devices on the UltraSPARC III have two I2C controllers. The
+ first I2C controller connects mainly to configuration PROMs (NVRAM,
+ CPU configuration, DIMM types, etc.). The second I2C controller
+ connects to environmental control devices such as fans and
+ temperature sensors. The second controller also connects to the
+ smartcard reader, if present. Say Y to enable support for these.
+
+config ENVCTRL
+ tristate "SUNW, envctrl support"
+ depends on PCI && SPARC64
+ help
+ Kernel support for temperature and fan monitoring on Sun SME
+ machines.
+
+ To compile this driver as a module, choose M here: the
+ module will be called envctrl.
+
+config DISPLAY7SEG
+ tristate "7-Segment Display support"
+ depends on PCI && SPARC64
+ ---help---
+ This is the driver for the 7-segment display and LED present on
+ Sun Microsystems CompactPCI models CP1400 and CP1500.
+
+ To compile this driver as a module, choose M here: the
+ module will be called display7seg.
+
+ If you do not have a CompactPCI model CP1400 or CP1500, or
+ another UltraSPARC-IIi-cEngine boardset with a 7-segment display,
+ you should say N to this option.
endmenu
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 973c51f..ae9e020 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1499,22 +1499,43 @@
return 0;
} /* End tw_scsiop_inquiry() */
+static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
+ void *data, unsigned int len)
+{
+ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+ void *buf;
+ unsigned int transfer_len;
+
+ if (cmd->use_sg) {
+ struct scatterlist *sg =
+ (struct scatterlist *)cmd->request_buffer;
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ transfer_len = min(sg->length, len);
+ } else {
+ buf = cmd->request_buffer;
+ transfer_len = min(cmd->request_bufflen, len);
+ }
+
+ memcpy(buf, data, transfer_len);
+
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ }
+}
+
/* This function is called by the isr to complete an inquiry command */
static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
{
unsigned char *is_unit_present;
- unsigned char *request_buffer;
+ unsigned char request_buffer[36];
TW_Param *param;
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
- /* Fill request buffer */
- if (tw_dev->srb[request_id]->request_buffer == NULL) {
- printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n");
- return 1;
- }
- request_buffer = tw_dev->srb[request_id]->request_buffer;
- memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+ memset(request_buffer, 0, sizeof(request_buffer));
request_buffer[0] = TYPE_DISK; /* Peripheral device type */
request_buffer[1] = 0; /* Device type modifier */
request_buffer[2] = 0; /* No ansi/iso compliance */
@@ -1522,6 +1543,8 @@
memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */
sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3);
+ tw_transfer_internal(tw_dev, request_id, request_buffer,
+ sizeof(request_buffer));
param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
if (param == NULL) {
@@ -1612,7 +1635,7 @@
{
TW_Param *param;
unsigned char *flags;
- unsigned char *request_buffer;
+ unsigned char request_buffer[8];
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
@@ -1622,8 +1645,7 @@
return 1;
}
flags = (char *)&(param->data[0]);
- request_buffer = tw_dev->srb[request_id]->buffer;
- memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+ memset(request_buffer, 0, sizeof(request_buffer));
request_buffer[0] = 0xf; /* mode data length */
request_buffer[1] = 0; /* default medium type */
@@ -1635,6 +1657,8 @@
request_buffer[6] = 0x4; /* WCE on */
else
request_buffer[6] = 0x0; /* WCE off */
+ tw_transfer_internal(tw_dev, request_id, request_buffer,
+ sizeof(request_buffer));
return 0;
} /* End tw_scsiop_mode_sense_complete() */
@@ -1701,17 +1725,12 @@
{
unsigned char *param_data;
u32 capacity;
- char *buff;
+ char buff[8];
TW_Param *param;
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
- buff = tw_dev->srb[request_id]->request_buffer;
- if (buff == NULL) {
- printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n");
- return 1;
- }
- memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
+ memset(buff, 0, sizeof(buff));
param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
if (param == NULL) {
printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n");
@@ -1739,6 +1758,8 @@
buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
buff[7] = TW_BLOCK_SIZE & 0xff;
+ tw_transfer_internal(tw_dev, request_id, buff, sizeof(buff));
+
return 0;
} /* End tw_scsiop_read_capacity_complete() */
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 12c208f..2d21265 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1,5 +1,11 @@
menu "SCSI device support"
+config RAID_ATTRS
+ tristate "RAID Transport Class"
+ default n
+ ---help---
+ Provides RAID
+
config SCSI
tristate "SCSI device support"
---help---
@@ -250,7 +256,7 @@
config SCSI_DECSII
tristate "DEC SII Scsi Driver"
- depends on MACH_DECSTATION && SCSI && MIPS32
+ depends on MACH_DECSTATION && SCSI && 32BIT
config BLK_DEV_3W_XXXX_RAID
tristate "3ware 5/6/7/8xxx ATA-RAID support"
@@ -459,6 +465,15 @@
If unsure, say N.
+config SCSI_SATA_MV
+ tristate "Marvell SATA support"
+ depends on SCSI_SATA && PCI && EXPERIMENTAL
+ help
+ This option enables support for the Marvell Serial ATA family.
+ Currently supports 88SX[56]0[48][01] chips.
+
+ If unsure, say N.
+
config SCSI_SATA_NV
tristate "NVIDIA SATA support"
depends on SCSI_SATA && PCI && EXPERIMENTAL
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 3746fb9..4b4fd94 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -22,6 +22,8 @@
obj-$(CONFIG_SCSI) += scsi_mod.o
+obj-$(CONFIG_RAID_ATTRS) += raid_class.o
+
# --- NOTE ORDERING HERE ---
# For kernel non-modular link, transport attributes need to
# be initialised before drivers
@@ -132,6 +134,7 @@
obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o
obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o
obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o
+obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index f8ec6fe..d40ba0b 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -88,6 +88,13 @@
*/
#include <scsi/scsi_dbg.h>
+#ifndef NDEBUG
+#define NDEBUG 0
+#endif
+#ifndef NDEBUG
+#define NDEBUG_ABORT 0
+#endif
+
#if (NDEBUG & NDEBUG_LISTS)
#define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
#define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
@@ -359,7 +366,7 @@
{PHASE_UNKNOWN, "UNKNOWN"}
};
-#ifdef NDEBUG
+#if NDEBUG
static struct {
unsigned char mask;
const char *name;
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 79ae73b..e1f2246 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -62,7 +62,7 @@
#define SYNC_MODE 0 /* Synchronous transfer mode */
-#if DEBUG
+#ifdef DEBUG
#undef NCR53C406A_DEBUG
#define NCR53C406A_DEBUG 1
#endif
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index ccdf440..a8e3dfc 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -133,6 +133,7 @@
static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
+static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
#ifdef AAC_DETAILED_STATUS_INFO
static char *aac_get_status_string(u32 status);
@@ -348,6 +349,27 @@
spin_unlock_irqrestore(host->host_lock, cpu_flags);
}
+static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len)
+{
+ void *buf;
+ unsigned int transfer_len;
+ struct scatterlist *sg = scsicmd->request_buffer;
+
+ if (scsicmd->use_sg) {
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ transfer_len = min(sg->length, len + offset);
+ } else {
+ buf = scsicmd->request_buffer;
+ transfer_len = min(scsicmd->request_bufflen, len + offset);
+ }
+
+ memcpy(buf + offset, data, transfer_len - offset);
+
+ if (scsicmd->use_sg)
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+
+}
+
static void get_container_name_callback(void *context, struct fib * fibptr)
{
struct aac_get_name_resp * get_name_reply;
@@ -363,18 +385,22 @@
/* Failure is irrelevant, using default value instead */
if ((le32_to_cpu(get_name_reply->status) == CT_OK)
&& (get_name_reply->data[0] != '\0')) {
- int count;
- char * dp;
- char * sp = get_name_reply->data;
+ char *sp = get_name_reply->data;
sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0';
while (*sp == ' ')
++sp;
- count = sizeof(((struct inquiry_data *)NULL)->inqd_pid);
- dp = ((struct inquiry_data *)scsicmd->request_buffer)->inqd_pid;
- if (*sp) do {
- *dp++ = (*sp) ? *sp++ : ' ';
- } while (--count > 0);
+ if (*sp) {
+ char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
+ int count = sizeof(d);
+ char *dp = d;
+ do {
+ *dp++ = (*sp) ? *sp++ : ' ';
+ } while (--count > 0);
+ aac_internal_transfer(scsicmd, d,
+ offsetof(struct inquiry_data, inqd_pid), sizeof(d));
+ }
}
+
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
fib_complete(fibptr);
@@ -777,34 +803,36 @@
/*
* 57 scatter gather elements
*/
- dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
- sizeof(struct aac_fibhdr) -
- sizeof(struct aac_write) + sizeof(struct sgmap)) /
- sizeof(struct sgmap);
- if (dev->dac_support) {
- /*
- * 38 scatter gather elements
- */
- dev->scsi_host_ptr->sg_tablesize =
- (dev->max_fib_size -
+ if (!(dev->raw_io_interface)) {
+ dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
sizeof(struct aac_fibhdr) -
- sizeof(struct aac_write64) +
- sizeof(struct sgmap64)) /
- sizeof(struct sgmap64);
- }
- dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
- if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
- /*
- * Worst case size that could cause sg overflow when
- * we break up SG elements that are larger than 64KB.
- * Would be nice if we could tell the SCSI layer what
- * the maximum SG element size can be. Worst case is
- * (sg_tablesize-1) 4KB elements with one 64KB
- * element.
- * 32bit -> 468 or 238KB 64bit -> 424 or 212KB
- */
- dev->scsi_host_ptr->max_sectors =
- (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
+ sizeof(struct aac_write) + sizeof(struct sgmap)) /
+ sizeof(struct sgmap);
+ if (dev->dac_support) {
+ /*
+ * 38 scatter gather elements
+ */
+ dev->scsi_host_ptr->sg_tablesize =
+ (dev->max_fib_size -
+ sizeof(struct aac_fibhdr) -
+ sizeof(struct aac_write64) +
+ sizeof(struct sgmap64)) /
+ sizeof(struct sgmap64);
+ }
+ dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
+ if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
+ /*
+ * Worst case size that could cause sg overflow when
+ * we break up SG elements that are larger than 64KB.
+ * Would be nice if we could tell the SCSI layer what
+ * the maximum SG element size can be. Worst case is
+ * (sg_tablesize-1) 4KB elements with one 64KB
+ * element.
+ * 32bit -> 468 or 238KB 64bit -> 424 or 212KB
+ */
+ dev->scsi_host_ptr->max_sectors =
+ (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
+ }
}
fib_complete(fibptr);
@@ -814,12 +842,11 @@
}
-static void read_callback(void *context, struct fib * fibptr)
+static void io_callback(void *context, struct fib * fibptr)
{
struct aac_dev *dev;
struct aac_read_reply *readreply;
struct scsi_cmnd *scsicmd;
- u32 lba;
u32 cid;
scsicmd = (struct scsi_cmnd *) context;
@@ -827,8 +854,7 @@
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
- lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
- dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+ dprintk((KERN_DEBUG "io_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3], jiffies));
if (fibptr == NULL)
BUG();
@@ -847,7 +873,7 @@
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
else {
#ifdef AAC_DETAILED_STATUS_INFO
- printk(KERN_WARNING "read_callback: io failed, status = %d\n",
+ printk(KERN_WARNING "io_callback: io failed, status = %d\n",
le32_to_cpu(readreply->status));
#endif
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
@@ -867,53 +893,6 @@
aac_io_done(scsicmd);
}
-static void write_callback(void *context, struct fib * fibptr)
-{
- struct aac_dev *dev;
- struct aac_write_reply *writereply;
- struct scsi_cmnd *scsicmd;
- u32 lba;
- u32 cid;
-
- scsicmd = (struct scsi_cmnd *) context;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
- cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
-
- lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
- dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
- if (fibptr == NULL)
- BUG();
-
- if(scsicmd->use_sg)
- pci_unmap_sg(dev->pdev,
- (struct scatterlist *)scsicmd->buffer,
- scsicmd->use_sg,
- scsicmd->sc_data_direction);
- else if(scsicmd->request_bufflen)
- pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
-
- writereply = (struct aac_write_reply *) fib_data(fibptr);
- if (le32_to_cpu(writereply->status) == ST_OK)
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
- else {
- printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR,
- SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 0, 0);
- memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
- sizeof(struct sense_data));
- }
-
- fib_complete(fibptr);
- fib_free(fibptr);
- aac_io_done(scsicmd);
-}
-
static int aac_read(struct scsi_cmnd * scsicmd, int cid)
{
u32 lba;
@@ -954,7 +933,32 @@
fib_init(cmd_fibcontext);
- if (dev->dac_support == 1) {
+ if (dev->raw_io_interface) {
+ struct aac_raw_io *readcmd;
+ readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
+ readcmd->block[0] = cpu_to_le32(lba);
+ readcmd->block[1] = 0;
+ readcmd->count = cpu_to_le32(count<<9);
+ readcmd->cid = cpu_to_le16(cid);
+ readcmd->flags = cpu_to_le16(1);
+ readcmd->bpTotal = 0;
+ readcmd->bpComplete = 0;
+
+ aac_build_sgraw(scsicmd, &readcmd->sg);
+ fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
+ if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
+ BUG();
+ /*
+ * Now send the Fib to the adapter
+ */
+ status = fib_send(ContainerRawIo,
+ cmd_fibcontext,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) scsicmd);
+ } else if (dev->dac_support == 1) {
struct aac_read64 *readcmd;
readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
readcmd->command = cpu_to_le32(VM_CtHostRead64);
@@ -968,7 +972,7 @@
fibsize = sizeof(struct aac_read64) +
((le32_to_cpu(readcmd->sg.count) - 1) *
sizeof (struct sgentry64));
- BUG_ON (fibsize > (sizeof(struct hw_fib) -
+ BUG_ON (fibsize > (dev->max_fib_size -
sizeof(struct aac_fibhdr)));
/*
* Now send the Fib to the adapter
@@ -978,7 +982,7 @@
fibsize,
FsaNormal,
0, 1,
- (fib_callback) read_callback,
+ (fib_callback) io_callback,
(void *) scsicmd);
} else {
struct aac_read *readcmd;
@@ -1002,7 +1006,7 @@
fibsize,
FsaNormal,
0, 1,
- (fib_callback) read_callback,
+ (fib_callback) io_callback,
(void *) scsicmd);
}
@@ -1061,7 +1065,32 @@
}
fib_init(cmd_fibcontext);
- if(dev->dac_support == 1) {
+ if (dev->raw_io_interface) {
+ struct aac_raw_io *writecmd;
+ writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
+ writecmd->block[0] = cpu_to_le32(lba);
+ writecmd->block[1] = 0;
+ writecmd->count = cpu_to_le32(count<<9);
+ writecmd->cid = cpu_to_le16(cid);
+ writecmd->flags = 0;
+ writecmd->bpTotal = 0;
+ writecmd->bpComplete = 0;
+
+ aac_build_sgraw(scsicmd, &writecmd->sg);
+ fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
+ if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
+ BUG();
+ /*
+ * Now send the Fib to the adapter
+ */
+ status = fib_send(ContainerRawIo,
+ cmd_fibcontext,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) scsicmd);
+ } else if (dev->dac_support == 1) {
struct aac_write64 *writecmd;
writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
writecmd->command = cpu_to_le32(VM_CtHostWrite64);
@@ -1085,7 +1114,7 @@
fibsize,
FsaNormal,
0, 1,
- (fib_callback) write_callback,
+ (fib_callback) io_callback,
(void *) scsicmd);
} else {
struct aac_write *writecmd;
@@ -1111,7 +1140,7 @@
fibsize,
FsaNormal,
0, 1,
- (fib_callback) write_callback,
+ (fib_callback) io_callback,
(void *) scsicmd);
}
@@ -1340,44 +1369,45 @@
switch (scsicmd->cmnd[0]) {
case INQUIRY:
{
- struct inquiry_data *inq_data_ptr;
+ struct inquiry_data inq_data;
dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id));
- inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
- memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
+ memset(&inq_data, 0, sizeof (struct inquiry_data));
- inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */
- inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */
- inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
- inq_data_ptr->inqd_len = 31;
+ inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
+ inq_data.inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */
+ inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
+ inq_data.inqd_len = 31;
/*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */
- inq_data_ptr->inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */
+ inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */
/*
* Set the Vendor, Product, and Revision Level
* see: <vendor>.c i.e. aac.c
*/
if (scsicmd->device->id == host->this_id) {
- setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *)));
- inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */
+ setinqstr(cardtype, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *)));
+ inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */
+ aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
}
- setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr[cid].type);
- inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
+ setinqstr(cardtype, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
+ inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
+ aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
return aac_get_container_name(scsicmd, cid);
}
case READ_CAPACITY:
{
u32 capacity;
- char *cp;
+ char cp[8];
dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
if (fsa_dev_ptr[cid].size <= 0x100000000LL)
capacity = fsa_dev_ptr[cid].size - 1;
else
capacity = (u32)-1;
- cp = scsicmd->request_buffer;
+
cp[0] = (capacity >> 24) & 0xff;
cp[1] = (capacity >> 16) & 0xff;
cp[2] = (capacity >> 8) & 0xff;
@@ -1386,6 +1416,7 @@
cp[5] = 0;
cp[6] = 2;
cp[7] = 0;
+ aac_internal_transfer(scsicmd, cp, 0, sizeof(cp));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -1395,15 +1426,15 @@
case MODE_SENSE:
{
- char *mode_buf;
+ char mode_buf[4];
dprintk((KERN_DEBUG "MODE SENSE command.\n"));
- mode_buf = scsicmd->request_buffer;
mode_buf[0] = 3; /* Mode data length */
mode_buf[1] = 0; /* Medium type - default */
mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */
mode_buf[3] = 0; /* Block descriptor length */
+ aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -1411,10 +1442,9 @@
}
case MODE_SENSE_10:
{
- char *mode_buf;
+ char mode_buf[8];
dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
- mode_buf = scsicmd->request_buffer;
mode_buf[0] = 0; /* Mode data length (MSB) */
mode_buf[1] = 6; /* Mode data length (LSB) */
mode_buf[2] = 0; /* Medium type - default */
@@ -1423,6 +1453,7 @@
mode_buf[5] = 0; /* reserved */
mode_buf[6] = 0; /* Block descriptor length (MSB) */
mode_buf[7] = 0; /* Block descriptor length (LSB) */
+ aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -1894,7 +1925,7 @@
srbcmd->id = cpu_to_le32(scsicmd->device->id);
srbcmd->lun = cpu_to_le32(scsicmd->device->lun);
srbcmd->flags = cpu_to_le32(flag);
- timeout = (scsicmd->timeout-jiffies)/HZ;
+ timeout = scsicmd->timeout_per_command/HZ;
if(timeout == 0){
timeout = 1;
}
@@ -2077,6 +2108,76 @@
return byte_count;
}
+static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
+{
+ struct Scsi_Host *host = scsicmd->device->host;
+ struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+ unsigned long byte_count = 0;
+
+ // Get rid of old data
+ psg->count = 0;
+ psg->sg[0].next = 0;
+ psg->sg[0].prev = 0;
+ psg->sg[0].addr[0] = 0;
+ psg->sg[0].addr[1] = 0;
+ psg->sg[0].count = 0;
+ psg->sg[0].flags = 0;
+ if (scsicmd->use_sg) {
+ struct scatterlist *sg;
+ int i;
+ int sg_count;
+ sg = (struct scatterlist *) scsicmd->request_buffer;
+
+ sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+ scsicmd->sc_data_direction);
+
+ for (i = 0; i < sg_count; i++) {
+ int count = sg_dma_len(sg);
+ u64 addr = sg_dma_address(sg);
+ psg->sg[i].next = 0;
+ psg->sg[i].prev = 0;
+ psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
+ psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+ psg->sg[i].count = cpu_to_le32(count);
+ psg->sg[i].flags = 0;
+ byte_count += count;
+ sg++;
+ }
+ psg->count = cpu_to_le32(sg_count);
+ /* hba wants the size to be exact */
+ if(byte_count > scsicmd->request_bufflen){
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsicmd->request_bufflen);
+ psg->sg[i-1].count = cpu_to_le32(temp);
+ byte_count = scsicmd->request_bufflen;
+ }
+ /* Check for command underflow */
+ if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+ printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+ byte_count, scsicmd->underflow);
+ }
+ }
+ else if(scsicmd->request_bufflen) {
+ int count;
+ u64 addr;
+ scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
+ scsicmd->request_buffer,
+ scsicmd->request_bufflen,
+ scsicmd->sc_data_direction);
+ addr = scsicmd->SCp.dma_handle;
+ count = scsicmd->request_bufflen;
+ psg->count = cpu_to_le32(1);
+ psg->sg[0].next = 0;
+ psg->sg[0].prev = 0;
+ psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32));
+ psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+ psg->sg[0].count = cpu_to_le32(count);
+ psg->sg[0].flags = 0;
+ byte_count = scsicmd->request_bufflen;
+ }
+ return byte_count;
+}
+
#ifdef AAC_DETAILED_STATUS_INFO
struct aac_srb_status_info {
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 4ab0786..e405281 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -110,6 +110,22 @@
u32 count; /* Length. */
};
+struct sgentryraw {
+ __le32 next; /* reserved for F/W use */
+ __le32 prev; /* reserved for F/W use */
+ __le32 addr[2];
+ __le32 count;
+ __le32 flags; /* reserved for F/W use */
+};
+
+struct user_sgentryraw {
+ u32 next; /* reserved for F/W use */
+ u32 prev; /* reserved for F/W use */
+ u32 addr[2];
+ u32 count;
+ u32 flags; /* reserved for F/W use */
+};
+
/*
* SGMAP
*
@@ -137,6 +153,16 @@
struct user_sgentry64 sg[1];
};
+struct sgmapraw {
+ __le32 count;
+ struct sgentryraw sg[1];
+};
+
+struct user_sgmapraw {
+ u32 count;
+ struct user_sgentryraw sg[1];
+};
+
struct creation_info
{
u8 buildnum; /* e.g., 588 */
@@ -351,6 +377,7 @@
*/
#define ContainerCommand 500
#define ContainerCommand64 501
+#define ContainerRawIo 502
/*
* Cluster Commands
*/
@@ -456,6 +483,7 @@
{
void (*adapter_interrupt)(struct aac_dev *dev);
void (*adapter_notify)(struct aac_dev *dev, u32 event);
+ void (*adapter_disable_int)(struct aac_dev *dev);
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
};
@@ -981,6 +1009,9 @@
u8 nondasd_support;
u8 dac_support;
u8 raid_scsi_mode;
+ /* macro side-effects BEWARE */
+# define raw_io_interface \
+ init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
u8 printf_enabled;
};
@@ -990,6 +1021,9 @@
#define aac_adapter_notify(dev, event) \
(dev)->a_ops.adapter_notify(dev, event)
+#define aac_adapter_disable_int(dev) \
+ (dev)->a_ops.adapter_disable_int(dev)
+
#define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \
(dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4)
@@ -1156,6 +1190,17 @@
__le32 committed;
};
+struct aac_raw_io
+{
+ __le32 block[2];
+ __le32 count;
+ __le16 cid;
+ __le16 flags; /* 00 W, 01 R */
+ __le16 bpTotal; /* reserved for F/W use */
+ __le16 bpComplete; /* reserved for F/W use */
+ struct sgmapraw sg;
+};
+
#define CT_FLUSH_CACHE 129
struct aac_synchronize {
__le32 command; /* VM_ContainerConfig */
@@ -1196,7 +1241,7 @@
};
/*
- * This and assocated data structs are used by the
+ * This and associated data structs are used by the
* ioctl caller and are in cpu order.
*/
struct user_aac_srb
@@ -1508,11 +1553,12 @@
struct revision
{
- u32 compat;
- u32 version;
- u32 build;
+ __le32 compat;
+ __le32 version;
+ __le32 build;
};
+
/*
* Ugly - non Linux like ioctl coding for back compat.
*/
@@ -1733,3 +1779,4 @@
int aac_send_shutdown(struct aac_dev *dev);
extern int numacb;
extern int acbsize;
+extern char aac_driver_version[];
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 8538709..71f1cad 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -287,7 +287,6 @@
kfree(fib->hw_fib);
kfree(fib);
status = 0;
- fibctx->jiffies = jiffies/HZ;
} else {
spin_unlock_irqrestore(&dev->fib_lock, flags);
if (f.wait) {
@@ -302,6 +301,7 @@
status = -EAGAIN;
}
}
+ fibctx->jiffies = jiffies/HZ;
return status;
}
@@ -405,10 +405,20 @@
static int check_revision(struct aac_dev *dev, void __user *arg)
{
struct revision response;
+ char *driver_version = aac_driver_version;
+ u32 version;
- response.compat = 1;
- response.version = le32_to_cpu(dev->adapter_info.kernelrev);
- response.build = le32_to_cpu(dev->adapter_info.kernelbuild);
+ response.compat = cpu_to_le32(1);
+ version = (simple_strtol(driver_version,
+ &driver_version, 10) << 24) | 0x00000400;
+ version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
+ version += simple_strtol(driver_version + 1, NULL, 10);
+ response.version = cpu_to_le32(version);
+# if (defined(AAC_DRIVER_BUILD))
+ response.build = cpu_to_le32(AAC_DRIVER_BUILD);
+# else
+ response.build = cpu_to_le32(9999);
+# endif
if (copy_to_user(arg, &response, sizeof(response)))
return -EFAULT;
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 43557bf..75abd04 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -44,7 +44,9 @@
#include "aacraid.h"
-struct aac_common aac_config;
+struct aac_common aac_config = {
+ .irq_mod = 1
+};
static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
{
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 5322865..a1d303f0 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -254,6 +254,7 @@
static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
{
struct aac_queue * q;
+ unsigned long idx;
/*
* All of the queues wrap when they reach the end, so we check
@@ -263,10 +264,23 @@
*/
q = &dev->queues->queue[qid];
-
- *index = le32_to_cpu(*(q->headers.producer));
- if ((*index - 2) == le32_to_cpu(*(q->headers.consumer)))
+
+ idx = *index = le32_to_cpu(*(q->headers.producer));
+ /* Interrupt Moderation, only interrupt for first two entries */
+ if (idx != le32_to_cpu(*(q->headers.consumer))) {
+ if (--idx == 0) {
+ if (qid == AdapHighCmdQueue)
+ idx = ADAP_HIGH_CMD_ENTRIES;
+ else if (qid == AdapNormCmdQueue)
+ idx = ADAP_NORM_CMD_ENTRIES;
+ else if (qid == AdapHighRespQueue)
+ idx = ADAP_HIGH_RESP_ENTRIES;
+ else if (qid == AdapNormRespQueue)
+ idx = ADAP_NORM_RESP_ENTRIES;
+ }
+ if (idx != le32_to_cpu(*(q->headers.consumer)))
*nonotify = 1;
+ }
if (qid == AdapHighCmdQueue) {
if (*index >= ADAP_HIGH_CMD_ENTRIES)
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 562da90..4ff29d7 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -27,8 +27,11 @@
* Abstract: Linux Driver entry module for Adaptec RAID Array Controller
*/
-#define AAC_DRIVER_VERSION "1.1.2-lk2"
-#define AAC_DRIVER_BUILD_DATE __DATE__
+#define AAC_DRIVER_VERSION "1.1-4"
+#ifndef AAC_DRIVER_BRANCH
+#define AAC_DRIVER_BRANCH ""
+#endif
+#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__
#define AAC_DRIVERNAME "aacraid"
#include <linux/compat.h>
@@ -58,16 +61,24 @@
#include "aacraid.h"
+#ifdef AAC_DRIVER_BUILD
+#define _str(x) #x
+#define str(x) _str(x)
+#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH
+#else
+#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE
+#endif
MODULE_AUTHOR("Red Hat Inc and Adaptec");
MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, "
"Adaptec Advanced Raid Products, "
"and HP NetRAID-4M SCSI driver");
MODULE_LICENSE("GPL");
-MODULE_VERSION(AAC_DRIVER_VERSION);
+MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
static LIST_HEAD(aac_devices);
static int aac_cfg_major = -1;
+char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
/*
* Because of the way Linux names scsi devices, the order in this table has
@@ -109,36 +120,39 @@
{ 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */
{ 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */
{ 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */
- { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 32 }, /* Themisto Jupiter Platform */
- { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 32 }, /* Themisto Jupiter Platform */
- { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 33 }, /* Callisto Jupiter Platform */
- { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 34 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
- { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 35 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
- { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 36 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
- { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 37 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
- { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 38 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
- { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 39 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
- { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 40 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
- { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 41 }, /* AAR-2610SA PCI SATA 6ch */
- { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 42 }, /* ASR-2240S (SabreExpress) */
- { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 43 }, /* ASR-4005SAS */
- { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 44 }, /* IBM 8i (AvonPark) */
- { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 44 }, /* IBM 8i (AvonPark Lite) */
- { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 45 }, /* ASR-4000SAS (BlackBird) */
- { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 46 }, /* ASR-4800SAS (Marauder-X) */
- { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 47 }, /* ASR-4805SAS (Marauder-E) */
- { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 48 }, /* ASR-4810SAS (Hurricane */
+ { 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */
+ { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 33 }, /* Themisto Jupiter Platform */
+ { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 33 }, /* Themisto Jupiter Platform */
+ { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 34 }, /* Callisto Jupiter Platform */
+ { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 35 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
+ { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 36 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
+ { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 37 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+ { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 38 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+ { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 39 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+ { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 40 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+ { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+ { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */
+ { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */
+ { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */
+ { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */
+ { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */
+ { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */
+ { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */
+ { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */
+ { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */
+ { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */
+ { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-4810SAS (Hurricane */
- { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 49 }, /* Perc 320/DC*/
- { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 50 }, /* Adaptec 5400S (Mustang)*/
- { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 51 }, /* Adaptec 5400S (Mustang)*/
- { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 52 }, /* Dell PERC2/QC */
- { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 53 }, /* HP NetRAID-4M */
+ { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/
+ { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/
+ { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 54 }, /* Adaptec 5400S (Mustang)*/
+ { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 55 }, /* Dell PERC2/QC */
+ { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 56 }, /* HP NetRAID-4M */
- { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 54 }, /* Dell Catchall */
- { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 55 }, /* Legend Catchall */
- { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 56 }, /* Adaptec Catch All */
- { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 57 }, /* Adaptec Rocket Catch All */
+ { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 57 }, /* Dell Catchall */
+ { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */
+ { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
+ { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
{ 0,}
};
MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -180,8 +194,9 @@
{ aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP5085AU ", 1 }, /* ICP5085AU (Hurricane) */
- { aac_rkt_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */
- { aac_rkt_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */
+ { aac_rx_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */
+ { aac_rx_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */
+ { aac_rkt_init, "aacraid", "ICP ", "ICP9067MA ", 1 }, /* ICP9067MA (Intruder-6) */
{ NULL , "aacraid", "ADAPTEC ", "Themisto ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */
{ aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
@@ -195,10 +210,12 @@
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */
{ aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */
+ { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */
+ { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */
- { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */
+ { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */
{ aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
@@ -839,11 +856,12 @@
return 0;
-out_deinit:
+ out_deinit:
kill_proc(aac->thread_pid, SIGKILL, 0);
wait_for_completion(&aac->aif_completion);
aac_send_shutdown(aac);
+ aac_adapter_disable_int(aac);
fib_map_free(aac);
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
kfree(aac->queues);
@@ -860,6 +878,13 @@
return error;
}
+static void aac_shutdown(struct pci_dev *dev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(dev);
+ struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+ aac_send_shutdown(aac);
+}
+
static void __devexit aac_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -871,6 +896,7 @@
wait_for_completion(&aac->aif_completion);
aac_send_shutdown(aac);
+ aac_adapter_disable_int(aac);
fib_map_free(aac);
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr,
aac->comm_phys);
@@ -891,14 +917,15 @@
.id_table = aac_pci_tbl,
.probe = aac_probe_one,
.remove = __devexit_p(aac_remove_one),
+ .shutdown = aac_shutdown,
};
static int __init aac_init(void)
{
int error;
- printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n",
- AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE);
+ printk(KERN_INFO "Adaptec %s driver (%s)\n",
+ AAC_DRIVERNAME, aac_driver_version);
error = pci_module_init(&aac_pci_driver);
if (error)
@@ -909,6 +936,7 @@
printk(KERN_WARNING
"aacraid: unable to register \"aac\" device.\n");
}
+
return 0;
}
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index 7d68b78..557287a 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -88,6 +88,16 @@
}
/**
+ * aac_rkt_disable_interrupt - Disable interrupts
+ * @dev: Adapter
+ */
+
+static void aac_rkt_disable_interrupt(struct aac_dev *dev)
+{
+ rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
+}
+
+/**
* rkt_sync_cmd - send a command and wait
* @dev: Adapter
* @command: Command to execute
@@ -412,10 +422,19 @@
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
+ dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
dev->a_ops.adapter_check_health = aac_rkt_check_health;
+ /*
+ * First clear out all interrupts. Then enable the one's that we
+ * can handle.
+ */
+ rkt_writeb(dev, MUnit.OIMR, 0xff);
+ rkt_writel(dev, MUnit.ODR, 0xffffffff);
+ rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+
if (aac_init_adapter(dev) == NULL)
goto error_irq;
/*
@@ -438,6 +457,7 @@
kfree(dev->queues);
error_irq:
+ rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap:
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 1ff25f4..a8459fa 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -88,6 +88,16 @@
}
/**
+ * aac_rx_disable_interrupt - Disable interrupts
+ * @dev: Adapter
+ */
+
+static void aac_rx_disable_interrupt(struct aac_dev *dev)
+{
+ rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
+}
+
+/**
* rx_sync_cmd - send a command and wait
* @dev: Adapter
* @command: Command to execute
@@ -412,10 +422,19 @@
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
+ dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
dev->a_ops.adapter_notify = aac_rx_notify_adapter;
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
+ /*
+ * First clear out all interrupts. Then enable the one's that we
+ * can handle.
+ */
+ rx_writeb(dev, MUnit.OIMR, 0xff);
+ rx_writel(dev, MUnit.ODR, 0xffffffff);
+ rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+
if (aac_init_adapter(dev) == NULL)
goto error_irq;
/*
@@ -438,6 +457,7 @@
kfree(dev->queues);
error_irq:
+ rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap:
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 0680249..3900abc 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -82,6 +82,16 @@
}
/**
+ * aac_sa_disable_interrupt - disable interrupt
+ * @dev: Which adapter to enable.
+ */
+
+static void aac_sa_disable_interrupt (struct aac_dev *dev)
+{
+ sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
+}
+
+/**
* aac_sa_notify_adapter - handle adapter notification
* @dev: Adapter that notification is for
* @event: Event to notidy
@@ -214,9 +224,8 @@
static void aac_sa_interrupt_adapter (struct aac_dev *dev)
{
- u32 ret;
sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
- &ret, NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL);
}
/**
@@ -352,10 +361,18 @@
*/
dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
+ dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
dev->a_ops.adapter_notify = aac_sa_notify_adapter;
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health;
+ /*
+ * First clear out all interrupts. Then enable the one's that
+ * we can handle.
+ */
+ sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
+ sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
+ DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
if(aac_init_adapter(dev) == NULL)
goto error_irq;
@@ -381,6 +398,7 @@
kfree(dev->queues);
error_irq:
+ sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap:
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 0fb9336..37ec541 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -9200,8 +9200,8 @@
(unsigned) s->serial_number, s->retries, s->allowed);
printk(
-" timeout_per_command %d, timeout_total %d, timeout %d\n",
- s->timeout_per_command, s->timeout_total, s->timeout);
+" timeout_per_command %d\n",
+ s->timeout_per_command);
printk(
" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 179c95c..320df6c 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -189,7 +189,6 @@
static void ahci_eng_timeout(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
-static void ahci_host_stop(struct ata_host_set *host_set);
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
@@ -242,7 +241,6 @@
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
- .host_stop = ahci_host_stop,
};
static struct ata_port_info ahci_port_info[] = {
@@ -252,7 +250,7 @@
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
ATA_FLAG_PIO_DMA,
- .pio_mask = 0x03, /* pio3-4 */
+ .pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
@@ -296,17 +294,9 @@
return base + 0x100 + (port * 0x80);
}
-static inline void *ahci_port_base (void *base, unsigned int port)
+static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
{
- return (void *) ahci_port_base_ul((unsigned long)base, port);
-}
-
-static void ahci_host_stop(struct ata_host_set *host_set)
-{
- struct ahci_host_priv *hpriv = host_set->private_data;
- kfree(hpriv);
-
- ata_host_stop(host_set);
+ return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
}
static int ahci_port_start(struct ata_port *ap)
@@ -314,8 +304,9 @@
struct device *dev = ap->host_set->dev;
struct ahci_host_priv *hpriv = ap->host_set->private_data;
struct ahci_port_priv *pp;
- void *mem, *mmio = ap->host_set->mmio_base;
- void *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void *mem;
dma_addr_t mem_dma;
pp = kmalloc(sizeof(*pp), GFP_KERNEL);
@@ -383,8 +374,8 @@
{
struct device *dev = ap->host_set->dev;
struct ahci_port_priv *pp = ap->private_data;
- void *mmio = ap->host_set->mmio_base;
- void *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
tmp = readl(port_mmio + PORT_CMD);
@@ -546,8 +537,8 @@
static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
{
- void *mmio = ap->host_set->mmio_base;
- void *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
int work;
@@ -595,8 +586,8 @@
static void ahci_eng_timeout(struct ata_port *ap)
{
struct ata_host_set *host_set = ap->host_set;
- void *mmio = host_set->mmio_base;
- void *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *mmio = host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
struct ata_queued_cmd *qc;
unsigned long flags;
@@ -626,8 +617,8 @@
static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
{
- void *mmio = ap->host_set->mmio_base;
- void *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 status, serr, ci;
serr = readl(port_mmio + PORT_SCR_ERR);
@@ -663,7 +654,7 @@
struct ata_host_set *host_set = dev_instance;
struct ahci_host_priv *hpriv;
unsigned int i, handled = 0;
- void *mmio;
+ void __iomem *mmio;
u32 irq_stat, irq_ack = 0;
VPRINTK("ENTER\n");
@@ -709,7 +700,7 @@
static int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void *port_mmio = (void *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
writel(1, port_mmio + PORT_CMD_ISSUE);
readl(port_mmio + PORT_CMD_ISSUE); /* flush */
@@ -894,7 +885,7 @@
{
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->mmio_base;
u32 vers, cap, impl, speed;
const char *speed_s;
u16 cc;
@@ -967,7 +958,7 @@
struct ata_probe_ent *probe_ent = NULL;
struct ahci_host_priv *hpriv;
unsigned long base;
- void *mmio_base;
+ void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
int have_msi, pci_dev_busy = 0;
int rc;
@@ -1004,8 +995,7 @@
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR),
- pci_resource_len(pdev, AHCI_PCI_BAR));
+ mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
@@ -1049,7 +1039,7 @@
err_out_hpriv:
kfree(hpriv);
err_out_iounmap:
- iounmap(mmio_base);
+ pci_iounmap(pdev, mmio_base);
err_out_free_ent:
kfree(probe_ent);
err_out_msi:
@@ -1089,7 +1079,8 @@
scsi_host_put(ap->host);
}
- host_set->ops->host_stop(host_set);
+ kfree(hpriv);
+ pci_iounmap(pdev, host_set->mmio_base);
kfree(host_set);
if (have_msi)
@@ -1106,7 +1097,6 @@
return pci_module_init(&ahci_pci_driver);
}
-
static void __exit ahci_exit(void)
{
pci_unregister_driver(&ahci_pci_driver);
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index c2523a3..69ed77f 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -5,6 +5,7 @@
config SCSI_AIC79XX
tristate "Adaptec AIC79xx U320 support"
depends on PCI && SCSI
+ select SCSI_SPI_ATTRS
help
This driver supports all of Adaptec's Ultra 320 PCI-X
based SCSI controllers.
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index 00f3bd1..527efd3 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -126,7 +126,6 @@
int
aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
{
- u_long l;
int error;
int have_seeprom;
u_int hostconf;
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index fd4b2f3..653fb0b 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1247,9 +1247,6 @@
uint16_t user_tagenable;/* Tagged Queuing allowed */
};
-TAILQ_HEAD(ahd_softc_tailq, ahd_softc);
-extern struct ahd_softc_tailq ahd_tailq;
-
/*************************** IO Cell Configuration ****************************/
#define AHD_PRECOMP_SLEW_INDEX \
(AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0)
@@ -1374,8 +1371,6 @@
void ahd_pause_and_flushwork(struct ahd_softc *ahd);
int ahd_suspend(struct ahd_softc *ahd);
int ahd_resume(struct ahd_softc *ahd);
-void ahd_softc_insert(struct ahd_softc *);
-struct ahd_softc *ahd_find_softc(struct ahd_softc *ahd);
void ahd_set_unit(struct ahd_softc *, int);
void ahd_set_name(struct ahd_softc *, char *);
struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
@@ -1524,7 +1519,6 @@
void ahd_print_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
void ahd_dump_sglist(struct scb *scb);
-void ahd_dump_all_cards_state(void);
void ahd_dump_card_state(struct ahd_softc *ahd);
int ahd_print_register(ahd_reg_parse_entry_t *table,
u_int num_entries,
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 137fb1a..4e8f00d 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -52,8 +52,6 @@
#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
#endif
-/******************************** Globals *************************************/
-struct ahd_softc_tailq ahd_tailq = TAILQ_HEAD_INITIALIZER(ahd_tailq);
/***************************** Lookup Tables **********************************/
char *ahd_chip_names[] =
@@ -5180,74 +5178,6 @@
}
void
-ahd_softc_insert(struct ahd_softc *ahd)
-{
- struct ahd_softc *list_ahd;
-
-#if AHD_PCI_CONFIG > 0
- /*
- * Second Function PCI devices need to inherit some
- * settings from function 0.
- */
- if ((ahd->features & AHD_MULTI_FUNC) != 0) {
- TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
- ahd_dev_softc_t list_pci;
- ahd_dev_softc_t pci;
-
- list_pci = list_ahd->dev_softc;
- pci = ahd->dev_softc;
- if (ahd_get_pci_slot(list_pci) == ahd_get_pci_slot(pci)
- && ahd_get_pci_bus(list_pci) == ahd_get_pci_bus(pci)) {
- struct ahd_softc *master;
- struct ahd_softc *slave;
-
- if (ahd_get_pci_function(list_pci) == 0) {
- master = list_ahd;
- slave = ahd;
- } else {
- master = ahd;
- slave = list_ahd;
- }
- slave->flags &= ~AHD_BIOS_ENABLED;
- slave->flags |=
- master->flags & AHD_BIOS_ENABLED;
- break;
- }
- }
- }
-#endif
-
- /*
- * Insertion sort into our list of softcs.
- */
- list_ahd = TAILQ_FIRST(&ahd_tailq);
- while (list_ahd != NULL
- && ahd_softc_comp(ahd, list_ahd) <= 0)
- list_ahd = TAILQ_NEXT(list_ahd, links);
- if (list_ahd != NULL)
- TAILQ_INSERT_BEFORE(list_ahd, ahd, links);
- else
- TAILQ_INSERT_TAIL(&ahd_tailq, ahd, links);
- ahd->init_level++;
-}
-
-/*
- * Verify that the passed in softc pointer is for a
- * controller that is still configured.
- */
-struct ahd_softc *
-ahd_find_softc(struct ahd_softc *ahd)
-{
- struct ahd_softc *list_ahd;
-
- TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
- if (list_ahd == ahd)
- return (ahd);
- }
- return (NULL);
-}
-
-void
ahd_set_unit(struct ahd_softc *ahd, int unit)
{
ahd->unit = unit;
@@ -7902,18 +7832,10 @@
static void
ahd_reset_poll(void *arg)
{
- struct ahd_softc *ahd;
+ struct ahd_softc *ahd = arg;
u_int scsiseq1;
- u_long l;
u_long s;
- ahd_list_lock(&l);
- ahd = ahd_find_softc((struct ahd_softc *)arg);
- if (ahd == NULL) {
- printf("ahd_reset_poll: Instance %p no longer exists\n", arg);
- ahd_list_unlock(&l);
- return;
- }
ahd_lock(ahd, &s);
ahd_pause(ahd);
ahd_update_modes(ahd);
@@ -7924,7 +7846,6 @@
ahd_reset_poll, ahd);
ahd_unpause(ahd);
ahd_unlock(ahd, &s);
- ahd_list_unlock(&l);
return;
}
@@ -7936,25 +7857,16 @@
ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
ahd_unlock(ahd, &s);
ahd_release_simq(ahd);
- ahd_list_unlock(&l);
}
/**************************** Statistics Processing ***************************/
static void
ahd_stat_timer(void *arg)
{
- struct ahd_softc *ahd;
- u_long l;
+ struct ahd_softc *ahd = arg;
u_long s;
int enint_coal;
- ahd_list_lock(&l);
- ahd = ahd_find_softc((struct ahd_softc *)arg);
- if (ahd == NULL) {
- printf("ahd_stat_timer: Instance %p no longer exists\n", arg);
- ahd_list_unlock(&l);
- return;
- }
ahd_lock(ahd, &s);
enint_coal = ahd->hs_mailbox & ENINT_COALESCE;
@@ -7981,7 +7893,6 @@
ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US,
ahd_stat_timer, ahd);
ahd_unlock(ahd, &s);
- ahd_list_unlock(&l);
}
/****************************** Status Processing *****************************/
@@ -8745,16 +8656,6 @@
return (last_probe);
}
-void
-ahd_dump_all_cards_state(void)
-{
- struct ahd_softc *list_ahd;
-
- TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
- ahd_dump_card_state(list_ahd);
- }
-}
-
int
ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
const char *name, u_int address, u_int value,
@@ -9039,7 +8940,6 @@
ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF);
}
printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
- ahd_platform_dump_card_state(ahd);
ahd_restore_modes(ahd, saved_modes);
if (paused == 0)
ahd_unpause(ahd);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 329cb23..6b6d4e2 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -46,32 +46,14 @@
#include "aic79xx_inline.h"
#include <scsi/scsicam.h>
-/*
- * Include aiclib.c as part of our
- * "module dependencies are hard" work around.
- */
-#include "aiclib.c"
+static struct scsi_transport_template *ahd_linux_transport_template = NULL;
#include <linux/init.h> /* __setup */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "sd.h" /* For geometry detection */
-#endif
-
#include <linux/mm.h> /* For fetching system memory size */
+#include <linux/blkdev.h> /* For block_size() */
#include <linux/delay.h> /* For ssleep/msleep */
/*
- * Lock protecting manipulation of the ahd softc list.
- */
-spinlock_t ahd_list_spinlock;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/* For dynamic sglist size calculation. */
-u_int ahd_linux_nseg;
-#endif
-
-/*
* Bucket size for counting good commands in between bad ones.
*/
#define AHD_LINUX_ERR_THRESH 1000
@@ -188,71 +170,6 @@
};
/*
- * By default, read streaming is disabled. In theory,
- * read streaming should enhance performance, but early
- * U320 drive firmware actually performs slower with
- * read streaming enabled.
- */
-#ifdef CONFIG_AIC79XX_ENABLE_RD_STRM
-#define AIC79XX_CONFIGED_RD_STRM 0xFFFF
-#else
-#define AIC79XX_CONFIGED_RD_STRM 0
-#endif
-
-static uint16_t aic79xx_rd_strm_info[] =
-{
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM,
- AIC79XX_CONFIGED_RD_STRM
-};
-
-/*
- * DV option:
- *
- * positive value = DV Enabled
- * zero = DV Disabled
- * negative value = DV Default for adapter type/seeprom
- */
-#ifdef CONFIG_AIC79XX_DV_SETTING
-#define AIC79XX_CONFIGED_DV CONFIG_AIC79XX_DV_SETTING
-#else
-#define AIC79XX_CONFIGED_DV -1
-#endif
-
-static int8_t aic79xx_dv_settings[] =
-{
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV,
- AIC79XX_CONFIGED_DV
-};
-
-/*
* The I/O cell on the chip is very configurable in respect to its analog
* characteristics. Set the defaults here; they can be overriden with
* the proper insmod parameters.
@@ -375,13 +292,6 @@
uint32_t aic79xx_allow_memio = ~0;
/*
- * aic79xx_detect() has been run, so register all device arrivals
- * immediately with the system rather than deferring to the sorted
- * attachment performed by aic79xx_detect().
- */
-int aic79xx_detect_complete;
-
-/*
* So that we can set how long each device is given as a selection timeout.
* The table of values goes like this:
* 0 - 256ms
@@ -412,7 +322,7 @@
MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC79XX_DRIVER_VERSION);
-module_param(aic79xx, charp, 0);
+module_param(aic79xx, charp, 0444);
MODULE_PARM_DESC(aic79xx,
"period delimited, options string.\n"
" verbose Enable verbose/diagnostic logging\n"
@@ -427,8 +337,6 @@
" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for all targets on all buses\n"
-" rd_strm:<rd_strm_masks> Set per-target read streaming setting.\n"
-" dv:<dv_settings> Set per-controller Domain Validation Setting.\n"
" slewrate:<slewrate_list>Set the signal slew rate (0-15).\n"
" precomp:<pcomp_list> Set the signal precompensation (0-7).\n"
" amplitude:<int> Set the signal amplitude (0-7).\n"
@@ -441,249 +349,35 @@
" Shorten the selection timeout to 128ms\n"
"\n"
" options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
-"\n"
-" Sample /etc/modprobe.conf line:\n"
-" Change Read Streaming for Controller's 2 and 3\n"
-"\n"
-" options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'");
+"\n");
static void ahd_linux_handle_scsi_status(struct ahd_softc *,
- struct ahd_linux_device *,
+ struct scsi_device *,
struct scb *);
static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
- Scsi_Cmnd *cmd);
-static void ahd_linux_filter_inquiry(struct ahd_softc *ahd,
- struct ahd_devinfo *devinfo);
-static void ahd_linux_dev_timed_unfreeze(u_long arg);
+ struct scsi_cmnd *cmd);
static void ahd_linux_sem_timeout(u_long arg);
+static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
-static void ahd_linux_size_nseg(void);
-static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);
-static void ahd_linux_start_dv(struct ahd_softc *ahd);
-static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);
-static int ahd_linux_dv_thread(void *data);
-static void ahd_linux_kill_dv_thread(struct ahd_softc *ahd);
-static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target);
-static void ahd_linux_dv_transition(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ);
-static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo);
-static void ahd_linux_dv_inq(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ,
- u_int request_length);
-static void ahd_linux_dv_tur(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo);
-static void ahd_linux_dv_rebd(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ);
-static void ahd_linux_dv_web(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ);
-static void ahd_linux_dv_reb(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ);
-static void ahd_linux_dv_su(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ);
-static int ahd_linux_fallback(struct ahd_softc *ahd,
- struct ahd_devinfo *devinfo);
-static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd,
- struct ahd_devinfo *devinfo);
-static void ahd_linux_dv_complete(Scsi_Cmnd *cmd);
-static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ);
static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
-static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd);
-static void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd);
-static void ahd_linux_device_queue_depth(struct ahd_softc *ahd,
- struct ahd_linux_device *dev);
-static struct ahd_linux_target* ahd_linux_alloc_target(struct ahd_softc*,
- u_int, u_int);
-static void ahd_linux_free_target(struct ahd_softc*,
- struct ahd_linux_target*);
-static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*,
- struct ahd_linux_target*,
- u_int);
-static void ahd_linux_free_device(struct ahd_softc*,
- struct ahd_linux_device*);
-static void ahd_linux_run_device_queue(struct ahd_softc*,
- struct ahd_linux_device*);
+static void ahd_linux_device_queue_depth(struct scsi_device *);
+static int ahd_linux_run_command(struct ahd_softc*,
+ struct ahd_linux_device *,
+ struct scsi_cmnd *);
static void ahd_linux_setup_tag_info_global(char *p);
-static aic_option_callback_t ahd_linux_setup_tag_info;
-static aic_option_callback_t ahd_linux_setup_rd_strm_info;
-static aic_option_callback_t ahd_linux_setup_dv;
-static aic_option_callback_t ahd_linux_setup_iocell_info;
-static int ahd_linux_next_unit(void);
-static void ahd_runq_tasklet(unsigned long data);
-static int aic79xx_setup(char *c);
+static int aic79xx_setup(char *c);
+
+static int ahd_linux_unit;
+
/****************************** Inlines ***************************************/
-static __inline void ahd_schedule_completeq(struct ahd_softc *ahd);
-static __inline void ahd_schedule_runq(struct ahd_softc *ahd);
-static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd);
-static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd);
-static __inline struct ahd_linux_device*
- ahd_linux_get_device(struct ahd_softc *ahd, u_int channel,
- u_int target, u_int lun, int alloc);
-static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd);
-static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd,
- struct ahd_linux_device *dev);
-static __inline struct ahd_linux_device *
- ahd_linux_next_device_to_run(struct ahd_softc *ahd);
-static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd);
static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
static __inline void
-ahd_schedule_completeq(struct ahd_softc *ahd)
-{
- if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) {
- ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER;
- ahd->platform_data->completeq_timer.expires = jiffies;
- add_timer(&ahd->platform_data->completeq_timer);
- }
-}
-
-/*
- * Must be called with our lock held.
- */
-static __inline void
-ahd_schedule_runq(struct ahd_softc *ahd)
-{
- tasklet_schedule(&ahd->platform_data->runq_tasklet);
-}
-
-static __inline
-void ahd_setup_runq_tasklet(struct ahd_softc *ahd)
-{
- tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet,
- (unsigned long)ahd);
-}
-
-static __inline void
-ahd_teardown_runq_tasklet(struct ahd_softc *ahd)
-{
- tasklet_kill(&ahd->platform_data->runq_tasklet);
-}
-
-static __inline struct ahd_linux_device*
-ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target,
- u_int lun, int alloc)
-{
- struct ahd_linux_target *targ;
- struct ahd_linux_device *dev;
- u_int target_offset;
-
- target_offset = target;
- if (channel != 0)
- target_offset += 8;
- targ = ahd->platform_data->targets[target_offset];
- if (targ == NULL) {
- if (alloc != 0) {
- targ = ahd_linux_alloc_target(ahd, channel, target);
- if (targ == NULL)
- return (NULL);
- } else
- return (NULL);
- }
- dev = targ->devices[lun];
- if (dev == NULL && alloc != 0)
- dev = ahd_linux_alloc_device(ahd, targ, lun);
- return (dev);
-}
-
-#define AHD_LINUX_MAX_RETURNED_ERRORS 4
-static struct ahd_cmd *
-ahd_linux_run_complete_queue(struct ahd_softc *ahd)
-{
- struct ahd_cmd *acmd;
- u_long done_flags;
- int with_errors;
-
- with_errors = 0;
- ahd_done_lock(ahd, &done_flags);
- while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) {
- Scsi_Cmnd *cmd;
-
- if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) {
- /*
- * Linux uses stack recursion to requeue
- * commands that need to be retried. Avoid
- * blowing out the stack by "spoon feeding"
- * commands that completed with error back
- * the operating system in case they are going
- * to be retried. "ick"
- */
- ahd_schedule_completeq(ahd);
- break;
- }
- TAILQ_REMOVE(&ahd->platform_data->completeq,
- acmd, acmd_links.tqe);
- cmd = &acmd_scsi_cmd(acmd);
- cmd->host_scribble = NULL;
- if (ahd_cmd_get_transaction_status(cmd) != DID_OK
- || (cmd->result & 0xFF) != SCSI_STATUS_OK)
- with_errors++;
-
- cmd->scsi_done(cmd);
- }
- ahd_done_unlock(ahd, &done_flags);
- return (acmd);
-}
-
-static __inline void
-ahd_linux_check_device_queue(struct ahd_softc *ahd,
- struct ahd_linux_device *dev)
-{
- if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0
- && dev->active == 0) {
- dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY;
- dev->qfrozen--;
- }
-
- if (TAILQ_FIRST(&dev->busyq) == NULL
- || dev->openings == 0 || dev->qfrozen != 0)
- return;
-
- ahd_linux_run_device_queue(ahd, dev);
-}
-
-static __inline struct ahd_linux_device *
-ahd_linux_next_device_to_run(struct ahd_softc *ahd)
-{
-
- if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0
- || (ahd->platform_data->qfrozen != 0
- && AHD_DV_SIMQ_FROZEN(ahd) == 0))
- return (NULL);
- return (TAILQ_FIRST(&ahd->platform_data->device_runq));
-}
-
-static __inline void
-ahd_linux_run_device_queues(struct ahd_softc *ahd)
-{
- struct ahd_linux_device *dev;
-
- while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
- TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
- dev->flags &= ~AHD_DEV_ON_RUN_LIST;
- ahd_linux_check_device_queue(ahd, dev);
- }
-}
-
-static __inline void
ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
{
- Scsi_Cmnd *cmd;
+ struct scsi_cmnd *cmd;
int direction;
cmd = scb->io_ctx;
@@ -705,197 +399,6 @@
#define BUILD_SCSIID(ahd, cmd) \
((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id)
-/************************ Host template entry points *************************/
-static int ahd_linux_detect(Scsi_Host_Template *);
-static const char *ahd_linux_info(struct Scsi_Host *);
-static int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static int ahd_linux_slave_alloc(Scsi_Device *);
-static int ahd_linux_slave_configure(Scsi_Device *);
-static void ahd_linux_slave_destroy(Scsi_Device *);
-#if defined(__i386__)
-static int ahd_linux_biosparam(struct scsi_device*,
- struct block_device*, sector_t, int[]);
-#endif
-#else
-static int ahd_linux_release(struct Scsi_Host *);
-static void ahd_linux_select_queue_depth(struct Scsi_Host *host,
- Scsi_Device *scsi_devs);
-#if defined(__i386__)
-static int ahd_linux_biosparam(Disk *, kdev_t, int[]);
-#endif
-#endif
-static int ahd_linux_bus_reset(Scsi_Cmnd *);
-static int ahd_linux_dev_reset(Scsi_Cmnd *);
-static int ahd_linux_abort(Scsi_Cmnd *);
-
-/*
- * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg).
- *
- * In pre-2.5.X...
- * The midlayer allocates an S/G array dynamically when a command is issued
- * using SCSI malloc. This array, which is in an OS dependent format that
- * must later be copied to our private S/G list, is sized to house just the
- * number of segments needed for the current transfer. Since the code that
- * sizes the SCSI malloc pool does not take into consideration fragmentation
- * of the pool, executing transactions numbering just a fraction of our
- * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will
- * quickly depleat the SCSI malloc pool of usable space. Unfortunately, the
- * mid-layer does not properly handle this scsi malloc failures for the S/G
- * array and the result can be a lockup of the I/O subsystem. We try to size
- * our S/G list so that it satisfies our drivers allocation requirements in
- * addition to avoiding fragmentation of the SCSI malloc pool.
- */
-static void
-ahd_linux_size_nseg(void)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- u_int cur_size;
- u_int best_size;
-
- /*
- * The SCSI allocator rounds to the nearest 512 bytes
- * an cannot allocate across a page boundary. Our algorithm
- * is to start at 1K of scsi malloc space per-command and
- * loop through all factors of the PAGE_SIZE and pick the best.
- */
- best_size = 0;
- for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
- u_int nseg;
-
- nseg = cur_size / sizeof(struct scatterlist);
- if (nseg < AHD_LINUX_MIN_NSEG)
- continue;
-
- if (best_size == 0) {
- best_size = cur_size;
- ahd_linux_nseg = nseg;
- } else {
- u_int best_rem;
- u_int cur_rem;
-
- /*
- * Compare the traits of the current "best_size"
- * with the current size to determine if the
- * current size is a better size.
- */
- best_rem = best_size % sizeof(struct scatterlist);
- cur_rem = cur_size % sizeof(struct scatterlist);
- if (cur_rem < best_rem) {
- best_size = cur_size;
- ahd_linux_nseg = nseg;
- }
- }
- }
-#endif
-}
-
-/*
- * Try to detect an Adaptec 79XX controller.
- */
-static int
-ahd_linux_detect(Scsi_Host_Template *template)
-{
- struct ahd_softc *ahd;
- int found;
- int error = 0;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- /*
- * It is a bug that the upper layer takes
- * this lock just prior to calling us.
- */
- spin_unlock_irq(&io_request_lock);
-#endif
-
- /*
- * Sanity checking of Linux SCSI data structures so
- * that some of our hacks^H^H^H^H^Hassumptions aren't
- * violated.
- */
- if (offsetof(struct ahd_cmd_internal, end)
- > offsetof(struct scsi_cmnd, host_scribble)) {
- printf("ahd_linux_detect: SCSI data structures changed.\n");
- printf("ahd_linux_detect: Unable to attach\n");
- return (0);
- }
- /*
- * Determine an appropriate size for our Scatter Gatther lists.
- */
- ahd_linux_size_nseg();
-#ifdef MODULE
- /*
- * If we've been passed any parameters, process them now.
- */
- if (aic79xx)
- aic79xx_setup(aic79xx);
-#endif
-
- template->proc_name = "aic79xx";
-
- /*
- * Initialize our softc list lock prior to
- * probing for any adapters.
- */
- ahd_list_lockinit();
-
-#ifdef CONFIG_PCI
- error = ahd_linux_pci_init();
- if (error)
- return error;
-#endif
-
- /*
- * Register with the SCSI layer all
- * controllers we've found.
- */
- found = 0;
- TAILQ_FOREACH(ahd, &ahd_tailq, links) {
-
- if (ahd_linux_register_host(ahd, template) == 0)
- found++;
- }
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- spin_lock_irq(&io_request_lock);
-#endif
- aic79xx_detect_complete++;
- return 0;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/*
- * Free the passed in Scsi_Host memory structures prior to unloading the
- * module.
- */
-static int
-ahd_linux_release(struct Scsi_Host * host)
-{
- struct ahd_softc *ahd;
- u_long l;
-
- ahd_list_lock(&l);
- if (host != NULL) {
-
- /*
- * We should be able to just perform
- * the free directly, but check our
- * list for extra sanity.
- */
- ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);
- if (ahd != NULL) {
- u_long s;
-
- ahd_lock(ahd, &s);
- ahd_intr_enable(ahd, FALSE);
- ahd_unlock(ahd, &s);
- ahd_free(ahd);
- }
- }
- ahd_list_unlock(&l);
- return (0);
-}
-#endif
-
/*
* Return a string describing the driver.
*/
@@ -928,220 +431,177 @@
* Queue an SCB to the controller.
*/
static int
-ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
{
struct ahd_softc *ahd;
- struct ahd_linux_device *dev;
- u_long flags;
+ struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device);
ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
/*
- * Save the callback on completion function.
- */
- cmd->scsi_done = scsi_done;
-
- ahd_midlayer_entrypoint_lock(ahd, &flags);
-
- /*
* Close the race of a command that was in the process of
* being queued to us just as our simq was frozen. Let
* DV commands through so long as we are only frozen to
* perform DV.
*/
- if (ahd->platform_data->qfrozen != 0
- && AHD_DV_CMD(cmd) == 0) {
+ if (ahd->platform_data->qfrozen != 0) {
+ printf("%s: queue frozen\n", ahd_name(ahd));
- ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
- ahd_linux_queue_cmd_complete(ahd, cmd);
- ahd_schedule_completeq(ahd);
- ahd_midlayer_entrypoint_unlock(ahd, &flags);
- return (0);
+ return SCSI_MLQUEUE_HOST_BUSY;
}
- dev = ahd_linux_get_device(ahd, cmd->device->channel,
- cmd->device->id, cmd->device->lun,
- /*alloc*/TRUE);
- if (dev == NULL) {
- ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
- ahd_linux_queue_cmd_complete(ahd, cmd);
- ahd_schedule_completeq(ahd);
- ahd_midlayer_entrypoint_unlock(ahd, &flags);
- printf("%s: aic79xx_linux_queue - Unable to allocate device!\n",
- ahd_name(ahd));
- return (0);
- }
- if (cmd->cmd_len > MAX_CDB_LEN)
- return (-EINVAL);
+
+ /*
+ * Save the callback on completion function.
+ */
+ cmd->scsi_done = scsi_done;
+
cmd->result = CAM_REQ_INPROG << 16;
- TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe);
- if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
- TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
- dev->flags |= AHD_DEV_ON_RUN_LIST;
- ahd_linux_run_device_queues(ahd);
- }
- ahd_midlayer_entrypoint_unlock(ahd, &flags);
- return (0);
+
+ return ahd_linux_run_command(ahd, dev, cmd);
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static int
-ahd_linux_slave_alloc(Scsi_Device *device)
+static inline struct scsi_target **
+ahd_linux_target_in_softc(struct scsi_target *starget)
{
- struct ahd_softc *ahd;
+ struct ahd_softc *ahd =
+ *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata);
+ unsigned int target_offset;
- ahd = *((struct ahd_softc **)device->host->hostdata);
- if (bootverbose)
- printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id);
- return (0);
+ target_offset = starget->id;
+ if (starget->channel != 0)
+ target_offset += 8;
+
+ return &ahd->platform_data->starget[target_offset];
}
static int
-ahd_linux_slave_configure(Scsi_Device *device)
+ahd_linux_target_alloc(struct scsi_target *starget)
{
- struct ahd_softc *ahd;
- struct ahd_linux_device *dev;
- u_long flags;
+ struct ahd_softc *ahd =
+ *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata);
+ unsigned long flags;
+ struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget);
+ struct ahd_linux_target *targ = scsi_transport_target_data(starget);
+ struct ahd_devinfo devinfo;
+ struct ahd_initiator_tinfo *tinfo;
+ struct ahd_tmode_tstate *tstate;
+ char channel = starget->channel + 'A';
- ahd = *((struct ahd_softc **)device->host->hostdata);
- if (bootverbose)
- printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id);
- ahd_midlayer_entrypoint_lock(ahd, &flags);
- /*
- * Since Linux has attached to the device, configure
- * it so we don't free and allocate the device
- * structure on every command.
- */
- dev = ahd_linux_get_device(ahd, device->channel,
- device->id, device->lun,
- /*alloc*/TRUE);
- if (dev != NULL) {
- dev->flags &= ~AHD_DEV_UNCONFIGURED;
- dev->flags |= AHD_DEV_SLAVE_CONFIGURED;
- dev->scsi_device = device;
- ahd_linux_device_queue_depth(ahd, dev);
- }
- ahd_midlayer_entrypoint_unlock(ahd, &flags);
- return (0);
-}
-
-static void
-ahd_linux_slave_destroy(Scsi_Device *device)
-{
- struct ahd_softc *ahd;
- struct ahd_linux_device *dev;
- u_long flags;
-
- ahd = *((struct ahd_softc **)device->host->hostdata);
- if (bootverbose)
- printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id);
- ahd_midlayer_entrypoint_lock(ahd, &flags);
- dev = ahd_linux_get_device(ahd, device->channel,
- device->id, device->lun,
- /*alloc*/FALSE);
-
- /*
- * Filter out "silly" deletions of real devices by only
- * deleting devices that have had slave_configure()
- * called on them. All other devices that have not
- * been configured will automatically be deleted by
- * the refcounting process.
- */
- if (dev != NULL
- && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) {
- dev->flags |= AHD_DEV_UNCONFIGURED;
- if (TAILQ_EMPTY(&dev->busyq)
- && dev->active == 0
- && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
- ahd_linux_free_device(ahd, dev);
- }
- ahd_midlayer_entrypoint_unlock(ahd, &flags);
-}
-#else
-/*
- * Sets the queue depth for each SCSI device hanging
- * off the input host adapter.
- */
-static void
-ahd_linux_select_queue_depth(struct Scsi_Host * host,
- Scsi_Device * scsi_devs)
-{
- Scsi_Device *device;
- Scsi_Device *ldev;
- struct ahd_softc *ahd;
- u_long flags;
-
- ahd = *((struct ahd_softc **)host->hostdata);
ahd_lock(ahd, &flags);
- for (device = scsi_devs; device != NULL; device = device->next) {
- /*
- * Watch out for duplicate devices. This works around
- * some quirks in how the SCSI scanning code does its
- * device management.
- */
- for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
- if (ldev->host == device->host
- && ldev->channel == device->channel
- && ldev->id == device->id
- && ldev->lun == device->lun)
- break;
- }
- /* Skip duplicate. */
- if (ldev != device)
- continue;
+ BUG_ON(*ahd_targp != NULL);
- if (device->host == host) {
- struct ahd_linux_device *dev;
+ *ahd_targp = starget;
+ memset(targ, 0, sizeof(*targ));
- /*
- * Since Linux has attached to the device, configure
- * it so we don't free and allocate the device
- * structure on every command.
- */
- dev = ahd_linux_get_device(ahd, device->channel,
- device->id, device->lun,
- /*alloc*/TRUE);
- if (dev != NULL) {
- dev->flags &= ~AHD_DEV_UNCONFIGURED;
- dev->scsi_device = device;
- ahd_linux_device_queue_depth(ahd, dev);
- device->queue_depth = dev->openings
- + dev->active;
- if ((dev->flags & (AHD_DEV_Q_BASIC
- | AHD_DEV_Q_TAGGED)) == 0) {
- /*
- * We allow the OS to queue 2 untagged
- * transactions to us at any time even
- * though we can only execute them
- * serially on the controller/device.
- * This should remove some latency.
- */
- device->queue_depth = 2;
- }
- }
- }
- }
+ tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,
+ starget->id, &tstate);
+ ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id,
+ CAM_LUN_WILDCARD, channel,
+ ROLE_INITIATOR);
+ spi_min_period(starget) = AHD_SYNCRATE_MAX; /* We can do U320 */
+ if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0)
+ spi_max_offset(starget) = MAX_OFFSET_PACED_BUG;
+ else
+ spi_max_offset(starget) = MAX_OFFSET_PACED;
+ spi_max_width(starget) = ahd->features & AHD_WIDE;
+
+ ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
+ AHD_TRANS_GOAL, /*paused*/FALSE);
+ ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+ AHD_TRANS_GOAL, /*paused*/FALSE);
ahd_unlock(ahd, &flags);
+
+ return 0;
}
-#endif
+
+static void
+ahd_linux_target_destroy(struct scsi_target *starget)
+{
+ struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget);
+
+ *ahd_targp = NULL;
+}
+
+static int
+ahd_linux_slave_alloc(struct scsi_device *sdev)
+{
+ struct ahd_softc *ahd =
+ *((struct ahd_softc **)sdev->host->hostdata);
+ struct scsi_target *starget = sdev->sdev_target;
+ struct ahd_linux_target *targ = scsi_transport_target_data(starget);
+ struct ahd_linux_device *dev;
+
+ if (bootverbose)
+ printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
+
+ BUG_ON(targ->sdev[sdev->lun] != NULL);
+
+ dev = scsi_transport_device_data(sdev);
+ memset(dev, 0, sizeof(*dev));
+
+ /*
+ * We start out life using untagged
+ * transactions of which we allow one.
+ */
+ dev->openings = 1;
+
+ /*
+ * Set maxtags to 0. This will be changed if we
+ * later determine that we are dealing with
+ * a tagged queuing capable device.
+ */
+ dev->maxtags = 0;
+
+ targ->sdev[sdev->lun] = sdev;
+
+ return (0);
+}
+
+static int
+ahd_linux_slave_configure(struct scsi_device *sdev)
+{
+ struct ahd_softc *ahd;
+
+ ahd = *((struct ahd_softc **)sdev->host->hostdata);
+ if (bootverbose)
+ printf("%s: Slave Configure %d\n", ahd_name(ahd), sdev->id);
+
+ ahd_linux_device_queue_depth(sdev);
+
+ /* Initial Domain Validation */
+ if (!spi_initial_dv(sdev->sdev_target))
+ spi_dv_device(sdev);
+
+ return 0;
+}
+
+static void
+ahd_linux_slave_destroy(struct scsi_device *sdev)
+{
+ struct ahd_softc *ahd;
+ struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
+ struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);
+
+ ahd = *((struct ahd_softc **)sdev->host->hostdata);
+ if (bootverbose)
+ printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id);
+
+ BUG_ON(dev->active);
+
+ targ->sdev[sdev->lun] = NULL;
+
+}
#if defined(__i386__)
/*
* Return the disk geometry for the given SCSI device.
*/
static int
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
{
uint8_t *bh;
-#else
-ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
-{
- struct scsi_device *sdev = disk->device;
- u_long capacity = disk->capacity;
- struct buffer_head *bh;
-#endif
int heads;
int sectors;
int cylinders;
@@ -1151,22 +611,11 @@
ahd = *((struct ahd_softc **)sdev->host->hostdata);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
bh = scsi_bios_ptable(bdev);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
- bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
-#else
- bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
-#endif
-
if (bh) {
ret = scsi_partsize(bh, capacity,
&geom[2], &geom[0], &geom[1]);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
kfree(bh);
-#else
- brelse(bh);
-#endif
if (ret != -1)
return (ret);
}
@@ -1194,17 +643,1419 @@
* Abort the current SCSI command(s).
*/
static int
-ahd_linux_abort(Scsi_Cmnd *cmd)
+ahd_linux_abort(struct scsi_cmnd *cmd)
+{
+ int error;
+
+ error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT);
+ if (error != 0)
+ printf("aic79xx_abort returns 0x%x\n", error);
+ return error;
+}
+
+/*
+ * Attempt to send a target reset message to the device that timed out.
+ */
+static int
+ahd_linux_dev_reset(struct scsi_cmnd *cmd)
+{
+ int error;
+
+ error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
+ if (error != 0)
+ printf("aic79xx_dev_reset returns 0x%x\n", error);
+ return error;
+}
+
+/*
+ * Reset the SCSI bus.
+ */
+static int
+ahd_linux_bus_reset(struct scsi_cmnd *cmd)
{
struct ahd_softc *ahd;
- struct ahd_cmd *acmd;
- struct ahd_cmd *list_acmd;
+ u_long s;
+ int found;
+
+ ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+ printf("%s: Bus reset called for cmd %p\n",
+ ahd_name(ahd), cmd);
+#endif
+ ahd_lock(ahd, &s);
+ found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
+ /*initiate reset*/TRUE);
+ ahd_unlock(ahd, &s);
+
+ if (bootverbose)
+ printf("%s: SCSI bus reset delivered. "
+ "%d SCBs aborted.\n", ahd_name(ahd), found);
+
+ return (SUCCESS);
+}
+
+struct scsi_host_template aic79xx_driver_template = {
+ .module = THIS_MODULE,
+ .name = "aic79xx",
+ .proc_name = "aic79xx",
+ .proc_info = ahd_linux_proc_info,
+ .info = ahd_linux_info,
+ .queuecommand = ahd_linux_queue,
+ .eh_abort_handler = ahd_linux_abort,
+ .eh_device_reset_handler = ahd_linux_dev_reset,
+ .eh_bus_reset_handler = ahd_linux_bus_reset,
+#if defined(__i386__)
+ .bios_param = ahd_linux_biosparam,
+#endif
+ .can_queue = AHD_MAX_QUEUE,
+ .this_id = -1,
+ .cmd_per_lun = 2,
+ .use_clustering = ENABLE_CLUSTERING,
+ .slave_alloc = ahd_linux_slave_alloc,
+ .slave_configure = ahd_linux_slave_configure,
+ .slave_destroy = ahd_linux_slave_destroy,
+ .target_alloc = ahd_linux_target_alloc,
+ .target_destroy = ahd_linux_target_destroy,
+};
+
+/******************************** Bus DMA *************************************/
+int
+ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
+ bus_size_t alignment, bus_size_t boundary,
+ dma_addr_t lowaddr, dma_addr_t highaddr,
+ bus_dma_filter_t *filter, void *filterarg,
+ bus_size_t maxsize, int nsegments,
+ bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag)
+{
+ bus_dma_tag_t dmat;
+
+ dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+ if (dmat == NULL)
+ return (ENOMEM);
+
+ /*
+ * Linux is very simplistic about DMA memory. For now don't
+ * maintain all specification information. Once Linux supplies
+ * better facilities for doing these operations, or the
+ * needs of this particular driver change, we might need to do
+ * more here.
+ */
+ dmat->alignment = alignment;
+ dmat->boundary = boundary;
+ dmat->maxsize = maxsize;
+ *ret_tag = dmat;
+ return (0);
+}
+
+void
+ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat)
+{
+ free(dmat, M_DEVBUF);
+}
+
+int
+ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr,
+ int flags, bus_dmamap_t *mapp)
+{
+ *vaddr = pci_alloc_consistent(ahd->dev_softc,
+ dmat->maxsize, mapp);
+ if (*vaddr == NULL)
+ return (ENOMEM);
+ return(0);
+}
+
+void
+ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,
+ void* vaddr, bus_dmamap_t map)
+{
+ pci_free_consistent(ahd->dev_softc, dmat->maxsize,
+ vaddr, map);
+}
+
+int
+ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map,
+ void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,
+ void *cb_arg, int flags)
+{
+ /*
+ * Assume for now that this will only be used during
+ * initialization and not for per-transaction buffer mapping.
+ */
+ bus_dma_segment_t stack_sg;
+
+ stack_sg.ds_addr = map;
+ stack_sg.ds_len = dmat->maxsize;
+ cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
+ return (0);
+}
+
+void
+ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+}
+
+int
+ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+ /* Nothing to do */
+ return (0);
+}
+
+/********************* Platform Dependent Functions ***************************/
+/*
+ * Compare "left hand" softc with "right hand" softc, returning:
+ * < 0 - lahd has a lower priority than rahd
+ * 0 - Softcs are equal
+ * > 0 - lahd has a higher priority than rahd
+ */
+int
+ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
+{
+ int value;
+
+ /*
+ * Under Linux, cards are ordered as follows:
+ * 1) PCI devices that are marked as the boot controller.
+ * 2) PCI devices with BIOS enabled sorted by bus/slot/func.
+ * 3) All remaining PCI devices sorted by bus/slot/func.
+ */
+#if 0
+ value = (lahd->flags & AHD_BOOT_CHANNEL)
+ - (rahd->flags & AHD_BOOT_CHANNEL);
+ if (value != 0)
+ /* Controllers set for boot have a *higher* priority */
+ return (value);
+#endif
+
+ value = (lahd->flags & AHD_BIOS_ENABLED)
+ - (rahd->flags & AHD_BIOS_ENABLED);
+ if (value != 0)
+ /* Controllers with BIOS enabled have a *higher* priority */
+ return (value);
+
+ /* Still equal. Sort by bus/slot/func. */
+ if (aic79xx_reverse_scan != 0)
+ value = ahd_get_pci_bus(lahd->dev_softc)
+ - ahd_get_pci_bus(rahd->dev_softc);
+ else
+ value = ahd_get_pci_bus(rahd->dev_softc)
+ - ahd_get_pci_bus(lahd->dev_softc);
+ if (value != 0)
+ return (value);
+ if (aic79xx_reverse_scan != 0)
+ value = ahd_get_pci_slot(lahd->dev_softc)
+ - ahd_get_pci_slot(rahd->dev_softc);
+ else
+ value = ahd_get_pci_slot(rahd->dev_softc)
+ - ahd_get_pci_slot(lahd->dev_softc);
+ if (value != 0)
+ return (value);
+
+ value = rahd->channel - lahd->channel;
+ return (value);
+}
+
+static void
+ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
+{
+
+ if ((instance >= 0)
+ && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
+ uint8_t *iocell_info;
+
+ iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
+ iocell_info[index] = value & 0xFFFF;
+ if (bootverbose)
+ printf("iocell[%d:%ld] = %d\n", instance, index, value);
+ }
+}
+
+static void
+ahd_linux_setup_tag_info_global(char *p)
+{
+ int tags, i, j;
+
+ tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
+ printf("Setting Global Tags= %d\n", tags);
+
+ for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) {
+ for (j = 0; j < AHD_NUM_TARGETS; j++) {
+ aic79xx_tag_info[i].tag_commands[j] = tags;
+ }
+ }
+}
+
+static void
+ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
+{
+
+ if ((instance >= 0) && (targ >= 0)
+ && (instance < NUM_ELEMENTS(aic79xx_tag_info))
+ && (targ < AHD_NUM_TARGETS)) {
+ aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
+ if (bootverbose)
+ printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+ }
+}
+
+static char *
+ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
+ void (*callback)(u_long, int, int, int32_t),
+ u_long callback_arg)
+{
+ char *tok_end;
+ char *tok_end2;
+ int i;
+ int instance;
+ int targ;
+ int done;
+ char tok_list[] = {'.', ',', '{', '}', '\0'};
+
+ /* All options use a ':' name/arg separator */
+ if (*opt_arg != ':')
+ return (opt_arg);
+ opt_arg++;
+ instance = -1;
+ targ = -1;
+ done = FALSE;
+ /*
+ * Restore separator that may be in
+ * the middle of our option argument.
+ */
+ tok_end = strchr(opt_arg, '\0');
+ if (tok_end < end)
+ *tok_end = ',';
+ while (!done) {
+ switch (*opt_arg) {
+ case '{':
+ if (instance == -1) {
+ instance = 0;
+ } else {
+ if (depth > 1) {
+ if (targ == -1)
+ targ = 0;
+ } else {
+ printf("Malformed Option %s\n",
+ opt_name);
+ done = TRUE;
+ }
+ }
+ opt_arg++;
+ break;
+ case '}':
+ if (targ != -1)
+ targ = -1;
+ else if (instance != -1)
+ instance = -1;
+ opt_arg++;
+ break;
+ case ',':
+ case '.':
+ if (instance == -1)
+ done = TRUE;
+ else if (targ >= 0)
+ targ++;
+ else if (instance >= 0)
+ instance++;
+ opt_arg++;
+ break;
+ case '\0':
+ done = TRUE;
+ break;
+ default:
+ tok_end = end;
+ for (i = 0; tok_list[i]; i++) {
+ tok_end2 = strchr(opt_arg, tok_list[i]);
+ if ((tok_end2) && (tok_end2 < tok_end))
+ tok_end = tok_end2;
+ }
+ callback(callback_arg, instance, targ,
+ simple_strtol(opt_arg, NULL, 0));
+ opt_arg = tok_end;
+ break;
+ }
+ }
+ return (opt_arg);
+}
+
+/*
+ * Handle Linux boot parameters. This routine allows for assigning a value
+ * to a parameter with a ':' between the parameter and the value.
+ * ie. aic79xx=stpwlev:1,extended
+ */
+static int
+aic79xx_setup(char *s)
+{
+ int i, n;
+ char *p;
+ char *end;
+
+ static struct {
+ const char *name;
+ uint32_t *flag;
+ } options[] = {
+ { "extended", &aic79xx_extended },
+ { "no_reset", &aic79xx_no_reset },
+ { "verbose", &aic79xx_verbose },
+ { "allow_memio", &aic79xx_allow_memio},
+#ifdef AHD_DEBUG
+ { "debug", &ahd_debug },
+#endif
+ { "reverse_scan", &aic79xx_reverse_scan },
+ { "periodic_otag", &aic79xx_periodic_otag },
+ { "pci_parity", &aic79xx_pci_parity },
+ { "seltime", &aic79xx_seltime },
+ { "tag_info", NULL },
+ { "global_tag_depth", NULL},
+ { "slewrate", NULL },
+ { "precomp", NULL },
+ { "amplitude", NULL },
+ };
+
+ end = strchr(s, '\0');
+
+ /*
+ * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
+ * will never be 0 in this case.
+ */
+ n = 0;
+
+ while ((p = strsep(&s, ",.")) != NULL) {
+ if (*p == '\0')
+ continue;
+ for (i = 0; i < NUM_ELEMENTS(options); i++) {
+
+ n = strlen(options[i].name);
+ if (strncmp(options[i].name, p, n) == 0)
+ break;
+ }
+ if (i == NUM_ELEMENTS(options))
+ continue;
+
+ if (strncmp(p, "global_tag_depth", n) == 0) {
+ ahd_linux_setup_tag_info_global(p + n);
+ } else if (strncmp(p, "tag_info", n) == 0) {
+ s = ahd_parse_brace_option("tag_info", p + n, end,
+ 2, ahd_linux_setup_tag_info, 0);
+ } else if (strncmp(p, "slewrate", n) == 0) {
+ s = ahd_parse_brace_option("slewrate",
+ p + n, end, 1, ahd_linux_setup_iocell_info,
+ AIC79XX_SLEWRATE_INDEX);
+ } else if (strncmp(p, "precomp", n) == 0) {
+ s = ahd_parse_brace_option("precomp",
+ p + n, end, 1, ahd_linux_setup_iocell_info,
+ AIC79XX_PRECOMP_INDEX);
+ } else if (strncmp(p, "amplitude", n) == 0) {
+ s = ahd_parse_brace_option("amplitude",
+ p + n, end, 1, ahd_linux_setup_iocell_info,
+ AIC79XX_AMPLITUDE_INDEX);
+ } else if (p[n] == ':') {
+ *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+ } else if (!strncmp(p, "verbose", n)) {
+ *(options[i].flag) = 1;
+ } else {
+ *(options[i].flag) ^= 0xFFFFFFFF;
+ }
+ }
+ return 1;
+}
+
+__setup("aic79xx=", aic79xx_setup);
+
+uint32_t aic79xx_verbose;
+
+int
+ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *template)
+{
+ char buf[80];
+ struct Scsi_Host *host;
+ char *new_name;
+ u_long s;
+
+ template->name = ahd->description;
+ host = scsi_host_alloc(template, sizeof(struct ahd_softc *));
+ if (host == NULL)
+ return (ENOMEM);
+
+ *((struct ahd_softc **)host->hostdata) = ahd;
+ ahd_lock(ahd, &s);
+ scsi_assign_lock(host, &ahd->platform_data->spin_lock);
+ ahd->platform_data->host = host;
+ host->can_queue = AHD_MAX_QUEUE;
+ host->cmd_per_lun = 2;
+ host->sg_tablesize = AHD_NSEG;
+ host->this_id = ahd->our_id;
+ host->irq = ahd->platform_data->irq;
+ host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8;
+ host->max_lun = AHD_NUM_LUNS;
+ host->max_channel = 0;
+ host->sg_tablesize = AHD_NSEG;
+ ahd_set_unit(ahd, ahd_linux_unit++);
+ sprintf(buf, "scsi%d", host->host_no);
+ new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+ if (new_name != NULL) {
+ strcpy(new_name, buf);
+ ahd_set_name(ahd, new_name);
+ }
+ host->unique_id = ahd->unit;
+ ahd_linux_initialize_scsi_bus(ahd);
+ ahd_intr_enable(ahd, TRUE);
+ ahd_unlock(ahd, &s);
+
+ host->transportt = ahd_linux_transport_template;
+
+ scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */
+ scsi_scan_host(host);
+ return (0);
+}
+
+uint64_t
+ahd_linux_get_memsize(void)
+{
+ struct sysinfo si;
+
+ si_meminfo(&si);
+ return ((uint64_t)si.totalram << PAGE_SHIFT);
+}
+
+/*
+ * Place the SCSI bus into a known state by either resetting it,
+ * or forcing transfer negotiations on the next command to any
+ * target.
+ */
+static void
+ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
+{
+ u_int target_id;
+ u_int numtarg;
+
+ target_id = 0;
+ numtarg = 0;
+
+ if (aic79xx_no_reset != 0)
+ ahd->flags &= ~AHD_RESET_BUS_A;
+
+ if ((ahd->flags & AHD_RESET_BUS_A) != 0)
+ ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE);
+ else
+ numtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
+
+ /*
+ * Force negotiation to async for all targets that
+ * will not see an initial bus reset.
+ */
+ for (; target_id < numtarg; target_id++) {
+ struct ahd_devinfo devinfo;
+ struct ahd_initiator_tinfo *tinfo;
+ struct ahd_tmode_tstate *tstate;
+
+ tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+ target_id, &tstate);
+ ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
+ CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
+ ahd_update_neg_request(ahd, &devinfo, tstate,
+ tinfo, AHD_NEG_ALWAYS);
+ }
+ /* Give the bus some time to recover */
+ if ((ahd->flags & AHD_RESET_BUS_A) != 0) {
+ ahd_freeze_simq(ahd);
+ init_timer(&ahd->platform_data->reset_timer);
+ ahd->platform_data->reset_timer.data = (u_long)ahd;
+ ahd->platform_data->reset_timer.expires =
+ jiffies + (AIC79XX_RESET_DELAY * HZ)/1000;
+ ahd->platform_data->reset_timer.function =
+ (ahd_linux_callback_t *)ahd_release_simq;
+ add_timer(&ahd->platform_data->reset_timer);
+ }
+}
+
+int
+ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
+{
+ ahd->platform_data =
+ malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);
+ if (ahd->platform_data == NULL)
+ return (ENOMEM);
+ memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
+ ahd->platform_data->irq = AHD_LINUX_NOIRQ;
+ ahd_lockinit(ahd);
+ init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);
+ ahd->seltime = (aic79xx_seltime & 0x3) << 4;
+ return (0);
+}
+
+void
+ahd_platform_free(struct ahd_softc *ahd)
+{
+ struct scsi_target *starget;
+ int i, j;
+
+ if (ahd->platform_data != NULL) {
+ if (ahd->platform_data->host != NULL) {
+ scsi_remove_host(ahd->platform_data->host);
+ scsi_host_put(ahd->platform_data->host);
+ }
+
+ /* destroy all of the device and target objects */
+ for (i = 0; i < AHD_NUM_TARGETS; i++) {
+ starget = ahd->platform_data->starget[i];
+ if (starget != NULL) {
+ for (j = 0; j < AHD_NUM_LUNS; j++) {
+ struct ahd_linux_target *targ =
+ scsi_transport_target_data(starget);
+ if (targ->sdev[j] == NULL)
+ continue;
+ targ->sdev[j] = NULL;
+ }
+ ahd->platform_data->starget[i] = NULL;
+ }
+ }
+
+ if (ahd->platform_data->irq != AHD_LINUX_NOIRQ)
+ free_irq(ahd->platform_data->irq, ahd);
+ if (ahd->tags[0] == BUS_SPACE_PIO
+ && ahd->bshs[0].ioport != 0)
+ release_region(ahd->bshs[0].ioport, 256);
+ if (ahd->tags[1] == BUS_SPACE_PIO
+ && ahd->bshs[1].ioport != 0)
+ release_region(ahd->bshs[1].ioport, 256);
+ if (ahd->tags[0] == BUS_SPACE_MEMIO
+ && ahd->bshs[0].maddr != NULL) {
+ iounmap(ahd->bshs[0].maddr);
+ release_mem_region(ahd->platform_data->mem_busaddr,
+ 0x1000);
+ }
+ free(ahd->platform_data, M_DEVBUF);
+ }
+}
+
+void
+ahd_platform_init(struct ahd_softc *ahd)
+{
+ /*
+ * Lookup and commit any modified IO Cell options.
+ */
+ if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) {
+ struct ahd_linux_iocell_opts *iocell_opts;
+
+ iocell_opts = &aic79xx_iocell_info[ahd->unit];
+ if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
+ AHD_SET_PRECOMP(ahd, iocell_opts->precomp);
+ if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE)
+ AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate);
+ if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE)
+ AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude);
+ }
+
+}
+
+void
+ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
+{
+ ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
+ SCB_GET_CHANNEL(ahd, scb),
+ SCB_GET_LUN(scb), SCB_LIST_NULL,
+ ROLE_UNKNOWN, CAM_REQUEUE_REQ);
+}
+
+void
+ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+ ahd_queue_alg alg)
+{
+ struct scsi_target *starget;
+ struct ahd_linux_target *targ;
+ struct ahd_linux_device *dev;
+ struct scsi_device *sdev;
+ int was_queuing;
+ int now_queuing;
+
+ starget = ahd->platform_data->starget[devinfo->target];
+ targ = scsi_transport_target_data(starget);
+ BUG_ON(targ == NULL);
+ sdev = targ->sdev[devinfo->lun];
+ if (sdev == NULL)
+ return;
+
+ dev = scsi_transport_device_data(sdev);
+
+ if (dev == NULL)
+ return;
+ was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED);
+ switch (alg) {
+ default:
+ case AHD_QUEUE_NONE:
+ now_queuing = 0;
+ break;
+ case AHD_QUEUE_BASIC:
+ now_queuing = AHD_DEV_Q_BASIC;
+ break;
+ case AHD_QUEUE_TAGGED:
+ now_queuing = AHD_DEV_Q_TAGGED;
+ break;
+ }
+ if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0
+ && (was_queuing != now_queuing)
+ && (dev->active != 0)) {
+ dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY;
+ dev->qfrozen++;
+ }
+
+ dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG);
+ if (now_queuing) {
+ u_int usertags;
+
+ usertags = ahd_linux_user_tagdepth(ahd, devinfo);
+ if (!was_queuing) {
+ /*
+ * Start out agressively and allow our
+ * dynamic queue depth algorithm to take
+ * care of the rest.
+ */
+ dev->maxtags = usertags;
+ dev->openings = dev->maxtags - dev->active;
+ }
+ if (dev->maxtags == 0) {
+ /*
+ * Queueing is disabled by the user.
+ */
+ dev->openings = 1;
+ } else if (alg == AHD_QUEUE_TAGGED) {
+ dev->flags |= AHD_DEV_Q_TAGGED;
+ if (aic79xx_periodic_otag != 0)
+ dev->flags |= AHD_DEV_PERIODIC_OTAG;
+ } else
+ dev->flags |= AHD_DEV_Q_BASIC;
+ } else {
+ /* We can only have one opening. */
+ dev->maxtags = 0;
+ dev->openings = 1 - dev->active;
+ }
+
+ switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {
+ case AHD_DEV_Q_BASIC:
+ scsi_adjust_queue_depth(sdev,
+ MSG_SIMPLE_TASK,
+ dev->openings + dev->active);
+ break;
+ case AHD_DEV_Q_TAGGED:
+ scsi_adjust_queue_depth(sdev,
+ MSG_ORDERED_TASK,
+ dev->openings + dev->active);
+ break;
+ default:
+ /*
+ * We allow the OS to queue 2 untagged transactions to
+ * us at any time even though we can only execute them
+ * serially on the controller/device. This should
+ * remove some latency.
+ */
+ scsi_adjust_queue_depth(sdev,
+ /*NON-TAGGED*/0,
+ /*queue depth*/2);
+ break;
+ }
+}
+
+int
+ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel,
+ int lun, u_int tag, role_t role, uint32_t status)
+{
+ return 0;
+}
+
+static u_int
+ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+ static int warned_user;
+ u_int tags;
+
+ tags = 0;
+ if ((ahd->user_discenable & devinfo->target_mask) != 0) {
+ if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {
+
+ if (warned_user == 0) {
+ printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient tag_info instances\n"
+"aic79xx: for installed controllers. Using defaults\n"
+"aic79xx: Please update the aic79xx_tag_info array in\n"
+"aic79xx: the aic79xx_osm.c source file.\n");
+ warned_user++;
+ }
+ tags = AHD_MAX_QUEUE;
+ } else {
+ adapter_tag_info_t *tag_info;
+
+ tag_info = &aic79xx_tag_info[ahd->unit];
+ tags = tag_info->tag_commands[devinfo->target_offset];
+ if (tags > AHD_MAX_QUEUE)
+ tags = AHD_MAX_QUEUE;
+ }
+ }
+ return (tags);
+}
+
+/*
+ * Determines the queue depth for a given device.
+ */
+static void
+ahd_linux_device_queue_depth(struct scsi_device *sdev)
+{
+ struct ahd_devinfo devinfo;
+ u_int tags;
+ struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata);
+
+ ahd_compile_devinfo(&devinfo,
+ ahd->our_id,
+ sdev->sdev_target->id, sdev->lun,
+ sdev->sdev_target->channel == 0 ? 'A' : 'B',
+ ROLE_INITIATOR);
+ tags = ahd_linux_user_tagdepth(ahd, &devinfo);
+ if (tags != 0 && sdev->tagged_supported != 0) {
+
+ ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
+ ahd_print_devinfo(ahd, &devinfo);
+ printf("Tagged Queuing enabled. Depth %d\n", tags);
+ } else {
+ ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
+ }
+}
+
+static int
+ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
+ struct scsi_cmnd *cmd)
+{
+ struct scb *scb;
+ struct hardware_scb *hscb;
+ struct ahd_initiator_tinfo *tinfo;
+ struct ahd_tmode_tstate *tstate;
+ u_int col_idx;
+ uint16_t mask;
+
+ /*
+ * Get an scb to use.
+ */
+ tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+ cmd->device->id, &tstate);
+ if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0
+ || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+ col_idx = AHD_NEVER_COL_IDX;
+ } else {
+ col_idx = AHD_BUILD_COL_IDX(cmd->device->id,
+ cmd->device->lun);
+ }
+ if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
+ ahd->flags |= AHD_RESOURCE_SHORTAGE;
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ scb->io_ctx = cmd;
+ scb->platform_data->dev = dev;
+ hscb = scb->hscb;
+ cmd->host_scribble = (char *)scb;
+
+ /*
+ * Fill out basics of the HSCB.
+ */
+ hscb->control = 0;
+ hscb->scsiid = BUILD_SCSIID(ahd, cmd);
+ hscb->lun = cmd->device->lun;
+ scb->hscb->task_management = 0;
+ mask = SCB_GET_TARGET_MASK(ahd, scb);
+
+ if ((ahd->user_discenable & mask) != 0)
+ hscb->control |= DISCENB;
+
+ if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0)
+ scb->flags |= SCB_PACKETIZED;
+
+ if ((tstate->auto_negotiate & mask) != 0) {
+ scb->flags |= SCB_AUTO_NEGOTIATE;
+ scb->hscb->control |= MK_MESSAGE;
+ }
+
+ if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
+ int msg_bytes;
+ uint8_t tag_msgs[2];
+
+ msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
+ if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
+ hscb->control |= tag_msgs[0];
+ if (tag_msgs[0] == MSG_ORDERED_TASK)
+ dev->commands_since_idle_or_otag = 0;
+ } else
+ if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH
+ && (dev->flags & AHD_DEV_Q_TAGGED) != 0) {
+ hscb->control |= MSG_ORDERED_TASK;
+ dev->commands_since_idle_or_otag = 0;
+ } else {
+ hscb->control |= MSG_SIMPLE_TASK;
+ }
+ }
+
+ hscb->cdb_len = cmd->cmd_len;
+ memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len);
+
+ scb->platform_data->xfer_len = 0;
+ ahd_set_residual(scb, 0);
+ ahd_set_sense_residual(scb, 0);
+ scb->sg_count = 0;
+ if (cmd->use_sg != 0) {
+ void *sg;
+ struct scatterlist *cur_seg;
+ u_int nseg;
+ int dir;
+
+ cur_seg = (struct scatterlist *)cmd->request_buffer;
+ dir = cmd->sc_data_direction;
+ nseg = pci_map_sg(ahd->dev_softc, cur_seg,
+ cmd->use_sg, dir);
+ scb->platform_data->xfer_len = 0;
+ for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) {
+ dma_addr_t addr;
+ bus_size_t len;
+
+ addr = sg_dma_address(cur_seg);
+ len = sg_dma_len(cur_seg);
+ scb->platform_data->xfer_len += len;
+ sg = ahd_sg_setup(ahd, scb, sg, addr, len,
+ /*last*/nseg == 1);
+ }
+ } else if (cmd->request_bufflen != 0) {
+ void *sg;
+ dma_addr_t addr;
+ int dir;
+
+ sg = scb->sg_list;
+ dir = cmd->sc_data_direction;
+ addr = pci_map_single(ahd->dev_softc,
+ cmd->request_buffer,
+ cmd->request_bufflen, dir);
+ scb->platform_data->xfer_len = cmd->request_bufflen;
+ scb->platform_data->buf_busaddr = addr;
+ sg = ahd_sg_setup(ahd, scb, sg, addr,
+ cmd->request_bufflen, /*last*/TRUE);
+ }
+
+ LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
+ dev->openings--;
+ dev->active++;
+ dev->commands_issued++;
+
+ if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0)
+ dev->commands_since_idle_or_otag++;
+ scb->flags |= SCB_ACTIVE;
+ ahd_queue_scb(ahd, scb);
+
+ return 0;
+}
+
+/*
+ * SCSI controller interrupt handler.
+ */
+irqreturn_t
+ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct ahd_softc *ahd;
+ u_long flags;
+ int ours;
+
+ ahd = (struct ahd_softc *) dev_id;
+ ahd_lock(ahd, &flags);
+ ours = ahd_intr(ahd);
+ ahd_unlock(ahd, &flags);
+ return IRQ_RETVAL(ours);
+}
+
+void
+ahd_platform_flushwork(struct ahd_softc *ahd)
+{
+
+}
+
+void
+ahd_send_async(struct ahd_softc *ahd, char channel,
+ u_int target, u_int lun, ac_code code, void *arg)
+{
+ switch (code) {
+ case AC_TRANSFER_NEG:
+ {
+ char buf[80];
+ struct scsi_target *starget;
+ struct ahd_linux_target *targ;
+ struct info_str info;
+ struct ahd_initiator_tinfo *tinfo;
+ struct ahd_tmode_tstate *tstate;
+ unsigned int target_ppr_options;
+
+ BUG_ON(target == CAM_TARGET_WILDCARD);
+
+ info.buffer = buf;
+ info.length = sizeof(buf);
+ info.offset = 0;
+ info.pos = 0;
+ tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,
+ target, &tstate);
+
+ /*
+ * Don't bother reporting results while
+ * negotiations are still pending.
+ */
+ if (tinfo->curr.period != tinfo->goal.period
+ || tinfo->curr.width != tinfo->goal.width
+ || tinfo->curr.offset != tinfo->goal.offset
+ || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
+ if (bootverbose == 0)
+ break;
+
+ /*
+ * Don't bother reporting results that
+ * are identical to those last reported.
+ */
+ starget = ahd->platform_data->starget[target];
+ if (starget == NULL)
+ break;
+ targ = scsi_transport_target_data(starget);
+
+ target_ppr_options =
+ (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0)
+ + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0)
+ + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0)
+ + (spi_rd_strm(starget) ? MSG_EXT_PPR_RD_STRM : 0)
+ + (spi_pcomp_en(starget) ? MSG_EXT_PPR_PCOMP_EN : 0)
+ + (spi_rti(starget) ? MSG_EXT_PPR_RTI : 0)
+ + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0)
+ + (spi_hold_mcs(starget) ? MSG_EXT_PPR_HOLD_MCS : 0);
+
+ if (tinfo->curr.period == spi_period(starget)
+ && tinfo->curr.width == spi_width(starget)
+ && tinfo->curr.offset == spi_offset(starget)
+ && tinfo->curr.ppr_options == target_ppr_options)
+ if (bootverbose == 0)
+ break;
+
+ spi_period(starget) = tinfo->curr.period;
+ spi_width(starget) = tinfo->curr.width;
+ spi_offset(starget) = tinfo->curr.offset;
+ spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0;
+ spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0;
+ spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0;
+ spi_rd_strm(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RD_STRM ? 1 : 0;
+ spi_pcomp_en(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_PCOMP_EN ? 1 : 0;
+ spi_rti(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RTI ? 1 : 0;
+ spi_wr_flow(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_WR_FLOW ? 1 : 0;
+ spi_hold_mcs(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_HOLD_MCS ? 1 : 0;
+ spi_display_xfer_agreement(starget);
+ break;
+ }
+ case AC_SENT_BDR:
+ {
+ WARN_ON(lun != CAM_LUN_WILDCARD);
+ scsi_report_device_reset(ahd->platform_data->host,
+ channel - 'A', target);
+ break;
+ }
+ case AC_BUS_RESET:
+ if (ahd->platform_data->host != NULL) {
+ scsi_report_bus_reset(ahd->platform_data->host,
+ channel - 'A');
+ }
+ break;
+ default:
+ panic("ahd_send_async: Unexpected async event");
+ }
+}
+
+/*
+ * Calls the higher level scsi done function and frees the scb.
+ */
+void
+ahd_done(struct ahd_softc *ahd, struct scb *scb)
+{
+ struct scsi_cmnd *cmd;
+ struct ahd_linux_device *dev;
+
+ if ((scb->flags & SCB_ACTIVE) == 0) {
+ printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
+ ahd_dump_card_state(ahd);
+ panic("Stopping for safety");
+ }
+ LIST_REMOVE(scb, pending_links);
+ cmd = scb->io_ctx;
+ dev = scb->platform_data->dev;
+ dev->active--;
+ dev->openings++;
+ if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) {
+ cmd->result &= ~(CAM_DEV_QFRZN << 16);
+ dev->qfrozen--;
+ }
+ ahd_linux_unmap_scb(ahd, scb);
+
+ /*
+ * Guard against stale sense data.
+ * The Linux mid-layer assumes that sense
+ * was retrieved anytime the first byte of
+ * the sense buffer looks "sane".
+ */
+ cmd->sense_buffer[0] = 0;
+ if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) {
+ uint32_t amount_xferred;
+
+ amount_xferred =
+ ahd_get_transfer_length(scb) - ahd_get_residual(scb);
+ if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) {
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MISC) != 0) {
+ ahd_print_path(ahd, scb);
+ printf("Set CAM_UNCOR_PARITY\n");
+ }
+#endif
+ ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
+#ifdef AHD_REPORT_UNDERFLOWS
+ /*
+ * This code is disabled by default as some
+ * clients of the SCSI system do not properly
+ * initialize the underflow parameter. This
+ * results in spurious termination of commands
+ * that complete as expected (e.g. underflow is
+ * allowed as command can return variable amounts
+ * of data.
+ */
+ } else if (amount_xferred < scb->io_ctx->underflow) {
+ u_int i;
+
+ ahd_print_path(ahd, scb);
+ printf("CDB:");
+ for (i = 0; i < scb->io_ctx->cmd_len; i++)
+ printf(" 0x%x", scb->io_ctx->cmnd[i]);
+ printf("\n");
+ ahd_print_path(ahd, scb);
+ printf("Saw underflow (%ld of %ld bytes). "
+ "Treated as error\n",
+ ahd_get_residual(scb),
+ ahd_get_transfer_length(scb));
+ ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+#endif
+ } else {
+ ahd_set_transaction_status(scb, CAM_REQ_CMP);
+ }
+ } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
+ ahd_linux_handle_scsi_status(ahd, cmd->device, scb);
+ }
+
+ if (dev->openings == 1
+ && ahd_get_transaction_status(scb) == CAM_REQ_CMP
+ && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)
+ dev->tag_success_count++;
+ /*
+ * Some devices deal with temporary internal resource
+ * shortages by returning queue full. When the queue
+ * full occurrs, we throttle back. Slowly try to get
+ * back to our previous queue depth.
+ */
+ if ((dev->openings + dev->active) < dev->maxtags
+ && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) {
+ dev->tag_success_count = 0;
+ dev->openings++;
+ }
+
+ if (dev->active == 0)
+ dev->commands_since_idle_or_otag = 0;
+
+ if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
+ printf("Recovery SCB completes\n");
+ if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
+ || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
+ ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
+ if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
+ ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
+ up(&ahd->platform_data->eh_sem);
+ }
+ }
+
+ ahd_free_scb(ahd, scb);
+ ahd_linux_queue_cmd_complete(ahd, cmd);
+}
+
+static void
+ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
+ struct scsi_device *sdev, struct scb *scb)
+{
+ struct ahd_devinfo devinfo;
+ struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
+
+ ahd_compile_devinfo(&devinfo,
+ ahd->our_id,
+ sdev->sdev_target->id, sdev->lun,
+ sdev->sdev_target->channel == 0 ? 'A' : 'B',
+ ROLE_INITIATOR);
+
+ /*
+ * We don't currently trust the mid-layer to
+ * properly deal with queue full or busy. So,
+ * when one occurs, we tell the mid-layer to
+ * unconditionally requeue the command to us
+ * so that we can retry it ourselves. We also
+ * implement our own throttling mechanism so
+ * we don't clobber the device with too many
+ * commands.
+ */
+ switch (ahd_get_scsi_status(scb)) {
+ default:
+ break;
+ case SCSI_STATUS_CHECK_COND:
+ case SCSI_STATUS_CMD_TERMINATED:
+ {
+ struct scsi_cmnd *cmd;
+
+ /*
+ * Copy sense information to the OS's cmd
+ * structure if it is available.
+ */
+ cmd = scb->io_ctx;
+ if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) {
+ struct scsi_status_iu_header *siu;
+ u_int sense_size;
+ u_int sense_offset;
+
+ if (scb->flags & SCB_SENSE) {
+ sense_size = MIN(sizeof(struct scsi_sense_data)
+ - ahd_get_sense_residual(scb),
+ sizeof(cmd->sense_buffer));
+ sense_offset = 0;
+ } else {
+ /*
+ * Copy only the sense data into the provided
+ * buffer.
+ */
+ siu = (struct scsi_status_iu_header *)
+ scb->sense_data;
+ sense_size = MIN(scsi_4btoul(siu->sense_length),
+ sizeof(cmd->sense_buffer));
+ sense_offset = SIU_SENSE_OFFSET(siu);
+ }
+
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ memcpy(cmd->sense_buffer,
+ ahd_get_sense_buf(ahd, scb)
+ + sense_offset, sense_size);
+ cmd->result |= (DRIVER_SENSE << 24);
+
+#ifdef AHD_DEBUG
+ if (ahd_debug & AHD_SHOW_SENSE) {
+ int i;
+
+ printf("Copied %d bytes of sense data at %d:",
+ sense_size, sense_offset);
+ for (i = 0; i < sense_size; i++) {
+ if ((i & 0xF) == 0)
+ printf("\n");
+ printf("0x%x ", cmd->sense_buffer[i]);
+ }
+ printf("\n");
+ }
+#endif
+ }
+ break;
+ }
+ case SCSI_STATUS_QUEUE_FULL:
+ /*
+ * By the time the core driver has returned this
+ * command, all other commands that were queued
+ * to us but not the device have been returned.
+ * This ensures that dev->active is equal to
+ * the number of commands actually queued to
+ * the device.
+ */
+ dev->tag_success_count = 0;
+ if (dev->active != 0) {
+ /*
+ * Drop our opening count to the number
+ * of commands currently outstanding.
+ */
+ dev->openings = 0;
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
+ ahd_print_path(ahd, scb);
+ printf("Dropping tag count to %d\n",
+ dev->active);
+ }
+#endif
+ if (dev->active == dev->tags_on_last_queuefull) {
+
+ dev->last_queuefull_same_count++;
+ /*
+ * If we repeatedly see a queue full
+ * at the same queue depth, this
+ * device has a fixed number of tag
+ * slots. Lock in this tag depth
+ * so we stop seeing queue fulls from
+ * this device.
+ */
+ if (dev->last_queuefull_same_count
+ == AHD_LOCK_TAGS_COUNT) {
+ dev->maxtags = dev->active;
+ ahd_print_path(ahd, scb);
+ printf("Locking max tag count at %d\n",
+ dev->active);
+ }
+ } else {
+ dev->tags_on_last_queuefull = dev->active;
+ dev->last_queuefull_same_count = 0;
+ }
+ ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
+ ahd_set_scsi_status(scb, SCSI_STATUS_OK);
+ ahd_platform_set_tags(ahd, &devinfo,
+ (dev->flags & AHD_DEV_Q_BASIC)
+ ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
+ break;
+ }
+ /*
+ * Drop down to a single opening, and treat this
+ * as if the target returned BUSY SCSI status.
+ */
+ dev->openings = 1;
+ ahd_platform_set_tags(ahd, &devinfo,
+ (dev->flags & AHD_DEV_Q_BASIC)
+ ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
+ ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
+ }
+}
+
+static void
+ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
+{
+ /*
+ * Map CAM error codes into Linux Error codes. We
+ * avoid the conversion so that the DV code has the
+ * full error information available when making
+ * state change decisions.
+ */
+ {
+ uint32_t status;
+ u_int new_status;
+
+ status = ahd_cmd_get_transaction_status(cmd);
+ switch (status) {
+ case CAM_REQ_INPROG:
+ case CAM_REQ_CMP:
+ case CAM_SCSI_STATUS_ERROR:
+ new_status = DID_OK;
+ break;
+ case CAM_REQ_ABORTED:
+ new_status = DID_ABORT;
+ break;
+ case CAM_BUSY:
+ new_status = DID_BUS_BUSY;
+ break;
+ case CAM_REQ_INVALID:
+ case CAM_PATH_INVALID:
+ new_status = DID_BAD_TARGET;
+ break;
+ case CAM_SEL_TIMEOUT:
+ new_status = DID_NO_CONNECT;
+ break;
+ case CAM_SCSI_BUS_RESET:
+ case CAM_BDR_SENT:
+ new_status = DID_RESET;
+ break;
+ case CAM_UNCOR_PARITY:
+ new_status = DID_PARITY;
+ break;
+ case CAM_CMD_TIMEOUT:
+ new_status = DID_TIME_OUT;
+ break;
+ case CAM_UA_ABORT:
+ case CAM_REQ_CMP_ERR:
+ case CAM_AUTOSENSE_FAIL:
+ case CAM_NO_HBA:
+ case CAM_DATA_RUN_ERR:
+ case CAM_UNEXP_BUSFREE:
+ case CAM_SEQUENCE_FAIL:
+ case CAM_CCB_LEN_ERR:
+ case CAM_PROVIDE_FAIL:
+ case CAM_REQ_TERMIO:
+ case CAM_UNREC_HBA_ERROR:
+ case CAM_REQ_TOO_BIG:
+ new_status = DID_ERROR;
+ break;
+ case CAM_REQUEUE_REQ:
+ new_status = DID_REQUEUE;
+ break;
+ default:
+ /* We should never get here */
+ new_status = DID_ERROR;
+ break;
+ }
+
+ ahd_cmd_set_transaction_status(cmd, new_status);
+ }
+
+ cmd->scsi_done(cmd);
+}
+
+static void
+ahd_linux_sem_timeout(u_long arg)
+{
+ struct ahd_softc *ahd;
+ u_long s;
+
+ ahd = (struct ahd_softc *)arg;
+
+ ahd_lock(ahd, &s);
+ if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
+ ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
+ up(&ahd->platform_data->eh_sem);
+ }
+ ahd_unlock(ahd, &s);
+}
+
+void
+ahd_freeze_simq(struct ahd_softc *ahd)
+{
+ ahd->platform_data->qfrozen++;
+ if (ahd->platform_data->qfrozen == 1) {
+ scsi_block_requests(ahd->platform_data->host);
+ ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+ CAM_LUN_WILDCARD, SCB_LIST_NULL,
+ ROLE_INITIATOR, CAM_REQUEUE_REQ);
+ }
+}
+
+void
+ahd_release_simq(struct ahd_softc *ahd)
+{
+ u_long s;
+ int unblock_reqs;
+
+ unblock_reqs = 0;
+ ahd_lock(ahd, &s);
+ if (ahd->platform_data->qfrozen > 0)
+ ahd->platform_data->qfrozen--;
+ if (ahd->platform_data->qfrozen == 0) {
+ unblock_reqs = 1;
+ }
+ ahd_unlock(ahd, &s);
+ /*
+ * There is still a race here. The mid-layer
+ * should keep its own freeze count and use
+ * a bottom half handler to run the queues
+ * so we can unblock with our own lock held.
+ */
+ if (unblock_reqs)
+ scsi_unblock_requests(ahd->platform_data->host);
+}
+
+static int
+ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
+{
+ struct ahd_softc *ahd;
struct ahd_linux_device *dev;
struct scb *pending_scb;
- u_long s;
u_int saved_scbptr;
u_int active_scbptr;
u_int last_phase;
+ u_int saved_scsiid;
u_int cdb_byte;
int retval;
int was_paused;
@@ -1217,30 +2068,18 @@
paused = FALSE;
wait = FALSE;
ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
- acmd = (struct ahd_cmd *)cmd;
- printf("%s:%d:%d:%d: Attempting to abort cmd %p:",
- ahd_name(ahd), cmd->device->channel, cmd->device->id,
- cmd->device->lun, cmd);
+ printf("%s:%d:%d:%d: Attempting to queue a%s message:",
+ ahd_name(ahd), cmd->device->channel,
+ cmd->device->id, cmd->device->lun,
+ flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
+
+ printf("CDB:");
for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
printf(" 0x%x", cmd->cmnd[cdb_byte]);
printf("\n");
- /*
- * In all versions of Linux, we have to work around
- * a major flaw in how the mid-layer is locked down
- * if we are to sleep successfully in our error handler
- * while allowing our interrupt handler to run. Since
- * the midlayer acquires either the io_request_lock or
- * our lock prior to calling us, we must use the
- * spin_unlock_irq() method for unlocking our lock.
- * This will force interrupts to be enabled on the
- * current CPU. Since the EH thread should not have
- * been running with CPU interrupts disabled other than
- * by acquiring either the io_request_lock or our own
- * lock, this *should* be safe.
- */
- ahd_midlayer_entrypoint_lock(ahd, &s);
+ spin_lock_irq(&ahd->platform_data->spin_lock);
/*
* First determine if we currently own this command.
@@ -1249,9 +2088,7 @@
* at all, and the system wanted us to just abort the
* command, return success.
*/
- dev = ahd_linux_get_device(ahd, cmd->device->channel,
- cmd->device->id, cmd->device->lun,
- /*alloc*/FALSE);
+ dev = scsi_transport_device_data(cmd->device);
if (dev == NULL) {
/*
@@ -1265,22 +2102,6 @@
goto no_cmd;
}
- TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {
- if (list_acmd == acmd)
- break;
- }
-
- if (list_acmd != NULL) {
- printf("%s:%d:%d:%d: Command found on device queue\n",
- ahd_name(ahd), cmd->device->channel, cmd->device->id,
- cmd->device->lun);
- TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
- cmd->result = DID_ABORT << 16;
- ahd_linux_queue_cmd_complete(ahd, cmd);
- retval = SUCCESS;
- goto done;
- }
-
/*
* See if we can find a matching cmd in the pending list.
*/
@@ -1289,6 +2110,18 @@
break;
}
+ if (pending_scb == NULL && flag == SCB_DEVICE_RESET) {
+
+ /* Any SCB for this device will do for a target reset */
+ LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
+ if (ahd_match_scb(ahd, pending_scb, cmd->device->id,
+ cmd->device->channel + 'A',
+ CAM_LUN_WILDCARD,
+ SCB_LIST_NULL, ROLE_INITIATOR) == 0)
+ break;
+ }
+ }
+
if (pending_scb == NULL) {
printf("%s:%d:%d:%d: Command not found\n",
ahd_name(ahd), cmd->device->channel, cmd->device->id,
@@ -1326,15 +2159,25 @@
ahd_dump_card_state(ahd);
disconnected = TRUE;
- if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A',
- cmd->device->lun, SCB_GET_TAG(pending_scb),
- ROLE_INITIATOR, CAM_REQ_ABORTED,
- SEARCH_COMPLETE) > 0) {
- printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
- ahd_name(ahd), cmd->device->channel, cmd->device->id,
- cmd->device->lun);
- retval = SUCCESS;
- goto done;
+ if (flag == SCB_ABORT) {
+ if (ahd_search_qinfifo(ahd, cmd->device->id,
+ cmd->device->channel + 'A',
+ cmd->device->lun,
+ pending_scb->hscb->tag,
+ ROLE_INITIATOR, CAM_REQ_ABORTED,
+ SEARCH_COMPLETE) > 0) {
+ printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+ ahd_name(ahd), cmd->device->channel,
+ cmd->device->id, cmd->device->lun);
+ retval = SUCCESS;
+ goto done;
+ }
+ } else if (ahd_search_qinfifo(ahd, cmd->device->id,
+ cmd->device->channel + 'A',
+ cmd->device->lun, pending_scb->hscb->tag,
+ ROLE_INITIATOR, /*status*/0,
+ SEARCH_COUNT) > 0) {
+ disconnected = FALSE;
}
saved_modes = ahd_save_modes(ahd);
@@ -1348,6 +2191,10 @@
bus_scb = ahd_lookup_scb(ahd, active_scbptr);
if (bus_scb == pending_scb)
disconnected = FALSE;
+ else if (flag != SCB_ABORT
+ && ahd_inb(ahd, SAVED_SCSIID) == pending_scb->hscb->scsiid
+ && ahd_inb(ahd, SAVED_LUN) == SCB_GET_LUN(pending_scb))
+ disconnected = FALSE;
}
/*
@@ -1355,15 +2202,18 @@
* passed in command. That command is currently active on the
* bus or is in the disconnected state.
*/
+ saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
if (last_phase != P_BUSFREE
- && SCB_GET_TAG(pending_scb) == active_scbptr) {
+ && (SCB_GET_TAG(pending_scb) == active_scbptr
+ || (flag == SCB_DEVICE_RESET
+ && SCSIID_TARGET(ahd, saved_scsiid) == cmd->device->id))) {
/*
* We're active on the bus, so assert ATN
* and hope that the target responds.
*/
pending_scb = ahd_lookup_scb(ahd, active_scbptr);
- pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
+ pending_scb->flags |= SCB_RECOVERY_SCB|flag;
ahd_outb(ahd, MSG_OUT, HOST_MSG);
ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
printf("%s:%d:%d:%d: Device is active, asserting ATN\n",
@@ -1451,10 +2301,10 @@
struct timer_list timer;
int ret;
- pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
+ ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM;
spin_unlock_irq(&ahd->platform_data->spin_lock);
init_timer(&timer);
- timer.data = (u_long)pending_scb;
+ timer.data = (u_long)ahd;
timer.expires = jiffies + (5 * HZ);
timer.function = ahd_linux_sem_timeout;
add_timer(&timer);
@@ -1468,3549 +2318,471 @@
}
spin_lock_irq(&ahd->platform_data->spin_lock);
}
- ahd_schedule_runq(ahd);
- ahd_linux_run_complete_queue(ahd);
- ahd_midlayer_entrypoint_unlock(ahd, &s);
+ spin_unlock_irq(&ahd->platform_data->spin_lock);
return (retval);
}
-
-static void
-ahd_linux_dev_reset_complete(Scsi_Cmnd *cmd)
+static void ahd_linux_set_width(struct scsi_target *starget, int width)
{
- free(cmd, M_DEVBUF);
-}
-
-/*
- * Attempt to send a target reset message to the device that timed out.
- */
-static int
-ahd_linux_dev_reset(Scsi_Cmnd *cmd)
-{
- struct ahd_softc *ahd;
- struct scsi_cmnd *recovery_cmd;
- struct ahd_linux_device *dev;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_tmode_tstate *tstate;
- struct scb *scb;
- struct hardware_scb *hscb;
- u_long s;
- struct timer_list timer;
- int retval;
-
- ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
- recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
- if (!recovery_cmd)
- return (FAILED);
- memset(recovery_cmd, 0, sizeof(struct scsi_cmnd));
- recovery_cmd->device = cmd->device;
- recovery_cmd->scsi_done = ahd_linux_dev_reset_complete;
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
- printf("%s:%d:%d:%d: Device reset called for cmd %p\n",
- ahd_name(ahd), cmd->device->channel, cmd->device->id,
- cmd->device->lun, cmd);
-#endif
- ahd_lock(ahd, &s);
-
- dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id,
- cmd->device->lun, /*alloc*/FALSE);
- if (dev == NULL) {
- ahd_unlock(ahd, &s);
- kfree(recovery_cmd);
- return (FAILED);
- }
- if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) {
- ahd_unlock(ahd, &s);
- kfree(recovery_cmd);
- return (FAILED);
- }
- tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
- cmd->device->id, &tstate);
- recovery_cmd->result = CAM_REQ_INPROG << 16;
- recovery_cmd->host_scribble = (char *)scb;
- scb->io_ctx = recovery_cmd;
- scb->platform_data->dev = dev;
- scb->sg_count = 0;
- ahd_set_residual(scb, 0);
- ahd_set_sense_residual(scb, 0);
- hscb = scb->hscb;
- hscb->control = 0;
- hscb->scsiid = BUILD_SCSIID(ahd, cmd);
- hscb->lun = cmd->device->lun;
- hscb->cdb_len = 0;
- hscb->task_management = SIU_TASKMGMT_LUN_RESET;
- scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;
- if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
- scb->flags |= SCB_PACKETIZED;
- } else {
- hscb->control |= MK_MESSAGE;
- }
- dev->openings--;
- dev->active++;
- dev->commands_issued++;
- LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
- ahd_queue_scb(ahd, scb);
-
- scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
- ahd_unlock(ahd, &s);
- init_timer(&timer);
- timer.data = (u_long)scb;
- timer.expires = jiffies + (5 * HZ);
- timer.function = ahd_linux_sem_timeout;
- add_timer(&timer);
- printf("Recovery code sleeping\n");
- down(&ahd->platform_data->eh_sem);
- printf("Recovery code awake\n");
- retval = SUCCESS;
- if (del_timer_sync(&timer) == 0) {
- printf("Timer Expired\n");
- retval = FAILED;
- }
- ahd_lock(ahd, &s);
- ahd_schedule_runq(ahd);
- ahd_linux_run_complete_queue(ahd);
- ahd_unlock(ahd, &s);
- printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
- return (retval);
-}
-
-/*
- * Reset the SCSI bus.
- */
-static int
-ahd_linux_bus_reset(Scsi_Cmnd *cmd)
-{
- struct ahd_softc *ahd;
- u_long s;
- int found;
-
- ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
- printf("%s: Bus reset called for cmd %p\n",
- ahd_name(ahd), cmd);
-#endif
- ahd_lock(ahd, &s);
- found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
- /*initiate reset*/TRUE);
- ahd_linux_run_complete_queue(ahd);
- ahd_unlock(ahd, &s);
-
- if (bootverbose)
- printf("%s: SCSI bus reset delivered. "
- "%d SCBs aborted.\n", ahd_name(ahd), found);
-
- return (SUCCESS);
-}
-
-Scsi_Host_Template aic79xx_driver_template = {
- .module = THIS_MODULE,
- .name = "aic79xx",
- .proc_info = ahd_linux_proc_info,
- .info = ahd_linux_info,
- .queuecommand = ahd_linux_queue,
- .eh_abort_handler = ahd_linux_abort,
- .eh_device_reset_handler = ahd_linux_dev_reset,
- .eh_bus_reset_handler = ahd_linux_bus_reset,
-#if defined(__i386__)
- .bios_param = ahd_linux_biosparam,
-#endif
- .can_queue = AHD_MAX_QUEUE,
- .this_id = -1,
- .cmd_per_lun = 2,
- .use_clustering = ENABLE_CLUSTERING,
- .slave_alloc = ahd_linux_slave_alloc,
- .slave_configure = ahd_linux_slave_configure,
- .slave_destroy = ahd_linux_slave_destroy,
-};
-
-/**************************** Tasklet Handler *********************************/
-
-/*
- * In 2.4.X and above, this routine is called from a tasklet,
- * so we must re-acquire our lock prior to executing this code.
- * In all prior kernels, ahd_schedule_runq() calls this routine
- * directly and ahd_schedule_runq() is called with our lock held.
- */
-static void
-ahd_runq_tasklet(unsigned long data)
-{
- struct ahd_softc* ahd;
- struct ahd_linux_device *dev;
- u_long flags;
-
- ahd = (struct ahd_softc *)data;
- ahd_lock(ahd, &flags);
- while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
-
- TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
- dev->flags &= ~AHD_DEV_ON_RUN_LIST;
- ahd_linux_check_device_queue(ahd, dev);
- /* Yeild to our interrupt handler */
- ahd_unlock(ahd, &flags);
- ahd_lock(ahd, &flags);
- }
- ahd_unlock(ahd, &flags);
-}
-
-/******************************** Bus DMA *************************************/
-int
-ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
- bus_size_t alignment, bus_size_t boundary,
- dma_addr_t lowaddr, dma_addr_t highaddr,
- bus_dma_filter_t *filter, void *filterarg,
- bus_size_t maxsize, int nsegments,
- bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag)
-{
- bus_dma_tag_t dmat;
-
- dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
- if (dmat == NULL)
- return (ENOMEM);
-
- /*
- * Linux is very simplistic about DMA memory. For now don't
- * maintain all specification information. Once Linux supplies
- * better facilities for doing these operations, or the
- * needs of this particular driver change, we might need to do
- * more here.
- */
- dmat->alignment = alignment;
- dmat->boundary = boundary;
- dmat->maxsize = maxsize;
- *ret_tag = dmat;
- return (0);
-}
-
-void
-ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat)
-{
- free(dmat, M_DEVBUF);
-}
-
-int
-ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr,
- int flags, bus_dmamap_t *mapp)
-{
- bus_dmamap_t map;
-
- map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
- if (map == NULL)
- return (ENOMEM);
- /*
- * Although we can dma data above 4GB, our
- * "consistent" memory is below 4GB for
- * space efficiency reasons (only need a 4byte
- * address). For this reason, we have to reset
- * our dma mask when doing allocations.
- */
- if (ahd->dev_softc != NULL)
- if (pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF)) {
- printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");
- kfree(map);
- return (ENODEV);
- }
- *vaddr = pci_alloc_consistent(ahd->dev_softc,
- dmat->maxsize, &map->bus_addr);
- if (ahd->dev_softc != NULL)
- if (pci_set_dma_mask(ahd->dev_softc,
- ahd->platform_data->hw_dma_mask)) {
- printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");
- kfree(map);
- return (ENODEV);
- }
- if (*vaddr == NULL)
- return (ENOMEM);
- *mapp = map;
- return(0);
-}
-
-void
-ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,
- void* vaddr, bus_dmamap_t map)
-{
- pci_free_consistent(ahd->dev_softc, dmat->maxsize,
- vaddr, map->bus_addr);
-}
-
-int
-ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map,
- void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,
- void *cb_arg, int flags)
-{
- /*
- * Assume for now that this will only be used during
- * initialization and not for per-transaction buffer mapping.
- */
- bus_dma_segment_t stack_sg;
-
- stack_sg.ds_addr = map->bus_addr;
- stack_sg.ds_len = dmat->maxsize;
- cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
- return (0);
-}
-
-void
-ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
-{
- /*
- * The map may is NULL in our < 2.3.X implementation.
- */
- if (map != NULL)
- free(map, M_DEVBUF);
-}
-
-int
-ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
-{
- /* Nothing to do */
- return (0);
-}
-
-/********************* Platform Dependent Functions ***************************/
-/*
- * Compare "left hand" softc with "right hand" softc, returning:
- * < 0 - lahd has a lower priority than rahd
- * 0 - Softcs are equal
- * > 0 - lahd has a higher priority than rahd
- */
-int
-ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
-{
- int value;
-
- /*
- * Under Linux, cards are ordered as follows:
- * 1) PCI devices that are marked as the boot controller.
- * 2) PCI devices with BIOS enabled sorted by bus/slot/func.
- * 3) All remaining PCI devices sorted by bus/slot/func.
- */
-#if 0
- value = (lahd->flags & AHD_BOOT_CHANNEL)
- - (rahd->flags & AHD_BOOT_CHANNEL);
- if (value != 0)
- /* Controllers set for boot have a *higher* priority */
- return (value);
-#endif
-
- value = (lahd->flags & AHD_BIOS_ENABLED)
- - (rahd->flags & AHD_BIOS_ENABLED);
- if (value != 0)
- /* Controllers with BIOS enabled have a *higher* priority */
- return (value);
-
- /* Still equal. Sort by bus/slot/func. */
- if (aic79xx_reverse_scan != 0)
- value = ahd_get_pci_bus(lahd->dev_softc)
- - ahd_get_pci_bus(rahd->dev_softc);
- else
- value = ahd_get_pci_bus(rahd->dev_softc)
- - ahd_get_pci_bus(lahd->dev_softc);
- if (value != 0)
- return (value);
- if (aic79xx_reverse_scan != 0)
- value = ahd_get_pci_slot(lahd->dev_softc)
- - ahd_get_pci_slot(rahd->dev_softc);
- else
- value = ahd_get_pci_slot(rahd->dev_softc)
- - ahd_get_pci_slot(lahd->dev_softc);
- if (value != 0)
- return (value);
-
- value = rahd->channel - lahd->channel;
- return (value);
-}
-
-static void
-ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
-{
-
- if ((instance >= 0) && (targ >= 0)
- && (instance < NUM_ELEMENTS(aic79xx_tag_info))
- && (targ < AHD_NUM_TARGETS)) {
- aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
- if (bootverbose)
- printf("tag_info[%d:%d] = %d\n", instance, targ, value);
- }
-}
-
-static void
-ahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value)
-{
- if ((instance >= 0)
- && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
- aic79xx_rd_strm_info[instance] = value & 0xFFFF;
- if (bootverbose)
- printf("rd_strm[%d] = 0x%x\n", instance, value);
- }
-}
-
-static void
-ahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
-{
- if ((instance >= 0)
- && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
- aic79xx_dv_settings[instance] = value;
- if (bootverbose)
- printf("dv[%d] = %d\n", instance, value);
- }
-}
-
-static void
-ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
-{
-
- if ((instance >= 0)
- && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
- uint8_t *iocell_info;
-
- iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
- iocell_info[index] = value & 0xFFFF;
- if (bootverbose)
- printf("iocell[%d:%ld] = %d\n", instance, index, value);
- }
-}
-
-static void
-ahd_linux_setup_tag_info_global(char *p)
-{
- int tags, i, j;
-
- tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
- printf("Setting Global Tags= %d\n", tags);
-
- for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) {
- for (j = 0; j < AHD_NUM_TARGETS; j++) {
- aic79xx_tag_info[i].tag_commands[j] = tags;
- }
- }
-}
-
-/*
- * Handle Linux boot parameters. This routine allows for assigning a value
- * to a parameter with a ':' between the parameter and the value.
- * ie. aic79xx=stpwlev:1,extended
- */
-static int
-aic79xx_setup(char *s)
-{
- int i, n;
- char *p;
- char *end;
-
- static struct {
- const char *name;
- uint32_t *flag;
- } options[] = {
- { "extended", &aic79xx_extended },
- { "no_reset", &aic79xx_no_reset },
- { "verbose", &aic79xx_verbose },
- { "allow_memio", &aic79xx_allow_memio},
-#ifdef AHD_DEBUG
- { "debug", &ahd_debug },
-#endif
- { "reverse_scan", &aic79xx_reverse_scan },
- { "periodic_otag", &aic79xx_periodic_otag },
- { "pci_parity", &aic79xx_pci_parity },
- { "seltime", &aic79xx_seltime },
- { "tag_info", NULL },
- { "global_tag_depth", NULL},
- { "rd_strm", NULL },
- { "dv", NULL },
- { "slewrate", NULL },
- { "precomp", NULL },
- { "amplitude", NULL },
- };
-
- end = strchr(s, '\0');
-
- /*
- * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
- * will never be 0 in this case.
- */
- n = 0;
-
- while ((p = strsep(&s, ",.")) != NULL) {
- if (*p == '\0')
- continue;
- for (i = 0; i < NUM_ELEMENTS(options); i++) {
-
- n = strlen(options[i].name);
- if (strncmp(options[i].name, p, n) == 0)
- break;
- }
- if (i == NUM_ELEMENTS(options))
- continue;
-
- if (strncmp(p, "global_tag_depth", n) == 0) {
- ahd_linux_setup_tag_info_global(p + n);
- } else if (strncmp(p, "tag_info", n) == 0) {
- s = aic_parse_brace_option("tag_info", p + n, end,
- 2, ahd_linux_setup_tag_info, 0);
- } else if (strncmp(p, "rd_strm", n) == 0) {
- s = aic_parse_brace_option("rd_strm", p + n, end,
- 1, ahd_linux_setup_rd_strm_info, 0);
- } else if (strncmp(p, "dv", n) == 0) {
- s = aic_parse_brace_option("dv", p + n, end, 1,
- ahd_linux_setup_dv, 0);
- } else if (strncmp(p, "slewrate", n) == 0) {
- s = aic_parse_brace_option("slewrate",
- p + n, end, 1, ahd_linux_setup_iocell_info,
- AIC79XX_SLEWRATE_INDEX);
- } else if (strncmp(p, "precomp", n) == 0) {
- s = aic_parse_brace_option("precomp",
- p + n, end, 1, ahd_linux_setup_iocell_info,
- AIC79XX_PRECOMP_INDEX);
- } else if (strncmp(p, "amplitude", n) == 0) {
- s = aic_parse_brace_option("amplitude",
- p + n, end, 1, ahd_linux_setup_iocell_info,
- AIC79XX_AMPLITUDE_INDEX);
- } else if (p[n] == ':') {
- *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
- } else if (!strncmp(p, "verbose", n)) {
- *(options[i].flag) = 1;
- } else {
- *(options[i].flag) ^= 0xFFFFFFFF;
- }
- }
- return 1;
-}
-
-__setup("aic79xx=", aic79xx_setup);
-
-uint32_t aic79xx_verbose;
-
-int
-ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
-{
- char buf[80];
- struct Scsi_Host *host;
- char *new_name;
- u_long s;
- u_long target;
-
- template->name = ahd->description;
- host = scsi_host_alloc(template, sizeof(struct ahd_softc *));
- if (host == NULL)
- return (ENOMEM);
-
- *((struct ahd_softc **)host->hostdata) = ahd;
- ahd_lock(ahd, &s);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- scsi_assign_lock(host, &ahd->platform_data->spin_lock);
-#elif AHD_SCSI_HAS_HOST_LOCK != 0
- host->lock = &ahd->platform_data->spin_lock;
-#endif
- ahd->platform_data->host = host;
- host->can_queue = AHD_MAX_QUEUE;
- host->cmd_per_lun = 2;
- host->sg_tablesize = AHD_NSEG;
- host->this_id = ahd->our_id;
- host->irq = ahd->platform_data->irq;
- host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8;
- host->max_lun = AHD_NUM_LUNS;
- host->max_channel = 0;
- host->sg_tablesize = AHD_NSEG;
- ahd_set_unit(ahd, ahd_linux_next_unit());
- sprintf(buf, "scsi%d", host->host_no);
- new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
- if (new_name != NULL) {
- strcpy(new_name, buf);
- ahd_set_name(ahd, new_name);
- }
- host->unique_id = ahd->unit;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- scsi_set_pci_device(host, ahd->dev_softc);
-#endif
- ahd_linux_setup_user_rd_strm_settings(ahd);
- ahd_linux_initialize_scsi_bus(ahd);
- ahd_unlock(ahd, &s);
- ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0);
- ahd_lock(ahd, &s);
- if (ahd->platform_data->dv_pid < 0) {
- printf("%s: Failed to create DV thread, error= %d\n",
- ahd_name(ahd), ahd->platform_data->dv_pid);
- return (-ahd->platform_data->dv_pid);
- }
- /*
- * Initially allocate *all* of our linux target objects
- * so that the DV thread will scan them all in parallel
- * just after driver initialization. Any device that
- * does not exist will have its target object destroyed
- * by the selection timeout handler. In the case of a
- * device that appears after the initial DV scan, async
- * negotiation will occur for the first command, and DV
- * will comence should that first command be successful.
- */
- for (target = 0; target < host->max_id; target++) {
-
- /*
- * Skip our own ID. Some Compaq/HP storage devices
- * have enclosure management devices that respond to
- * single bit selection (i.e. selecting ourselves).
- * It is expected that either an external application
- * or a modified kernel will be used to probe this
- * ID if it is appropriate. To accommodate these
- * installations, ahc_linux_alloc_target() will allocate
- * for our ID if asked to do so.
- */
- if (target == ahd->our_id)
- continue;
-
- ahd_linux_alloc_target(ahd, 0, target);
- }
- ahd_intr_enable(ahd, TRUE);
- ahd_linux_start_dv(ahd);
- ahd_unlock(ahd, &s);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */
- scsi_scan_host(host);
-#endif
- return (0);
-}
-
-uint64_t
-ahd_linux_get_memsize(void)
-{
- struct sysinfo si;
-
- si_meminfo(&si);
- return ((uint64_t)si.totalram << PAGE_SHIFT);
-}
-
-/*
- * Find the smallest available unit number to use
- * for a new device. We don't just use a static
- * count to handle the "repeated hot-(un)plug"
- * scenario.
- */
-static int
-ahd_linux_next_unit(void)
-{
- struct ahd_softc *ahd;
- int unit;
-
- unit = 0;
-retry:
- TAILQ_FOREACH(ahd, &ahd_tailq, links) {
- if (ahd->unit == unit) {
- unit++;
- goto retry;
- }
- }
- return (unit);
-}
-
-/*
- * Place the SCSI bus into a known state by either resetting it,
- * or forcing transfer negotiations on the next command to any
- * target.
- */
-static void
-ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
-{
- u_int target_id;
- u_int numtarg;
-
- target_id = 0;
- numtarg = 0;
-
- if (aic79xx_no_reset != 0)
- ahd->flags &= ~AHD_RESET_BUS_A;
-
- if ((ahd->flags & AHD_RESET_BUS_A) != 0)
- ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE);
- else
- numtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
-
- /*
- * Force negotiation to async for all targets that
- * will not see an initial bus reset.
- */
- for (; target_id < numtarg; target_id++) {
- struct ahd_devinfo devinfo;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_tmode_tstate *tstate;
-
- tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
- target_id, &tstate);
- ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
- CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
- ahd_update_neg_request(ahd, &devinfo, tstate,
- tinfo, AHD_NEG_ALWAYS);
- }
- /* Give the bus some time to recover */
- if ((ahd->flags & AHD_RESET_BUS_A) != 0) {
- ahd_freeze_simq(ahd);
- init_timer(&ahd->platform_data->reset_timer);
- ahd->platform_data->reset_timer.data = (u_long)ahd;
- ahd->platform_data->reset_timer.expires =
- jiffies + (AIC79XX_RESET_DELAY * HZ)/1000;
- ahd->platform_data->reset_timer.function =
- (ahd_linux_callback_t *)ahd_release_simq;
- add_timer(&ahd->platform_data->reset_timer);
- }
-}
-
-int
-ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
-{
- ahd->platform_data =
- malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);
- if (ahd->platform_data == NULL)
- return (ENOMEM);
- memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
- TAILQ_INIT(&ahd->platform_data->completeq);
- TAILQ_INIT(&ahd->platform_data->device_runq);
- ahd->platform_data->irq = AHD_LINUX_NOIRQ;
- ahd->platform_data->hw_dma_mask = 0xFFFFFFFF;
- ahd_lockinit(ahd);
- ahd_done_lockinit(ahd);
- init_timer(&ahd->platform_data->completeq_timer);
- ahd->platform_data->completeq_timer.data = (u_long)ahd;
- ahd->platform_data->completeq_timer.function =
- (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue;
- init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);
- init_MUTEX_LOCKED(&ahd->platform_data->dv_sem);
- init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem);
- ahd_setup_runq_tasklet(ahd);
- ahd->seltime = (aic79xx_seltime & 0x3) << 4;
- return (0);
-}
-
-void
-ahd_platform_free(struct ahd_softc *ahd)
-{
- struct ahd_linux_target *targ;
- struct ahd_linux_device *dev;
- int i, j;
-
- if (ahd->platform_data != NULL) {
- del_timer_sync(&ahd->platform_data->completeq_timer);
- ahd_linux_kill_dv_thread(ahd);
- ahd_teardown_runq_tasklet(ahd);
- if (ahd->platform_data->host != NULL) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- scsi_remove_host(ahd->platform_data->host);
-#endif
- scsi_host_put(ahd->platform_data->host);
- }
-
- /* destroy all of the device and target objects */
- for (i = 0; i < AHD_NUM_TARGETS; i++) {
- targ = ahd->platform_data->targets[i];
- if (targ != NULL) {
- /* Keep target around through the loop. */
- targ->refcount++;
- for (j = 0; j < AHD_NUM_LUNS; j++) {
-
- if (targ->devices[j] == NULL)
- continue;
- dev = targ->devices[j];
- ahd_linux_free_device(ahd, dev);
- }
- /*
- * Forcibly free the target now that
- * all devices are gone.
- */
- ahd_linux_free_target(ahd, targ);
- }
- }
-
- if (ahd->platform_data->irq != AHD_LINUX_NOIRQ)
- free_irq(ahd->platform_data->irq, ahd);
- if (ahd->tags[0] == BUS_SPACE_PIO
- && ahd->bshs[0].ioport != 0)
- release_region(ahd->bshs[0].ioport, 256);
- if (ahd->tags[1] == BUS_SPACE_PIO
- && ahd->bshs[1].ioport != 0)
- release_region(ahd->bshs[1].ioport, 256);
- if (ahd->tags[0] == BUS_SPACE_MEMIO
- && ahd->bshs[0].maddr != NULL) {
- iounmap(ahd->bshs[0].maddr);
- release_mem_region(ahd->platform_data->mem_busaddr,
- 0x1000);
- }
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- /*
- * In 2.4 we detach from the scsi midlayer before the PCI
- * layer invokes our remove callback. No per-instance
- * detach is provided, so we must reach inside the PCI
- * subsystem's internals and detach our driver manually.
- */
- if (ahd->dev_softc != NULL)
- ahd->dev_softc->driver = NULL;
-#endif
- free(ahd->platform_data, M_DEVBUF);
- }
-}
-
-void
-ahd_platform_init(struct ahd_softc *ahd)
-{
- /*
- * Lookup and commit any modified IO Cell options.
- */
- if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) {
- struct ahd_linux_iocell_opts *iocell_opts;
-
- iocell_opts = &aic79xx_iocell_info[ahd->unit];
- if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
- AHD_SET_PRECOMP(ahd, iocell_opts->precomp);
- if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE)
- AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate);
- if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE)
- AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude);
- }
-
-}
-
-void
-ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
-{
- ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
- SCB_GET_CHANNEL(ahd, scb),
- SCB_GET_LUN(scb), SCB_LIST_NULL,
- ROLE_UNKNOWN, CAM_REQUEUE_REQ);
-}
-
-void
-ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
- ahd_queue_alg alg)
-{
- struct ahd_linux_device *dev;
- int was_queuing;
- int now_queuing;
-
- dev = ahd_linux_get_device(ahd, devinfo->channel - 'A',
- devinfo->target,
- devinfo->lun, /*alloc*/FALSE);
- if (dev == NULL)
- return;
- was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED);
- switch (alg) {
- default:
- case AHD_QUEUE_NONE:
- now_queuing = 0;
- break;
- case AHD_QUEUE_BASIC:
- now_queuing = AHD_DEV_Q_BASIC;
- break;
- case AHD_QUEUE_TAGGED:
- now_queuing = AHD_DEV_Q_TAGGED;
- break;
- }
- if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0
- && (was_queuing != now_queuing)
- && (dev->active != 0)) {
- dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY;
- dev->qfrozen++;
- }
-
- dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG);
- if (now_queuing) {
- u_int usertags;
-
- usertags = ahd_linux_user_tagdepth(ahd, devinfo);
- if (!was_queuing) {
- /*
- * Start out agressively and allow our
- * dynamic queue depth algorithm to take
- * care of the rest.
- */
- dev->maxtags = usertags;
- dev->openings = dev->maxtags - dev->active;
- }
- if (dev->maxtags == 0) {
- /*
- * Queueing is disabled by the user.
- */
- dev->openings = 1;
- } else if (alg == AHD_QUEUE_TAGGED) {
- dev->flags |= AHD_DEV_Q_TAGGED;
- if (aic79xx_periodic_otag != 0)
- dev->flags |= AHD_DEV_PERIODIC_OTAG;
- } else
- dev->flags |= AHD_DEV_Q_BASIC;
- } else {
- /* We can only have one opening. */
- dev->maxtags = 0;
- dev->openings = 1 - dev->active;
- }
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- if (dev->scsi_device != NULL) {
- switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {
- case AHD_DEV_Q_BASIC:
- scsi_adjust_queue_depth(dev->scsi_device,
- MSG_SIMPLE_TASK,
- dev->openings + dev->active);
- break;
- case AHD_DEV_Q_TAGGED:
- scsi_adjust_queue_depth(dev->scsi_device,
- MSG_ORDERED_TASK,
- dev->openings + dev->active);
- break;
- default:
- /*
- * We allow the OS to queue 2 untagged transactions to
- * us at any time even though we can only execute them
- * serially on the controller/device. This should
- * remove some latency.
- */
- scsi_adjust_queue_depth(dev->scsi_device,
- /*NON-TAGGED*/0,
- /*queue depth*/2);
- break;
- }
- }
-#endif
-}
-
-int
-ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel,
- int lun, u_int tag, role_t role, uint32_t status)
-{
- int targ;
- int maxtarg;
- int maxlun;
- int clun;
- int count;
-
- if (tag != SCB_LIST_NULL)
- return (0);
-
- targ = 0;
- if (target != CAM_TARGET_WILDCARD) {
- targ = target;
- maxtarg = targ + 1;
- } else {
- maxtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
- }
- clun = 0;
- if (lun != CAM_LUN_WILDCARD) {
- clun = lun;
- maxlun = clun + 1;
- } else {
- maxlun = AHD_NUM_LUNS;
- }
-
- count = 0;
- for (; targ < maxtarg; targ++) {
-
- for (; clun < maxlun; clun++) {
- struct ahd_linux_device *dev;
- struct ahd_busyq *busyq;
- struct ahd_cmd *acmd;
-
- dev = ahd_linux_get_device(ahd, /*chan*/0, targ,
- clun, /*alloc*/FALSE);
- if (dev == NULL)
- continue;
-
- busyq = &dev->busyq;
- while ((acmd = TAILQ_FIRST(busyq)) != NULL) {
- Scsi_Cmnd *cmd;
-
- cmd = &acmd_scsi_cmd(acmd);
- TAILQ_REMOVE(busyq, acmd,
- acmd_links.tqe);
- count++;
- cmd->result = status << 16;
- ahd_linux_queue_cmd_complete(ahd, cmd);
- }
- }
- }
-
- return (count);
-}
-
-static void
-ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd)
-{
- u_long flags;
-
- ahd_lock(ahd, &flags);
- del_timer(&ahd->platform_data->completeq_timer);
- ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER;
- ahd_linux_run_complete_queue(ahd);
- ahd_unlock(ahd, &flags);
-}
-
-static void
-ahd_linux_start_dv(struct ahd_softc *ahd)
-{
-
- /*
- * Freeze the simq and signal ahd_linux_queue to not let any
- * more commands through
- */
- if ((ahd->platform_data->flags & AHD_DV_ACTIVE) == 0) {
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV)
- printf("%s: Starting DV\n", ahd_name(ahd));
-#endif
-
- ahd->platform_data->flags |= AHD_DV_ACTIVE;
- ahd_freeze_simq(ahd);
-
- /* Wake up the DV kthread */
- up(&ahd->platform_data->dv_sem);
- }
-}
-
-static int
-ahd_linux_dv_thread(void *data)
-{
- struct ahd_softc *ahd;
- int target;
- u_long s;
-
- ahd = (struct ahd_softc *)data;
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV)
- printf("In DV Thread\n");
-#endif
-
- /*
- * Complete thread creation.
- */
- lock_kernel();
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
- /*
- * Don't care about any signals.
- */
- siginitsetinv(¤t->blocked, 0);
-
- daemonize();
- sprintf(current->comm, "ahd_dv_%d", ahd->unit);
-#else
- daemonize("ahd_dv_%d", ahd->unit);
- current->flags |= PF_NOFREEZE;
-#endif
- unlock_kernel();
-
- while (1) {
- /*
- * Use down_interruptible() rather than down() to
- * avoid inclusion in the load average.
- */
- down_interruptible(&ahd->platform_data->dv_sem);
-
- /* Check to see if we've been signaled to exit */
- ahd_lock(ahd, &s);
- if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) {
- ahd_unlock(ahd, &s);
- break;
- }
- ahd_unlock(ahd, &s);
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV)
- printf("%s: Beginning Domain Validation\n",
- ahd_name(ahd));
-#endif
-
- /*
- * Wait for any pending commands to drain before proceeding.
- */
- ahd_lock(ahd, &s);
- while (LIST_FIRST(&ahd->pending_scbs) != NULL) {
- ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_EMPTY;
- ahd_unlock(ahd, &s);
- down_interruptible(&ahd->platform_data->dv_sem);
- ahd_lock(ahd, &s);
- }
-
- /*
- * Wait for the SIMQ to be released so that DV is the
- * only reason the queue is frozen.
- */
- while (AHD_DV_SIMQ_FROZEN(ahd) == 0) {
- ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE;
- ahd_unlock(ahd, &s);
- down_interruptible(&ahd->platform_data->dv_sem);
- ahd_lock(ahd, &s);
- }
- ahd_unlock(ahd, &s);
-
- for (target = 0; target < AHD_NUM_TARGETS; target++)
- ahd_linux_dv_target(ahd, target);
-
- ahd_lock(ahd, &s);
- ahd->platform_data->flags &= ~AHD_DV_ACTIVE;
- ahd_unlock(ahd, &s);
-
- /*
- * Release the SIMQ so that normal commands are
- * allowed to continue on the bus.
- */
- ahd_release_simq(ahd);
- }
- up(&ahd->platform_data->eh_sem);
- return (0);
-}
-
-static void
-ahd_linux_kill_dv_thread(struct ahd_softc *ahd)
-{
- u_long s;
-
- ahd_lock(ahd, &s);
- if (ahd->platform_data->dv_pid != 0) {
- ahd->platform_data->flags |= AHD_DV_SHUTDOWN;
- ahd_unlock(ahd, &s);
- up(&ahd->platform_data->dv_sem);
-
- /*
- * Use the eh_sem as an indicator that the
- * dv thread is exiting. Note that the dv
- * thread must still return after performing
- * the up on our semaphore before it has
- * completely exited this module. Unfortunately,
- * there seems to be no easy way to wait for the
- * exit of a thread for which you are not the
- * parent (dv threads are parented by init).
- * Cross your fingers...
- */
- down(&ahd->platform_data->eh_sem);
-
- /*
- * Mark the dv thread as already dead. This
- * avoids attempting to kill it a second time.
- * This is necessary because we must kill the
- * DV thread before calling ahd_free() in the
- * module shutdown case to avoid bogus locking
- * in the SCSI mid-layer, but we ahd_free() is
- * called without killing the DV thread in the
- * instance detach case, so ahd_platform_free()
- * calls us again to verify that the DV thread
- * is dead.
- */
- ahd->platform_data->dv_pid = 0;
- } else {
- ahd_unlock(ahd, &s);
- }
-}
-
-#define AHD_LINUX_DV_INQ_SHORT_LEN 36
-#define AHD_LINUX_DV_INQ_LEN 256
-#define AHD_LINUX_DV_TIMEOUT (HZ / 4)
-
-#define AHD_SET_DV_STATE(ahd, targ, newstate) \
- ahd_set_dv_state(ahd, targ, newstate, __LINE__)
-
-static __inline void
-ahd_set_dv_state(struct ahd_softc *ahd, struct ahd_linux_target *targ,
- ahd_dv_state newstate, u_int line)
-{
- ahd_dv_state oldstate;
-
- oldstate = targ->dv_state;
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV)
- printf("%s:%d: Going from state %d to state %d\n",
- ahd_name(ahd), line, oldstate, newstate);
-#endif
-
- if (oldstate == newstate)
- targ->dv_state_retry++;
- else
- targ->dv_state_retry = 0;
- targ->dv_state = newstate;
-}
-
-static void
-ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
-{
- struct ahd_devinfo devinfo;
- struct ahd_linux_target *targ;
- struct scsi_cmnd *cmd;
- struct scsi_device *scsi_dev;
- struct scsi_sense_data *sense;
- uint8_t *buffer;
- u_long s;
- u_int timeout;
- int echo_size;
-
- sense = NULL;
- buffer = NULL;
- echo_size = 0;
- ahd_lock(ahd, &s);
- targ = ahd->platform_data->targets[target_offset];
- if (targ == NULL || (targ->flags & AHD_DV_REQUIRED) == 0) {
- ahd_unlock(ahd, &s);
- return;
- }
- ahd_compile_devinfo(&devinfo, ahd->our_id, targ->target, /*lun*/0,
- targ->channel + 'A', ROLE_INITIATOR);
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, &devinfo);
- printf("Performing DV\n");
- }
-#endif
-
- ahd_unlock(ahd, &s);
-
- cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
- scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK);
- scsi_dev->host = ahd->platform_data->host;
- scsi_dev->id = devinfo.target;
- scsi_dev->lun = devinfo.lun;
- scsi_dev->channel = devinfo.channel - 'A';
- ahd->platform_data->dv_scsi_dev = scsi_dev;
-
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_SHORT_ASYNC);
-
- while (targ->dv_state != AHD_DV_STATE_EXIT) {
- timeout = AHD_LINUX_DV_TIMEOUT;
- switch (targ->dv_state) {
- case AHD_DV_STATE_INQ_SHORT_ASYNC:
- case AHD_DV_STATE_INQ_ASYNC:
- case AHD_DV_STATE_INQ_ASYNC_VERIFY:
- /*
- * Set things to async narrow to reduce the
- * chance that the INQ will fail.
- */
- ahd_lock(ahd, &s);
- ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
- AHD_TRANS_GOAL, /*paused*/FALSE);
- ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
- AHD_TRANS_GOAL, /*paused*/FALSE);
- ahd_unlock(ahd, &s);
- timeout = 10 * HZ;
- targ->flags &= ~AHD_INQ_VALID;
- /* FALLTHROUGH */
- case AHD_DV_STATE_INQ_VERIFY:
- {
- u_int inq_len;
-
- if (targ->dv_state == AHD_DV_STATE_INQ_SHORT_ASYNC)
- inq_len = AHD_LINUX_DV_INQ_SHORT_LEN;
- else
- inq_len = targ->inq_data->additional_length + 5;
- ahd_linux_dv_inq(ahd, cmd, &devinfo, targ, inq_len);
- break;
- }
- case AHD_DV_STATE_TUR:
- case AHD_DV_STATE_BUSY:
- timeout = 5 * HZ;
- ahd_linux_dv_tur(ahd, cmd, &devinfo);
- break;
- case AHD_DV_STATE_REBD:
- ahd_linux_dv_rebd(ahd, cmd, &devinfo, targ);
- break;
- case AHD_DV_STATE_WEB:
- ahd_linux_dv_web(ahd, cmd, &devinfo, targ);
- break;
-
- case AHD_DV_STATE_REB:
- ahd_linux_dv_reb(ahd, cmd, &devinfo, targ);
- break;
-
- case AHD_DV_STATE_SU:
- ahd_linux_dv_su(ahd, cmd, &devinfo, targ);
- timeout = 50 * HZ;
- break;
-
- default:
- ahd_print_devinfo(ahd, &devinfo);
- printf("Unknown DV state %d\n", targ->dv_state);
- goto out;
- }
-
- /* Queue the command and wait for it to complete */
- /* Abuse eh_timeout in the scsi_cmnd struct for our purposes */
- init_timer(&cmd->eh_timeout);
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- /*
- * All of the printfs during negotiation
- * really slow down the negotiation.
- * Add a bit of time just to be safe.
- */
- timeout += HZ;
-#endif
- scsi_add_timer(cmd, timeout, ahd_linux_dv_timeout);
- /*
- * In 2.5.X, it is assumed that all calls from the
- * "midlayer" (which we are emulating) will have the
- * ahd host lock held. For other kernels, the
- * io_request_lock must be held.
- */
-#if AHD_SCSI_HAS_HOST_LOCK != 0
- ahd_lock(ahd, &s);
-#else
- spin_lock_irqsave(&io_request_lock, s);
-#endif
- ahd_linux_queue(cmd, ahd_linux_dv_complete);
-#if AHD_SCSI_HAS_HOST_LOCK != 0
- ahd_unlock(ahd, &s);
-#else
- spin_unlock_irqrestore(&io_request_lock, s);
-#endif
- down_interruptible(&ahd->platform_data->dv_cmd_sem);
- /*
- * Wait for the SIMQ to be released so that DV is the
- * only reason the queue is frozen.
- */
- ahd_lock(ahd, &s);
- while (AHD_DV_SIMQ_FROZEN(ahd) == 0) {
- ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE;
- ahd_unlock(ahd, &s);
- down_interruptible(&ahd->platform_data->dv_sem);
- ahd_lock(ahd, &s);
- }
- ahd_unlock(ahd, &s);
-
- ahd_linux_dv_transition(ahd, cmd, &devinfo, targ);
- }
-
-out:
- if ((targ->flags & AHD_INQ_VALID) != 0
- && ahd_linux_get_device(ahd, devinfo.channel - 'A',
- devinfo.target, devinfo.lun,
- /*alloc*/FALSE) == NULL) {
- /*
- * The DV state machine failed to configure this device.
- * This is normal if DV is disabled. Since we have inquiry
- * data, filter it and use the "optimistic" negotiation
- * parameters found in the inquiry string.
- */
- ahd_linux_filter_inquiry(ahd, &devinfo);
- if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) {
- ahd_print_devinfo(ahd, &devinfo);
- printf("DV failed to configure device. "
- "Please file a bug report against "
- "this driver.\n");
- }
- }
-
- if (cmd != NULL)
- free(cmd, M_DEVBUF);
-
- if (ahd->platform_data->dv_scsi_dev != NULL) {
- free(ahd->platform_data->dv_scsi_dev, M_DEVBUF);
- ahd->platform_data->dv_scsi_dev = NULL;
- }
-
- ahd_lock(ahd, &s);
- if (targ->dv_buffer != NULL) {
- free(targ->dv_buffer, M_DEVBUF);
- targ->dv_buffer = NULL;
- }
- if (targ->dv_buffer1 != NULL) {
- free(targ->dv_buffer1, M_DEVBUF);
- targ->dv_buffer1 = NULL;
- }
- targ->flags &= ~AHD_DV_REQUIRED;
- if (targ->refcount == 0)
- ahd_linux_free_target(ahd, targ);
- ahd_unlock(ahd, &s);
-}
-
-static __inline int
-ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
-{
- u_long s;
- int retval;
-
- ahd_lock(ahd, &s);
- retval = ahd_linux_fallback(ahd, devinfo);
- ahd_unlock(ahd, &s);
-
- return (retval);
-}
-
-static void
-ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ)
-{
- u_int32_t status;
-
- status = aic_error_action(cmd, targ->inq_data,
- ahd_cmd_get_transaction_status(cmd),
- ahd_cmd_get_scsi_status(cmd));
-
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Entering ahd_linux_dv_transition, state= %d, "
- "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state,
- status, cmd->result);
- }
-#endif
-
- switch (targ->dv_state) {
- case AHD_DV_STATE_INQ_SHORT_ASYNC:
- case AHD_DV_STATE_INQ_ASYNC:
- switch (status & SS_MASK) {
- case SS_NOP:
- {
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
- break;
- }
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_TUR:
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ)
- targ->dv_state_retry--;
- if ((status & SS_ERRMASK) == EBUSY)
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
- if (targ->dv_state_retry < 10)
- break;
- /* FALLTHROUGH */
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Failed DV inquiry, skipping\n");
- }
-#endif
- break;
- }
- break;
- case AHD_DV_STATE_INQ_ASYNC_VERIFY:
- switch (status & SS_MASK) {
- case SS_NOP:
- {
- u_int xportflags;
- u_int spi3data;
-
- if (memcmp(targ->inq_data, targ->dv_buffer,
- AHD_LINUX_DV_INQ_LEN) != 0) {
- /*
- * Inquiry data must have changed.
- * Try from the top again.
- */
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- }
-
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
- targ->flags |= AHD_INQ_VALID;
- if (ahd_linux_user_dv_setting(ahd) == 0)
- break;
-
- xportflags = targ->inq_data->flags;
- if ((xportflags & (SID_Sync|SID_WBus16)) == 0)
- break;
-
- spi3data = targ->inq_data->spi3data;
- switch (spi3data & SID_SPI_CLOCK_DT_ST) {
- default:
- case SID_SPI_CLOCK_ST:
- /* Assume only basic DV is supported. */
- targ->flags |= AHD_BASIC_DV;
- break;
- case SID_SPI_CLOCK_DT:
- case SID_SPI_CLOCK_DT_ST:
- targ->flags |= AHD_ENHANCED_DV;
- break;
- }
- break;
- }
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_TUR:
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ)
- targ->dv_state_retry--;
-
- if ((status & SS_ERRMASK) == EBUSY)
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
- if (targ->dv_state_retry < 10)
- break;
- /* FALLTHROUGH */
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Failed DV inquiry, skipping\n");
- }
-#endif
- break;
- }
- break;
- case AHD_DV_STATE_INQ_VERIFY:
- switch (status & SS_MASK) {
- case SS_NOP:
- {
-
- if (memcmp(targ->inq_data, targ->dv_buffer,
- AHD_LINUX_DV_INQ_LEN) == 0) {
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- int i;
-
- ahd_print_devinfo(ahd, devinfo);
- printf("Inquiry buffer mismatch:");
- for (i = 0; i < AHD_LINUX_DV_INQ_LEN; i++) {
- if ((i & 0xF) == 0)
- printf("\n ");
- printf("0x%x:0x0%x ",
- ((uint8_t *)targ->inq_data)[i],
- targ->dv_buffer[i]);
- }
- printf("\n");
- }
-#endif
-
- if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- /*
- * Do not count "falling back"
- * against our retries.
- */
- targ->dv_state_retry = 0;
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- break;
- }
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_TUR:
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ) {
- targ->dv_state_retry--;
- } else if ((status & SSQ_FALLBACK) != 0) {
- if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_EXIT);
- break;
- }
- /*
- * Do not count "falling back"
- * against our retries.
- */
- targ->dv_state_retry = 0;
- } else if ((status & SS_ERRMASK) == EBUSY)
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
- if (targ->dv_state_retry < 10)
- break;
- /* FALLTHROUGH */
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Failed DV inquiry, skipping\n");
- }
-#endif
- break;
- }
- break;
-
- case AHD_DV_STATE_TUR:
- switch (status & SS_MASK) {
- case SS_NOP:
- if ((targ->flags & AHD_BASIC_DV) != 0) {
- ahd_linux_filter_inquiry(ahd, devinfo);
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_VERIFY);
- } else if ((targ->flags & AHD_ENHANCED_DV) != 0) {
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD);
- } else {
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- }
- break;
- case SS_RETRY:
- case SS_TUR:
- if ((status & SS_ERRMASK) == EBUSY) {
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
- break;
- }
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ) {
- targ->dv_state_retry--;
- } else if ((status & SSQ_FALLBACK) != 0) {
- if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_EXIT);
- break;
- }
- /*
- * Do not count "falling back"
- * against our retries.
- */
- targ->dv_state_retry = 0;
- }
- if (targ->dv_state_retry >= 10) {
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("DV TUR reties exhausted\n");
- }
-#endif
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- if (status & SSQ_DELAY)
- ssleep(1);
-
- break;
- case SS_START:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_SU);
- break;
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- break;
-
- case AHD_DV_STATE_REBD:
- switch (status & SS_MASK) {
- case SS_NOP:
- {
- uint32_t echo_size;
-
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB);
- echo_size = scsi_3btoul(&targ->dv_buffer[1]);
- echo_size &= 0x1FFF;
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Echo buffer size= %d\n", echo_size);
- }
-#endif
- if (echo_size == 0) {
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
-
- /* Generate the buffer pattern */
- targ->dv_echo_size = echo_size;
- ahd_linux_generate_dv_pattern(targ);
- /*
- * Setup initial negotiation values.
- */
- ahd_linux_filter_inquiry(ahd, devinfo);
- break;
- }
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ)
- targ->dv_state_retry--;
- if (targ->dv_state_retry <= 10)
- break;
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("DV REBD reties exhausted\n");
- }
-#endif
- /* FALLTHROUGH */
- case SS_FATAL:
- default:
- /*
- * Setup initial negotiation values
- * and try level 1 DV.
- */
- ahd_linux_filter_inquiry(ahd, devinfo);
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_VERIFY);
- targ->dv_echo_size = 0;
- break;
- }
- break;
-
- case AHD_DV_STATE_WEB:
- switch (status & SS_MASK) {
- case SS_NOP:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REB);
- break;
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ) {
- targ->dv_state_retry--;
- } else if ((status & SSQ_FALLBACK) != 0) {
- if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_EXIT);
- break;
- }
- /*
- * Do not count "falling back"
- * against our retries.
- */
- targ->dv_state_retry = 0;
- }
- if (targ->dv_state_retry <= 10)
- break;
- /* FALLTHROUGH */
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("DV WEB reties exhausted\n");
- }
-#endif
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- break;
-
- case AHD_DV_STATE_REB:
- switch (status & SS_MASK) {
- case SS_NOP:
- if (memcmp(targ->dv_buffer, targ->dv_buffer1,
- targ->dv_echo_size) != 0) {
- if (ahd_linux_dv_fallback(ahd, devinfo) != 0)
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_EXIT);
- else
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_WEB);
- break;
- }
-
- if (targ->dv_buffer != NULL) {
- free(targ->dv_buffer, M_DEVBUF);
- targ->dv_buffer = NULL;
- }
- if (targ->dv_buffer1 != NULL) {
- free(targ->dv_buffer1, M_DEVBUF);
- targ->dv_buffer1 = NULL;
- }
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ) {
- targ->dv_state_retry--;
- } else if ((status & SSQ_FALLBACK) != 0) {
- if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_EXIT);
- break;
- }
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB);
- }
- if (targ->dv_state_retry <= 10) {
- if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0)
- msleep(ahd->our_id*1000/10);
- break;
- }
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("DV REB reties exhausted\n");
- }
-#endif
- /* FALLTHROUGH */
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- break;
-
- case AHD_DV_STATE_SU:
- switch (status & SS_MASK) {
- case SS_NOP:
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- break;
-
- case AHD_DV_STATE_BUSY:
- switch (status & SS_MASK) {
- case SS_NOP:
- case SS_INQ_REFRESH:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_SHORT_ASYNC);
- break;
- case SS_TUR:
- case SS_RETRY:
- AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
- if (ahd_cmd_get_transaction_status(cmd)
- == CAM_REQUEUE_REQ) {
- targ->dv_state_retry--;
- } else if (targ->dv_state_retry < 60) {
- if ((status & SSQ_DELAY) != 0)
- ssleep(1);
- } else {
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("DV BUSY reties exhausted\n");
- }
-#endif
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- }
- break;
- default:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
- break;
-
- default:
- printf("%s: Invalid DV completion state %d\n", ahd_name(ahd),
- targ->dv_state);
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
- break;
- }
-}
-
-static void
-ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo)
-{
- memset(cmd, 0, sizeof(struct scsi_cmnd));
- cmd->device = ahd->platform_data->dv_scsi_dev;
- cmd->scsi_done = ahd_linux_dv_complete;
-}
-
-/*
- * Synthesize an inquiry command. On the return trip, it'll be
- * sniffed and the device transfer settings set for us.
- */
-static void
-ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo, struct ahd_linux_target *targ,
- u_int request_length)
-{
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Sending INQ\n");
- }
-#endif
- if (targ->inq_data == NULL)
- targ->inq_data = malloc(AHD_LINUX_DV_INQ_LEN,
- M_DEVBUF, M_WAITOK);
- if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) {
- if (targ->dv_buffer != NULL)
- free(targ->dv_buffer, M_DEVBUF);
- targ->dv_buffer = malloc(AHD_LINUX_DV_INQ_LEN,
- M_DEVBUF, M_WAITOK);
- }
-
- ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
- cmd->sc_data_direction = DMA_FROM_DEVICE;
- cmd->cmd_len = 6;
- cmd->cmnd[0] = INQUIRY;
- cmd->cmnd[4] = request_length;
- cmd->request_bufflen = request_length;
- if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC)
- cmd->request_buffer = targ->dv_buffer;
- else
- cmd->request_buffer = targ->inq_data;
- memset(cmd->request_buffer, 0, AHD_LINUX_DV_INQ_LEN);
-}
-
-static void
-ahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo)
-{
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Sending TUR\n");
- }
-#endif
- /* Do a TUR to clear out any non-fatal transitional state */
- ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
- cmd->sc_data_direction = DMA_NONE;
- cmd->cmd_len = 6;
- cmd->cmnd[0] = TEST_UNIT_READY;
-}
-
-#define AHD_REBD_LEN 4
-
-static void
-ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
-{
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Sending REBD\n");
- }
-#endif
- if (targ->dv_buffer != NULL)
- free(targ->dv_buffer, M_DEVBUF);
- targ->dv_buffer = malloc(AHD_REBD_LEN, M_DEVBUF, M_WAITOK);
- ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
- cmd->sc_data_direction = DMA_FROM_DEVICE;
- cmd->cmd_len = 10;
- cmd->cmnd[0] = READ_BUFFER;
- cmd->cmnd[1] = 0x0b;
- scsi_ulto3b(AHD_REBD_LEN, &cmd->cmnd[6]);
- cmd->request_bufflen = AHD_REBD_LEN;
- cmd->underflow = cmd->request_bufflen;
- cmd->request_buffer = targ->dv_buffer;
-}
-
-static void
-ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
-{
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Sending WEB\n");
- }
-#endif
- ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
- cmd->sc_data_direction = DMA_TO_DEVICE;
- cmd->cmd_len = 10;
- cmd->cmnd[0] = WRITE_BUFFER;
- cmd->cmnd[1] = 0x0a;
- scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
- cmd->request_bufflen = targ->dv_echo_size;
- cmd->underflow = cmd->request_bufflen;
- cmd->request_buffer = targ->dv_buffer;
-}
-
-static void
-ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
-{
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Sending REB\n");
- }
-#endif
- ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
- cmd->sc_data_direction = DMA_FROM_DEVICE;
- cmd->cmd_len = 10;
- cmd->cmnd[0] = READ_BUFFER;
- cmd->cmnd[1] = 0x0a;
- scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
- cmd->request_bufflen = targ->dv_echo_size;
- cmd->underflow = cmd->request_bufflen;
- cmd->request_buffer = targ->dv_buffer1;
-}
-
-static void
-ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- struct ahd_linux_target *targ)
-{
- u_int le;
-
- le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0;
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Sending SU\n");
- }
-#endif
- ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
- cmd->sc_data_direction = DMA_NONE;
- cmd->cmd_len = 6;
- cmd->cmnd[0] = START_STOP_UNIT;
- cmd->cmnd[4] = le | SSS_START;
-}
-
-static int
-ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
-{
- struct ahd_linux_target *targ;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_transinfo *goal;
- struct ahd_tmode_tstate *tstate;
- u_int width;
- u_int period;
- u_int offset;
- u_int ppr_options;
- u_int cur_speed;
- u_int wide_speed;
- u_int narrow_speed;
- u_int fallback_speed;
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- ahd_print_devinfo(ahd, devinfo);
- printf("Trying to fallback\n");
- }
-#endif
- targ = ahd->platform_data->targets[devinfo->target_offset];
- tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
- devinfo->our_scsiid,
- devinfo->target, &tstate);
- goal = &tinfo->goal;
- width = goal->width;
- period = goal->period;
- offset = goal->offset;
- ppr_options = goal->ppr_options;
- if (offset == 0)
- period = AHD_ASYNC_XFER_PERIOD;
- if (targ->dv_next_narrow_period == 0)
- targ->dv_next_narrow_period = MAX(period, AHD_SYNCRATE_ULTRA2);
- if (targ->dv_next_wide_period == 0)
- targ->dv_next_wide_period = period;
- if (targ->dv_max_width == 0)
- targ->dv_max_width = width;
- if (targ->dv_max_ppr_options == 0)
- targ->dv_max_ppr_options = ppr_options;
- if (targ->dv_last_ppr_options == 0)
- targ->dv_last_ppr_options = ppr_options;
-
- cur_speed = aic_calc_speed(width, period, offset, AHD_SYNCRATE_MIN);
- wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT,
- targ->dv_next_wide_period,
- MAX_OFFSET, AHD_SYNCRATE_MIN);
- narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT,
- targ->dv_next_narrow_period,
- MAX_OFFSET, AHD_SYNCRATE_MIN);
- fallback_speed = aic_calc_speed(width, period+1, offset,
- AHD_SYNCRATE_MIN);
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, "
- "fallback_speed= %d\n", cur_speed, wide_speed,
- narrow_speed, fallback_speed);
- }
-#endif
-
- if (cur_speed > 160000) {
- /*
- * Paced/DT/IU_REQ only transfer speeds. All we
- * can do is fallback in terms of syncrate.
- */
- period++;
- } else if (cur_speed > 80000) {
- if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
- /*
- * Try without IU_REQ as it may be confusing
- * an expander.
- */
- ppr_options &= ~MSG_EXT_PPR_IU_REQ;
- } else {
- /*
- * Paced/DT only transfer speeds. All we
- * can do is fallback in terms of syncrate.
- */
- period++;
- ppr_options = targ->dv_max_ppr_options;
- }
- } else if (cur_speed > 3300) {
-
- /*
- * In this range we the following
- * options ordered from highest to
- * lowest desireability:
- *
- * o Wide/DT
- * o Wide/non-DT
- * o Narrow at a potentally higher sync rate.
- *
- * All modes are tested with and without IU_REQ
- * set since using IUs may confuse an expander.
- */
- if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
-
- ppr_options &= ~MSG_EXT_PPR_IU_REQ;
- } else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
- /*
- * Try going non-DT.
- */
- ppr_options = targ->dv_max_ppr_options;
- ppr_options &= ~MSG_EXT_PPR_DT_REQ;
- } else if (targ->dv_last_ppr_options != 0) {
- /*
- * Try without QAS or any other PPR options.
- * We may need a non-PPR message to work with
- * an expander. We look at the "last PPR options"
- * so we will perform this fallback even if the
- * target responded to our PPR negotiation with
- * no option bits set.
- */
- ppr_options = 0;
- } else if (width == MSG_EXT_WDTR_BUS_16_BIT) {
- /*
- * If the next narrow speed is greater than
- * the next wide speed, fallback to narrow.
- * Otherwise fallback to the next DT/Wide setting.
- * The narrow async speed will always be smaller
- * than the wide async speed, so handle this case
- * specifically.
- */
- ppr_options = targ->dv_max_ppr_options;
- if (narrow_speed > fallback_speed
- || period >= AHD_ASYNC_XFER_PERIOD) {
- targ->dv_next_wide_period = period+1;
- width = MSG_EXT_WDTR_BUS_8_BIT;
- period = targ->dv_next_narrow_period;
- } else {
- period++;
- }
- } else if ((ahd->features & AHD_WIDE) != 0
- && targ->dv_max_width != 0
- && wide_speed >= fallback_speed
- && (targ->dv_next_wide_period <= AHD_ASYNC_XFER_PERIOD
- || period >= AHD_ASYNC_XFER_PERIOD)) {
-
- /*
- * We are narrow. Try falling back
- * to the next wide speed with
- * all supported ppr options set.
- */
- targ->dv_next_narrow_period = period+1;
- width = MSG_EXT_WDTR_BUS_16_BIT;
- period = targ->dv_next_wide_period;
- ppr_options = targ->dv_max_ppr_options;
- } else {
- /* Only narrow fallback is allowed. */
- period++;
- ppr_options = targ->dv_max_ppr_options;
- }
- } else {
- return (-1);
- }
- offset = MAX_OFFSET;
- ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_PACED);
- ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, FALSE);
- if (period == 0) {
- period = 0;
- offset = 0;
- ppr_options = 0;
- if (width == MSG_EXT_WDTR_BUS_8_BIT)
- targ->dv_next_narrow_period = AHD_ASYNC_XFER_PERIOD;
- else
- targ->dv_next_wide_period = AHD_ASYNC_XFER_PERIOD;
- }
- ahd_set_syncrate(ahd, devinfo, period, offset,
- ppr_options, AHD_TRANS_GOAL, FALSE);
- targ->dv_last_ppr_options = ppr_options;
- return (0);
-}
-
-static void
-ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
-{
- struct ahd_softc *ahd;
- struct scb *scb;
- u_long flags;
-
- ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
- ahd_lock(ahd, &flags);
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV) {
- printf("%s: Timeout while doing DV command %x.\n",
- ahd_name(ahd), cmd->cmnd[0]);
- ahd_dump_card_state(ahd);
- }
-#endif
-
- /*
- * Guard against "done race". No action is
- * required if we just completed.
- */
- if ((scb = (struct scb *)cmd->host_scribble) == NULL) {
- ahd_unlock(ahd, &flags);
- return;
- }
-
- /*
- * Command has not completed. Mark this
- * SCB as having failing status prior to
- * resetting the bus, so we get the correct
- * error code.
- */
- if ((scb->flags & SCB_SENSE) != 0)
- ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
- else
- ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
- ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE);
-
- /*
- * Add a minimal bus settle delay for devices that are slow to
- * respond after bus resets.
- */
- ahd_freeze_simq(ahd);
- init_timer(&ahd->platform_data->reset_timer);
- ahd->platform_data->reset_timer.data = (u_long)ahd;
- ahd->platform_data->reset_timer.expires = jiffies + HZ / 2;
- ahd->platform_data->reset_timer.function =
- (ahd_linux_callback_t *)ahd_release_simq;
- add_timer(&ahd->platform_data->reset_timer);
- if (ahd_linux_next_device_to_run(ahd) != NULL)
- ahd_schedule_runq(ahd);
- ahd_linux_run_complete_queue(ahd);
- ahd_unlock(ahd, &flags);
-}
-
-static void
-ahd_linux_dv_complete(struct scsi_cmnd *cmd)
-{
- struct ahd_softc *ahd;
-
- ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
-
- /* Delete the DV timer before it goes off! */
- scsi_delete_timer(cmd);
-
-#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_DV)
- printf("%s:%c:%d: Command completed, status= 0x%x\n",
- ahd_name(ahd), cmd->device->channel, cmd->device->id,
- cmd->result);
-#endif
-
- /* Wake up the state machine */
- up(&ahd->platform_data->dv_cmd_sem);
-}
-
-static void
-ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ)
-{
- uint16_t b;
- u_int i;
- u_int j;
-
- if (targ->dv_buffer != NULL)
- free(targ->dv_buffer, M_DEVBUF);
- targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
- if (targ->dv_buffer1 != NULL)
- free(targ->dv_buffer1, M_DEVBUF);
- targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
-
- i = 0;
-
- b = 0x0001;
- for (j = 0 ; i < targ->dv_echo_size; j++) {
- if (j < 32) {
- /*
- * 32bytes of sequential numbers.
- */
- targ->dv_buffer[i++] = j & 0xff;
- } else if (j < 48) {
- /*
- * 32bytes of repeating 0x0000, 0xffff.
- */
- targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00;
- } else if (j < 64) {
- /*
- * 32bytes of repeating 0x5555, 0xaaaa.
- */
- targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55;
- } else {
- /*
- * Remaining buffer is filled with a repeating
- * patter of:
- *
- * 0xffff
- * ~0x0001 << shifted once in each loop.
- */
- if (j & 0x02) {
- if (j & 0x01) {
- targ->dv_buffer[i++] = ~(b >> 8) & 0xff;
- b <<= 1;
- if (b == 0x0000)
- b = 0x0001;
- } else {
- targ->dv_buffer[i++] = (~b & 0xff);
- }
- } else {
- targ->dv_buffer[i++] = 0xff;
- }
- }
- }
-}
-
-static u_int
-ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
-{
- static int warned_user;
- u_int tags;
-
- tags = 0;
- if ((ahd->user_discenable & devinfo->target_mask) != 0) {
- if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {
-
- if (warned_user == 0) {
- printf(KERN_WARNING
-"aic79xx: WARNING: Insufficient tag_info instances\n"
-"aic79xx: for installed controllers. Using defaults\n"
-"aic79xx: Please update the aic79xx_tag_info array in\n"
-"aic79xx: the aic79xx_osm.c source file.\n");
- warned_user++;
- }
- tags = AHD_MAX_QUEUE;
- } else {
- adapter_tag_info_t *tag_info;
-
- tag_info = &aic79xx_tag_info[ahd->unit];
- tags = tag_info->tag_commands[devinfo->target_offset];
- if (tags > AHD_MAX_QUEUE)
- tags = AHD_MAX_QUEUE;
- }
- }
- return (tags);
-}
-
-static u_int
-ahd_linux_user_dv_setting(struct ahd_softc *ahd)
-{
- static int warned_user;
- int dv;
-
- if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) {
-
- if (warned_user == 0) {
- printf(KERN_WARNING
-"aic79xx: WARNING: Insufficient dv settings instances\n"
-"aic79xx: for installed controllers. Using defaults\n"
-"aic79xx: Please update the aic79xx_dv_settings array in"
-"aic79xx: the aic79xx_osm.c source file.\n");
- warned_user++;
- }
- dv = -1;
- } else {
-
- dv = aic79xx_dv_settings[ahd->unit];
- }
-
- if (dv < 0) {
- /*
- * Apply the default.
- */
- dv = 1;
- if (ahd->seep_config != 0)
- dv = (ahd->seep_config->bios_control & CFENABLEDV);
- }
- return (dv);
-}
-
-static void
-ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd)
-{
- static int warned_user;
- u_int rd_strm_mask;
- u_int target_id;
-
- /*
- * If we have specific read streaming info for this controller,
- * apply it. Otherwise use the defaults.
- */
- if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) {
-
- if (warned_user == 0) {
-
- printf(KERN_WARNING
-"aic79xx: WARNING: Insufficient rd_strm instances\n"
-"aic79xx: for installed controllers. Using defaults\n"
-"aic79xx: Please update the aic79xx_rd_strm_info array\n"
-"aic79xx: in the aic79xx_osm.c source file.\n");
- warned_user++;
- }
- rd_strm_mask = AIC79XX_CONFIGED_RD_STRM;
- } else {
-
- rd_strm_mask = aic79xx_rd_strm_info[ahd->unit];
- }
- for (target_id = 0; target_id < 16; target_id++) {
- struct ahd_devinfo devinfo;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_tmode_tstate *tstate;
-
- tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
- target_id, &tstate);
- ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
- CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
- tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM;
- if ((rd_strm_mask & devinfo.target_mask) != 0)
- tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM;
- }
-}
-
-/*
- * Determines the queue depth for a given device.
- */
-static void
-ahd_linux_device_queue_depth(struct ahd_softc *ahd,
- struct ahd_linux_device *dev)
-{
- struct ahd_devinfo devinfo;
- u_int tags;
-
- ahd_compile_devinfo(&devinfo,
- ahd->our_id,
- dev->target->target, dev->lun,
- dev->target->channel == 0 ? 'A' : 'B',
- ROLE_INITIATOR);
- tags = ahd_linux_user_tagdepth(ahd, &devinfo);
- if (tags != 0
- && dev->scsi_device != NULL
- && dev->scsi_device->tagged_supported != 0) {
-
- ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
- ahd_print_devinfo(ahd, &devinfo);
- printf("Tagged Queuing enabled. Depth %d\n", tags);
- } else {
- ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
- }
-}
-
-static void
-ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev)
-{
- struct ahd_cmd *acmd;
- struct scsi_cmnd *cmd;
- struct scb *scb;
- struct hardware_scb *hscb;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_tmode_tstate *tstate;
- u_int col_idx;
- uint16_t mask;
-
- if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0)
- panic("running device on run list");
-
- while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
- && dev->openings > 0 && dev->qfrozen == 0) {
-
- /*
- * Schedule us to run later. The only reason we are not
- * running is because the whole controller Q is frozen.
- */
- if (ahd->platform_data->qfrozen != 0
- && AHD_DV_SIMQ_FROZEN(ahd) == 0) {
-
- TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
- dev, links);
- dev->flags |= AHD_DEV_ON_RUN_LIST;
- return;
- }
-
- cmd = &acmd_scsi_cmd(acmd);
-
- /*
- * Get an scb to use.
- */
- tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
- cmd->device->id, &tstate);
- if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0
- || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
- col_idx = AHD_NEVER_COL_IDX;
- } else {
- col_idx = AHD_BUILD_COL_IDX(cmd->device->id,
- cmd->device->lun);
- }
- if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
- TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
- dev, links);
- dev->flags |= AHD_DEV_ON_RUN_LIST;
- ahd->flags |= AHD_RESOURCE_SHORTAGE;
- return;
- }
- TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe);
- scb->io_ctx = cmd;
- scb->platform_data->dev = dev;
- hscb = scb->hscb;
- cmd->host_scribble = (char *)scb;
-
- /*
- * Fill out basics of the HSCB.
- */
- hscb->control = 0;
- hscb->scsiid = BUILD_SCSIID(ahd, cmd);
- hscb->lun = cmd->device->lun;
- scb->hscb->task_management = 0;
- mask = SCB_GET_TARGET_MASK(ahd, scb);
-
- if ((ahd->user_discenable & mask) != 0)
- hscb->control |= DISCENB;
-
- if (AHD_DV_CMD(cmd) != 0)
- scb->flags |= SCB_SILENT;
-
- if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0)
- scb->flags |= SCB_PACKETIZED;
-
- if ((tstate->auto_negotiate & mask) != 0) {
- scb->flags |= SCB_AUTO_NEGOTIATE;
- scb->hscb->control |= MK_MESSAGE;
- }
-
- if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- int msg_bytes;
- uint8_t tag_msgs[2];
-
- msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
- if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
- hscb->control |= tag_msgs[0];
- if (tag_msgs[0] == MSG_ORDERED_TASK)
- dev->commands_since_idle_or_otag = 0;
- } else
-#endif
- if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH
- && (dev->flags & AHD_DEV_Q_TAGGED) != 0) {
- hscb->control |= MSG_ORDERED_TASK;
- dev->commands_since_idle_or_otag = 0;
- } else {
- hscb->control |= MSG_SIMPLE_TASK;
- }
- }
-
- hscb->cdb_len = cmd->cmd_len;
- memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len);
-
- scb->sg_count = 0;
- ahd_set_residual(scb, 0);
- ahd_set_sense_residual(scb, 0);
- if (cmd->use_sg != 0) {
- void *sg;
- struct scatterlist *cur_seg;
- u_int nseg;
- int dir;
-
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- dir = cmd->sc_data_direction;
- nseg = pci_map_sg(ahd->dev_softc, cur_seg,
- cmd->use_sg, dir);
- scb->platform_data->xfer_len = 0;
- for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) {
- dma_addr_t addr;
- bus_size_t len;
-
- addr = sg_dma_address(cur_seg);
- len = sg_dma_len(cur_seg);
- scb->platform_data->xfer_len += len;
- sg = ahd_sg_setup(ahd, scb, sg, addr, len,
- /*last*/nseg == 1);
- }
- } else if (cmd->request_bufflen != 0) {
- void *sg;
- dma_addr_t addr;
- int dir;
-
- sg = scb->sg_list;
- dir = cmd->sc_data_direction;
- addr = pci_map_single(ahd->dev_softc,
- cmd->request_buffer,
- cmd->request_bufflen, dir);
- scb->platform_data->xfer_len = cmd->request_bufflen;
- scb->platform_data->buf_busaddr = addr;
- sg = ahd_sg_setup(ahd, scb, sg, addr,
- cmd->request_bufflen, /*last*/TRUE);
- }
-
- LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
- dev->openings--;
- dev->active++;
- dev->commands_issued++;
-
- /* Update the error counting bucket and dump if needed */
- if (dev->target->cmds_since_error) {
- dev->target->cmds_since_error++;
- if (dev->target->cmds_since_error >
- AHD_LINUX_ERR_THRESH)
- dev->target->cmds_since_error = 0;
- }
-
- if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0)
- dev->commands_since_idle_or_otag++;
- scb->flags |= SCB_ACTIVE;
- ahd_queue_scb(ahd, scb);
- }
-}
-
-/*
- * SCSI controller interrupt handler.
- */
-irqreturn_t
-ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
-{
- struct ahd_softc *ahd;
- u_long flags;
- int ours;
-
- ahd = (struct ahd_softc *) dev_id;
- ahd_lock(ahd, &flags);
- ours = ahd_intr(ahd);
- if (ahd_linux_next_device_to_run(ahd) != NULL)
- ahd_schedule_runq(ahd);
- ahd_linux_run_complete_queue(ahd);
- ahd_unlock(ahd, &flags);
- return IRQ_RETVAL(ours);
-}
-
-void
-ahd_platform_flushwork(struct ahd_softc *ahd)
-{
-
- while (ahd_linux_run_complete_queue(ahd) != NULL)
- ;
-}
-
-static struct ahd_linux_target*
-ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target)
-{
- struct ahd_linux_target *targ;
-
- targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT);
- if (targ == NULL)
- return (NULL);
- memset(targ, 0, sizeof(*targ));
- targ->channel = channel;
- targ->target = target;
- targ->ahd = ahd;
- targ->flags = AHD_DV_REQUIRED;
- ahd->platform_data->targets[target] = targ;
- return (targ);
-}
-
-static void
-ahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ)
-{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
struct ahd_devinfo devinfo;
- struct ahd_initiator_tinfo *tinfo;
+ unsigned long flags;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_lock(ahd, &flags);
+ ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_period(struct scsi_target *starget, int period)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
struct ahd_tmode_tstate *tstate;
- u_int our_id;
- u_int target_offset;
- char channel;
-
- /*
- * Force a negotiation to async/narrow on any
- * future command to this device unless a bus
- * reset occurs between now and that command.
- */
- channel = 'A' + targ->channel;
- our_id = ahd->our_id;
- target_offset = targ->target;
- tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
- targ->target, &tstate);
- ahd_compile_devinfo(&devinfo, our_id, targ->target, CAM_LUN_WILDCARD,
- channel, ROLE_INITIATOR);
- ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
- AHD_TRANS_GOAL, /*paused*/FALSE);
- ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
- AHD_TRANS_GOAL, /*paused*/FALSE);
- ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS);
- ahd->platform_data->targets[target_offset] = NULL;
- if (targ->inq_data != NULL)
- free(targ->inq_data, M_DEVBUF);
- if (targ->dv_buffer != NULL)
- free(targ->dv_buffer, M_DEVBUF);
- if (targ->dv_buffer1 != NULL)
- free(targ->dv_buffer1, M_DEVBUF);
- free(targ, M_DEVBUF);
-}
-
-static struct ahd_linux_device*
-ahd_linux_alloc_device(struct ahd_softc *ahd,
- struct ahd_linux_target *targ, u_int lun)
-{
- struct ahd_linux_device *dev;
-
- dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);
- if (dev == NULL)
- return (NULL);
- memset(dev, 0, sizeof(*dev));
- init_timer(&dev->timer);
- TAILQ_INIT(&dev->busyq);
- dev->flags = AHD_DEV_UNCONFIGURED;
- dev->lun = lun;
- dev->target = targ;
-
- /*
- * We start out life using untagged
- * transactions of which we allow one.
- */
- dev->openings = 1;
-
- /*
- * Set maxtags to 0. This will be changed if we
- * later determine that we are dealing with
- * a tagged queuing capable device.
- */
- dev->maxtags = 0;
-
- targ->refcount++;
- targ->devices[lun] = dev;
- return (dev);
-}
-
-static void
-ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev)
-{
- struct ahd_linux_target *targ;
-
- del_timer(&dev->timer);
- targ = dev->target;
- targ->devices[dev->lun] = NULL;
- free(dev, M_DEVBUF);
- targ->refcount--;
- if (targ->refcount == 0
- && (targ->flags & AHD_DV_REQUIRED) == 0)
- ahd_linux_free_target(ahd, targ);
-}
-
-void
-ahd_send_async(struct ahd_softc *ahd, char channel,
- u_int target, u_int lun, ac_code code, void *arg)
-{
- switch (code) {
- case AC_TRANSFER_NEG:
- {
- char buf[80];
- struct ahd_linux_target *targ;
- struct info_str info;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_tmode_tstate *tstate;
-
- info.buffer = buf;
- info.length = sizeof(buf);
- info.offset = 0;
- info.pos = 0;
- tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,
- target, &tstate);
-
- /*
- * Don't bother reporting results while
- * negotiations are still pending.
- */
- if (tinfo->curr.period != tinfo->goal.period
- || tinfo->curr.width != tinfo->goal.width
- || tinfo->curr.offset != tinfo->goal.offset
- || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
- if (bootverbose == 0)
- break;
-
- /*
- * Don't bother reporting results that
- * are identical to those last reported.
- */
- targ = ahd->platform_data->targets[target];
- if (targ == NULL)
- break;
- if (tinfo->curr.period == targ->last_tinfo.period
- && tinfo->curr.width == targ->last_tinfo.width
- && tinfo->curr.offset == targ->last_tinfo.offset
- && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
- if (bootverbose == 0)
- break;
-
- targ->last_tinfo.period = tinfo->curr.period;
- targ->last_tinfo.width = tinfo->curr.width;
- targ->last_tinfo.offset = tinfo->curr.offset;
- targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
-
- printf("(%s:%c:", ahd_name(ahd), channel);
- if (target == CAM_TARGET_WILDCARD)
- printf("*): ");
- else
- printf("%d): ", target);
- ahd_format_transinfo(&info, &tinfo->curr);
- if (info.pos < info.length)
- *info.buffer = '\0';
- else
- buf[info.length - 1] = '\0';
- printf("%s", buf);
- break;
- }
- case AC_SENT_BDR:
- {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- WARN_ON(lun != CAM_LUN_WILDCARD);
- scsi_report_device_reset(ahd->platform_data->host,
- channel - 'A', target);
-#else
- Scsi_Device *scsi_dev;
-
- /*
- * Find the SCSI device associated with this
- * request and indicate that a UA is expected.
- */
- for (scsi_dev = ahd->platform_data->host->host_queue;
- scsi_dev != NULL; scsi_dev = scsi_dev->next) {
- if (channel - 'A' == scsi_dev->channel
- && target == scsi_dev->id
- && (lun == CAM_LUN_WILDCARD
- || lun == scsi_dev->lun)) {
- scsi_dev->was_reset = 1;
- scsi_dev->expecting_cc_ua = 1;
- }
- }
-#endif
- break;
- }
- case AC_BUS_RESET:
- if (ahd->platform_data->host != NULL) {
- scsi_report_bus_reset(ahd->platform_data->host,
- channel - 'A');
- }
- break;
- default:
- panic("ahd_send_async: Unexpected async event");
- }
-}
-
-/*
- * Calls the higher level scsi done function and frees the scb.
- */
-void
-ahd_done(struct ahd_softc *ahd, struct scb *scb)
-{
- Scsi_Cmnd *cmd;
- struct ahd_linux_device *dev;
-
- if ((scb->flags & SCB_ACTIVE) == 0) {
- printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
- ahd_dump_card_state(ahd);
- panic("Stopping for safety");
- }
- LIST_REMOVE(scb, pending_links);
- cmd = scb->io_ctx;
- dev = scb->platform_data->dev;
- dev->active--;
- dev->openings++;
- if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) {
- cmd->result &= ~(CAM_DEV_QFRZN << 16);
- dev->qfrozen--;
- }
- ahd_linux_unmap_scb(ahd, scb);
-
- /*
- * Guard against stale sense data.
- * The Linux mid-layer assumes that sense
- * was retrieved anytime the first byte of
- * the sense buffer looks "sane".
- */
- cmd->sense_buffer[0] = 0;
- if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) {
- uint32_t amount_xferred;
-
- amount_xferred =
- ahd_get_transfer_length(scb) - ahd_get_residual(scb);
- if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) {
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_MISC) != 0) {
- ahd_print_path(ahd, scb);
- printf("Set CAM_UNCOR_PARITY\n");
- }
-#endif
- ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
-#ifdef AHD_REPORT_UNDERFLOWS
- /*
- * This code is disabled by default as some
- * clients of the SCSI system do not properly
- * initialize the underflow parameter. This
- * results in spurious termination of commands
- * that complete as expected (e.g. underflow is
- * allowed as command can return variable amounts
- * of data.
- */
- } else if (amount_xferred < scb->io_ctx->underflow) {
- u_int i;
-
- ahd_print_path(ahd, scb);
- printf("CDB:");
- for (i = 0; i < scb->io_ctx->cmd_len; i++)
- printf(" 0x%x", scb->io_ctx->cmnd[i]);
- printf("\n");
- ahd_print_path(ahd, scb);
- printf("Saw underflow (%ld of %ld bytes). "
- "Treated as error\n",
- ahd_get_residual(scb),
- ahd_get_transfer_length(scb));
- ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
-#endif
- } else {
- ahd_set_transaction_status(scb, CAM_REQ_CMP);
- }
- } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
- ahd_linux_handle_scsi_status(ahd, dev, scb);
- } else if (ahd_get_transaction_status(scb) == CAM_SEL_TIMEOUT) {
- dev->flags |= AHD_DEV_UNCONFIGURED;
- if (AHD_DV_CMD(cmd) == FALSE)
- dev->target->flags &= ~AHD_DV_REQUIRED;
- }
- /*
- * Start DV for devices that require it assuming the first command
- * sent does not result in a selection timeout.
- */
- if (ahd_get_transaction_status(scb) != CAM_SEL_TIMEOUT
- && (dev->target->flags & AHD_DV_REQUIRED) != 0)
- ahd_linux_start_dv(ahd);
-
- if (dev->openings == 1
- && ahd_get_transaction_status(scb) == CAM_REQ_CMP
- && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)
- dev->tag_success_count++;
- /*
- * Some devices deal with temporary internal resource
- * shortages by returning queue full. When the queue
- * full occurrs, we throttle back. Slowly try to get
- * back to our previous queue depth.
- */
- if ((dev->openings + dev->active) < dev->maxtags
- && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) {
- dev->tag_success_count = 0;
- dev->openings++;
- }
-
- if (dev->active == 0)
- dev->commands_since_idle_or_otag = 0;
-
- if (TAILQ_EMPTY(&dev->busyq)) {
- if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
- && dev->active == 0
- && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
- ahd_linux_free_device(ahd, dev);
- } else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
- TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
- dev->flags |= AHD_DEV_ON_RUN_LIST;
- }
-
- if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
- printf("Recovery SCB completes\n");
- if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
- || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
- ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
- if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
- scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
- up(&ahd->platform_data->eh_sem);
- }
- }
-
- ahd_free_scb(ahd, scb);
- ahd_linux_queue_cmd_complete(ahd, cmd);
-
- if ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_EMPTY) != 0
- && LIST_FIRST(&ahd->pending_scbs) == NULL) {
- ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_EMPTY;
- up(&ahd->platform_data->dv_sem);
- }
-}
-
-static void
-ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
- struct ahd_linux_device *dev, struct scb *scb)
-{
- struct ahd_devinfo devinfo;
-
- ahd_compile_devinfo(&devinfo,
- ahd->our_id,
- dev->target->target, dev->lun,
- dev->target->channel == 0 ? 'A' : 'B',
- ROLE_INITIATOR);
-
- /*
- * We don't currently trust the mid-layer to
- * properly deal with queue full or busy. So,
- * when one occurs, we tell the mid-layer to
- * unconditionally requeue the command to us
- * so that we can retry it ourselves. We also
- * implement our own throttling mechanism so
- * we don't clobber the device with too many
- * commands.
- */
- switch (ahd_get_scsi_status(scb)) {
- default:
- break;
- case SCSI_STATUS_CHECK_COND:
- case SCSI_STATUS_CMD_TERMINATED:
- {
- Scsi_Cmnd *cmd;
-
- /*
- * Copy sense information to the OS's cmd
- * structure if it is available.
- */
- cmd = scb->io_ctx;
- if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) {
- struct scsi_status_iu_header *siu;
- u_int sense_size;
- u_int sense_offset;
-
- if (scb->flags & SCB_SENSE) {
- sense_size = MIN(sizeof(struct scsi_sense_data)
- - ahd_get_sense_residual(scb),
- sizeof(cmd->sense_buffer));
- sense_offset = 0;
- } else {
- /*
- * Copy only the sense data into the provided
- * buffer.
- */
- siu = (struct scsi_status_iu_header *)
- scb->sense_data;
- sense_size = MIN(scsi_4btoul(siu->sense_length),
- sizeof(cmd->sense_buffer));
- sense_offset = SIU_SENSE_OFFSET(siu);
- }
-
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- memcpy(cmd->sense_buffer,
- ahd_get_sense_buf(ahd, scb)
- + sense_offset, sense_size);
- cmd->result |= (DRIVER_SENSE << 24);
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options;
+ unsigned int dt;
+ unsigned long flags;
+ unsigned long offset = tinfo->goal.offset;
#ifdef AHD_DEBUG
- if (ahd_debug & AHD_SHOW_SENSE) {
- int i;
-
- printf("Copied %d bytes of sense data at %d:",
- sense_size, sense_offset);
- for (i = 0; i < sense_size; i++) {
- if ((i & 0xF) == 0)
- printf("\n");
- printf("0x%x ", cmd->sense_buffer[i]);
- }
- printf("\n");
- }
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: set period to %d\n", ahd_name(ahd), period);
#endif
- }
- break;
+ if (offset == 0)
+ offset = MAX_OFFSET;
+
+ if (period < 8)
+ period = 8;
+ if (period < 10) {
+ ppr_options |= MSG_EXT_PPR_DT_REQ;
+ if (period == 8)
+ ppr_options |= MSG_EXT_PPR_IU_REQ;
}
- case SCSI_STATUS_QUEUE_FULL:
- {
- /*
- * By the time the core driver has returned this
- * command, all other commands that were queued
- * to us but not the device have been returned.
- * This ensures that dev->active is equal to
- * the number of commands actually queued to
- * the device.
- */
- dev->tag_success_count = 0;
- if (dev->active != 0) {
- /*
- * Drop our opening count to the number
- * of commands currently outstanding.
- */
- dev->openings = 0;
+
+ dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+
+ /* all PPR requests apart from QAS require wide transfers */
+ if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) {
+ if (spi_width(starget) == 0)
+ ppr_options &= MSG_EXT_PPR_QAS_REQ;
+ }
+
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_offset(struct scsi_target *starget, int offset)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = 0;
+ unsigned int period = 0;
+ unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+ unsigned long flags;
+
#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
- ahd_print_path(ahd, scb);
- printf("Dropping tag count to %d\n",
- dev->active);
- }
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: set offset to %d\n", ahd_name(ahd), offset);
#endif
- if (dev->active == dev->tags_on_last_queuefull) {
- dev->last_queuefull_same_count++;
- /*
- * If we repeatedly see a queue full
- * at the same queue depth, this
- * device has a fixed number of tag
- * slots. Lock in this tag depth
- * so we stop seeing queue fulls from
- * this device.
- */
- if (dev->last_queuefull_same_count
- == AHD_LOCK_TAGS_COUNT) {
- dev->maxtags = dev->active;
- ahd_print_path(ahd, scb);
- printf("Locking max tag count at %d\n",
- dev->active);
- }
- } else {
- dev->tags_on_last_queuefull = dev->active;
- dev->last_queuefull_same_count = 0;
- }
- ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
- ahd_set_scsi_status(scb, SCSI_STATUS_OK);
- ahd_platform_set_tags(ahd, &devinfo,
- (dev->flags & AHD_DEV_Q_BASIC)
- ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
- break;
- }
- /*
- * Drop down to a single opening, and treat this
- * as if the target returned BUSY SCSI status.
- */
- dev->openings = 1;
- ahd_platform_set_tags(ahd, &devinfo,
- (dev->flags & AHD_DEV_Q_BASIC)
- ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
- ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
- /* FALLTHROUGH */
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ if (offset != 0) {
+ period = tinfo->goal.period;
+ ppr_options = tinfo->goal.ppr_options;
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
}
- case SCSI_STATUS_BUSY:
- /*
- * Set a short timer to defer sending commands for
- * a bit since Linux will not delay in this case.
- */
- if ((dev->flags & AHD_DEV_TIMER_ACTIVE) != 0) {
- printf("%s:%c:%d: Device Timer still active during "
- "busy processing\n", ahd_name(ahd),
- dev->target->channel, dev->target->target);
- break;
- }
- dev->flags |= AHD_DEV_TIMER_ACTIVE;
- dev->qfrozen++;
- init_timer(&dev->timer);
- dev->timer.data = (u_long)dev;
- dev->timer.expires = jiffies + (HZ/2);
- dev->timer.function = ahd_linux_dev_timed_unfreeze;
- add_timer(&dev->timer);
- break;
- }
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options,
+ AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
}
-static void
-ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd)
+static void ahd_linux_set_dt(struct scsi_target *starget, int dt)
{
- /*
- * Typically, the complete queue has very few entries
- * queued to it before the queue is emptied by
- * ahd_linux_run_complete_queue, so sorting the entries
- * by generation number should be inexpensive.
- * We perform the sort so that commands that complete
- * with an error are retuned in the order origionally
- * queued to the controller so that any subsequent retries
- * are performed in order. The underlying ahd routines do
- * not guarantee the order that aborted commands will be
- * returned to us.
- */
- struct ahd_completeq *completeq;
- struct ahd_cmd *list_cmd;
- struct ahd_cmd *acmd;
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_DT_REQ;
+ unsigned int period = tinfo->goal.period;
+ unsigned int width = tinfo->goal.width;
+ unsigned long flags;
- /*
- * Map CAM error codes into Linux Error codes. We
- * avoid the conversion so that the DV code has the
- * full error information available when making
- * state change decisions.
- */
- if (AHD_DV_CMD(cmd) == FALSE) {
- uint32_t status;
- u_int new_status;
-
- status = ahd_cmd_get_transaction_status(cmd);
- if (status != CAM_REQ_CMP) {
- struct ahd_linux_device *dev;
- struct ahd_devinfo devinfo;
- cam_status cam_status;
- uint32_t action;
- u_int scsi_status;
-
- dev = ahd_linux_get_device(ahd, cmd->device->channel,
- cmd->device->id,
- cmd->device->lun,
- /*alloc*/FALSE);
-
- if (dev == NULL)
- goto no_fallback;
-
- ahd_compile_devinfo(&devinfo,
- ahd->our_id,
- dev->target->target, dev->lun,
- dev->target->channel == 0 ? 'A':'B',
- ROLE_INITIATOR);
-
- scsi_status = ahd_cmd_get_scsi_status(cmd);
- cam_status = ahd_cmd_get_transaction_status(cmd);
- action = aic_error_action(cmd, dev->target->inq_data,
- cam_status, scsi_status);
- if ((action & SSQ_FALLBACK) != 0) {
-
- /* Update stats */
- dev->target->errors_detected++;
- if (dev->target->cmds_since_error == 0)
- dev->target->cmds_since_error++;
- else {
- dev->target->cmds_since_error = 0;
- ahd_linux_fallback(ahd, &devinfo);
- }
- }
- }
-no_fallback:
- switch (status) {
- case CAM_REQ_INPROG:
- case CAM_REQ_CMP:
- case CAM_SCSI_STATUS_ERROR:
- new_status = DID_OK;
- break;
- case CAM_REQ_ABORTED:
- new_status = DID_ABORT;
- break;
- case CAM_BUSY:
- new_status = DID_BUS_BUSY;
- break;
- case CAM_REQ_INVALID:
- case CAM_PATH_INVALID:
- new_status = DID_BAD_TARGET;
- break;
- case CAM_SEL_TIMEOUT:
- new_status = DID_NO_CONNECT;
- break;
- case CAM_SCSI_BUS_RESET:
- case CAM_BDR_SENT:
- new_status = DID_RESET;
- break;
- case CAM_UNCOR_PARITY:
- new_status = DID_PARITY;
- break;
- case CAM_CMD_TIMEOUT:
- new_status = DID_TIME_OUT;
- break;
- case CAM_UA_ABORT:
- case CAM_REQ_CMP_ERR:
- case CAM_AUTOSENSE_FAIL:
- case CAM_NO_HBA:
- case CAM_DATA_RUN_ERR:
- case CAM_UNEXP_BUSFREE:
- case CAM_SEQUENCE_FAIL:
- case CAM_CCB_LEN_ERR:
- case CAM_PROVIDE_FAIL:
- case CAM_REQ_TERMIO:
- case CAM_UNREC_HBA_ERROR:
- case CAM_REQ_TOO_BIG:
- new_status = DID_ERROR;
- break;
- case CAM_REQUEUE_REQ:
- /*
- * If we want the request requeued, make sure there
- * are sufficent retries. In the old scsi error code,
- * we used to be able to specify a result code that
- * bypassed the retry count. Now we must use this
- * hack. We also "fake" a check condition with
- * a sense code of ABORTED COMMAND. This seems to
- * evoke a retry even if this command is being sent
- * via the eh thread. Ick! Ick! Ick!
- */
- if (cmd->retries > 0)
- cmd->retries--;
- new_status = DID_OK;
- ahd_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND);
- cmd->result |= (DRIVER_SENSE << 24);
- memset(cmd->sense_buffer, 0,
- sizeof(cmd->sense_buffer));
- cmd->sense_buffer[0] = SSD_ERRCODE_VALID
- | SSD_CURRENT_ERROR;
- cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND;
- break;
- default:
- /* We should never get here */
- new_status = DID_ERROR;
- break;
- }
-
- ahd_cmd_set_transaction_status(cmd, new_status);
- }
-
- completeq = &ahd->platform_data->completeq;
- list_cmd = TAILQ_FIRST(completeq);
- acmd = (struct ahd_cmd *)cmd;
- while (list_cmd != NULL
- && acmd_scsi_cmd(list_cmd).serial_number
- < acmd_scsi_cmd(acmd).serial_number)
- list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);
- if (list_cmd != NULL)
- TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);
- else
- TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);
-}
-
-static void
-ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
-{
- struct scsi_inquiry_data *sid;
- struct ahd_initiator_tinfo *tinfo;
- struct ahd_transinfo *user;
- struct ahd_transinfo *goal;
- struct ahd_transinfo *curr;
- struct ahd_tmode_tstate *tstate;
- struct ahd_linux_device *dev;
- u_int width;
- u_int period;
- u_int offset;
- u_int ppr_options;
- u_int trans_version;
- u_int prot_version;
-
- /*
- * Determine if this lun actually exists. If so,
- * hold on to its corresponding device structure.
- * If not, make sure we release the device and
- * don't bother processing the rest of this inquiry
- * command.
- */
- dev = ahd_linux_get_device(ahd, devinfo->channel - 'A',
- devinfo->target, devinfo->lun,
- /*alloc*/TRUE);
-
- sid = (struct scsi_inquiry_data *)dev->target->inq_data;
- if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
-
- dev->flags &= ~AHD_DEV_UNCONFIGURED;
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s DT\n", ahd_name(ahd),
+ dt ? "enabling" : "disabling");
+#endif
+ if (dt) {
+ ppr_options |= MSG_EXT_PPR_DT_REQ;
+ if (!width)
+ ahd_linux_set_width(starget, 1);
} else {
- dev->flags |= AHD_DEV_UNCONFIGURED;
+ if (period <= 9)
+ period = 10; /* If resetting DT, period must be >= 25ns */
+ /* IU is invalid without DT set */
+ ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+ }
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_qas(struct scsi_target *starget, int qas)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_QAS_REQ;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt;
+ unsigned long flags;
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s QAS\n", ahd_name(ahd),
+ qas ? "enabling" : "disabling");
+#endif
+
+ if (qas) {
+ ppr_options |= MSG_EXT_PPR_QAS_REQ;
+ }
+
+ dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_iu(struct scsi_target *starget, int iu)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_IU_REQ;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt;
+ unsigned long flags;
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s IU\n", ahd_name(ahd),
+ iu ? "enabling" : "disabling");
+#endif
+
+ if (iu) {
+ ppr_options |= MSG_EXT_PPR_IU_REQ;
+ ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */
+ }
+
+ dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_RD_STRM;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+ unsigned long flags;
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s Read Streaming\n", ahd_name(ahd),
+ rdstrm ? "enabling" : "disabling");
+#endif
+
+ if (rdstrm)
+ ppr_options |= MSG_EXT_PPR_RD_STRM;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_WR_FLOW;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+ unsigned long flags;
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s Write Flow Control\n", ahd_name(ahd),
+ wrflow ? "enabling" : "disabling");
+#endif
+
+ if (wrflow)
+ ppr_options |= MSG_EXT_PPR_WR_FLOW;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_rti(struct scsi_target *starget, int rti)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_RTI;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+ unsigned long flags;
+
+ if ((ahd->features & AHD_RTI) == 0) {
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: RTI not available\n", ahd_name(ahd));
+#endif
return;
}
- /*
- * Update our notion of this device's transfer
- * negotiation capabilities.
- */
- tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
- devinfo->our_scsiid,
- devinfo->target, &tstate);
- user = &tinfo->user;
- goal = &tinfo->goal;
- curr = &tinfo->curr;
- width = user->width;
- period = user->period;
- offset = user->offset;
- ppr_options = user->ppr_options;
- trans_version = user->transport_version;
- prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid));
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s RTI\n", ahd_name(ahd),
+ rti ? "enabling" : "disabling");
+#endif
- /*
- * Only attempt SPI3/4 once we've verified that
- * the device claims to support SPI3/4 features.
- */
- if (prot_version < SCSI_REV_2)
- trans_version = SID_ANSI_REV(sid);
- else
- trans_version = SCSI_REV_2;
+ if (rti)
+ ppr_options |= MSG_EXT_PPR_RTI;
- if ((sid->flags & SID_WBus16) == 0)
- width = MSG_EXT_WDTR_BUS_8_BIT;
- if ((sid->flags & SID_Sync) == 0) {
- period = 0;
- offset = 0;
- ppr_options = 0;
- }
- if ((sid->spi3data & SID_SPI_QAS) == 0)
- ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
- if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
- ppr_options &= MSG_EXT_PPR_QAS_REQ;
- if ((sid->spi3data & SID_SPI_IUS) == 0)
- ppr_options &= (MSG_EXT_PPR_DT_REQ
- | MSG_EXT_PPR_QAS_REQ);
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
- if (prot_version > SCSI_REV_2
- && ppr_options != 0)
- trans_version = user->transport_version;
-
- ahd_validate_width(ahd, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN);
- ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
- ahd_validate_offset(ahd, /*tinfo limit*/NULL, period,
- &offset, width, ROLE_UNKNOWN);
- if (offset == 0 || period == 0) {
- period = 0;
- offset = 0;
- ppr_options = 0;
- }
- /* Apply our filtered user settings. */
- curr->transport_version = trans_version;
- curr->protocol_version = prot_version;
- ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, /*paused*/FALSE);
- ahd_set_syncrate(ahd, devinfo, period, offset, ppr_options,
- AHD_TRANS_GOAL, /*paused*/FALSE);
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
}
-void
-ahd_freeze_simq(struct ahd_softc *ahd)
+static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
{
- ahd->platform_data->qfrozen++;
- if (ahd->platform_data->qfrozen == 1) {
- scsi_block_requests(ahd->platform_data->host);
- ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
- CAM_LUN_WILDCARD, SCB_LIST_NULL,
- ROLE_INITIATOR, CAM_REQUEUE_REQ);
- }
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_PCOMP_EN;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+ unsigned long flags;
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_DV) != 0)
+ printf("%s: %s Precompensation\n", ahd_name(ahd),
+ pcomp ? "Enable" : "Disable");
+#endif
+
+ if (pcomp)
+ ppr_options |= MSG_EXT_PPR_PCOMP_EN;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
}
-void
-ahd_release_simq(struct ahd_softc *ahd)
+static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold)
{
- u_long s;
- int unblock_reqs;
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+ struct ahd_tmode_tstate *tstate;
+ struct ahd_initiator_tinfo *tinfo
+ = ahd_fetch_transinfo(ahd,
+ starget->channel + 'A',
+ shost->this_id, starget->id, &tstate);
+ struct ahd_devinfo devinfo;
+ unsigned int ppr_options = tinfo->goal.ppr_options
+ & ~MSG_EXT_PPR_HOLD_MCS;
+ unsigned int period = tinfo->goal.period;
+ unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+ unsigned long flags;
- unblock_reqs = 0;
- ahd_lock(ahd, &s);
- if (ahd->platform_data->qfrozen > 0)
- ahd->platform_data->qfrozen--;
- if (ahd->platform_data->qfrozen == 0) {
- unblock_reqs = 1;
- }
- if (AHD_DV_SIMQ_FROZEN(ahd)
- && ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_RELEASE) != 0)) {
- ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE;
- up(&ahd->platform_data->dv_sem);
- }
- ahd_schedule_runq(ahd);
- ahd_unlock(ahd, &s);
- /*
- * There is still a race here. The mid-layer
- * should keep its own freeze count and use
- * a bottom half handler to run the queues
- * so we can unblock with our own lock held.
- */
- if (unblock_reqs)
- scsi_unblock_requests(ahd->platform_data->host);
+ if (hold)
+ ppr_options |= MSG_EXT_PPR_HOLD_MCS;
+
+ ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+ starget->channel + 'A', ROLE_INITIATOR);
+ ahd_find_syncrate(ahd, &period, &ppr_options,
+ dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+ ahd_lock(ahd, &flags);
+ ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+ ppr_options, AHD_TRANS_GOAL, FALSE);
+ ahd_unlock(ahd, &flags);
}
-static void
-ahd_linux_sem_timeout(u_long arg)
-{
- struct scb *scb;
- struct ahd_softc *ahd;
- u_long s;
- scb = (struct scb *)arg;
- ahd = scb->ahd_softc;
- ahd_lock(ahd, &s);
- if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
- scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
- up(&ahd->platform_data->eh_sem);
- }
- ahd_unlock(ahd, &s);
-}
-static void
-ahd_linux_dev_timed_unfreeze(u_long arg)
-{
- struct ahd_linux_device *dev;
- struct ahd_softc *ahd;
- u_long s;
-
- dev = (struct ahd_linux_device *)arg;
- ahd = dev->target->ahd;
- ahd_lock(ahd, &s);
- dev->flags &= ~AHD_DEV_TIMER_ACTIVE;
- if (dev->qfrozen > 0)
- dev->qfrozen--;
- if (dev->qfrozen == 0
- && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0)
- ahd_linux_run_device_queue(ahd, dev);
- if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
- && dev->active == 0)
- ahd_linux_free_device(ahd, dev);
- ahd_unlock(ahd, &s);
-}
-
-void
-ahd_platform_dump_card_state(struct ahd_softc *ahd)
-{
- struct ahd_linux_device *dev;
- int target;
- int maxtarget;
- int lun;
- int i;
-
- maxtarget = (ahd->features & AHD_WIDE) ? 15 : 7;
- for (target = 0; target <=maxtarget; target++) {
-
- for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
- struct ahd_cmd *acmd;
-
- dev = ahd_linux_get_device(ahd, 0, target,
- lun, /*alloc*/FALSE);
- if (dev == NULL)
- continue;
-
- printf("DevQ(%d:%d:%d): ", 0, target, lun);
- i = 0;
- TAILQ_FOREACH(acmd, &dev->busyq, acmd_links.tqe) {
- if (i++ > AHD_SCB_MAX)
- break;
- }
- printf("%d waiting\n", i);
- }
- }
-}
+static struct spi_function_template ahd_linux_transport_functions = {
+ .set_offset = ahd_linux_set_offset,
+ .show_offset = 1,
+ .set_period = ahd_linux_set_period,
+ .show_period = 1,
+ .set_width = ahd_linux_set_width,
+ .show_width = 1,
+ .set_dt = ahd_linux_set_dt,
+ .show_dt = 1,
+ .set_iu = ahd_linux_set_iu,
+ .show_iu = 1,
+ .set_qas = ahd_linux_set_qas,
+ .show_qas = 1,
+ .set_rd_strm = ahd_linux_set_rd_strm,
+ .show_rd_strm = 1,
+ .set_wr_flow = ahd_linux_set_wr_flow,
+ .show_wr_flow = 1,
+ .set_rti = ahd_linux_set_rti,
+ .show_rti = 1,
+ .set_pcomp_en = ahd_linux_set_pcomp_en,
+ .show_pcomp_en = 1,
+ .set_hold_mcs = ahd_linux_set_hold_mcs,
+ .show_hold_mcs = 1,
+};
static int __init
ahd_linux_init(void)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- return ahd_linux_detect(&aic79xx_driver_template);
-#else
- scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template);
- if (aic79xx_driver_template.present == 0) {
- scsi_unregister_module(MODULE_SCSI_HA,
- &aic79xx_driver_template);
- return (-ENODEV);
- }
+ int error = 0;
- return (0);
-#endif
+ /*
+ * If we've been passed any parameters, process them now.
+ */
+ if (aic79xx)
+ aic79xx_setup(aic79xx);
+
+ ahd_linux_transport_template =
+ spi_attach_transport(&ahd_linux_transport_functions);
+ if (!ahd_linux_transport_template)
+ return -ENODEV;
+
+ scsi_transport_reserve_target(ahd_linux_transport_template,
+ sizeof(struct ahd_linux_target));
+ scsi_transport_reserve_device(ahd_linux_transport_template,
+ sizeof(struct ahd_linux_device));
+
+ error = ahd_linux_pci_init();
+ if (error)
+ spi_release_transport(ahd_linux_transport_template);
+ return error;
}
static void __exit
ahd_linux_exit(void)
{
- struct ahd_softc *ahd;
-
- /*
- * Shutdown DV threads before going into the SCSI mid-layer.
- * This avoids situations where the mid-layer locks the entire
- * kernel so that waiting for our DV threads to exit leads
- * to deadlock.
- */
- TAILQ_FOREACH(ahd, &ahd_tailq, links) {
-
- ahd_linux_kill_dv_thread(ahd);
- }
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- /*
- * In 2.4 we have to unregister from the PCI core _after_
- * unregistering from the scsi midlayer to avoid dangling
- * references.
- */
- scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template);
-#endif
ahd_linux_pci_exit();
+ spi_release_transport(ahd_linux_transport_template);
}
module_init(ahd_linux_init);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 7823e52..052c661 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -42,6 +42,7 @@
#ifndef _AIC79XX_LINUX_H_
#define _AIC79XX_LINUX_H_
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -49,18 +50,23 @@
#include <linux/pci.h>
#include <linux/smp_lock.h>
#include <linux/version.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <linux/interrupt.h> /* For tasklet support. */
-#include <linux/config.h>
-#include <linux/slab.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahd
-#include "scsi.h"
-#include <scsi/scsi_host.h>
/* Name space conflict with BSD queue macros */
#ifdef LIST_HEAD
@@ -95,7 +101,7 @@
/************************* Forward Declarations *******************************/
struct ahd_softc;
typedef struct pci_dev *ahd_dev_softc_t;
-typedef Scsi_Cmnd *ahd_io_ctx_t;
+typedef struct scsi_cmnd *ahd_io_ctx_t;
/******************************* Byte Order ***********************************/
#define ahd_htobe16(x) cpu_to_be16(x)
@@ -114,8 +120,7 @@
/************************* Configuration Data *********************************/
extern uint32_t aic79xx_allow_memio;
-extern int aic79xx_detect_complete;
-extern Scsi_Host_Template aic79xx_driver_template;
+extern struct scsi_host_template aic79xx_driver_template;
/***************************** Bus Space/DMA **********************************/
@@ -145,11 +150,7 @@
};
typedef struct ahd_linux_dma_tag* bus_dma_tag_t;
-struct ahd_linux_dmamap
-{
- dma_addr_t bus_addr;
-};
-typedef struct ahd_linux_dmamap* bus_dmamap_t;
+typedef dma_addr_t bus_dmamap_t;
typedef int bus_dma_filter_t(void*, dma_addr_t);
typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
@@ -226,12 +227,12 @@
#define ahd_timer_init init_timer
#define ahd_timer_stop del_timer_sync
typedef void ahd_linux_callback_t (u_long);
-static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec,
+static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec,
ahd_callback_t *func, void *arg);
static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec);
static __inline void
-ahd_timer_reset(ahd_timer_t *timer, u_int usec, ahd_callback_t *func, void *arg)
+ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
{
struct ahd_softc *ahd;
@@ -252,43 +253,8 @@
/***************************** SMP support ************************************/
#include <linux/spinlock.h>
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
-#define AHD_SCSI_HAS_HOST_LOCK 1
-#else
-#define AHD_SCSI_HAS_HOST_LOCK 0
-#endif
-
#define AIC79XX_DRIVER_VERSION "1.3.11"
-/**************************** Front End Queues ********************************/
-/*
- * Data structure used to cast the Linux struct scsi_cmnd to something
- * that allows us to use the queue macros. The linux structure has
- * plenty of space to hold the links fields as required by the queue
- * macros, but the queue macors require them to have the correct type.
- */
-struct ahd_cmd_internal {
- /* Area owned by the Linux scsi layer. */
- uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)];
- union {
- STAILQ_ENTRY(ahd_cmd) ste;
- LIST_ENTRY(ahd_cmd) le;
- TAILQ_ENTRY(ahd_cmd) tqe;
- } links;
- uint32_t end;
-};
-
-struct ahd_cmd {
- union {
- struct ahd_cmd_internal icmd;
- struct scsi_cmnd scsi_cmd;
- } un;
-};
-
-#define acmd_icmd(cmd) ((cmd)->un.icmd)
-#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd)
-#define acmd_links un.icmd.links
-
/*************************** Device Data Structures ***************************/
/*
* A per probed device structure used to deal with some error recovery
@@ -297,22 +263,17 @@
* after a successfully completed inquiry command to the target when
* that inquiry data indicates a lun is present.
*/
-TAILQ_HEAD(ahd_busyq, ahd_cmd);
+
typedef enum {
- AHD_DEV_UNCONFIGURED = 0x01,
AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
- AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */
- AHD_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */
AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */
AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */
AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */
- AHD_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */
} ahd_linux_dev_flags;
struct ahd_linux_target;
struct ahd_linux_device {
TAILQ_ENTRY(ahd_linux_device) links;
- struct ahd_busyq busyq;
/*
* The number of transactions currently
@@ -388,62 +349,12 @@
*/
u_int commands_since_idle_or_otag;
#define AHD_OTAG_THRESH 500
-
- int lun;
- Scsi_Device *scsi_device;
- struct ahd_linux_target *target;
};
-typedef enum {
- AHD_DV_REQUIRED = 0x01,
- AHD_INQ_VALID = 0x02,
- AHD_BASIC_DV = 0x04,
- AHD_ENHANCED_DV = 0x08
-} ahd_linux_targ_flags;
-
-/* DV States */
-typedef enum {
- AHD_DV_STATE_EXIT = 0,
- AHD_DV_STATE_INQ_SHORT_ASYNC,
- AHD_DV_STATE_INQ_ASYNC,
- AHD_DV_STATE_INQ_ASYNC_VERIFY,
- AHD_DV_STATE_TUR,
- AHD_DV_STATE_REBD,
- AHD_DV_STATE_INQ_VERIFY,
- AHD_DV_STATE_WEB,
- AHD_DV_STATE_REB,
- AHD_DV_STATE_SU,
- AHD_DV_STATE_BUSY
-} ahd_dv_state;
-
struct ahd_linux_target {
- struct ahd_linux_device *devices[AHD_NUM_LUNS];
- int channel;
- int target;
- int refcount;
+ struct scsi_device *sdev[AHD_NUM_LUNS];
struct ahd_transinfo last_tinfo;
struct ahd_softc *ahd;
- ahd_linux_targ_flags flags;
- struct scsi_inquiry_data *inq_data;
- /*
- * The next "fallback" period to use for narrow/wide transfers.
- */
- uint8_t dv_next_narrow_period;
- uint8_t dv_next_wide_period;
- uint8_t dv_max_width;
- uint8_t dv_max_ppr_options;
- uint8_t dv_last_ppr_options;
- u_int dv_echo_size;
- ahd_dv_state dv_state;
- u_int dv_state_retry;
- uint8_t *dv_buffer;
- uint8_t *dv_buffer1;
-
- /*
- * Cumulative counter of errors.
- */
- u_long errors_detected;
- u_long cmds_since_error;
};
/********************* Definitions Required by the Core ***********************/
@@ -453,32 +364,16 @@
* manner and are allocated below 4GB, the number of S/G segments is
* unrestricted.
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/*
- * We dynamically adjust the number of segments in pre-2.5 kernels to
- * avoid fragmentation issues in the SCSI mid-layer's private memory
- * allocator. See aic79xx_osm.c ahd_linux_size_nseg() for details.
- */
-extern u_int ahd_linux_nseg;
-#define AHD_NSEG ahd_linux_nseg
-#define AHD_LINUX_MIN_NSEG 64
-#else
#define AHD_NSEG 128
-#endif
/*
* Per-SCB OSM storage.
*/
-typedef enum {
- AHD_SCB_UP_EH_SEM = 0x1
-} ahd_linux_scb_flags;
-
struct scb_platform_data {
struct ahd_linux_device *dev;
dma_addr_t buf_busaddr;
uint32_t xfer_len;
uint32_t sense_resid; /* Auto-Sense residual */
- ahd_linux_scb_flags flags;
};
/*
@@ -487,44 +382,23 @@
* alignment restrictions of the various platforms supported by
* this driver.
*/
-typedef enum {
- AHD_DV_WAIT_SIMQ_EMPTY = 0x01,
- AHD_DV_WAIT_SIMQ_RELEASE = 0x02,
- AHD_DV_ACTIVE = 0x04,
- AHD_DV_SHUTDOWN = 0x08,
- AHD_RUN_CMPLT_Q_TIMER = 0x10
-} ahd_linux_softc_flags;
-
-TAILQ_HEAD(ahd_completeq, ahd_cmd);
-
struct ahd_platform_data {
/*
* Fields accessed from interrupt context.
*/
- struct ahd_linux_target *targets[AHD_NUM_TARGETS];
- TAILQ_HEAD(, ahd_linux_device) device_runq;
- struct ahd_completeq completeq;
+ struct scsi_target *starget[AHD_NUM_TARGETS];
spinlock_t spin_lock;
- struct tasklet_struct runq_tasklet;
u_int qfrozen;
- pid_t dv_pid;
- struct timer_list completeq_timer;
struct timer_list reset_timer;
- struct timer_list stats_timer;
struct semaphore eh_sem;
- struct semaphore dv_sem;
- struct semaphore dv_cmd_sem; /* XXX This needs to be in
- * the target struct
- */
- struct scsi_device *dv_scsi_dev;
struct Scsi_Host *host; /* pointer to scsi host */
#define AHD_LINUX_NOIRQ ((uint32_t)~0)
uint32_t irq; /* IRQ for this adapter */
uint32_t bios_address;
uint32_t mem_busaddr; /* Mem Base Addr */
- uint64_t hw_dma_mask;
- ahd_linux_softc_flags flags;
+#define AHD_SCB_UP_EH_SEM 0x1
+ uint32_t flags;
};
/************************** OS Utility Wrappers *******************************/
@@ -641,7 +515,7 @@
/**************************** Initialization **********************************/
int ahd_linux_register_host(struct ahd_softc *,
- Scsi_Host_Template *);
+ struct scsi_host_template *);
uint64_t ahd_linux_get_memsize(void);
@@ -657,28 +531,6 @@
struct ahd_transinfo *tinfo);
/******************************** Locking *************************************/
-/* Lock protecting internal data structures */
-static __inline void ahd_lockinit(struct ahd_softc *);
-static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags);
-static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags);
-
-/* Lock acquisition and release of the above lock in midlayer entry points. */
-static __inline void ahd_midlayer_entrypoint_lock(struct ahd_softc *,
- unsigned long *flags);
-static __inline void ahd_midlayer_entrypoint_unlock(struct ahd_softc *,
- unsigned long *flags);
-
-/* Lock held during command compeletion to the upper layer */
-static __inline void ahd_done_lockinit(struct ahd_softc *);
-static __inline void ahd_done_lock(struct ahd_softc *, unsigned long *flags);
-static __inline void ahd_done_unlock(struct ahd_softc *, unsigned long *flags);
-
-/* Lock held during ahd_list manipulation and ahd softc frees */
-extern spinlock_t ahd_list_spinlock;
-static __inline void ahd_list_lockinit(void);
-static __inline void ahd_list_lock(unsigned long *flags);
-static __inline void ahd_list_unlock(unsigned long *flags);
-
static __inline void
ahd_lockinit(struct ahd_softc *ahd)
{
@@ -697,75 +549,6 @@
spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags);
}
-static __inline void
-ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags)
-{
- /*
- * In 2.5.X and some 2.4.X versions, the midlayer takes our
- * lock just before calling us, so we avoid locking again.
- * For other kernel versions, the io_request_lock is taken
- * just before our entry point is called. In this case, we
- * trade the io_request_lock for our per-softc lock.
- */
-#if AHD_SCSI_HAS_HOST_LOCK == 0
- spin_unlock(&io_request_lock);
- spin_lock(&ahd->platform_data->spin_lock);
-#endif
-}
-
-static __inline void
-ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags)
-{
-#if AHD_SCSI_HAS_HOST_LOCK == 0
- spin_unlock(&ahd->platform_data->spin_lock);
- spin_lock(&io_request_lock);
-#endif
-}
-
-static __inline void
-ahd_done_lockinit(struct ahd_softc *ahd)
-{
- /*
- * In 2.5.X, our own lock is held during completions.
- * In previous versions, the io_request_lock is used.
- * In either case, we can't initialize this lock again.
- */
-}
-
-static __inline void
-ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags)
-{
-#if AHD_SCSI_HAS_HOST_LOCK == 0
- spin_lock(&io_request_lock);
-#endif
-}
-
-static __inline void
-ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags)
-{
-#if AHD_SCSI_HAS_HOST_LOCK == 0
- spin_unlock(&io_request_lock);
-#endif
-}
-
-static __inline void
-ahd_list_lockinit(void)
-{
- spin_lock_init(&ahd_list_spinlock);
-}
-
-static __inline void
-ahd_list_lock(unsigned long *flags)
-{
- spin_lock_irqsave(&ahd_list_spinlock, *flags);
-}
-
-static __inline void
-ahd_list_unlock(unsigned long *flags)
-{
- spin_unlock_irqrestore(&ahd_list_spinlock, *flags);
-}
-
/******************************* PCI Definitions ******************************/
/*
* PCIM_xxx: mask to locate subfield in register
@@ -925,27 +708,17 @@
}
/**************************** Proc FS Support *********************************/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-int ahd_linux_proc_info(char *, char **, off_t, int, int, int);
-#else
int ahd_linux_proc_info(struct Scsi_Host *, char *, char **,
off_t, int, int);
-#endif
-
-/*************************** Domain Validation ********************************/
-#define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete)
-#define AHD_DV_SIMQ_FROZEN(ahd) \
- ((((ahd)->platform_data->flags & AHD_DV_ACTIVE) != 0) \
- && (ahd)->platform_data->qfrozen == 1)
/*********************** Transaction Access Wrappers **************************/
-static __inline void ahd_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t);
static __inline void ahd_set_transaction_status(struct scb *, uint32_t);
-static __inline void ahd_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t);
static __inline void ahd_set_scsi_status(struct scb *, uint32_t);
-static __inline uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd);
static __inline uint32_t ahd_get_transaction_status(struct scb *);
-static __inline uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd);
static __inline uint32_t ahd_get_scsi_status(struct scb *);
static __inline void ahd_set_transaction_tag(struct scb *, int, u_int);
static __inline u_long ahd_get_transfer_length(struct scb *);
@@ -964,7 +737,7 @@
static __inline void ahd_freeze_scb(struct scb *scb);
static __inline
-void ahd_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status)
+void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status)
{
cmd->result &= ~(CAM_STATUS_MASK << 16);
cmd->result |= status << 16;
@@ -977,7 +750,7 @@
}
static __inline
-void ahd_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status)
+void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status)
{
cmd->result &= ~0xFFFF;
cmd->result |= status;
@@ -990,7 +763,7 @@
}
static __inline
-uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd)
+uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd)
{
return ((cmd->result >> 16) & CAM_STATUS_MASK);
}
@@ -1002,7 +775,7 @@
}
static __inline
-uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd)
+uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd)
{
return (cmd->result & 0xFFFF);
}
@@ -1117,7 +890,6 @@
void ahd_send_async(struct ahd_softc *, char channel,
u_int target, u_int lun, ac_code, void *);
void ahd_print_path(struct ahd_softc *, struct scb *);
-void ahd_platform_dump_card_state(struct ahd_softc *ahd);
#ifdef CONFIG_PCI
#define AHD_PCI_CONFIG 1
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 91daf0c..390b538 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -92,27 +92,31 @@
static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
{
- struct ahd_softc *ahd;
- u_long l;
+ struct ahd_softc *ahd = pci_get_drvdata(pdev);
+ u_long s;
- /*
- * We should be able to just perform
- * the free directly, but check our
- * list for extra sanity.
- */
- ahd_list_lock(&l);
- ahd = ahd_find_softc((struct ahd_softc *)pci_get_drvdata(pdev));
- if (ahd != NULL) {
- u_long s;
+ ahd_lock(ahd, &s);
+ ahd_intr_enable(ahd, FALSE);
+ ahd_unlock(ahd, &s);
+ ahd_free(ahd);
+}
- TAILQ_REMOVE(&ahd_tailq, ahd, links);
- ahd_list_unlock(&l);
- ahd_lock(ahd, &s);
- ahd_intr_enable(ahd, FALSE);
- ahd_unlock(ahd, &s);
- ahd_free(ahd);
- } else
- ahd_list_unlock(&l);
+static void
+ahd_linux_pci_inherit_flags(struct ahd_softc *ahd)
+{
+ struct pci_dev *pdev = ahd->dev_softc, *master_pdev;
+ unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+
+ master_pdev = pci_get_slot(pdev->bus, master_devfn);
+ if (master_pdev) {
+ struct ahd_softc *master = pci_get_drvdata(master_pdev);
+ if (master) {
+ ahd->flags &= ~AHD_BIOS_ENABLED;
+ ahd->flags |= master->flags & AHD_BIOS_ENABLED;
+ } else
+ printk(KERN_ERR "aic79xx: no multichannel peer found!\n");
+ pci_dev_put(master_pdev);
+ }
}
static int
@@ -125,22 +129,6 @@
char *name;
int error;
- /*
- * Some BIOSen report the same device multiple times.
- */
- TAILQ_FOREACH(ahd, &ahd_tailq, links) {
- struct pci_dev *probed_pdev;
-
- probed_pdev = ahd->dev_softc;
- if (probed_pdev->bus->number == pdev->bus->number
- && probed_pdev->devfn == pdev->devfn)
- break;
- }
- if (ahd != NULL) {
- /* Skip duplicate. */
- return (-ENODEV);
- }
-
pci = pdev;
entry = ahd_find_pci_device(pci);
if (entry == NULL)
@@ -177,15 +165,12 @@
if (memsize >= 0x8000000000ULL
&& pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
ahd->flags |= AHD_64BIT_ADDRESSING;
- ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK;
} else if (memsize > 0x80000000
&& pci_set_dma_mask(pdev, mask_39bit) == 0) {
ahd->flags |= AHD_39BIT_ADDRESSING;
- ahd->platform_data->hw_dma_mask = mask_39bit;
}
} else {
pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK;
}
ahd->dev_softc = pci;
error = ahd_pci_config(ahd, entry);
@@ -193,16 +178,17 @@
ahd_free(ahd);
return (-error);
}
+
+ /*
+ * Second Function PCI devices need to inherit some
+ * * settings from function 0.
+ */
+ if ((ahd->features & AHD_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0)
+ ahd_linux_pci_inherit_flags(ahd);
+
pci_set_drvdata(pdev, ahd);
- if (aic79xx_detect_complete) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- ahd_linux_register_host(ahd, &aic79xx_driver_template);
-#else
- printf("aic79xx: ignoring PCI device found after "
- "initialization\n");
- return (-ENODEV);
-#endif
- }
+
+ ahd_linux_register_host(ahd, &aic79xx_driver_template);
return (0);
}
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 703f6e4..2131db6 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -283,7 +283,6 @@
ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
{
struct scb_data *shared_scb_data;
- u_long l;
u_int command;
uint32_t devconfig;
uint16_t subvendor;
@@ -373,16 +372,9 @@
* Allow interrupts now that we are completely setup.
*/
error = ahd_pci_map_int(ahd);
- if (error != 0)
- return (error);
-
- ahd_list_lock(&l);
- /*
- * Link this softc in with all other ahd instances.
- */
- ahd_softc_insert(ahd);
- ahd_list_unlock(&l);
- return (0);
+ if (!error)
+ ahd->init_level++;
+ return error;
}
/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index e01cd61..39a2784 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -49,10 +49,53 @@
u_int our_id, char channel,
u_int target_id, u_int target_offset);
static void ahd_dump_device_state(struct info_str *info,
- struct ahd_linux_device *dev);
+ struct scsi_device *sdev);
static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
char *buffer, int length);
+/*
+ * Table of syncrates that don't follow the "divisible by 4"
+ * rule. This table will be expanded in future SCSI specs.
+ */
+static struct {
+ u_int period_factor;
+ u_int period; /* in 100ths of ns */
+} scsi_syncrates[] = {
+ { 0x08, 625 }, /* FAST-160 */
+ { 0x09, 1250 }, /* FAST-80 */
+ { 0x0a, 2500 }, /* FAST-40 40MHz */
+ { 0x0b, 3030 }, /* FAST-40 33MHz */
+ { 0x0c, 5000 } /* FAST-20 */
+};
+
+/*
+ * Return the frequency in kHz corresponding to the given
+ * sync period factor.
+ */
+static u_int
+ahd_calc_syncsrate(u_int period_factor)
+{
+ int i;
+ int num_syncrates;
+
+ num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
+ /* See if the period is in the "exception" table */
+ for (i = 0; i < num_syncrates; i++) {
+
+ if (period_factor == scsi_syncrates[i].period_factor) {
+ /* Period in kHz */
+ return (100000000 / scsi_syncrates[i].period);
+ }
+ }
+
+ /*
+ * Wasn't in the table, so use the standard
+ * 4 times conversion.
+ */
+ return (10000000 / (period_factor * 4 * 10));
+}
+
+
static void
copy_mem_info(struct info_str *info, char *data, int len)
{
@@ -109,7 +152,7 @@
speed = 3300;
freq = 0;
if (tinfo->offset != 0) {
- freq = aic_calc_syncsrate(tinfo->period);
+ freq = ahd_calc_syncsrate(tinfo->period);
speed = freq;
}
speed *= (0x01 << tinfo->width);
@@ -167,6 +210,7 @@
u_int target_offset)
{
struct ahd_linux_target *targ;
+ struct scsi_target *starget;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
int lun;
@@ -176,20 +220,20 @@
copy_info(info, "Target %d Negotiation Settings\n", target_id);
copy_info(info, "\tUser: ");
ahd_format_transinfo(info, &tinfo->user);
- targ = ahd->platform_data->targets[target_offset];
- if (targ == NULL)
+ starget = ahd->platform_data->starget[target_offset];
+ if (starget == NULL)
return;
+ targ = scsi_transport_target_data(starget);
copy_info(info, "\tGoal: ");
ahd_format_transinfo(info, &tinfo->goal);
copy_info(info, "\tCurr: ");
ahd_format_transinfo(info, &tinfo->curr);
- copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected);
for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
- struct ahd_linux_device *dev;
+ struct scsi_device *dev;
- dev = targ->devices[lun];
+ dev = targ->sdev[lun];
if (dev == NULL)
continue;
@@ -199,10 +243,13 @@
}
static void
-ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev)
+ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev)
{
+ struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
+
copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
- dev->target->channel + 'A', dev->target->target, dev->lun);
+ sdev->sdev_target->channel + 'A',
+ sdev->sdev_target->id, sdev->lun);
copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
copy_info(info, "\t\tCommands Active %d\n", dev->active);
@@ -278,36 +325,16 @@
* Return information to handle /proc support for the driver.
*/
int
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-ahd_linux_proc_info(char *buffer, char **start, off_t offset,
- int length, int hostno, int inout)
-#else
ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
off_t offset, int length, int inout)
-#endif
{
- struct ahd_softc *ahd;
+ struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
struct info_str info;
char ahd_info[256];
- u_long l;
u_int max_targ;
u_int i;
int retval;
- retval = -EINVAL;
- ahd_list_lock(&l);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- TAILQ_FOREACH(ahd, &ahd_tailq, links) {
- if (ahd->platform_data->host->host_no == hostno)
- break;
- }
-#else
- ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata);
-#endif
-
- if (ahd == NULL)
- goto done;
-
/* Has data been written to the file? */
if (inout == TRUE) {
retval = ahd_proc_write_seeprom(ahd, buffer, length);
@@ -357,6 +384,5 @@
}
retval = info.pos > info.offset ? info.pos - info.offset : 0;
done:
- ahd_list_unlock(&l);
return (retval);
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 088cbc2..91d294c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#79 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $
*
* $FreeBSD$
*/
@@ -243,7 +243,7 @@
*/
AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA,
AHC_AIC7860_FE = AHC_AIC7850_FE,
- AHC_AIC7870_FE = AHC_TARGETMODE,
+ AHC_AIC7870_FE = AHC_TARGETMODE|AHC_AUTOPAUSE,
AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA,
/*
* Although we have space for both the initiator and
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index 810ec70..e196d83 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@@ -1306,7 +1306,6 @@
*/
MWI_RESIDUAL {
size 1
- alias TARG_IMMEDIATE_SCB
}
/*
* SCBID of the next SCB to be started by the controller.
@@ -1461,6 +1460,7 @@
*/
LAST_MSG {
size 1
+ alias TARG_IMMEDIATE_SCB
}
/*
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index d84b741..1519639 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -40,7 +40,7 @@
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $"
PATCH_ARG_LIST = "struct ahc_softc *ahc"
PREFIX = "ahc_"
@@ -679,6 +679,7 @@
clr SCSIBUSL; /* Prevent bit leakage durint SELTO */
}
and SXFRCTL0, ~SPIOEN;
+ mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT;
test SSTAT1,REQINIT|BUSFREE jz .;
test SSTAT1, BUSFREE jnz poll_for_work;
mvi MISSED_BUSFREE call set_seqint;
@@ -1097,7 +1098,7 @@
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
if ((ahc->flags & AHC_TARGETROLE) != 0) {
test SSTAT0, TARGET jz dma_last_sg;
- if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) {
+ if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) {
test DMAPARAMS, DIRECTION jz dma_mid_sg;
}
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
index 468d612..3cb07e1 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
@@ -28,9 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#19 $
*/
/*
@@ -64,7 +62,6 @@
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB
* first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip.
- *
*/
#ifdef __linux__
@@ -81,14 +78,22 @@
* Right now, we only have to read the SEEPROM. But we make it easier to
* add other 93Cx6 functions.
*/
-static struct seeprom_cmd {
+struct seeprom_cmd {
uint8_t len;
- uint8_t bits[9];
-} seeprom_read = {3, {1, 1, 0}};
+ uint8_t bits[11];
+};
+/* Short opcodes for the c46 */
static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+/* Long opcodes for the C56/C66 */
+static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+/* Common opcodes */
static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
+static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
/*
* Wait for the SEERDY to go high; about 800 ns.
@@ -222,12 +227,25 @@
ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
u_int start_addr, u_int count)
{
+ struct seeprom_cmd *ewen, *ewds;
uint16_t v;
uint8_t temp;
int i, k;
/* Place the chip into write-enable mode */
- send_seeprom_cmd(sd, &seeprom_ewen);
+ if (sd->sd_chip == C46) {
+ ewen = &seeprom_ewen;
+ ewds = &seeprom_ewds;
+ } else if (sd->sd_chip == C56_66) {
+ ewen = &seeprom_long_ewen;
+ ewds = &seeprom_long_ewds;
+ } else {
+ printf("ahc_write_seeprom: unsupported seeprom type %d\n",
+ sd->sd_chip);
+ return (0);
+ }
+
+ send_seeprom_cmd(sd, ewen);
reset_seeprom(sd);
/* Write all requested data out to the seeprom. */
@@ -277,7 +295,7 @@
}
/* Put the chip back into write-protect mode */
- send_seeprom_cmd(sd, &seeprom_ewds);
+ send_seeprom_cmd(sd, ewds);
reset_seeprom(sd);
return (1);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 7bc01e4..58ac461 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -37,9 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#134 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $
*/
#ifdef __linux__
@@ -287,10 +285,19 @@
ahc_outb(ahc, SEQ_FLAGS2,
ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
}
+
+ /*
+ * Clear any pending sequencer interrupt. It is no
+ * longer relevant since we're resetting the Program
+ * Counter.
+ */
+ ahc_outb(ahc, CLRINT, CLRSEQINT);
+
ahc_outb(ahc, MWI_RESIDUAL, 0);
ahc_outb(ahc, SEQCTL, ahc->seqctl);
ahc_outb(ahc, SEQADDR0, 0);
ahc_outb(ahc, SEQADDR1, 0);
+
ahc_unpause(ahc);
}
@@ -1174,19 +1181,20 @@
scb_index);
}
#endif
- /*
- * Force a renegotiation with this target just in
- * case the cable was pulled and will later be
- * re-attached. The target may forget its negotiation
- * settings with us should it attempt to reselect
- * during the interruption. The target will not issue
- * a unit attention in this case, so we must always
- * renegotiate.
- */
ahc_scb_devinfo(ahc, &devinfo, scb);
- ahc_force_renegotiation(ahc, &devinfo);
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb);
+
+ /*
+ * Cancel any pending transactions on the device
+ * now that it seems to be missing. This will
+ * also revert us to async/narrow transfers until
+ * we can renegotiate with the device.
+ */
+ ahc_handle_devreset(ahc, &devinfo,
+ CAM_SEL_TIMEOUT,
+ "Selection Timeout",
+ /*verbose_level*/1);
}
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_restart(ahc);
@@ -3763,8 +3771,9 @@
/*period*/0, /*offset*/0, /*ppr_options*/0,
AHC_TRANS_CUR, /*paused*/TRUE);
- ahc_send_async(ahc, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ if (status != CAM_SEL_TIMEOUT)
+ ahc_send_async(ahc, devinfo->channel, devinfo->target,
+ CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
if (message != NULL
&& (verbose_level <= bootverbose))
@@ -4003,14 +4012,6 @@
* to disturb the integrity of the bus.
*/
ahc_pause(ahc);
- if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) {
- /*
- * The chip has not been initialized since
- * PCI/EISA/VLB bus reset. Don't trust
- * "left over BIOS data".
- */
- ahc->flags |= AHC_NO_BIOS_INIT;
- }
sxfrctl1_b = 0;
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
u_int sblkctl;
@@ -5036,14 +5037,23 @@
ahc->flags |= AHC_ALL_INTERRUPTS;
paused = FALSE;
do {
- if (paused)
+ if (paused) {
ahc_unpause(ahc);
+ /*
+ * Give the sequencer some time to service
+ * any active selections.
+ */
+ ahc_delay(500);
+ }
ahc_intr(ahc);
ahc_pause(ahc);
paused = TRUE;
ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
- ahc_clear_critical_section(ahc);
intstat = ahc_inb(ahc, INTSTAT);
+ if ((intstat & INT_PEND) == 0) {
+ ahc_clear_critical_section(ahc);
+ intstat = ahc_inb(ahc, INTSTAT);
+ }
} while (--maxloops
&& (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
&& ((intstat & INT_PEND) != 0
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 687f19e..c932b3b 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -125,12 +125,6 @@
static struct scsi_transport_template *ahc_linux_transport_template = NULL;
-/*
- * Include aiclib.c as part of our
- * "module dependencies are hard" work around.
- */
-#include "aiclib.c"
-
#include <linux/init.h> /* __setup */
#include <linux/mm.h> /* For fetching system memory size */
#include <linux/blkdev.h> /* For block_size() */
@@ -391,7 +385,6 @@
struct ahc_linux_device *,
struct scsi_cmnd *);
static void ahc_linux_setup_tag_info_global(char *p);
-static aic_option_callback_t ahc_linux_setup_tag_info;
static int aic7xxx_setup(char *s);
static int ahc_linux_unit;
@@ -635,6 +628,8 @@
targ->sdev[sdev->lun] = sdev;
+ spi_period(starget) = 0;
+
return 0;
}
@@ -918,6 +913,86 @@
}
}
+static char *
+ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
+ void (*callback)(u_long, int, int, int32_t),
+ u_long callback_arg)
+{
+ char *tok_end;
+ char *tok_end2;
+ int i;
+ int instance;
+ int targ;
+ int done;
+ char tok_list[] = {'.', ',', '{', '}', '\0'};
+
+ /* All options use a ':' name/arg separator */
+ if (*opt_arg != ':')
+ return (opt_arg);
+ opt_arg++;
+ instance = -1;
+ targ = -1;
+ done = FALSE;
+ /*
+ * Restore separator that may be in
+ * the middle of our option argument.
+ */
+ tok_end = strchr(opt_arg, '\0');
+ if (tok_end < end)
+ *tok_end = ',';
+ while (!done) {
+ switch (*opt_arg) {
+ case '{':
+ if (instance == -1) {
+ instance = 0;
+ } else {
+ if (depth > 1) {
+ if (targ == -1)
+ targ = 0;
+ } else {
+ printf("Malformed Option %s\n",
+ opt_name);
+ done = TRUE;
+ }
+ }
+ opt_arg++;
+ break;
+ case '}':
+ if (targ != -1)
+ targ = -1;
+ else if (instance != -1)
+ instance = -1;
+ opt_arg++;
+ break;
+ case ',':
+ case '.':
+ if (instance == -1)
+ done = TRUE;
+ else if (targ >= 0)
+ targ++;
+ else if (instance >= 0)
+ instance++;
+ opt_arg++;
+ break;
+ case '\0':
+ done = TRUE;
+ break;
+ default:
+ tok_end = end;
+ for (i = 0; tok_list[i]; i++) {
+ tok_end2 = strchr(opt_arg, tok_list[i]);
+ if ((tok_end2) && (tok_end2 < tok_end))
+ tok_end = tok_end2;
+ }
+ callback(callback_arg, instance, targ,
+ simple_strtol(opt_arg, NULL, 0));
+ opt_arg = tok_end;
+ break;
+ }
+ }
+ return (opt_arg);
+}
+
/*
* Handle Linux boot parameters. This routine allows for assigning a value
* to a parameter with a ':' between the parameter and the value.
@@ -972,7 +1047,7 @@
if (strncmp(p, "global_tag_depth", n) == 0) {
ahc_linux_setup_tag_info_global(p + n);
} else if (strncmp(p, "tag_info", n) == 0) {
- s = aic_parse_brace_option("tag_info", p + n, end,
+ s = ahc_parse_brace_option("tag_info", p + n, end,
2, ahc_linux_setup_tag_info, 0);
} else if (p[n] == ':') {
*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
@@ -1612,9 +1687,9 @@
if (channel == 'B')
target_offset += 8;
starget = ahc->platform_data->starget[target_offset];
- targ = scsi_transport_target_data(starget);
- if (targ == NULL)
+ if (starget == NULL)
break;
+ targ = scsi_transport_target_data(starget);
target_ppr_options =
(spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0)
@@ -2329,8 +2404,6 @@
{
}
-static void ahc_linux_exit(void);
-
static void ahc_linux_set_width(struct scsi_target *starget, int width)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 0e47ac2..c529962 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -265,7 +265,7 @@
/***************************** SMP support ************************************/
#include <linux/spinlock.h>
-#define AIC7XXX_DRIVER_VERSION "6.2.36"
+#define AIC7XXX_DRIVER_VERSION "7.0"
/*************************** Device Data Structures ***************************/
/*
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 9d318ce..0d44a69 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -149,6 +149,27 @@
ahc_free(ahc);
}
+static void
+ahc_linux_pci_inherit_flags(struct ahc_softc *ahc)
+{
+ struct pci_dev *pdev = ahc->dev_softc, *master_pdev;
+ unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+
+ master_pdev = pci_get_slot(pdev->bus, master_devfn);
+ if (master_pdev) {
+ struct ahc_softc *master = pci_get_drvdata(master_pdev);
+ if (master) {
+ ahc->flags &= ~AHC_BIOS_ENABLED;
+ ahc->flags |= master->flags & AHC_BIOS_ENABLED;
+
+ ahc->flags &= ~AHC_PRIMARY_CHANNEL;
+ ahc->flags |= master->flags & AHC_PRIMARY_CHANNEL;
+ } else
+ printk(KERN_ERR "aic7xxx: no multichannel peer found!\n");
+ pci_dev_put(master_pdev);
+ }
+}
+
static int
ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -203,6 +224,14 @@
ahc_free(ahc);
return (-error);
}
+
+ /*
+ * Second Function PCI devices need to inherit some
+ * settings from function 0.
+ */
+ if ((ahc->features & AHC_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0)
+ ahc_linux_pci_inherit_flags(ahc);
+
pci_set_drvdata(pdev, ahc);
ahc_linux_register_host(ahc, &aic7xxx_driver_template);
return (0);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index 3802c91..04a3506 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -54,6 +54,49 @@
static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
char *buffer, int length);
+/*
+ * Table of syncrates that don't follow the "divisible by 4"
+ * rule. This table will be expanded in future SCSI specs.
+ */
+static struct {
+ u_int period_factor;
+ u_int period; /* in 100ths of ns */
+} scsi_syncrates[] = {
+ { 0x08, 625 }, /* FAST-160 */
+ { 0x09, 1250 }, /* FAST-80 */
+ { 0x0a, 2500 }, /* FAST-40 40MHz */
+ { 0x0b, 3030 }, /* FAST-40 33MHz */
+ { 0x0c, 5000 } /* FAST-20 */
+};
+
+/*
+ * Return the frequency in kHz corresponding to the given
+ * sync period factor.
+ */
+static u_int
+ahc_calc_syncsrate(u_int period_factor)
+{
+ int i;
+ int num_syncrates;
+
+ num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
+ /* See if the period is in the "exception" table */
+ for (i = 0; i < num_syncrates; i++) {
+
+ if (period_factor == scsi_syncrates[i].period_factor) {
+ /* Period in kHz */
+ return (100000000 / scsi_syncrates[i].period);
+ }
+ }
+
+ /*
+ * Wasn't in the table, so use the standard
+ * 4 times conversion.
+ */
+ return (10000000 / (period_factor * 4 * 10));
+}
+
+
static void
copy_mem_info(struct info_str *info, char *data, int len)
{
@@ -106,7 +149,7 @@
speed = 3300;
freq = 0;
if (tinfo->offset != 0) {
- freq = aic_calc_syncsrate(tinfo->period);
+ freq = ahc_calc_syncsrate(tinfo->period);
speed = freq;
}
speed *= (0x01 << tinfo->width);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
index 7c1390e..2ce1feb 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated
* from the following source files:
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
*/
typedef int (ahc_reg_print_t)(u_int, u_int *, u_int);
typedef struct ahc_reg_parse_entry {
@@ -1298,7 +1298,6 @@
#define CMDSIZE_TABLE_TAIL 0x34
#define MWI_RESIDUAL 0x38
-#define TARG_IMMEDIATE_SCB 0x38
#define NEXT_QUEUED_SCB 0x39
@@ -1380,6 +1379,7 @@
#define RETURN_2 0x52
#define LAST_MSG 0x53
+#define TARG_IMMEDIATE_SCB 0x53
#define SCSISEQ_TEMPLATE 0x54
#define ENSELO 0x40
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
index 9c71377..88bfd76 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated
* from the following source files:
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
*/
#include "aic7xxx_osm.h"
diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
index cf41136..4cee085 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
@@ -2,13 +2,13 @@
* DO NOT EDIT - This file is automatically generated
* from the following source files:
*
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
*/
static uint8_t seqprog[] = {
0xb2, 0x00, 0x00, 0x08,
0xf7, 0x11, 0x22, 0x08,
- 0x00, 0x65, 0xec, 0x59,
+ 0x00, 0x65, 0xee, 0x59,
0xf7, 0x01, 0x02, 0x08,
0xff, 0x6a, 0x24, 0x08,
0x40, 0x00, 0x40, 0x68,
@@ -21,15 +21,15 @@
0x01, 0x4d, 0xc8, 0x30,
0x00, 0x4c, 0x12, 0x70,
0x01, 0x39, 0xa2, 0x30,
- 0x00, 0x6a, 0xc0, 0x5e,
+ 0x00, 0x6a, 0xc2, 0x5e,
0x01, 0x51, 0x20, 0x31,
0x01, 0x57, 0xae, 0x00,
0x0d, 0x6a, 0x76, 0x00,
- 0x00, 0x51, 0x12, 0x5e,
+ 0x00, 0x51, 0x14, 0x5e,
0x01, 0x51, 0xc8, 0x30,
0x00, 0x39, 0xc8, 0x60,
0x00, 0xbb, 0x30, 0x70,
- 0xc1, 0x6a, 0xd8, 0x5e,
+ 0xc1, 0x6a, 0xda, 0x5e,
0x01, 0xbf, 0x72, 0x30,
0x01, 0x40, 0x7e, 0x31,
0x01, 0x90, 0x80, 0x30,
@@ -49,10 +49,10 @@
0x08, 0x6a, 0x78, 0x00,
0x01, 0x50, 0xc8, 0x30,
0xe0, 0x6a, 0xcc, 0x00,
- 0x48, 0x6a, 0xfc, 0x5d,
+ 0x48, 0x6a, 0xfe, 0x5d,
0x01, 0x6a, 0xdc, 0x01,
0x88, 0x6a, 0xcc, 0x00,
- 0x48, 0x6a, 0xfc, 0x5d,
+ 0x48, 0x6a, 0xfe, 0x5d,
0x01, 0x6a, 0x26, 0x01,
0xf0, 0x19, 0x7a, 0x08,
0x0f, 0x18, 0xc8, 0x08,
@@ -93,7 +93,7 @@
0x00, 0x65, 0x20, 0x41,
0x02, 0x57, 0xae, 0x00,
0x00, 0x65, 0x9e, 0x40,
- 0x61, 0x6a, 0xd8, 0x5e,
+ 0x61, 0x6a, 0xda, 0x5e,
0x08, 0x51, 0x20, 0x71,
0x02, 0x0b, 0xb2, 0x78,
0x00, 0x65, 0xae, 0x40,
@@ -106,7 +106,7 @@
0x80, 0x3d, 0x7a, 0x00,
0x20, 0x6a, 0x16, 0x00,
0x00, 0x65, 0xcc, 0x41,
- 0x00, 0x65, 0xb2, 0x5e,
+ 0x00, 0x65, 0xb4, 0x5e,
0x00, 0x65, 0x12, 0x40,
0x20, 0x11, 0xd2, 0x68,
0x20, 0x6a, 0x18, 0x00,
@@ -140,27 +140,27 @@
0x80, 0x0b, 0xc4, 0x79,
0x12, 0x01, 0x02, 0x00,
0x01, 0xab, 0xac, 0x30,
- 0xe4, 0x6a, 0x6e, 0x5d,
+ 0xe4, 0x6a, 0x70, 0x5d,
0x40, 0x6a, 0x16, 0x00,
- 0x80, 0x3e, 0x84, 0x5d,
+ 0x80, 0x3e, 0x86, 0x5d,
0x20, 0xb8, 0x18, 0x79,
- 0x20, 0x6a, 0x84, 0x5d,
- 0x00, 0xab, 0x84, 0x5d,
+ 0x20, 0x6a, 0x86, 0x5d,
+ 0x00, 0xab, 0x86, 0x5d,
0x01, 0xa9, 0x78, 0x30,
0x10, 0xb8, 0x20, 0x79,
- 0xe4, 0x6a, 0x6e, 0x5d,
+ 0xe4, 0x6a, 0x70, 0x5d,
0x00, 0x65, 0xae, 0x40,
0x10, 0x03, 0x3c, 0x69,
0x08, 0x3c, 0x5a, 0x69,
0x04, 0x3c, 0x92, 0x69,
0x02, 0x3c, 0x98, 0x69,
0x01, 0x3c, 0x44, 0x79,
- 0xff, 0x6a, 0x70, 0x00,
+ 0xff, 0x6a, 0xa6, 0x00,
0x00, 0x65, 0xa4, 0x59,
- 0x00, 0x6a, 0xc0, 0x5e,
- 0xff, 0x38, 0x30, 0x71,
+ 0x00, 0x6a, 0xc2, 0x5e,
+ 0xff, 0x53, 0x30, 0x71,
0x0d, 0x6a, 0x76, 0x00,
- 0x00, 0x38, 0x12, 0x5e,
+ 0x00, 0x53, 0x14, 0x5e,
0x00, 0x65, 0xea, 0x58,
0x12, 0x01, 0x02, 0x00,
0x00, 0x65, 0x18, 0x41,
@@ -168,10 +168,10 @@
0x00, 0x65, 0xf2, 0x58,
0xfd, 0x57, 0xae, 0x08,
0x00, 0x65, 0xae, 0x40,
- 0xe4, 0x6a, 0x6e, 0x5d,
+ 0xe4, 0x6a, 0x70, 0x5d,
0x20, 0x3c, 0x4a, 0x79,
- 0x02, 0x6a, 0x84, 0x5d,
- 0x04, 0x6a, 0x84, 0x5d,
+ 0x02, 0x6a, 0x86, 0x5d,
+ 0x04, 0x6a, 0x86, 0x5d,
0x01, 0x03, 0x4c, 0x69,
0xf7, 0x11, 0x22, 0x08,
0xff, 0x6a, 0x24, 0x08,
@@ -182,13 +182,13 @@
0x80, 0x86, 0xc8, 0x08,
0x01, 0x4f, 0xc8, 0x30,
0x00, 0x50, 0x6c, 0x61,
- 0xc4, 0x6a, 0x6e, 0x5d,
+ 0xc4, 0x6a, 0x70, 0x5d,
0x40, 0x3c, 0x68, 0x79,
- 0x28, 0x6a, 0x84, 0x5d,
+ 0x28, 0x6a, 0x86, 0x5d,
0x00, 0x65, 0x4c, 0x41,
- 0x08, 0x6a, 0x84, 0x5d,
+ 0x08, 0x6a, 0x86, 0x5d,
0x00, 0x65, 0x4c, 0x41,
- 0x84, 0x6a, 0x6e, 0x5d,
+ 0x84, 0x6a, 0x70, 0x5d,
0x00, 0x65, 0xf2, 0x58,
0x01, 0x66, 0xc8, 0x30,
0x01, 0x64, 0xd8, 0x31,
@@ -208,16 +208,16 @@
0xf7, 0x3c, 0x78, 0x08,
0x00, 0x65, 0x20, 0x41,
0x40, 0xaa, 0x7e, 0x10,
- 0x04, 0xaa, 0x6e, 0x5d,
- 0x00, 0x65, 0x56, 0x42,
- 0xc4, 0x6a, 0x6e, 0x5d,
+ 0x04, 0xaa, 0x70, 0x5d,
+ 0x00, 0x65, 0x58, 0x42,
+ 0xc4, 0x6a, 0x70, 0x5d,
0xc0, 0x6a, 0x7e, 0x00,
- 0x00, 0xa8, 0x84, 0x5d,
+ 0x00, 0xa8, 0x86, 0x5d,
0xe4, 0x6a, 0x06, 0x00,
- 0x00, 0x6a, 0x84, 0x5d,
+ 0x00, 0x6a, 0x86, 0x5d,
0x00, 0x65, 0x4c, 0x41,
0x10, 0x3c, 0xa8, 0x69,
- 0x00, 0xbb, 0x8a, 0x44,
+ 0x00, 0xbb, 0x8c, 0x44,
0x18, 0x6a, 0xda, 0x01,
0x01, 0x69, 0xd8, 0x31,
0x1c, 0x6a, 0xd0, 0x01,
@@ -227,31 +227,32 @@
0x01, 0x93, 0x26, 0x01,
0x03, 0x6a, 0x2a, 0x01,
0x01, 0x69, 0x32, 0x31,
- 0x1c, 0x6a, 0xe0, 0x5d,
+ 0x1c, 0x6a, 0xe2, 0x5d,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xa8, 0x5e,
+ 0x00, 0x65, 0xaa, 0x5e,
0x01, 0x50, 0xa0, 0x18,
0x02, 0x6a, 0x22, 0x05,
0x1a, 0x01, 0x02, 0x00,
0x80, 0x6a, 0x74, 0x00,
0x40, 0x6a, 0x78, 0x00,
0x40, 0x6a, 0x16, 0x00,
- 0x00, 0x65, 0xd8, 0x5d,
+ 0x00, 0x65, 0xda, 0x5d,
0x01, 0x3f, 0xc8, 0x30,
- 0xbf, 0x64, 0x56, 0x7a,
- 0x80, 0x64, 0x9e, 0x73,
- 0xa0, 0x64, 0x00, 0x74,
- 0xc0, 0x64, 0xf4, 0x73,
- 0xe0, 0x64, 0x30, 0x74,
- 0x01, 0x6a, 0xd8, 0x5e,
+ 0xbf, 0x64, 0x58, 0x7a,
+ 0x80, 0x64, 0xa0, 0x73,
+ 0xa0, 0x64, 0x02, 0x74,
+ 0xc0, 0x64, 0xf6, 0x73,
+ 0xe0, 0x64, 0x32, 0x74,
+ 0x01, 0x6a, 0xda, 0x5e,
0x00, 0x65, 0xcc, 0x41,
0xf7, 0x11, 0x22, 0x08,
0x01, 0x06, 0xd4, 0x30,
0xff, 0x6a, 0x24, 0x08,
0xf7, 0x01, 0x02, 0x08,
- 0x09, 0x0c, 0xe6, 0x79,
+ 0xc0, 0x6a, 0x78, 0x00,
+ 0x09, 0x0c, 0xe8, 0x79,
0x08, 0x0c, 0x04, 0x68,
- 0xb1, 0x6a, 0xd8, 0x5e,
+ 0xb1, 0x6a, 0xda, 0x5e,
0xff, 0x6a, 0x26, 0x09,
0x12, 0x01, 0x02, 0x00,
0x02, 0x6a, 0x08, 0x30,
@@ -264,29 +265,29 @@
0x00, 0xa5, 0x4a, 0x21,
0x00, 0xa6, 0x4c, 0x21,
0x00, 0xa7, 0x4e, 0x25,
- 0x08, 0xeb, 0xdc, 0x7e,
- 0x80, 0xeb, 0x06, 0x7a,
+ 0x08, 0xeb, 0xde, 0x7e,
+ 0x80, 0xeb, 0x08, 0x7a,
0xff, 0x6a, 0xd6, 0x09,
- 0x08, 0xeb, 0x0a, 0x6a,
+ 0x08, 0xeb, 0x0c, 0x6a,
0xff, 0x6a, 0xd4, 0x0c,
- 0x80, 0xa3, 0xdc, 0x6e,
- 0x88, 0xeb, 0x20, 0x72,
- 0x08, 0xeb, 0xdc, 0x6e,
- 0x04, 0xea, 0x24, 0xe2,
- 0x08, 0xee, 0xdc, 0x6e,
+ 0x80, 0xa3, 0xde, 0x6e,
+ 0x88, 0xeb, 0x22, 0x72,
+ 0x08, 0xeb, 0xde, 0x6e,
+ 0x04, 0xea, 0x26, 0xe2,
+ 0x08, 0xee, 0xde, 0x6e,
0x04, 0x6a, 0xd0, 0x81,
0x05, 0xa4, 0xc0, 0x89,
0x03, 0xa5, 0xc2, 0x31,
0x09, 0x6a, 0xd6, 0x05,
- 0x00, 0x65, 0x08, 0x5a,
+ 0x00, 0x65, 0x0a, 0x5a,
0x06, 0xa4, 0xd4, 0x89,
- 0x80, 0x94, 0xdc, 0x7e,
+ 0x80, 0x94, 0xde, 0x7e,
0x07, 0xe9, 0x10, 0x31,
0x01, 0xe9, 0x46, 0x31,
- 0x00, 0xa3, 0xba, 0x5e,
- 0x00, 0x65, 0xfa, 0x59,
+ 0x00, 0xa3, 0xbc, 0x5e,
+ 0x00, 0x65, 0xfc, 0x59,
0x01, 0xa4, 0xca, 0x30,
- 0x80, 0xa3, 0x34, 0x7a,
+ 0x80, 0xa3, 0x36, 0x7a,
0x02, 0x65, 0xca, 0x00,
0x01, 0x65, 0xf8, 0x31,
0x80, 0x93, 0x26, 0x01,
@@ -294,162 +295,162 @@
0x01, 0x8c, 0xc8, 0x30,
0x00, 0x88, 0xc8, 0x18,
0x02, 0x64, 0xc8, 0x88,
- 0xff, 0x64, 0xdc, 0x7e,
- 0xff, 0x8d, 0x4a, 0x6a,
- 0xff, 0x8e, 0x4a, 0x6a,
+ 0xff, 0x64, 0xde, 0x7e,
+ 0xff, 0x8d, 0x4c, 0x6a,
+ 0xff, 0x8e, 0x4c, 0x6a,
0x03, 0x8c, 0xd4, 0x98,
- 0x00, 0x65, 0xdc, 0x56,
+ 0x00, 0x65, 0xde, 0x56,
0x01, 0x64, 0x70, 0x30,
0xff, 0x64, 0xc8, 0x10,
0x01, 0x64, 0xc8, 0x18,
0x00, 0x8c, 0x18, 0x19,
0xff, 0x8d, 0x1a, 0x21,
0xff, 0x8e, 0x1c, 0x25,
- 0xc0, 0x3c, 0x5a, 0x7a,
- 0x21, 0x6a, 0xd8, 0x5e,
+ 0xc0, 0x3c, 0x5c, 0x7a,
+ 0x21, 0x6a, 0xda, 0x5e,
0xa8, 0x6a, 0x76, 0x00,
0x79, 0x6a, 0x76, 0x00,
- 0x40, 0x3f, 0x62, 0x6a,
+ 0x40, 0x3f, 0x64, 0x6a,
0x04, 0x3b, 0x76, 0x00,
0x04, 0x6a, 0xd4, 0x81,
- 0x20, 0x3c, 0x6a, 0x7a,
- 0x51, 0x6a, 0xd8, 0x5e,
- 0x00, 0x65, 0x82, 0x42,
+ 0x20, 0x3c, 0x6c, 0x7a,
+ 0x51, 0x6a, 0xda, 0x5e,
+ 0x00, 0x65, 0x84, 0x42,
0x20, 0x3c, 0x78, 0x00,
- 0x00, 0xb3, 0xba, 0x5e,
+ 0x00, 0xb3, 0xbc, 0x5e,
0x07, 0xac, 0x10, 0x31,
0x05, 0xb3, 0x46, 0x31,
0x88, 0x6a, 0xcc, 0x00,
- 0xac, 0x6a, 0xee, 0x5d,
+ 0xac, 0x6a, 0xf0, 0x5d,
0xa3, 0x6a, 0xcc, 0x00,
- 0xb3, 0x6a, 0xf2, 0x5d,
- 0x00, 0x65, 0x3a, 0x5a,
+ 0xb3, 0x6a, 0xf4, 0x5d,
+ 0x00, 0x65, 0x3c, 0x5a,
0xfd, 0xa4, 0x48, 0x09,
0x03, 0x8c, 0x10, 0x30,
- 0x00, 0x65, 0xe6, 0x5d,
- 0x01, 0xa4, 0x94, 0x7a,
+ 0x00, 0x65, 0xe8, 0x5d,
+ 0x01, 0xa4, 0x96, 0x7a,
0x04, 0x3b, 0x76, 0x08,
0x01, 0x3b, 0x26, 0x31,
0x80, 0x02, 0x04, 0x00,
- 0x10, 0x0c, 0x8a, 0x7a,
- 0x03, 0x9e, 0x8c, 0x6a,
+ 0x10, 0x0c, 0x8c, 0x7a,
+ 0x03, 0x9e, 0x8e, 0x6a,
0x7f, 0x02, 0x04, 0x08,
- 0x91, 0x6a, 0xd8, 0x5e,
+ 0x91, 0x6a, 0xda, 0x5e,
0x00, 0x65, 0xcc, 0x41,
0x01, 0xa4, 0xca, 0x30,
- 0x80, 0xa3, 0x9a, 0x7a,
+ 0x80, 0xa3, 0x9c, 0x7a,
0x02, 0x65, 0xca, 0x00,
0x01, 0x65, 0xf8, 0x31,
0x01, 0x3b, 0x26, 0x31,
- 0x00, 0x65, 0x0e, 0x5a,
- 0x01, 0xfc, 0xa8, 0x6a,
- 0x80, 0x0b, 0x9e, 0x6a,
- 0x10, 0x0c, 0x9e, 0x7a,
- 0x20, 0x93, 0x9e, 0x6a,
+ 0x00, 0x65, 0x10, 0x5a,
+ 0x01, 0xfc, 0xaa, 0x6a,
+ 0x80, 0x0b, 0xa0, 0x6a,
+ 0x10, 0x0c, 0xa0, 0x7a,
+ 0x20, 0x93, 0xa0, 0x6a,
0x02, 0x93, 0x26, 0x01,
- 0x02, 0xfc, 0xb2, 0x7a,
- 0x40, 0x0d, 0xc6, 0x6a,
+ 0x02, 0xfc, 0xb4, 0x7a,
+ 0x40, 0x0d, 0xc8, 0x6a,
0x01, 0xa4, 0x48, 0x01,
- 0x00, 0x65, 0xc6, 0x42,
- 0x40, 0x0d, 0xb8, 0x6a,
- 0x00, 0x65, 0x0e, 0x5a,
- 0x00, 0x65, 0xaa, 0x42,
- 0x80, 0xfc, 0xc2, 0x7a,
- 0x80, 0xa4, 0xc2, 0x6a,
+ 0x00, 0x65, 0xc8, 0x42,
+ 0x40, 0x0d, 0xba, 0x6a,
+ 0x00, 0x65, 0x10, 0x5a,
+ 0x00, 0x65, 0xac, 0x42,
+ 0x80, 0xfc, 0xc4, 0x7a,
+ 0x80, 0xa4, 0xc4, 0x6a,
0xff, 0xa5, 0x4a, 0x19,
0xff, 0xa6, 0x4c, 0x21,
0xff, 0xa7, 0x4e, 0x21,
0xf8, 0xfc, 0x48, 0x09,
0x7f, 0xa3, 0x46, 0x09,
- 0x04, 0x3b, 0xe2, 0x6a,
+ 0x04, 0x3b, 0xe4, 0x6a,
0x02, 0x93, 0x26, 0x01,
- 0x01, 0x94, 0xc8, 0x7a,
- 0x01, 0x94, 0xc8, 0x7a,
- 0x01, 0x94, 0xc8, 0x7a,
- 0x01, 0x94, 0xc8, 0x7a,
- 0x01, 0x94, 0xc8, 0x7a,
- 0x01, 0xa4, 0xe0, 0x7a,
- 0x01, 0xfc, 0xd6, 0x7a,
- 0x01, 0x94, 0xe2, 0x6a,
- 0x01, 0x94, 0xe2, 0x6a,
- 0x01, 0x94, 0xe2, 0x6a,
- 0x00, 0x65, 0x82, 0x42,
- 0x01, 0x94, 0xe0, 0x7a,
- 0x10, 0x94, 0xe2, 0x6a,
+ 0x01, 0x94, 0xca, 0x7a,
+ 0x01, 0x94, 0xca, 0x7a,
+ 0x01, 0x94, 0xca, 0x7a,
+ 0x01, 0x94, 0xca, 0x7a,
+ 0x01, 0x94, 0xca, 0x7a,
+ 0x01, 0xa4, 0xe2, 0x7a,
+ 0x01, 0xfc, 0xd8, 0x7a,
+ 0x01, 0x94, 0xe4, 0x6a,
+ 0x01, 0x94, 0xe4, 0x6a,
+ 0x01, 0x94, 0xe4, 0x6a,
+ 0x00, 0x65, 0x84, 0x42,
+ 0x01, 0x94, 0xe2, 0x7a,
+ 0x10, 0x94, 0xe4, 0x6a,
0xd7, 0x93, 0x26, 0x09,
- 0x28, 0x93, 0xe6, 0x6a,
+ 0x28, 0x93, 0xe8, 0x6a,
0x01, 0x85, 0x0a, 0x01,
- 0x02, 0xfc, 0xee, 0x6a,
+ 0x02, 0xfc, 0xf0, 0x6a,
0x01, 0x14, 0x46, 0x31,
0xff, 0x6a, 0x10, 0x09,
0xfe, 0x85, 0x0a, 0x09,
- 0xff, 0x38, 0xfc, 0x6a,
- 0x80, 0xa3, 0xfc, 0x7a,
- 0x80, 0x0b, 0xfa, 0x7a,
- 0x04, 0x3b, 0xfc, 0x7a,
+ 0xff, 0x38, 0xfe, 0x6a,
+ 0x80, 0xa3, 0xfe, 0x7a,
+ 0x80, 0x0b, 0xfc, 0x7a,
+ 0x04, 0x3b, 0xfe, 0x7a,
0xbf, 0x3b, 0x76, 0x08,
0x01, 0x3b, 0x26, 0x31,
- 0x00, 0x65, 0x0e, 0x5a,
- 0x01, 0x0b, 0x0a, 0x6b,
- 0x10, 0x0c, 0xfe, 0x7a,
- 0x04, 0x93, 0x08, 0x6b,
- 0x01, 0x94, 0x06, 0x7b,
- 0x10, 0x94, 0x08, 0x6b,
+ 0x00, 0x65, 0x10, 0x5a,
+ 0x01, 0x0b, 0x0c, 0x6b,
+ 0x10, 0x0c, 0x00, 0x7b,
+ 0x04, 0x93, 0x0a, 0x6b,
+ 0x01, 0x94, 0x08, 0x7b,
+ 0x10, 0x94, 0x0a, 0x6b,
0xc7, 0x93, 0x26, 0x09,
0x01, 0x99, 0xd4, 0x30,
- 0x38, 0x93, 0x0c, 0x6b,
- 0xff, 0x08, 0x5a, 0x6b,
- 0xff, 0x09, 0x5a, 0x6b,
- 0xff, 0x0a, 0x5a, 0x6b,
- 0xff, 0x38, 0x28, 0x7b,
+ 0x38, 0x93, 0x0e, 0x6b,
+ 0xff, 0x08, 0x5c, 0x6b,
+ 0xff, 0x09, 0x5c, 0x6b,
+ 0xff, 0x0a, 0x5c, 0x6b,
+ 0xff, 0x38, 0x2a, 0x7b,
0x04, 0x14, 0x10, 0x31,
0x01, 0x38, 0x18, 0x31,
0x02, 0x6a, 0x1a, 0x31,
0x88, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0xf4, 0x5d,
- 0x00, 0x38, 0xe0, 0x5d,
+ 0x14, 0x6a, 0xf6, 0x5d,
+ 0x00, 0x38, 0xe2, 0x5d,
0xff, 0x6a, 0x70, 0x08,
- 0x00, 0x65, 0x54, 0x43,
- 0x80, 0xa3, 0x2e, 0x7b,
+ 0x00, 0x65, 0x56, 0x43,
+ 0x80, 0xa3, 0x30, 0x7b,
0x01, 0xa4, 0x48, 0x01,
- 0x00, 0x65, 0x5a, 0x43,
- 0x08, 0xeb, 0x34, 0x7b,
- 0x00, 0x65, 0x0e, 0x5a,
- 0x08, 0xeb, 0x30, 0x6b,
+ 0x00, 0x65, 0x5c, 0x43,
+ 0x08, 0xeb, 0x36, 0x7b,
+ 0x00, 0x65, 0x10, 0x5a,
+ 0x08, 0xeb, 0x32, 0x6b,
0x07, 0xe9, 0x10, 0x31,
0x01, 0xe9, 0xca, 0x30,
0x01, 0x65, 0x46, 0x31,
- 0x00, 0x6a, 0xba, 0x5e,
+ 0x00, 0x6a, 0xbc, 0x5e,
0x88, 0x6a, 0xcc, 0x00,
- 0xa4, 0x6a, 0xf4, 0x5d,
- 0x08, 0x6a, 0xe0, 0x5d,
+ 0xa4, 0x6a, 0xf6, 0x5d,
+ 0x08, 0x6a, 0xe2, 0x5d,
0x0d, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xa8, 0x5e,
+ 0x00, 0x65, 0xaa, 0x5e,
0x88, 0x6a, 0xcc, 0x00,
- 0x00, 0x65, 0x8a, 0x5e,
+ 0x00, 0x65, 0x8c, 0x5e,
0x01, 0x99, 0x46, 0x31,
- 0x00, 0xa3, 0xba, 0x5e,
+ 0x00, 0xa3, 0xbc, 0x5e,
0x01, 0x88, 0x10, 0x31,
- 0x00, 0x65, 0x3a, 0x5a,
- 0x00, 0x65, 0xfa, 0x59,
+ 0x00, 0x65, 0x3c, 0x5a,
+ 0x00, 0x65, 0xfc, 0x59,
0x03, 0x8c, 0x10, 0x30,
- 0x00, 0x65, 0xe6, 0x5d,
- 0x80, 0x0b, 0x82, 0x6a,
- 0x80, 0x0b, 0x62, 0x6b,
- 0x01, 0x0c, 0x5c, 0x7b,
- 0x10, 0x0c, 0x82, 0x7a,
- 0x03, 0x9e, 0x82, 0x6a,
- 0x00, 0x65, 0x04, 0x5a,
- 0x00, 0x6a, 0xba, 0x5e,
- 0x01, 0xa4, 0x82, 0x6b,
- 0xff, 0x38, 0x78, 0x7b,
+ 0x00, 0x65, 0xe8, 0x5d,
+ 0x80, 0x0b, 0x84, 0x6a,
+ 0x80, 0x0b, 0x64, 0x6b,
+ 0x01, 0x0c, 0x5e, 0x7b,
+ 0x10, 0x0c, 0x84, 0x7a,
+ 0x03, 0x9e, 0x84, 0x6a,
+ 0x00, 0x65, 0x06, 0x5a,
+ 0x00, 0x6a, 0xbc, 0x5e,
+ 0x01, 0xa4, 0x84, 0x6b,
+ 0xff, 0x38, 0x7a, 0x7b,
0x01, 0x38, 0xc8, 0x30,
0x00, 0x08, 0x40, 0x19,
0xff, 0x6a, 0xc8, 0x08,
0x00, 0x09, 0x42, 0x21,
0x00, 0x0a, 0x44, 0x21,
0xff, 0x6a, 0x70, 0x08,
- 0x00, 0x65, 0x7a, 0x43,
+ 0x00, 0x65, 0x7c, 0x43,
0x03, 0x08, 0x40, 0x31,
0x03, 0x08, 0x40, 0x31,
0x01, 0x08, 0x40, 0x31,
@@ -461,16 +462,16 @@
0x04, 0x3c, 0xcc, 0x79,
0xfb, 0x3c, 0x78, 0x08,
0x04, 0x93, 0x20, 0x79,
- 0x01, 0x0c, 0x8e, 0x6b,
+ 0x01, 0x0c, 0x90, 0x6b,
0x80, 0xba, 0x20, 0x79,
0x80, 0x04, 0x20, 0x79,
- 0xe4, 0x6a, 0x6e, 0x5d,
- 0x23, 0x6a, 0x84, 0x5d,
- 0x01, 0x6a, 0x84, 0x5d,
+ 0xe4, 0x6a, 0x70, 0x5d,
+ 0x23, 0x6a, 0x86, 0x5d,
+ 0x01, 0x6a, 0x86, 0x5d,
0x00, 0x65, 0x20, 0x41,
0x00, 0x65, 0xcc, 0x41,
- 0x80, 0x3c, 0xa2, 0x7b,
- 0x21, 0x6a, 0xd8, 0x5e,
+ 0x80, 0x3c, 0xa4, 0x7b,
+ 0x21, 0x6a, 0xda, 0x5e,
0x01, 0xbc, 0x18, 0x31,
0x02, 0x6a, 0x1a, 0x31,
0x02, 0x6a, 0xf8, 0x01,
@@ -480,16 +481,16 @@
0xff, 0x6a, 0x12, 0x08,
0xff, 0x6a, 0x14, 0x08,
0xf3, 0xbc, 0xd4, 0x18,
- 0xa0, 0x6a, 0xc8, 0x53,
+ 0xa0, 0x6a, 0xca, 0x53,
0x04, 0xa0, 0x10, 0x31,
0xac, 0x6a, 0x26, 0x01,
0x04, 0xa0, 0x10, 0x31,
0x03, 0x08, 0x18, 0x31,
0x88, 0x6a, 0xcc, 0x00,
- 0xa0, 0x6a, 0xf4, 0x5d,
- 0x00, 0xbc, 0xe0, 0x5d,
+ 0xa0, 0x6a, 0xf6, 0x5d,
+ 0x00, 0xbc, 0xe2, 0x5d,
0x3d, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0xe0, 0x43,
+ 0x00, 0x65, 0xe2, 0x43,
0xff, 0x6a, 0x10, 0x09,
0xa4, 0x6a, 0x26, 0x01,
0x0c, 0xa0, 0x32, 0x31,
@@ -499,128 +500,128 @@
0x36, 0x6a, 0x26, 0x01,
0x02, 0x93, 0x26, 0x01,
0x35, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0x9c, 0x5e,
- 0x00, 0x65, 0x9c, 0x5e,
+ 0x00, 0x65, 0x9e, 0x5e,
+ 0x00, 0x65, 0x9e, 0x5e,
0x02, 0x93, 0x26, 0x01,
0xbf, 0x3c, 0x78, 0x08,
- 0x04, 0x0b, 0xe6, 0x6b,
- 0x10, 0x0c, 0xe2, 0x7b,
- 0x01, 0x03, 0xe6, 0x6b,
- 0x20, 0x93, 0xe8, 0x6b,
- 0x04, 0x0b, 0xee, 0x6b,
+ 0x04, 0x0b, 0xe8, 0x6b,
+ 0x10, 0x0c, 0xe4, 0x7b,
+ 0x01, 0x03, 0xe8, 0x6b,
+ 0x20, 0x93, 0xea, 0x6b,
+ 0x04, 0x0b, 0xf0, 0x6b,
0x40, 0x3c, 0x78, 0x00,
0xc7, 0x93, 0x26, 0x09,
- 0x38, 0x93, 0xf0, 0x6b,
+ 0x38, 0x93, 0xf2, 0x6b,
0x00, 0x65, 0xcc, 0x41,
- 0x80, 0x3c, 0x56, 0x6c,
+ 0x80, 0x3c, 0x58, 0x6c,
0x01, 0x06, 0x50, 0x31,
0x80, 0xb8, 0x70, 0x01,
0x00, 0x65, 0xcc, 0x41,
0x10, 0x3f, 0x06, 0x00,
0x10, 0x6a, 0x06, 0x00,
0x01, 0x3a, 0xca, 0x30,
- 0x80, 0x65, 0x1c, 0x64,
- 0x10, 0xb8, 0x40, 0x6c,
+ 0x80, 0x65, 0x1e, 0x64,
+ 0x10, 0xb8, 0x42, 0x6c,
0xc0, 0x3e, 0xca, 0x00,
- 0x40, 0xb8, 0x0c, 0x6c,
+ 0x40, 0xb8, 0x0e, 0x6c,
0xbf, 0x65, 0xca, 0x08,
- 0x20, 0xb8, 0x20, 0x7c,
+ 0x20, 0xb8, 0x22, 0x7c,
0x01, 0x65, 0x0c, 0x30,
- 0x00, 0x65, 0xd8, 0x5d,
- 0xa0, 0x3f, 0x28, 0x64,
+ 0x00, 0x65, 0xda, 0x5d,
+ 0xa0, 0x3f, 0x2a, 0x64,
0x23, 0xb8, 0x0c, 0x08,
- 0x00, 0x65, 0xd8, 0x5d,
- 0xa0, 0x3f, 0x28, 0x64,
- 0x00, 0xbb, 0x20, 0x44,
- 0xff, 0x65, 0x20, 0x64,
- 0x00, 0x65, 0x40, 0x44,
+ 0x00, 0x65, 0xda, 0x5d,
+ 0xa0, 0x3f, 0x2a, 0x64,
+ 0x00, 0xbb, 0x22, 0x44,
+ 0xff, 0x65, 0x22, 0x64,
+ 0x00, 0x65, 0x42, 0x44,
0x40, 0x6a, 0x18, 0x00,
0x01, 0x65, 0x0c, 0x30,
- 0x00, 0x65, 0xd8, 0x5d,
- 0xa0, 0x3f, 0xfc, 0x73,
+ 0x00, 0x65, 0xda, 0x5d,
+ 0xa0, 0x3f, 0xfe, 0x73,
0x40, 0x6a, 0x18, 0x00,
0x01, 0x3a, 0xa6, 0x30,
0x08, 0x6a, 0x74, 0x00,
0x00, 0x65, 0xcc, 0x41,
- 0x64, 0x6a, 0x68, 0x5d,
- 0x80, 0x64, 0xd8, 0x6c,
- 0x04, 0x64, 0x9a, 0x74,
- 0x02, 0x64, 0xaa, 0x74,
- 0x00, 0x6a, 0x60, 0x74,
- 0x03, 0x64, 0xc8, 0x74,
- 0x23, 0x64, 0x48, 0x74,
- 0x08, 0x64, 0x5c, 0x74,
- 0x61, 0x6a, 0xd8, 0x5e,
- 0x00, 0x65, 0xd8, 0x5d,
+ 0x64, 0x6a, 0x6a, 0x5d,
+ 0x80, 0x64, 0xda, 0x6c,
+ 0x04, 0x64, 0x9c, 0x74,
+ 0x02, 0x64, 0xac, 0x74,
+ 0x00, 0x6a, 0x62, 0x74,
+ 0x03, 0x64, 0xca, 0x74,
+ 0x23, 0x64, 0x4a, 0x74,
+ 0x08, 0x64, 0x5e, 0x74,
+ 0x61, 0x6a, 0xda, 0x5e,
+ 0x00, 0x65, 0xda, 0x5d,
0x08, 0x51, 0xce, 0x71,
- 0x00, 0x65, 0x40, 0x44,
- 0x80, 0x04, 0x5a, 0x7c,
- 0x51, 0x6a, 0x5e, 0x5d,
- 0x01, 0x51, 0x5a, 0x64,
- 0x01, 0xa4, 0x52, 0x7c,
- 0x80, 0xba, 0x5c, 0x6c,
- 0x41, 0x6a, 0xd8, 0x5e,
- 0x00, 0x65, 0x5c, 0x44,
- 0x21, 0x6a, 0xd8, 0x5e,
- 0x00, 0x65, 0x5c, 0x44,
- 0x07, 0x6a, 0x54, 0x5d,
+ 0x00, 0x65, 0x42, 0x44,
+ 0x80, 0x04, 0x5c, 0x7c,
+ 0x51, 0x6a, 0x60, 0x5d,
+ 0x01, 0x51, 0x5c, 0x64,
+ 0x01, 0xa4, 0x54, 0x7c,
+ 0x80, 0xba, 0x5e, 0x6c,
+ 0x41, 0x6a, 0xda, 0x5e,
+ 0x00, 0x65, 0x5e, 0x44,
+ 0x21, 0x6a, 0xda, 0x5e,
+ 0x00, 0x65, 0x5e, 0x44,
+ 0x07, 0x6a, 0x56, 0x5d,
0x01, 0x06, 0xd4, 0x30,
0x00, 0x65, 0xcc, 0x41,
- 0x80, 0xb8, 0x56, 0x7c,
- 0xc0, 0x3c, 0x6a, 0x7c,
- 0x80, 0x3c, 0x56, 0x6c,
- 0xff, 0xa8, 0x6a, 0x6c,
- 0x40, 0x3c, 0x56, 0x6c,
- 0x10, 0xb8, 0x6e, 0x7c,
- 0xa1, 0x6a, 0xd8, 0x5e,
- 0x01, 0xb4, 0x74, 0x6c,
- 0x02, 0xb4, 0x76, 0x6c,
- 0x01, 0xa4, 0x76, 0x7c,
- 0xff, 0xa8, 0x86, 0x7c,
+ 0x80, 0xb8, 0x58, 0x7c,
+ 0xc0, 0x3c, 0x6c, 0x7c,
+ 0x80, 0x3c, 0x58, 0x6c,
+ 0xff, 0xa8, 0x6c, 0x6c,
+ 0x40, 0x3c, 0x58, 0x6c,
+ 0x10, 0xb8, 0x70, 0x7c,
+ 0xa1, 0x6a, 0xda, 0x5e,
+ 0x01, 0xb4, 0x76, 0x6c,
+ 0x02, 0xb4, 0x78, 0x6c,
+ 0x01, 0xa4, 0x78, 0x7c,
+ 0xff, 0xa8, 0x88, 0x7c,
0x04, 0xb4, 0x68, 0x01,
0x01, 0x6a, 0x76, 0x00,
- 0x00, 0xbb, 0x12, 0x5e,
- 0xff, 0xa8, 0x86, 0x7c,
- 0x71, 0x6a, 0xd8, 0x5e,
- 0x40, 0x51, 0x86, 0x64,
- 0x00, 0x65, 0xb2, 0x5e,
+ 0x00, 0xbb, 0x14, 0x5e,
+ 0xff, 0xa8, 0x88, 0x7c,
+ 0x71, 0x6a, 0xda, 0x5e,
+ 0x40, 0x51, 0x88, 0x64,
+ 0x00, 0x65, 0xb4, 0x5e,
0x00, 0x65, 0xde, 0x41,
- 0x00, 0xbb, 0x8a, 0x5c,
+ 0x00, 0xbb, 0x8c, 0x5c,
0x00, 0x65, 0xde, 0x41,
- 0x00, 0x65, 0xb2, 0x5e,
+ 0x00, 0x65, 0xb4, 0x5e,
0x01, 0x65, 0xa2, 0x30,
0x01, 0xf8, 0xc8, 0x30,
0x01, 0x4e, 0xc8, 0x30,
- 0x00, 0x6a, 0xb6, 0xdd,
- 0x00, 0x51, 0xc8, 0x5d,
+ 0x00, 0x6a, 0xb8, 0xdd,
+ 0x00, 0x51, 0xca, 0x5d,
0x01, 0x4e, 0x9c, 0x18,
0x02, 0x6a, 0x22, 0x05,
- 0xc0, 0x3c, 0x56, 0x6c,
+ 0xc0, 0x3c, 0x58, 0x6c,
0x04, 0xb8, 0x70, 0x01,
- 0x00, 0x65, 0xd4, 0x5e,
+ 0x00, 0x65, 0xd6, 0x5e,
0x20, 0xb8, 0xde, 0x69,
0x01, 0xbb, 0xa2, 0x30,
0x3f, 0xba, 0x7c, 0x08,
- 0x00, 0xb9, 0xce, 0x5c,
+ 0x00, 0xb9, 0xd0, 0x5c,
0x00, 0x65, 0xde, 0x41,
0x01, 0x06, 0xd4, 0x30,
0x20, 0x3c, 0xcc, 0x79,
- 0x20, 0x3c, 0x5c, 0x7c,
- 0x01, 0xa4, 0xb8, 0x7c,
+ 0x20, 0x3c, 0x5e, 0x7c,
+ 0x01, 0xa4, 0xba, 0x7c,
0x01, 0xb4, 0x68, 0x01,
0x00, 0x65, 0xcc, 0x41,
- 0x00, 0x65, 0x5c, 0x44,
+ 0x00, 0x65, 0x5e, 0x44,
0x04, 0x14, 0x58, 0x31,
0x01, 0x06, 0xd4, 0x30,
0x08, 0xa0, 0x60, 0x31,
0xac, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0xf4, 0x5d,
+ 0x14, 0x6a, 0xf6, 0x5d,
0x01, 0x06, 0xd4, 0x30,
- 0xa0, 0x6a, 0xec, 0x5d,
+ 0xa0, 0x6a, 0xee, 0x5d,
0x00, 0x65, 0xcc, 0x41,
0xdf, 0x3c, 0x78, 0x08,
0x12, 0x01, 0x02, 0x00,
- 0x00, 0x65, 0x5c, 0x44,
+ 0x00, 0x65, 0x5e, 0x44,
0x4c, 0x65, 0xcc, 0x28,
0x01, 0x3e, 0x20, 0x31,
0xd0, 0x66, 0xcc, 0x18,
@@ -631,102 +632,102 @@
0xd0, 0x65, 0xca, 0x18,
0x01, 0x3e, 0x20, 0x31,
0x30, 0x65, 0xd4, 0x18,
- 0x00, 0x65, 0xe6, 0x4c,
+ 0x00, 0x65, 0xe8, 0x4c,
0xe1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
0x20, 0x65, 0xd4, 0x18,
- 0x00, 0x65, 0xee, 0x54,
+ 0x00, 0x65, 0xf0, 0x54,
0xe1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
0x20, 0x65, 0xca, 0x18,
0xe0, 0x65, 0xd4, 0x18,
- 0x00, 0x65, 0xf8, 0x4c,
+ 0x00, 0x65, 0xfa, 0x4c,
0xe1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
0xd0, 0x65, 0xd4, 0x18,
- 0x00, 0x65, 0x00, 0x55,
+ 0x00, 0x65, 0x02, 0x55,
0xe1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
0x01, 0x6c, 0xa2, 0x30,
- 0xff, 0x51, 0x12, 0x75,
- 0x00, 0x51, 0x8e, 0x5d,
+ 0xff, 0x51, 0x14, 0x75,
+ 0x00, 0x51, 0x90, 0x5d,
0x01, 0x51, 0x20, 0x31,
- 0x00, 0x65, 0x34, 0x45,
+ 0x00, 0x65, 0x36, 0x45,
0x3f, 0xba, 0xc8, 0x08,
- 0x00, 0x3e, 0x34, 0x75,
- 0x00, 0x65, 0xb0, 0x5e,
+ 0x00, 0x3e, 0x36, 0x75,
+ 0x00, 0x65, 0xb2, 0x5e,
0x80, 0x3c, 0x78, 0x00,
0x01, 0x06, 0xd4, 0x30,
- 0x00, 0x65, 0xd8, 0x5d,
+ 0x00, 0x65, 0xda, 0x5d,
0x01, 0x3c, 0x78, 0x00,
- 0xe0, 0x3f, 0x50, 0x65,
+ 0xe0, 0x3f, 0x52, 0x65,
0x02, 0x3c, 0x78, 0x00,
- 0x20, 0x12, 0x50, 0x65,
- 0x51, 0x6a, 0x5e, 0x5d,
- 0x00, 0x51, 0x8e, 0x5d,
- 0x51, 0x6a, 0x5e, 0x5d,
+ 0x20, 0x12, 0x52, 0x65,
+ 0x51, 0x6a, 0x60, 0x5d,
+ 0x00, 0x51, 0x90, 0x5d,
+ 0x51, 0x6a, 0x60, 0x5d,
0x01, 0x51, 0x20, 0x31,
0x04, 0x3c, 0x78, 0x00,
0x01, 0xb9, 0xc8, 0x30,
- 0x00, 0x3d, 0x4e, 0x65,
+ 0x00, 0x3d, 0x50, 0x65,
0x08, 0x3c, 0x78, 0x00,
0x3f, 0xba, 0xc8, 0x08,
- 0x00, 0x3e, 0x4e, 0x65,
+ 0x00, 0x3e, 0x50, 0x65,
0x10, 0x3c, 0x78, 0x00,
- 0x04, 0xb8, 0x4e, 0x7d,
+ 0x04, 0xb8, 0x50, 0x7d,
0xfb, 0xb8, 0x70, 0x09,
- 0x20, 0xb8, 0x44, 0x6d,
+ 0x20, 0xb8, 0x46, 0x6d,
0x01, 0x90, 0xc8, 0x30,
0xff, 0x6a, 0xa2, 0x00,
- 0x00, 0x3d, 0xce, 0x5c,
+ 0x00, 0x3d, 0xd0, 0x5c,
0x01, 0x64, 0x20, 0x31,
0xff, 0x6a, 0x78, 0x08,
0x00, 0x65, 0xea, 0x58,
- 0x10, 0xb8, 0x5c, 0x7c,
- 0xff, 0x6a, 0x54, 0x5d,
- 0x00, 0x65, 0x5c, 0x44,
- 0x00, 0x65, 0xb0, 0x5e,
- 0x31, 0x6a, 0xd8, 0x5e,
- 0x00, 0x65, 0x5c, 0x44,
+ 0x10, 0xb8, 0x5e, 0x7c,
+ 0xff, 0x6a, 0x56, 0x5d,
+ 0x00, 0x65, 0x5e, 0x44,
+ 0x00, 0x65, 0xb2, 0x5e,
+ 0x31, 0x6a, 0xda, 0x5e,
+ 0x00, 0x65, 0x5e, 0x44,
0x10, 0x3f, 0x06, 0x00,
0x10, 0x6a, 0x06, 0x00,
0x01, 0x65, 0x74, 0x34,
- 0x81, 0x6a, 0xd8, 0x5e,
- 0x00, 0x65, 0x60, 0x45,
+ 0x81, 0x6a, 0xda, 0x5e,
+ 0x00, 0x65, 0x62, 0x45,
0x01, 0x06, 0xd4, 0x30,
- 0x01, 0x0c, 0x60, 0x7d,
- 0x04, 0x0c, 0x5a, 0x6d,
+ 0x01, 0x0c, 0x62, 0x7d,
+ 0x04, 0x0c, 0x5c, 0x6d,
0xe0, 0x03, 0x7e, 0x08,
0xe0, 0x3f, 0xcc, 0x61,
0x01, 0x65, 0xcc, 0x30,
0x01, 0x12, 0xda, 0x34,
0x01, 0x06, 0xd4, 0x34,
- 0x01, 0x03, 0x6e, 0x6d,
+ 0x01, 0x03, 0x70, 0x6d,
0x40, 0x03, 0xcc, 0x08,
0x01, 0x65, 0x06, 0x30,
0x40, 0x65, 0xc8, 0x08,
- 0x00, 0x66, 0x7c, 0x75,
- 0x40, 0x65, 0x7c, 0x7d,
- 0x00, 0x65, 0x7c, 0x5d,
+ 0x00, 0x66, 0x7e, 0x75,
+ 0x40, 0x65, 0x7e, 0x7d,
+ 0x00, 0x65, 0x7e, 0x5d,
0xff, 0x6a, 0xd4, 0x08,
0xff, 0x6a, 0xd4, 0x08,
0xff, 0x6a, 0xd4, 0x08,
0xff, 0x6a, 0xd4, 0x0c,
0x08, 0x01, 0x02, 0x00,
- 0x02, 0x0b, 0x86, 0x7d,
+ 0x02, 0x0b, 0x88, 0x7d,
0x01, 0x65, 0x0c, 0x30,
- 0x02, 0x0b, 0x8a, 0x7d,
+ 0x02, 0x0b, 0x8c, 0x7d,
0xf7, 0x01, 0x02, 0x0c,
0x01, 0x65, 0xc8, 0x30,
- 0xff, 0x41, 0xae, 0x75,
+ 0xff, 0x41, 0xb0, 0x75,
0x01, 0x41, 0x20, 0x31,
0xff, 0x6a, 0xa4, 0x00,
- 0x00, 0x65, 0x9e, 0x45,
- 0xff, 0xbf, 0xae, 0x75,
+ 0x00, 0x65, 0xa0, 0x45,
+ 0xff, 0xbf, 0xb0, 0x75,
0x01, 0x90, 0xa4, 0x30,
0x01, 0xbf, 0x20, 0x31,
- 0x00, 0xbb, 0x98, 0x65,
- 0xff, 0x52, 0xac, 0x75,
+ 0x00, 0xbb, 0x9a, 0x65,
+ 0xff, 0x52, 0xae, 0x75,
0x01, 0xbf, 0xcc, 0x30,
0x01, 0x90, 0xca, 0x30,
0x01, 0x52, 0x20, 0x31,
@@ -734,28 +735,28 @@
0x01, 0x65, 0x20, 0x35,
0x01, 0xbf, 0x82, 0x34,
0x01, 0x64, 0xa2, 0x30,
- 0x00, 0x6a, 0xc0, 0x5e,
+ 0x00, 0x6a, 0xc2, 0x5e,
0x0d, 0x6a, 0x76, 0x00,
- 0x00, 0x51, 0x12, 0x46,
+ 0x00, 0x51, 0x14, 0x46,
0x01, 0x65, 0xa4, 0x30,
0xe0, 0x6a, 0xcc, 0x00,
- 0x48, 0x6a, 0x06, 0x5e,
+ 0x48, 0x6a, 0x08, 0x5e,
0x01, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x05,
0x88, 0x6a, 0xcc, 0x00,
- 0x48, 0x6a, 0x06, 0x5e,
- 0x01, 0x6a, 0xe0, 0x5d,
+ 0x48, 0x6a, 0x08, 0x5e,
+ 0x01, 0x6a, 0xe2, 0x5d,
0x01, 0x6a, 0x26, 0x05,
0x01, 0x65, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0xcc, 0x7d,
+ 0x80, 0xee, 0xce, 0x7d,
0xff, 0x6a, 0xdc, 0x0d,
0x01, 0x65, 0x32, 0x31,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xa8, 0x46,
- 0x81, 0x6a, 0xd8, 0x5e,
- 0x01, 0x0c, 0xd8, 0x7d,
- 0x04, 0x0c, 0xd6, 0x6d,
+ 0x00, 0x65, 0xaa, 0x46,
+ 0x81, 0x6a, 0xda, 0x5e,
+ 0x01, 0x0c, 0xda, 0x7d,
+ 0x04, 0x0c, 0xd8, 0x6d,
0xe0, 0x03, 0x06, 0x08,
0xe0, 0x03, 0x7e, 0x0c,
0x01, 0x65, 0x18, 0x31,
@@ -774,7 +775,7 @@
0x01, 0x6c, 0xda, 0x34,
0x3d, 0x64, 0xa4, 0x28,
0x55, 0x64, 0xc8, 0x28,
- 0x00, 0x65, 0x06, 0x46,
+ 0x00, 0x65, 0x08, 0x46,
0x2e, 0x64, 0xa4, 0x28,
0x66, 0x64, 0xc8, 0x28,
0x00, 0x6c, 0xda, 0x18,
@@ -785,63 +786,63 @@
0x00, 0x6c, 0xda, 0x24,
0x01, 0x65, 0xc8, 0x30,
0xe0, 0x6a, 0xcc, 0x00,
- 0x44, 0x6a, 0x02, 0x5e,
+ 0x44, 0x6a, 0x04, 0x5e,
0x01, 0x90, 0xe2, 0x31,
- 0x04, 0x3b, 0x26, 0x7e,
+ 0x04, 0x3b, 0x28, 0x7e,
0x30, 0x6a, 0xd0, 0x01,
0x20, 0x6a, 0xd0, 0x01,
0x1d, 0x6a, 0xdc, 0x01,
- 0xdc, 0xee, 0x22, 0x66,
- 0x00, 0x65, 0x3e, 0x46,
+ 0xdc, 0xee, 0x24, 0x66,
+ 0x00, 0x65, 0x40, 0x46,
0x20, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x01,
0x20, 0xa0, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x2e, 0x7e,
+ 0x80, 0xee, 0x30, 0x7e,
0x11, 0x6a, 0xdc, 0x01,
- 0x50, 0xee, 0x32, 0x66,
+ 0x50, 0xee, 0x34, 0x66,
0x20, 0x6a, 0xd0, 0x01,
0x09, 0x6a, 0xdc, 0x01,
- 0x88, 0xee, 0x38, 0x66,
+ 0x88, 0xee, 0x3a, 0x66,
0x19, 0x6a, 0xdc, 0x01,
- 0xd8, 0xee, 0x3c, 0x66,
+ 0xd8, 0xee, 0x3e, 0x66,
0xff, 0x6a, 0xdc, 0x09,
- 0x18, 0xee, 0x40, 0x6e,
+ 0x18, 0xee, 0x42, 0x6e,
0xff, 0x6a, 0xd4, 0x0c,
0x88, 0x6a, 0xcc, 0x00,
- 0x44, 0x6a, 0x02, 0x5e,
- 0x20, 0x6a, 0xe0, 0x5d,
+ 0x44, 0x6a, 0x04, 0x5e,
+ 0x20, 0x6a, 0xe2, 0x5d,
0x01, 0x3b, 0x26, 0x31,
- 0x04, 0x3b, 0x5a, 0x6e,
+ 0x04, 0x3b, 0x5c, 0x6e,
0xa0, 0x6a, 0xca, 0x00,
0x20, 0x65, 0xc8, 0x18,
- 0x00, 0x65, 0x98, 0x5e,
- 0x00, 0x65, 0x52, 0x66,
+ 0x00, 0x65, 0x9a, 0x5e,
+ 0x00, 0x65, 0x54, 0x66,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xa8, 0x46,
+ 0x00, 0x65, 0xaa, 0x46,
0xa0, 0x6a, 0xcc, 0x00,
0xff, 0x6a, 0xc8, 0x08,
- 0x20, 0x94, 0x5e, 0x6e,
- 0x10, 0x94, 0x60, 0x6e,
- 0x08, 0x94, 0x7a, 0x6e,
- 0x08, 0x94, 0x7a, 0x6e,
- 0x08, 0x94, 0x7a, 0x6e,
+ 0x20, 0x94, 0x60, 0x6e,
+ 0x10, 0x94, 0x62, 0x6e,
+ 0x08, 0x94, 0x7c, 0x6e,
+ 0x08, 0x94, 0x7c, 0x6e,
+ 0x08, 0x94, 0x7c, 0x6e,
0xff, 0x8c, 0xc8, 0x10,
0xc1, 0x64, 0xc8, 0x18,
0xf8, 0x64, 0xc8, 0x08,
0x01, 0x99, 0xda, 0x30,
- 0x00, 0x66, 0x6e, 0x66,
- 0xc0, 0x66, 0xaa, 0x76,
+ 0x00, 0x66, 0x70, 0x66,
+ 0xc0, 0x66, 0xac, 0x76,
0x60, 0x66, 0xc8, 0x18,
0x3d, 0x64, 0xc8, 0x28,
- 0x00, 0x65, 0x5e, 0x46,
+ 0x00, 0x65, 0x60, 0x46,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x7c, 0x6e,
+ 0x08, 0x93, 0x7e, 0x6e,
0x00, 0x62, 0xc4, 0x18,
- 0x00, 0x65, 0xa8, 0x5e,
- 0x00, 0x65, 0x88, 0x5e,
- 0x00, 0x65, 0x88, 0x5e,
- 0x00, 0x65, 0x88, 0x5e,
+ 0x00, 0x65, 0xaa, 0x5e,
+ 0x00, 0x65, 0x8a, 0x5e,
+ 0x00, 0x65, 0x8a, 0x5e,
+ 0x00, 0x65, 0x8a, 0x5e,
0x01, 0x99, 0xda, 0x30,
0x01, 0x99, 0xda, 0x30,
0x01, 0x99, 0xda, 0x30,
@@ -858,11 +859,11 @@
0x01, 0x6c, 0x32, 0x31,
0x01, 0x6c, 0x32, 0x31,
0x01, 0x6c, 0x32, 0x35,
- 0x08, 0x94, 0xa8, 0x7e,
+ 0x08, 0x94, 0xaa, 0x7e,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0xac, 0x6e,
+ 0x08, 0x93, 0xae, 0x6e,
0xff, 0x6a, 0xd4, 0x0c,
- 0x04, 0xb8, 0xd4, 0x6e,
+ 0x04, 0xb8, 0xd6, 0x6e,
0x01, 0x42, 0x7e, 0x31,
0xff, 0x6a, 0x76, 0x01,
0x01, 0x90, 0x84, 0x34,
@@ -870,14 +871,14 @@
0x01, 0x85, 0x0a, 0x01,
0x7f, 0x65, 0x10, 0x09,
0xfe, 0x85, 0x0a, 0x0d,
- 0xff, 0x42, 0xd0, 0x66,
- 0xff, 0x41, 0xc8, 0x66,
- 0xd1, 0x6a, 0xd8, 0x5e,
+ 0xff, 0x42, 0xd2, 0x66,
+ 0xff, 0x41, 0xca, 0x66,
+ 0xd1, 0x6a, 0xda, 0x5e,
0xff, 0x6a, 0xca, 0x04,
0x01, 0x41, 0x20, 0x31,
0x01, 0xbf, 0x82, 0x30,
0x01, 0x6a, 0x76, 0x00,
- 0x00, 0xbb, 0x12, 0x46,
+ 0x00, 0xbb, 0x14, 0x46,
0x01, 0x42, 0x20, 0x31,
0x01, 0xbf, 0x84, 0x34,
0x01, 0x41, 0x7e, 0x31,
@@ -941,7 +942,7 @@
static int
ahc_patch17_func(struct ahc_softc *ahc)
{
- return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0);
+ return ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0);
}
static ahc_patch_func_t ahc_patch16_func;
@@ -1142,152 +1143,152 @@
{ ahc_patch0_func, 196, 1, 1 },
{ ahc_patch9_func, 212, 6, 2 },
{ ahc_patch0_func, 218, 6, 1 },
- { ahc_patch8_func, 226, 20, 2 },
+ { ahc_patch8_func, 226, 21, 2 },
{ ahc_patch1_func, 241, 1, 1 },
- { ahc_patch1_func, 248, 1, 2 },
- { ahc_patch0_func, 249, 2, 2 },
- { ahc_patch11_func, 250, 1, 1 },
- { ahc_patch9_func, 258, 27, 3 },
- { ahc_patch1_func, 274, 10, 2 },
- { ahc_patch13_func, 277, 1, 1 },
- { ahc_patch14_func, 285, 14, 1 },
- { ahc_patch1_func, 301, 1, 2 },
- { ahc_patch0_func, 302, 1, 1 },
- { ahc_patch9_func, 305, 1, 1 },
- { ahc_patch13_func, 310, 1, 1 },
- { ahc_patch9_func, 311, 2, 2 },
- { ahc_patch0_func, 313, 4, 1 },
- { ahc_patch14_func, 317, 1, 1 },
- { ahc_patch15_func, 319, 2, 3 },
- { ahc_patch9_func, 319, 1, 2 },
- { ahc_patch0_func, 320, 1, 1 },
- { ahc_patch6_func, 325, 1, 2 },
- { ahc_patch0_func, 326, 1, 1 },
- { ahc_patch1_func, 330, 47, 11 },
- { ahc_patch6_func, 337, 2, 4 },
- { ahc_patch7_func, 337, 1, 1 },
- { ahc_patch8_func, 338, 1, 1 },
- { ahc_patch0_func, 339, 1, 1 },
- { ahc_patch16_func, 340, 1, 1 },
- { ahc_patch6_func, 356, 6, 3 },
- { ahc_patch16_func, 356, 5, 1 },
- { ahc_patch0_func, 362, 7, 1 },
- { ahc_patch13_func, 372, 5, 1 },
- { ahc_patch0_func, 377, 52, 17 },
- { ahc_patch14_func, 377, 1, 1 },
- { ahc_patch7_func, 379, 2, 2 },
- { ahc_patch17_func, 380, 1, 1 },
- { ahc_patch9_func, 383, 1, 1 },
- { ahc_patch18_func, 390, 1, 1 },
- { ahc_patch14_func, 395, 9, 3 },
- { ahc_patch9_func, 396, 3, 2 },
- { ahc_patch0_func, 399, 3, 1 },
- { ahc_patch9_func, 407, 6, 2 },
- { ahc_patch0_func, 413, 9, 2 },
- { ahc_patch13_func, 413, 1, 1 },
- { ahc_patch13_func, 422, 2, 1 },
- { ahc_patch14_func, 424, 1, 1 },
- { ahc_patch9_func, 426, 1, 2 },
- { ahc_patch0_func, 427, 1, 1 },
- { ahc_patch7_func, 428, 1, 1 },
+ { ahc_patch1_func, 249, 1, 2 },
+ { ahc_patch0_func, 250, 2, 2 },
+ { ahc_patch11_func, 251, 1, 1 },
+ { ahc_patch9_func, 259, 27, 3 },
+ { ahc_patch1_func, 275, 10, 2 },
+ { ahc_patch13_func, 278, 1, 1 },
+ { ahc_patch14_func, 286, 14, 1 },
+ { ahc_patch1_func, 302, 1, 2 },
+ { ahc_patch0_func, 303, 1, 1 },
+ { ahc_patch9_func, 306, 1, 1 },
+ { ahc_patch13_func, 311, 1, 1 },
+ { ahc_patch9_func, 312, 2, 2 },
+ { ahc_patch0_func, 314, 4, 1 },
+ { ahc_patch14_func, 318, 1, 1 },
+ { ahc_patch15_func, 320, 2, 3 },
+ { ahc_patch9_func, 320, 1, 2 },
+ { ahc_patch0_func, 321, 1, 1 },
+ { ahc_patch6_func, 326, 1, 2 },
+ { ahc_patch0_func, 327, 1, 1 },
+ { ahc_patch1_func, 331, 47, 11 },
+ { ahc_patch6_func, 338, 2, 4 },
+ { ahc_patch7_func, 338, 1, 1 },
+ { ahc_patch8_func, 339, 1, 1 },
+ { ahc_patch0_func, 340, 1, 1 },
+ { ahc_patch16_func, 341, 1, 1 },
+ { ahc_patch6_func, 357, 6, 3 },
+ { ahc_patch16_func, 357, 5, 1 },
+ { ahc_patch0_func, 363, 7, 1 },
+ { ahc_patch13_func, 373, 5, 1 },
+ { ahc_patch0_func, 378, 52, 17 },
+ { ahc_patch14_func, 378, 1, 1 },
+ { ahc_patch7_func, 380, 2, 2 },
+ { ahc_patch17_func, 381, 1, 1 },
+ { ahc_patch9_func, 384, 1, 1 },
+ { ahc_patch18_func, 391, 1, 1 },
+ { ahc_patch14_func, 396, 9, 3 },
+ { ahc_patch9_func, 397, 3, 2 },
+ { ahc_patch0_func, 400, 3, 1 },
+ { ahc_patch9_func, 408, 6, 2 },
+ { ahc_patch0_func, 414, 9, 2 },
+ { ahc_patch13_func, 414, 1, 1 },
+ { ahc_patch13_func, 423, 2, 1 },
+ { ahc_patch14_func, 425, 1, 1 },
+ { ahc_patch9_func, 427, 1, 2 },
+ { ahc_patch0_func, 428, 1, 1 },
{ ahc_patch7_func, 429, 1, 1 },
- { ahc_patch8_func, 430, 3, 3 },
- { ahc_patch6_func, 431, 1, 2 },
- { ahc_patch0_func, 432, 1, 1 },
- { ahc_patch9_func, 433, 1, 1 },
- { ahc_patch15_func, 434, 1, 2 },
- { ahc_patch13_func, 434, 1, 1 },
- { ahc_patch14_func, 436, 9, 4 },
- { ahc_patch9_func, 436, 1, 1 },
- { ahc_patch9_func, 443, 2, 1 },
- { ahc_patch0_func, 445, 4, 3 },
- { ahc_patch9_func, 445, 1, 2 },
- { ahc_patch0_func, 446, 3, 1 },
- { ahc_patch1_func, 450, 2, 1 },
- { ahc_patch7_func, 452, 10, 2 },
- { ahc_patch0_func, 462, 1, 1 },
- { ahc_patch8_func, 463, 118, 22 },
- { ahc_patch1_func, 465, 3, 2 },
- { ahc_patch0_func, 468, 5, 3 },
- { ahc_patch9_func, 468, 2, 2 },
- { ahc_patch0_func, 470, 3, 1 },
- { ahc_patch1_func, 475, 2, 2 },
- { ahc_patch0_func, 477, 6, 3 },
- { ahc_patch9_func, 477, 2, 2 },
- { ahc_patch0_func, 479, 3, 1 },
- { ahc_patch1_func, 485, 2, 2 },
- { ahc_patch0_func, 487, 9, 7 },
- { ahc_patch9_func, 487, 5, 6 },
- { ahc_patch19_func, 487, 1, 2 },
- { ahc_patch0_func, 488, 1, 1 },
- { ahc_patch19_func, 490, 1, 2 },
- { ahc_patch0_func, 491, 1, 1 },
- { ahc_patch0_func, 492, 4, 1 },
- { ahc_patch6_func, 497, 3, 2 },
- { ahc_patch0_func, 500, 1, 1 },
- { ahc_patch6_func, 510, 1, 2 },
- { ahc_patch0_func, 511, 1, 1 },
- { ahc_patch20_func, 548, 7, 1 },
- { ahc_patch3_func, 583, 1, 2 },
- { ahc_patch0_func, 584, 1, 1 },
- { ahc_patch21_func, 587, 1, 1 },
- { ahc_patch8_func, 589, 106, 33 },
- { ahc_patch4_func, 591, 1, 1 },
- { ahc_patch1_func, 597, 2, 2 },
- { ahc_patch0_func, 599, 1, 1 },
- { ahc_patch1_func, 602, 1, 2 },
- { ahc_patch0_func, 603, 1, 1 },
- { ahc_patch9_func, 604, 3, 3 },
- { ahc_patch15_func, 605, 1, 1 },
- { ahc_patch0_func, 607, 4, 1 },
- { ahc_patch19_func, 616, 2, 2 },
- { ahc_patch0_func, 618, 1, 1 },
- { ahc_patch19_func, 622, 10, 3 },
- { ahc_patch5_func, 624, 8, 1 },
- { ahc_patch0_func, 632, 9, 2 },
- { ahc_patch5_func, 633, 8, 1 },
- { ahc_patch4_func, 643, 1, 2 },
- { ahc_patch0_func, 644, 1, 1 },
- { ahc_patch19_func, 645, 1, 2 },
- { ahc_patch0_func, 646, 3, 2 },
- { ahc_patch4_func, 648, 1, 1 },
- { ahc_patch5_func, 649, 1, 1 },
- { ahc_patch5_func, 652, 1, 1 },
- { ahc_patch5_func, 654, 1, 1 },
- { ahc_patch4_func, 656, 2, 2 },
- { ahc_patch0_func, 658, 2, 1 },
- { ahc_patch5_func, 660, 1, 1 },
- { ahc_patch5_func, 663, 1, 1 },
- { ahc_patch5_func, 666, 1, 1 },
- { ahc_patch19_func, 670, 1, 1 },
- { ahc_patch19_func, 673, 1, 1 },
- { ahc_patch4_func, 679, 1, 1 },
- { ahc_patch6_func, 682, 1, 2 },
- { ahc_patch0_func, 683, 1, 1 },
- { ahc_patch7_func, 695, 16, 1 },
- { ahc_patch4_func, 711, 20, 1 },
- { ahc_patch9_func, 732, 4, 2 },
- { ahc_patch0_func, 736, 4, 1 },
- { ahc_patch9_func, 740, 4, 2 },
- { ahc_patch0_func, 744, 3, 1 },
- { ahc_patch6_func, 750, 1, 1 },
- { ahc_patch22_func, 752, 14, 1 },
- { ahc_patch7_func, 766, 3, 1 },
- { ahc_patch9_func, 778, 24, 8 },
- { ahc_patch19_func, 782, 1, 2 },
- { ahc_patch0_func, 783, 1, 1 },
- { ahc_patch15_func, 788, 4, 2 },
- { ahc_patch0_func, 792, 7, 3 },
- { ahc_patch23_func, 792, 5, 2 },
- { ahc_patch0_func, 797, 2, 1 },
- { ahc_patch0_func, 802, 42, 3 },
- { ahc_patch18_func, 814, 18, 2 },
- { ahc_patch0_func, 832, 1, 1 },
- { ahc_patch4_func, 856, 1, 1 },
- { ahc_patch4_func, 857, 3, 2 },
- { ahc_patch0_func, 860, 1, 1 },
- { ahc_patch13_func, 861, 3, 1 },
- { ahc_patch4_func, 864, 12, 1 }
+ { ahc_patch7_func, 430, 1, 1 },
+ { ahc_patch8_func, 431, 3, 3 },
+ { ahc_patch6_func, 432, 1, 2 },
+ { ahc_patch0_func, 433, 1, 1 },
+ { ahc_patch9_func, 434, 1, 1 },
+ { ahc_patch15_func, 435, 1, 2 },
+ { ahc_patch13_func, 435, 1, 1 },
+ { ahc_patch14_func, 437, 9, 4 },
+ { ahc_patch9_func, 437, 1, 1 },
+ { ahc_patch9_func, 444, 2, 1 },
+ { ahc_patch0_func, 446, 4, 3 },
+ { ahc_patch9_func, 446, 1, 2 },
+ { ahc_patch0_func, 447, 3, 1 },
+ { ahc_patch1_func, 451, 2, 1 },
+ { ahc_patch7_func, 453, 10, 2 },
+ { ahc_patch0_func, 463, 1, 1 },
+ { ahc_patch8_func, 464, 118, 22 },
+ { ahc_patch1_func, 466, 3, 2 },
+ { ahc_patch0_func, 469, 5, 3 },
+ { ahc_patch9_func, 469, 2, 2 },
+ { ahc_patch0_func, 471, 3, 1 },
+ { ahc_patch1_func, 476, 2, 2 },
+ { ahc_patch0_func, 478, 6, 3 },
+ { ahc_patch9_func, 478, 2, 2 },
+ { ahc_patch0_func, 480, 3, 1 },
+ { ahc_patch1_func, 486, 2, 2 },
+ { ahc_patch0_func, 488, 9, 7 },
+ { ahc_patch9_func, 488, 5, 6 },
+ { ahc_patch19_func, 488, 1, 2 },
+ { ahc_patch0_func, 489, 1, 1 },
+ { ahc_patch19_func, 491, 1, 2 },
+ { ahc_patch0_func, 492, 1, 1 },
+ { ahc_patch0_func, 493, 4, 1 },
+ { ahc_patch6_func, 498, 3, 2 },
+ { ahc_patch0_func, 501, 1, 1 },
+ { ahc_patch6_func, 511, 1, 2 },
+ { ahc_patch0_func, 512, 1, 1 },
+ { ahc_patch20_func, 549, 7, 1 },
+ { ahc_patch3_func, 584, 1, 2 },
+ { ahc_patch0_func, 585, 1, 1 },
+ { ahc_patch21_func, 588, 1, 1 },
+ { ahc_patch8_func, 590, 106, 33 },
+ { ahc_patch4_func, 592, 1, 1 },
+ { ahc_patch1_func, 598, 2, 2 },
+ { ahc_patch0_func, 600, 1, 1 },
+ { ahc_patch1_func, 603, 1, 2 },
+ { ahc_patch0_func, 604, 1, 1 },
+ { ahc_patch9_func, 605, 3, 3 },
+ { ahc_patch15_func, 606, 1, 1 },
+ { ahc_patch0_func, 608, 4, 1 },
+ { ahc_patch19_func, 617, 2, 2 },
+ { ahc_patch0_func, 619, 1, 1 },
+ { ahc_patch19_func, 623, 10, 3 },
+ { ahc_patch5_func, 625, 8, 1 },
+ { ahc_patch0_func, 633, 9, 2 },
+ { ahc_patch5_func, 634, 8, 1 },
+ { ahc_patch4_func, 644, 1, 2 },
+ { ahc_patch0_func, 645, 1, 1 },
+ { ahc_patch19_func, 646, 1, 2 },
+ { ahc_patch0_func, 647, 3, 2 },
+ { ahc_patch4_func, 649, 1, 1 },
+ { ahc_patch5_func, 650, 1, 1 },
+ { ahc_patch5_func, 653, 1, 1 },
+ { ahc_patch5_func, 655, 1, 1 },
+ { ahc_patch4_func, 657, 2, 2 },
+ { ahc_patch0_func, 659, 2, 1 },
+ { ahc_patch5_func, 661, 1, 1 },
+ { ahc_patch5_func, 664, 1, 1 },
+ { ahc_patch5_func, 667, 1, 1 },
+ { ahc_patch19_func, 671, 1, 1 },
+ { ahc_patch19_func, 674, 1, 1 },
+ { ahc_patch4_func, 680, 1, 1 },
+ { ahc_patch6_func, 683, 1, 2 },
+ { ahc_patch0_func, 684, 1, 1 },
+ { ahc_patch7_func, 696, 16, 1 },
+ { ahc_patch4_func, 712, 20, 1 },
+ { ahc_patch9_func, 733, 4, 2 },
+ { ahc_patch0_func, 737, 4, 1 },
+ { ahc_patch9_func, 741, 4, 2 },
+ { ahc_patch0_func, 745, 3, 1 },
+ { ahc_patch6_func, 751, 1, 1 },
+ { ahc_patch22_func, 753, 14, 1 },
+ { ahc_patch7_func, 767, 3, 1 },
+ { ahc_patch9_func, 779, 24, 8 },
+ { ahc_patch19_func, 783, 1, 2 },
+ { ahc_patch0_func, 784, 1, 1 },
+ { ahc_patch15_func, 789, 4, 2 },
+ { ahc_patch0_func, 793, 7, 3 },
+ { ahc_patch23_func, 793, 5, 2 },
+ { ahc_patch0_func, 798, 2, 1 },
+ { ahc_patch0_func, 803, 42, 3 },
+ { ahc_patch18_func, 815, 18, 2 },
+ { ahc_patch0_func, 833, 1, 1 },
+ { ahc_patch4_func, 857, 1, 1 },
+ { ahc_patch4_func, 858, 3, 2 },
+ { ahc_patch0_func, 861, 1, 1 },
+ { ahc_patch13_func, 862, 3, 1 },
+ { ahc_patch4_func, 865, 12, 1 }
};
static struct cs {
@@ -1296,11 +1297,11 @@
} critical_sections[] = {
{ 11, 18 },
{ 21, 30 },
- { 711, 727 },
- { 857, 860 },
- { 864, 870 },
- { 872, 874 },
- { 874, 876 }
+ { 712, 728 },
+ { 858, 861 },
+ { 865, 871 },
+ { 873, 875 },
+ { 875, 877 }
};
static const int num_critical_sections = sizeof(critical_sections)
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
index 7c5a6db..828ae3d 100644
--- a/drivers/scsi/aic7xxx/aiclib.c
+++ b/drivers/scsi/aic7xxx/aiclib.c
@@ -30,1382 +30,5 @@
* $Id$
*/
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/version.h>
-
-/* Core SCSI definitions */
-#include <scsi/scsi_host.h>
#include "aiclib.h"
-#include "cam.h"
-
-#ifndef FALSE
-#define FALSE 0
-#endif /* FALSE */
-#ifndef TRUE
-#define TRUE 1
-#endif /* TRUE */
-#ifndef ERESTART
-#define ERESTART -1 /* restart syscall */
-#endif
-#ifndef EJUSTRETURN
-#define EJUSTRETURN -2 /* don't modify regs, just return */
-#endif
-
-static int ascentrycomp(const void *key, const void *member);
-static int senseentrycomp(const void *key, const void *member);
-static void fetchtableentries(int sense_key, int asc, int ascq,
- struct scsi_inquiry_data *,
- const struct sense_key_table_entry **,
- const struct asc_table_entry **);
-static void * scsibsearch(const void *key, const void *base, size_t nmemb,
- size_t size,
- int (*compar)(const void *, const void *));
-typedef int (cam_quirkmatch_t)(caddr_t, caddr_t);
-static int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern,
- int str_len);
-static caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table,
- int num_entries, int entry_size,
- cam_quirkmatch_t *comp_func);
-
-#define SCSI_NO_SENSE_STRINGS 1
-#if !defined(SCSI_NO_SENSE_STRINGS)
-#define SST(asc, ascq, action, desc) \
- asc, ascq, action, desc
-#else
-static const char empty_string[] = "";
-
-#define SST(asc, ascq, action, desc) \
- asc, ascq, action, empty_string
-#endif
-
-static const struct sense_key_table_entry sense_key_table[] =
-{
- { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
- { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
- {
- SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
- "NOT READY"
- },
- { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
- { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
- { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
- { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" },
- { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" },
- { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" },
- { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" },
- { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" },
- { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" },
- { SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
- { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
- { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
- { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
-};
-
-static const int sense_key_table_size =
- sizeof(sense_key_table)/sizeof(sense_key_table[0]);
-
-static struct asc_table_entry quantum_fireball_entries[] = {
- {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
- "Logical unit not ready, initializing cmd. required")}
-};
-
-static struct asc_table_entry sony_mo_entries[] = {
- {SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
- "Logical unit not ready, cause not reportable")}
-};
-
-static struct scsi_sense_quirk_entry sense_quirk_table[] = {
- {
- /*
- * The Quantum Fireball ST and SE like to return 0x04 0x0b when
- * they really should return 0x04 0x02. 0x04,0x0b isn't
- * defined in any SCSI spec, and it isn't mentioned in the
- * hardware manual for these drives.
- */
- {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
- /*num_sense_keys*/0,
- sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
- /*sense key entries*/NULL,
- quantum_fireball_entries
- },
- {
- /*
- * This Sony MO drive likes to return 0x04, 0x00 when it
- * isn't spun up.
- */
- {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
- /*num_sense_keys*/0,
- sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
- /*sense key entries*/NULL,
- sony_mo_entries
- }
-};
-
-static const int sense_quirk_table_size =
- sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
-
-static struct asc_table_entry asc_table[] = {
-/*
- * From File: ASC-NUM.TXT
- * SCSI ASC/ASCQ Assignments
- * Numeric Sorted Listing
- * as of 5/12/97
- *
- * D - DIRECT ACCESS DEVICE (SBC) device column key
- * .T - SEQUENTIAL ACCESS DEVICE (SSC) -------------------
- * . L - PRINTER DEVICE (SSC) blank = reserved
- * . P - PROCESSOR DEVICE (SPC) not blank = allowed
- * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)
- * . . R - CD DEVICE (MMC)
- * . . S - SCANNER DEVICE (SGC)
- * . . .O - OPTICAL MEMORY DEVICE (SBC)
- * . . . M - MEDIA CHANGER DEVICE (SMC)
- * . . . C - COMMUNICATION DEVICE (SSC)
- * . . . .A - STORAGE ARRAY DEVICE (SCC)
- * . . . . E - ENCLOSURE SERVICES DEVICE (SES)
- * DTLPWRSOMCAE ASC ASCQ Action Description
- * ------------ ---- ---- ------ -----------------------------------*/
-/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP,
- "No additional sense information") },
-/* T S */{SST(0x00, 0x01, SS_RDEF,
- "Filemark detected") },
-/* T S */{SST(0x00, 0x02, SS_RDEF,
- "End-of-partition/medium detected") },
-/* T */{SST(0x00, 0x03, SS_RDEF,
- "Setmark detected") },
-/* T S */{SST(0x00, 0x04, SS_RDEF,
- "Beginning-of-partition/medium detected") },
-/* T S */{SST(0x00, 0x05, SS_RDEF,
- "End-of-data detected") },
-/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF,
- "I/O process terminated") },
-/* R */{SST(0x00, 0x11, SS_FATAL|EBUSY,
- "Audio play operation in progress") },
-/* R */{SST(0x00, 0x12, SS_NOP,
- "Audio play operation paused") },
-/* R */{SST(0x00, 0x13, SS_NOP,
- "Audio play operation successfully completed") },
-/* R */{SST(0x00, 0x14, SS_RDEF,
- "Audio play operation stopped due to error") },
-/* R */{SST(0x00, 0x15, SS_NOP,
- "No current audio status to return") },
-/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY,
- "Operation in progress") },
-/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF,
- "Cleaning requested") },
-/* D W O */{SST(0x01, 0x00, SS_RDEF,
- "No index/sector signal") },
-/* D WR OM */{SST(0x02, 0x00, SS_RDEF,
- "No seek complete") },
-/* DTL W SO */{SST(0x03, 0x00, SS_RDEF,
- "Peripheral device write fault") },
-/* T */{SST(0x03, 0x01, SS_RDEF,
- "No write current") },
-/* T */{SST(0x03, 0x02, SS_RDEF,
- "Excessive write errors") },
-/* DTLPWRSOMCAE */{SST(0x04, 0x00,
- SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO,
- "Logical unit not ready, cause not reportable") },
-/* DTLPWRSOMCAE */{SST(0x04, 0x01,
- SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
- "Logical unit is in process of becoming ready") },
-/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
- "Logical unit not ready, initializing cmd. required") },
-/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO,
- "Logical unit not ready, manual intervention required")},
-/* DTL O */{SST(0x04, 0x04, SS_FATAL|EBUSY,
- "Logical unit not ready, format in progress") },
-/* DT W OMCA */{SST(0x04, 0x05, SS_FATAL|EBUSY,
- "Logical unit not ready, rebuild in progress") },
-/* DT W OMCA */{SST(0x04, 0x06, SS_FATAL|EBUSY,
- "Logical unit not ready, recalculation in progress") },
-/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY,
- "Logical unit not ready, operation in progress") },
-/* R */{SST(0x04, 0x08, SS_FATAL|EBUSY,
- "Logical unit not ready, long write in progress") },
-/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF,
- "Logical unit does not respond to selection") },
-/* D WR OM */{SST(0x06, 0x00, SS_RDEF,
- "No reference position found") },
-/* DTL WRSOM */{SST(0x07, 0x00, SS_RDEF,
- "Multiple peripheral devices selected") },
-/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF,
- "Logical unit communication failure") },
-/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF,
- "Logical unit communication time-out") },
-/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF,
- "Logical unit communication parity error") },
-/* DT R OM */{SST(0x08, 0x03, SS_RDEF,
- "Logical unit communication crc error (ultra-dma/32)")},
-/* DT WR O */{SST(0x09, 0x00, SS_RDEF,
- "Track following error") },
-/* WR O */{SST(0x09, 0x01, SS_RDEF,
- "Tracking servo failure") },
-/* WR O */{SST(0x09, 0x02, SS_RDEF,
- "Focus servo failure") },
-/* WR O */{SST(0x09, 0x03, SS_RDEF,
- "Spindle servo failure") },
-/* DT WR O */{SST(0x09, 0x04, SS_RDEF,
- "Head select fault") },
-/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC,
- "Error log overflow") },
-/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF,
- "Warning") },
-/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF,
- "Specified temperature exceeded") },
-/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF,
- "Enclosure degraded") },
-/* T RS */{SST(0x0C, 0x00, SS_RDEF,
- "Write error") },
-/* D W O */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
- "Write error - recovered with auto reallocation") },
-/* D W O */{SST(0x0C, 0x02, SS_RDEF,
- "Write error - auto reallocation failed") },
-/* D W O */{SST(0x0C, 0x03, SS_RDEF,
- "Write error - recommend reassignment") },
-/* DT W O */{SST(0x0C, 0x04, SS_RDEF,
- "Compression check miscompare error") },
-/* DT W O */{SST(0x0C, 0x05, SS_RDEF,
- "Data expansion occurred during compression") },
-/* DT W O */{SST(0x0C, 0x06, SS_RDEF,
- "Block not compressible") },
-/* R */{SST(0x0C, 0x07, SS_RDEF,
- "Write error - recovery needed") },
-/* R */{SST(0x0C, 0x08, SS_RDEF,
- "Write error - recovery failed") },
-/* R */{SST(0x0C, 0x09, SS_RDEF,
- "Write error - loss of streaming") },
-/* R */{SST(0x0C, 0x0A, SS_RDEF,
- "Write error - padding blocks added") },
-/* D W O */{SST(0x10, 0x00, SS_RDEF,
- "ID CRC or ECC error") },
-/* DT WRSO */{SST(0x11, 0x00, SS_RDEF,
- "Unrecovered read error") },
-/* DT W SO */{SST(0x11, 0x01, SS_RDEF,
- "Read retries exhausted") },
-/* DT W SO */{SST(0x11, 0x02, SS_RDEF,
- "Error too long to correct") },
-/* DT W SO */{SST(0x11, 0x03, SS_RDEF,
- "Multiple read errors") },
-/* D W O */{SST(0x11, 0x04, SS_RDEF,
- "Unrecovered read error - auto reallocate failed") },
-/* WR O */{SST(0x11, 0x05, SS_RDEF,
- "L-EC uncorrectable error") },
-/* WR O */{SST(0x11, 0x06, SS_RDEF,
- "CIRC unrecovered error") },
-/* W O */{SST(0x11, 0x07, SS_RDEF,
- "Data re-synchronization error") },
-/* T */{SST(0x11, 0x08, SS_RDEF,
- "Incomplete block read") },
-/* T */{SST(0x11, 0x09, SS_RDEF,
- "No gap found") },
-/* DT O */{SST(0x11, 0x0A, SS_RDEF,
- "Miscorrected error") },
-/* D W O */{SST(0x11, 0x0B, SS_RDEF,
- "Unrecovered read error - recommend reassignment") },
-/* D W O */{SST(0x11, 0x0C, SS_RDEF,
- "Unrecovered read error - recommend rewrite the data")},
-/* DT WR O */{SST(0x11, 0x0D, SS_RDEF,
- "De-compression CRC error") },
-/* DT WR O */{SST(0x11, 0x0E, SS_RDEF,
- "Cannot decompress using declared algorithm") },
-/* R */{SST(0x11, 0x0F, SS_RDEF,
- "Error reading UPC/EAN number") },
-/* R */{SST(0x11, 0x10, SS_RDEF,
- "Error reading ISRC number") },
-/* R */{SST(0x11, 0x11, SS_RDEF,
- "Read error - loss of streaming") },
-/* D W O */{SST(0x12, 0x00, SS_RDEF,
- "Address mark not found for id field") },
-/* D W O */{SST(0x13, 0x00, SS_RDEF,
- "Address mark not found for data field") },
-/* DTL WRSO */{SST(0x14, 0x00, SS_RDEF,
- "Recorded entity not found") },
-/* DT WR O */{SST(0x14, 0x01, SS_RDEF,
- "Record not found") },
-/* T */{SST(0x14, 0x02, SS_RDEF,
- "Filemark or setmark not found") },
-/* T */{SST(0x14, 0x03, SS_RDEF,
- "End-of-data not found") },
-/* T */{SST(0x14, 0x04, SS_RDEF,
- "Block sequence error") },
-/* DT W O */{SST(0x14, 0x05, SS_RDEF,
- "Record not found - recommend reassignment") },
-/* DT W O */{SST(0x14, 0x06, SS_RDEF,
- "Record not found - data auto-reallocated") },
-/* DTL WRSOM */{SST(0x15, 0x00, SS_RDEF,
- "Random positioning error") },
-/* DTL WRSOM */{SST(0x15, 0x01, SS_RDEF,
- "Mechanical positioning error") },
-/* DT WR O */{SST(0x15, 0x02, SS_RDEF,
- "Positioning error detected by read of medium") },
-/* D W O */{SST(0x16, 0x00, SS_RDEF,
- "Data synchronization mark error") },
-/* D W O */{SST(0x16, 0x01, SS_RDEF,
- "Data sync error - data rewritten") },
-/* D W O */{SST(0x16, 0x02, SS_RDEF,
- "Data sync error - recommend rewrite") },
-/* D W O */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE,
- "Data sync error - data auto-reallocated") },
-/* D W O */{SST(0x16, 0x04, SS_RDEF,
- "Data sync error - recommend reassignment") },
-/* DT WRSO */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with no error correction applied") },
-/* DT WRSO */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with retries") },
-/* DT WR O */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with positive head offset") },
-/* DT WR O */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with negative head offset") },
-/* WR O */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with retries and/or CIRC applied") },
-/* D WR O */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data using previous sector id") },
-/* D W O */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data without ECC - data auto-reallocated") },
-/* D W O */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data without ECC - recommend reassignment")},
-/* D W O */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data without ECC - recommend rewrite") },
-/* D W O */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data without ECC - data rewritten") },
-/* D W O */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with error correction applied") },
-/* D WR O */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with error corr. & retries applied") },
-/* D WR O */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data - data auto-reallocated") },
-/* R */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with CIRC") },
-/* R */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with L-EC") },
-/* D WR O */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data - recommend reassignment") },
-/* D WR O */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data - recommend rewrite") },
-/* D W O */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered data with ECC - data rewritten") },
-/* D O */{SST(0x19, 0x00, SS_RDEF,
- "Defect list error") },
-/* D O */{SST(0x19, 0x01, SS_RDEF,
- "Defect list not available") },
-/* D O */{SST(0x19, 0x02, SS_RDEF,
- "Defect list error in primary list") },
-/* D O */{SST(0x19, 0x03, SS_RDEF,
- "Defect list error in grown list") },
-/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF,
- "Parameter list length error") },
-/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF,
- "Synchronous data transfer error") },
-/* D O */{SST(0x1C, 0x00, SS_RDEF,
- "Defect list not found") },
-/* D O */{SST(0x1C, 0x01, SS_RDEF,
- "Primary defect list not found") },
-/* D O */{SST(0x1C, 0x02, SS_RDEF,
- "Grown defect list not found") },
-/* D W O */{SST(0x1D, 0x00, SS_FATAL,
- "Miscompare during verify operation" )},
-/* D W O */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE,
- "Recovered id with ecc correction") },
-/* D O */{SST(0x1F, 0x00, SS_RDEF,
- "Partial defect list transfer") },
-/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL,
- "Invalid command operation code") },
-/* DT WR OM */{SST(0x21, 0x00, SS_FATAL|EINVAL,
- "Logical block address out of range" )},
-/* DT WR OM */{SST(0x21, 0x01, SS_FATAL|EINVAL,
- "Invalid element address") },
-/* D */{SST(0x22, 0x00, SS_FATAL|EINVAL,
- "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */
-/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL,
- "Invalid field in CDB") },
-/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO,
- "Logical unit not supported") },
-/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL,
- "Invalid field in parameter list") },
-/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL,
- "Parameter not supported") },
-/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL,
- "Parameter value invalid") },
-/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL,
- "Threshold parameters not supported") },
-/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL,
- "Invalid release of active persistent reservation") },
-/* DT W O */{SST(0x27, 0x00, SS_FATAL|EACCES,
- "Write protected") },
-/* DT W O */{SST(0x27, 0x01, SS_FATAL|EACCES,
- "Hardware write protected") },
-/* DT W O */{SST(0x27, 0x02, SS_FATAL|EACCES,
- "Logical unit software write protected") },
-/* T */{SST(0x27, 0x03, SS_FATAL|EACCES,
- "Associated write protect") },
-/* T */{SST(0x27, 0x04, SS_FATAL|EACCES,
- "Persistent write protect") },
-/* T */{SST(0x27, 0x05, SS_FATAL|EACCES,
- "Permanent write protect") },
-/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_RDEF,
- "Not ready to ready change, medium may have changed") },
-/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO,
- "Import or export element accessed") },
-/*
- * XXX JGibbs - All of these should use the same errno, but I don't think
- * ENXIO is the correct choice. Should we borrow from the networking
- * errnos? ECONNRESET anyone?
- */
-/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_RDEF,
- "Power on, reset, or bus device reset occurred") },
-/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF,
- "Power on occurred") },
-/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF,
- "Scsi bus reset occurred") },
-/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF,
- "Bus device reset function occurred") },
-/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF,
- "Device internal reset") },
-/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF,
- "Transceiver mode changed to single-ended") },
-/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF,
- "Transceiver mode changed to LVD") },
-/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF,
- "Parameters changed") },
-/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF,
- "Mode parameters changed") },
-/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF,
- "Log parameters changed") },
-/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF,
- "Reservations preempted") },
-/* DTLPWRSO C */{SST(0x2B, 0x00, SS_RDEF,
- "Copy cannot execute since host cannot disconnect") },
-/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF,
- "Command sequence error") },
-/* S */{SST(0x2C, 0x01, SS_RDEF,
- "Too many windows specified") },
-/* S */{SST(0x2C, 0x02, SS_RDEF,
- "Invalid combination of windows specified") },
-/* R */{SST(0x2C, 0x03, SS_RDEF,
- "Current program area is not empty") },
-/* R */{SST(0x2C, 0x04, SS_RDEF,
- "Current program area is empty") },
-/* T */{SST(0x2D, 0x00, SS_RDEF,
- "Overwrite error on update in place") },
-/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF,
- "Commands cleared by another initiator") },
-/* DT WR OM */{SST(0x30, 0x00, SS_RDEF,
- "Incompatible medium installed") },
-/* DT WR O */{SST(0x30, 0x01, SS_RDEF,
- "Cannot read medium - unknown format") },
-/* DT WR O */{SST(0x30, 0x02, SS_RDEF,
- "Cannot read medium - incompatible format") },
-/* DT */{SST(0x30, 0x03, SS_RDEF,
- "Cleaning cartridge installed") },
-/* DT WR O */{SST(0x30, 0x04, SS_RDEF,
- "Cannot write medium - unknown format") },
-/* DT WR O */{SST(0x30, 0x05, SS_RDEF,
- "Cannot write medium - incompatible format") },
-/* DT W O */{SST(0x30, 0x06, SS_RDEF,
- "Cannot format medium - incompatible medium") },
-/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF,
- "Cleaning failure") },
-/* R */{SST(0x30, 0x08, SS_RDEF,
- "Cannot write - application code mismatch") },
-/* R */{SST(0x30, 0x09, SS_RDEF,
- "Current session not fixated for append") },
-/* DT WR O */{SST(0x31, 0x00, SS_RDEF,
- "Medium format corrupted") },
-/* D L R O */{SST(0x31, 0x01, SS_RDEF,
- "Format command failed") },
-/* D W O */{SST(0x32, 0x00, SS_RDEF,
- "No defect spare location available") },
-/* D W O */{SST(0x32, 0x01, SS_RDEF,
- "Defect list update failure") },
-/* T */{SST(0x33, 0x00, SS_RDEF,
- "Tape length error") },
-/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF,
- "Enclosure failure") },
-/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF,
- "Enclosure services failure") },
-/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF,
- "Unsupported enclosure function") },
-/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF,
- "Enclosure services unavailable") },
-/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF,
- "Enclosure services transfer failure") },
-/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF,
- "Enclosure services transfer refused") },
-/* L */{SST(0x36, 0x00, SS_RDEF,
- "Ribbon, ink, or toner failure") },
-/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF,
- "Rounded parameter") },
-/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF,
- "Saving parameters not supported") },
-/* DTL WRSOM */{SST(0x3A, 0x00, SS_NOP,
- "Medium not present") },
-/* DT WR OM */{SST(0x3A, 0x01, SS_NOP,
- "Medium not present - tray closed") },
-/* DT WR OM */{SST(0x3A, 0x01, SS_NOP,
- "Medium not present - tray open") },
-/* DT WR OM */{SST(0x3A, 0x03, SS_NOP,
- "Medium not present - Loadable") },
-/* DT WR OM */{SST(0x3A, 0x04, SS_NOP,
- "Medium not present - medium auxiliary "
- "memory accessible") },
-/* DT WR OM */{SST(0x3A, 0xFF, SS_NOP, NULL) },/* Range 0x05->0xFF */
-/* TL */{SST(0x3B, 0x00, SS_RDEF,
- "Sequential positioning error") },
-/* T */{SST(0x3B, 0x01, SS_RDEF,
- "Tape position error at beginning-of-medium") },
-/* T */{SST(0x3B, 0x02, SS_RDEF,
- "Tape position error at end-of-medium") },
-/* L */{SST(0x3B, 0x03, SS_RDEF,
- "Tape or electronic vertical forms unit not ready") },
-/* L */{SST(0x3B, 0x04, SS_RDEF,
- "Slew failure") },
-/* L */{SST(0x3B, 0x05, SS_RDEF,
- "Paper jam") },
-/* L */{SST(0x3B, 0x06, SS_RDEF,
- "Failed to sense top-of-form") },
-/* L */{SST(0x3B, 0x07, SS_RDEF,
- "Failed to sense bottom-of-form") },
-/* T */{SST(0x3B, 0x08, SS_RDEF,
- "Reposition error") },
-/* S */{SST(0x3B, 0x09, SS_RDEF,
- "Read past end of medium") },
-/* S */{SST(0x3B, 0x0A, SS_RDEF,
- "Read past beginning of medium") },
-/* S */{SST(0x3B, 0x0B, SS_RDEF,
- "Position past end of medium") },
-/* T S */{SST(0x3B, 0x0C, SS_RDEF,
- "Position past beginning of medium") },
-/* DT WR OM */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC,
- "Medium destination element full") },
-/* DT WR OM */{SST(0x3B, 0x0E, SS_RDEF,
- "Medium source element empty") },
-/* R */{SST(0x3B, 0x0F, SS_RDEF,
- "End of medium reached") },
-/* DT WR OM */{SST(0x3B, 0x11, SS_RDEF,
- "Medium magazine not accessible") },
-/* DT WR OM */{SST(0x3B, 0x12, SS_RDEF,
- "Medium magazine removed") },
-/* DT WR OM */{SST(0x3B, 0x13, SS_RDEF,
- "Medium magazine inserted") },
-/* DT WR OM */{SST(0x3B, 0x14, SS_RDEF,
- "Medium magazine locked") },
-/* DT WR OM */{SST(0x3B, 0x15, SS_RDEF,
- "Medium magazine unlocked") },
-/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF,
- "Invalid bits in identify message") },
-/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF,
- "Logical unit has not self-configured yet") },
-/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF,
- "Logical unit failure") },
-/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF,
- "Timeout on logical unit") },
-/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF,
- "Target operating conditions have changed") },
-/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF,
- "Microcode has been changed") },
-/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_RDEF,
- "Changed operating definition") },
-/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_INQ_REFRESH|SSQ_DECREMENT_COUNT,
- "Inquiry data has changed") },
-/* DT WR OMCAE */{SST(0x3F, 0x04, SS_RDEF,
- "Component device attached") },
-/* DT WR OMCAE */{SST(0x3F, 0x05, SS_RDEF,
- "Device identifier changed") },
-/* DT WR OMCAE */{SST(0x3F, 0x06, SS_RDEF,
- "Redundancy group created or modified") },
-/* DT WR OMCAE */{SST(0x3F, 0x07, SS_RDEF,
- "Redundancy group deleted") },
-/* DT WR OMCAE */{SST(0x3F, 0x08, SS_RDEF,
- "Spare created or modified") },
-/* DT WR OMCAE */{SST(0x3F, 0x09, SS_RDEF,
- "Spare deleted") },
-/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF,
- "Volume set created or modified") },
-/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF,
- "Volume set deleted") },
-/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF,
- "Volume set deassigned") },
-/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF,
- "Volume set reassigned") },
-/* DTLPWRSOMCAE */{SST(0x3F, 0x0E, SS_RDEF,
- "Reported luns data has changed") },
-/* DTLPWRSOMCAE */{SST(0x3F, 0x0F, SS_RETRY|SSQ_DECREMENT_COUNT
- | SSQ_DELAY_RANDOM|EBUSY,
- "Echo buffer overwritten") },
-/* DT WR OM B*/{SST(0x3F, 0x0F, SS_RDEF, "Medium Loadable") },
-/* DT WR OM B*/{SST(0x3F, 0x0F, SS_RDEF,
- "Medium auxiliary memory accessible") },
-/* D */{SST(0x40, 0x00, SS_RDEF,
- "Ram failure") }, /* deprecated - use 40 NN instead */
-/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF,
- "Diagnostic failure: ASCQ = Component ID") },
-/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE,
- NULL) },/* Range 0x80->0xFF */
-/* D */{SST(0x41, 0x00, SS_RDEF,
- "Data path failure") }, /* deprecated - use 40 NN instead */
-/* D */{SST(0x42, 0x00, SS_RDEF,
- "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */
-/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF,
- "Message error") },
-/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF,
- "Internal target failure") },
-/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF,
- "Select or reselect failure") },
-/* DTLPWRSOMC */{SST(0x46, 0x00, SS_RDEF,
- "Unsuccessful soft reset") },
-/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF|SSQ_FALLBACK,
- "SCSI parity error") },
-/* DTLPWRSOMCAE */{SST(0x47, 0x01, SS_RDEF|SSQ_FALLBACK,
- "Data Phase CRC error detected") },
-/* DTLPWRSOMCAE */{SST(0x47, 0x02, SS_RDEF|SSQ_FALLBACK,
- "SCSI parity error detected during ST data phase") },
-/* DTLPWRSOMCAE */{SST(0x47, 0x03, SS_RDEF|SSQ_FALLBACK,
- "Information Unit iuCRC error") },
-/* DTLPWRSOMCAE */{SST(0x47, 0x04, SS_RDEF|SSQ_FALLBACK,
- "Asynchronous information protection error detected") },
-/* DTLPWRSOMCAE */{SST(0x47, 0x05, SS_RDEF|SSQ_FALLBACK,
- "Protocol server CRC error") },
-/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF|SSQ_FALLBACK,
- "Initiator detected error message received") },
-/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF,
- "Invalid message error") },
-/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF,
- "Command phase error") },
-/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF,
- "Data phase error") },
-/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF,
- "Logical unit failed self-configuration") },
-/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF,
- "Tagged overlapped commands: ASCQ = Queue tag ID") },
-/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE,
- NULL)}, /* Range 0x00->0xFF */
-/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF,
- "Overlapped commands attempted") },
-/* T */{SST(0x50, 0x00, SS_RDEF,
- "Write append error") },
-/* T */{SST(0x50, 0x01, SS_RDEF,
- "Write append position error") },
-/* T */{SST(0x50, 0x02, SS_RDEF,
- "Position error related to timing") },
-/* T O */{SST(0x51, 0x00, SS_RDEF,
- "Erase failure") },
-/* T */{SST(0x52, 0x00, SS_RDEF,
- "Cartridge fault") },
-/* DTL WRSOM */{SST(0x53, 0x00, SS_RDEF,
- "Media load or eject failed") },
-/* T */{SST(0x53, 0x01, SS_RDEF,
- "Unload tape failure") },
-/* DT WR OM */{SST(0x53, 0x02, SS_RDEF,
- "Medium removal prevented") },
-/* P */{SST(0x54, 0x00, SS_RDEF,
- "Scsi to host system interface failure") },
-/* P */{SST(0x55, 0x00, SS_RDEF,
- "System resource failure") },
-/* D O */{SST(0x55, 0x01, SS_FATAL|ENOSPC,
- "System buffer full") },
-/* R */{SST(0x57, 0x00, SS_RDEF,
- "Unable to recover table-of-contents") },
-/* O */{SST(0x58, 0x00, SS_RDEF,
- "Generation does not exist") },
-/* O */{SST(0x59, 0x00, SS_RDEF,
- "Updated block read") },
-/* DTLPWRSOM */{SST(0x5A, 0x00, SS_RDEF,
- "Operator request or state change input") },
-/* DT WR OM */{SST(0x5A, 0x01, SS_RDEF,
- "Operator medium removal request") },
-/* DT W O */{SST(0x5A, 0x02, SS_RDEF,
- "Operator selected write protect") },
-/* DT W O */{SST(0x5A, 0x03, SS_RDEF,
- "Operator selected write permit") },
-/* DTLPWRSOM */{SST(0x5B, 0x00, SS_RDEF,
- "Log exception") },
-/* DTLPWRSOM */{SST(0x5B, 0x01, SS_RDEF,
- "Threshold condition met") },
-/* DTLPWRSOM */{SST(0x5B, 0x02, SS_RDEF,
- "Log counter at maximum") },
-/* DTLPWRSOM */{SST(0x5B, 0x03, SS_RDEF,
- "Log list codes exhausted") },
-/* D O */{SST(0x5C, 0x00, SS_RDEF,
- "RPL status change") },
-/* D O */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
- "Spindles synchronized") },
-/* D O */{SST(0x5C, 0x02, SS_RDEF,
- "Spindles not synchronized") },
-/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF,
- "Failure prediction threshold exceeded") },
-/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF,
- "Failure prediction threshold exceeded (false)") },
-/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_RDEF,
- "Low power condition on") },
-/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_RDEF,
- "Idle condition activated by timer") },
-/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_RDEF,
- "Standby condition activated by timer") },
-/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_RDEF,
- "Idle condition activated by command") },
-/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_RDEF,
- "Standby condition activated by command") },
-/* S */{SST(0x60, 0x00, SS_RDEF,
- "Lamp failure") },
-/* S */{SST(0x61, 0x00, SS_RDEF,
- "Video acquisition error") },
-/* S */{SST(0x61, 0x01, SS_RDEF,
- "Unable to acquire video") },
-/* S */{SST(0x61, 0x02, SS_RDEF,
- "Out of focus") },
-/* S */{SST(0x62, 0x00, SS_RDEF,
- "Scan head positioning error") },
-/* R */{SST(0x63, 0x00, SS_RDEF,
- "End of user area encountered on this track") },
-/* R */{SST(0x63, 0x01, SS_FATAL|ENOSPC,
- "Packet does not fit in available space") },
-/* R */{SST(0x64, 0x00, SS_RDEF,
- "Illegal mode for this track") },
-/* R */{SST(0x64, 0x01, SS_RDEF,
- "Invalid packet size") },
-/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF,
- "Voltage fault") },
-/* S */{SST(0x66, 0x00, SS_RDEF,
- "Automatic document feeder cover up") },
-/* S */{SST(0x66, 0x01, SS_RDEF,
- "Automatic document feeder lift up") },
-/* S */{SST(0x66, 0x02, SS_RDEF,
- "Document jam in automatic document feeder") },
-/* S */{SST(0x66, 0x03, SS_RDEF,
- "Document miss feed automatic in document feeder") },
-/* A */{SST(0x67, 0x00, SS_RDEF,
- "Configuration failure") },
-/* A */{SST(0x67, 0x01, SS_RDEF,
- "Configuration of incapable logical units failed") },
-/* A */{SST(0x67, 0x02, SS_RDEF,
- "Add logical unit failed") },
-/* A */{SST(0x67, 0x03, SS_RDEF,
- "Modification of logical unit failed") },
-/* A */{SST(0x67, 0x04, SS_RDEF,
- "Exchange of logical unit failed") },
-/* A */{SST(0x67, 0x05, SS_RDEF,
- "Remove of logical unit failed") },
-/* A */{SST(0x67, 0x06, SS_RDEF,
- "Attachment of logical unit failed") },
-/* A */{SST(0x67, 0x07, SS_RDEF,
- "Creation of logical unit failed") },
-/* A */{SST(0x68, 0x00, SS_RDEF,
- "Logical unit not configured") },
-/* A */{SST(0x69, 0x00, SS_RDEF,
- "Data loss on logical unit") },
-/* A */{SST(0x69, 0x01, SS_RDEF,
- "Multiple logical unit failures") },
-/* A */{SST(0x69, 0x02, SS_RDEF,
- "Parity/data mismatch") },
-/* A */{SST(0x6A, 0x00, SS_RDEF,
- "Informational, refer to log") },
-/* A */{SST(0x6B, 0x00, SS_RDEF,
- "State change has occurred") },
-/* A */{SST(0x6B, 0x01, SS_RDEF,
- "Redundancy level got better") },
-/* A */{SST(0x6B, 0x02, SS_RDEF,
- "Redundancy level got worse") },
-/* A */{SST(0x6C, 0x00, SS_RDEF,
- "Rebuild failure occurred") },
-/* A */{SST(0x6D, 0x00, SS_RDEF,
- "Recalculate failure occurred") },
-/* A */{SST(0x6E, 0x00, SS_RDEF,
- "Command to logical unit failed") },
-/* T */{SST(0x70, 0x00, SS_RDEF,
- "Decompression exception short: ASCQ = Algorithm ID") },
-/* T */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE,
- NULL) }, /* Range 0x00 -> 0xFF */
-/* T */{SST(0x71, 0x00, SS_RDEF,
- "Decompression exception long: ASCQ = Algorithm ID") },
-/* T */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE,
- NULL) }, /* Range 0x00 -> 0xFF */
-/* R */{SST(0x72, 0x00, SS_RDEF,
- "Session fixation error") },
-/* R */{SST(0x72, 0x01, SS_RDEF,
- "Session fixation error writing lead-in") },
-/* R */{SST(0x72, 0x02, SS_RDEF,
- "Session fixation error writing lead-out") },
-/* R */{SST(0x72, 0x03, SS_RDEF,
- "Session fixation error - incomplete track in session") },
-/* R */{SST(0x72, 0x04, SS_RDEF,
- "Empty or partially written reserved track") },
-/* R */{SST(0x73, 0x00, SS_RDEF,
- "CD control error") },
-/* R */{SST(0x73, 0x01, SS_RDEF,
- "Power calibration area almost full") },
-/* R */{SST(0x73, 0x02, SS_FATAL|ENOSPC,
- "Power calibration area is full") },
-/* R */{SST(0x73, 0x03, SS_RDEF,
- "Power calibration area error") },
-/* R */{SST(0x73, 0x04, SS_RDEF,
- "Program memory area update failure") },
-/* R */{SST(0x73, 0x05, SS_RDEF,
- "program memory area is full") }
-};
-
-static const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]);
-
-struct asc_key
-{
- int asc;
- int ascq;
-};
-
-static int
-ascentrycomp(const void *key, const void *member)
-{
- int asc;
- int ascq;
- const struct asc_table_entry *table_entry;
-
- asc = ((const struct asc_key *)key)->asc;
- ascq = ((const struct asc_key *)key)->ascq;
- table_entry = (const struct asc_table_entry *)member;
-
- if (asc >= table_entry->asc) {
-
- if (asc > table_entry->asc)
- return (1);
-
- if (ascq <= table_entry->ascq) {
- /* Check for ranges */
- if (ascq == table_entry->ascq
- || ((table_entry->action & SSQ_RANGE) != 0
- && ascq >= (table_entry - 1)->ascq))
- return (0);
- return (-1);
- }
- return (1);
- }
- return (-1);
-}
-
-static int
-senseentrycomp(const void *key, const void *member)
-{
- int sense_key;
- const struct sense_key_table_entry *table_entry;
-
- sense_key = *((const int *)key);
- table_entry = (const struct sense_key_table_entry *)member;
-
- if (sense_key >= table_entry->sense_key) {
- if (sense_key == table_entry->sense_key)
- return (0);
- return (1);
- }
- return (-1);
-}
-
-static void
-fetchtableentries(int sense_key, int asc, int ascq,
- struct scsi_inquiry_data *inq_data,
- const struct sense_key_table_entry **sense_entry,
- const struct asc_table_entry **asc_entry)
-{
- void *match;
- const struct asc_table_entry *asc_tables[2];
- const struct sense_key_table_entry *sense_tables[2];
- struct asc_key asc_ascq;
- size_t asc_tables_size[2];
- size_t sense_tables_size[2];
- int num_asc_tables;
- int num_sense_tables;
- int i;
-
- /* Default to failure */
- *sense_entry = NULL;
- *asc_entry = NULL;
- match = NULL;
- if (inq_data != NULL)
- match = cam_quirkmatch((void *)inq_data,
- (void *)sense_quirk_table,
- sense_quirk_table_size,
- sizeof(*sense_quirk_table),
- aic_inquiry_match);
-
- if (match != NULL) {
- struct scsi_sense_quirk_entry *quirk;
-
- quirk = (struct scsi_sense_quirk_entry *)match;
- asc_tables[0] = quirk->asc_info;
- asc_tables_size[0] = quirk->num_ascs;
- asc_tables[1] = asc_table;
- asc_tables_size[1] = asc_table_size;
- num_asc_tables = 2;
- sense_tables[0] = quirk->sense_key_info;
- sense_tables_size[0] = quirk->num_sense_keys;
- sense_tables[1] = sense_key_table;
- sense_tables_size[1] = sense_key_table_size;
- num_sense_tables = 2;
- } else {
- asc_tables[0] = asc_table;
- asc_tables_size[0] = asc_table_size;
- num_asc_tables = 1;
- sense_tables[0] = sense_key_table;
- sense_tables_size[0] = sense_key_table_size;
- num_sense_tables = 1;
- }
-
- asc_ascq.asc = asc;
- asc_ascq.ascq = ascq;
- for (i = 0; i < num_asc_tables; i++) {
- void *found_entry;
-
- found_entry = scsibsearch(&asc_ascq, asc_tables[i],
- asc_tables_size[i],
- sizeof(**asc_tables),
- ascentrycomp);
-
- if (found_entry) {
- *asc_entry = (struct asc_table_entry *)found_entry;
- break;
- }
- }
-
- for (i = 0; i < num_sense_tables; i++) {
- void *found_entry;
-
- found_entry = scsibsearch(&sense_key, sense_tables[i],
- sense_tables_size[i],
- sizeof(**sense_tables),
- senseentrycomp);
-
- if (found_entry) {
- *sense_entry =
- (struct sense_key_table_entry *)found_entry;
- break;
- }
- }
-}
-
-static void *
-scsibsearch(const void *key, const void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *))
-{
- const void *entry;
- u_int l;
- u_int u;
- u_int m;
-
- l = -1;
- u = nmemb;
- while (l + 1 != u) {
- m = (l + u) / 2;
- entry = base + m * size;
- if (compar(key, entry) > 0)
- l = m;
- else
- u = m;
- }
-
- entry = base + u * size;
- if (u == nmemb
- || compar(key, entry) != 0)
- return (NULL);
-
- return ((void *)entry);
-}
-
-/*
- * Compare string with pattern, returning 0 on match.
- * Short pattern matches trailing blanks in name,
- * wildcard '*' in pattern matches rest of name,
- * wildcard '?' matches a single non-space character.
- */
-static int
-cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len)
-{
-
- while (*pattern != '\0'&& str_len > 0) {
-
- if (*pattern == '*') {
- return (0);
- }
- if ((*pattern != *str)
- && (*pattern != '?' || *str == ' ')) {
- return (1);
- }
- pattern++;
- str++;
- str_len--;
- }
- while (str_len > 0 && *str++ == ' ')
- str_len--;
-
- return (str_len);
-}
-
-static caddr_t
-cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
- int entry_size, cam_quirkmatch_t *comp_func)
-{
- for (; num_entries > 0; num_entries--, quirk_table += entry_size) {
- if ((*comp_func)(target, quirk_table) == 0)
- return (quirk_table);
- }
- return (NULL);
-}
-
-void
-aic_sense_desc(int sense_key, int asc, int ascq,
- struct scsi_inquiry_data *inq_data,
- const char **sense_key_desc, const char **asc_desc)
-{
- const struct asc_table_entry *asc_entry;
- const struct sense_key_table_entry *sense_entry;
-
- fetchtableentries(sense_key, asc, ascq,
- inq_data,
- &sense_entry,
- &asc_entry);
-
- *sense_key_desc = sense_entry->desc;
-
- if (asc_entry != NULL)
- *asc_desc = asc_entry->desc;
- else if (asc >= 0x80 && asc <= 0xff)
- *asc_desc = "Vendor Specific ASC";
- else if (ascq >= 0x80 && ascq <= 0xff)
- *asc_desc = "Vendor Specific ASCQ";
- else
- *asc_desc = "Reserved ASC/ASCQ pair";
-}
-
-/*
- * Given sense and device type information, return the appropriate action.
- * If we do not understand the specific error as identified by the ASC/ASCQ
- * pair, fall back on the more generic actions derived from the sense key.
- */
-aic_sense_action
-aic_sense_error_action(struct scsi_sense_data *sense_data,
- struct scsi_inquiry_data *inq_data, uint32_t sense_flags)
-{
- const struct asc_table_entry *asc_entry;
- const struct sense_key_table_entry *sense_entry;
- int error_code, sense_key, asc, ascq;
- aic_sense_action action;
-
- scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq);
-
- if (error_code == SSD_DEFERRED_ERROR) {
- /*
- * XXX dufault@FreeBSD.org
- * This error doesn't relate to the command associated
- * with this request sense. A deferred error is an error
- * for a command that has already returned GOOD status
- * (see SCSI2 8.2.14.2).
- *
- * By my reading of that section, it looks like the current
- * command has been cancelled, we should now clean things up
- * (hopefully recovering any lost data) and then retry the
- * current command. There are two easy choices, both wrong:
- *
- * 1. Drop through (like we had been doing), thus treating
- * this as if the error were for the current command and
- * return and stop the current command.
- *
- * 2. Issue a retry (like I made it do) thus hopefully
- * recovering the current transfer, and ignoring the
- * fact that we've dropped a command.
- *
- * These should probably be handled in a device specific
- * sense handler or punted back up to a user mode daemon
- */
- action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
- } else {
- fetchtableentries(sense_key, asc, ascq,
- inq_data,
- &sense_entry,
- &asc_entry);
-
- /*
- * Override the 'No additional Sense' entry (0,0)
- * with the error action of the sense key.
- */
- if (asc_entry != NULL
- && (asc != 0 || ascq != 0))
- action = asc_entry->action;
- else
- action = sense_entry->action;
-
- if (sense_key == SSD_KEY_RECOVERED_ERROR) {
- /*
- * The action succeeded but the device wants
- * the user to know that some recovery action
- * was required.
- */
- action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK);
- action |= SS_NOP|SSQ_PRINT_SENSE;
- } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) {
- if ((sense_flags & SF_QUIET_IR) != 0)
- action &= ~SSQ_PRINT_SENSE;
- } else if (sense_key == SSD_KEY_UNIT_ATTENTION) {
- if ((sense_flags & SF_RETRY_UA) != 0
- && (action & SS_MASK) == SS_FAIL) {
- action &= ~(SS_MASK|SSQ_MASK);
- action |= SS_RETRY|SSQ_DECREMENT_COUNT|
- SSQ_PRINT_SENSE;
- }
- }
- }
-
- if ((sense_flags & SF_PRINT_ALWAYS) != 0)
- action |= SSQ_PRINT_SENSE;
- else if ((sense_flags & SF_NO_PRINT) != 0)
- action &= ~SSQ_PRINT_SENSE;
-
- return (action);
-}
-
-/*
- * Try make as good a match as possible with
- * available sub drivers
- */
-int
-aic_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
-{
- struct scsi_inquiry_pattern *entry;
- struct scsi_inquiry_data *inq;
-
- entry = (struct scsi_inquiry_pattern *)table_entry;
- inq = (struct scsi_inquiry_data *)inqbuffer;
-
- if (((SID_TYPE(inq) == entry->type)
- || (entry->type == T_ANY))
- && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
- : entry->media_type & SIP_MEDIA_FIXED)
- && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
- && (cam_strmatch(inq->product, entry->product,
- sizeof(inq->product)) == 0)
- && (cam_strmatch(inq->revision, entry->revision,
- sizeof(inq->revision)) == 0)) {
- return (0);
- }
- return (-1);
-}
-
-/*
- * Table of syncrates that don't follow the "divisible by 4"
- * rule. This table will be expanded in future SCSI specs.
- */
-static struct {
- u_int period_factor;
- u_int period; /* in 100ths of ns */
-} scsi_syncrates[] = {
- { 0x08, 625 }, /* FAST-160 */
- { 0x09, 1250 }, /* FAST-80 */
- { 0x0a, 2500 }, /* FAST-40 40MHz */
- { 0x0b, 3030 }, /* FAST-40 33MHz */
- { 0x0c, 5000 } /* FAST-20 */
-};
-
-/*
- * Return the frequency in kHz corresponding to the given
- * sync period factor.
- */
-u_int
-aic_calc_syncsrate(u_int period_factor)
-{
- int i;
- int num_syncrates;
-
- num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
- /* See if the period is in the "exception" table */
- for (i = 0; i < num_syncrates; i++) {
-
- if (period_factor == scsi_syncrates[i].period_factor) {
- /* Period in kHz */
- return (100000000 / scsi_syncrates[i].period);
- }
- }
-
- /*
- * Wasn't in the table, so use the standard
- * 4 times conversion.
- */
- return (10000000 / (period_factor * 4 * 10));
-}
-
-/*
- * Return speed in KB/s.
- */
-u_int
-aic_calc_speed(u_int width, u_int period, u_int offset, u_int min_rate)
-{
- u_int freq;
-
- if (offset != 0 && period < min_rate)
- freq = aic_calc_syncsrate(period);
- else
- /* Roughly 3.3MB/s for async */
- freq = 3300;
- freq <<= width;
- return (freq);
-}
-
-uint32_t
-aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data,
- cam_status status, u_int scsi_status)
-{
- aic_sense_action err_action;
- int sense;
-
- sense = (cmd->result >> 24) == DRIVER_SENSE;
-
- switch (status) {
- case CAM_REQ_CMP:
- err_action = SS_NOP;
- break;
- case CAM_AUTOSENSE_FAIL:
- case CAM_SCSI_STATUS_ERROR:
-
- switch (scsi_status) {
- case SCSI_STATUS_OK:
- case SCSI_STATUS_COND_MET:
- case SCSI_STATUS_INTERMED:
- case SCSI_STATUS_INTERMED_COND_MET:
- err_action = SS_NOP;
- break;
- case SCSI_STATUS_CMD_TERMINATED:
- case SCSI_STATUS_CHECK_COND:
- if (sense != 0) {
- struct scsi_sense_data *sense;
-
- sense = (struct scsi_sense_data *)
- &cmd->sense_buffer;
- err_action =
- aic_sense_error_action(sense, inq_data, 0);
-
- } else {
- err_action = SS_RETRY|SSQ_FALLBACK
- | SSQ_DECREMENT_COUNT|EIO;
- }
- break;
- case SCSI_STATUS_QUEUE_FULL:
- case SCSI_STATUS_BUSY:
- err_action = SS_RETRY|SSQ_DELAY|SSQ_MANY
- | SSQ_DECREMENT_COUNT|EBUSY;
- break;
- case SCSI_STATUS_RESERV_CONFLICT:
- default:
- err_action = SS_FAIL|EBUSY;
- break;
- }
- break;
- case CAM_CMD_TIMEOUT:
- case CAM_REQ_CMP_ERR:
- case CAM_UNEXP_BUSFREE:
- case CAM_UNCOR_PARITY:
- case CAM_DATA_RUN_ERR:
- err_action = SS_RETRY|SSQ_FALLBACK|EIO;
- break;
- case CAM_UA_ABORT:
- case CAM_UA_TERMIO:
- case CAM_MSG_REJECT_REC:
- case CAM_SEL_TIMEOUT:
- err_action = SS_FAIL|EIO;
- break;
- case CAM_REQ_INVALID:
- case CAM_PATH_INVALID:
- case CAM_DEV_NOT_THERE:
- case CAM_NO_HBA:
- case CAM_PROVIDE_FAIL:
- case CAM_REQ_TOO_BIG:
- case CAM_RESRC_UNAVAIL:
- case CAM_BUSY:
- default:
- /* panic?? These should never occur in our application. */
- err_action = SS_FAIL|EIO;
- break;
- case CAM_SCSI_BUS_RESET:
- case CAM_BDR_SENT:
- case CAM_REQUEUE_REQ:
- /* Unconditional requeue */
- err_action = SS_RETRY;
- break;
- }
-
- return (err_action);
-}
-
-char *
-aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
- aic_option_callback_t *callback, u_long callback_arg)
-{
- char *tok_end;
- char *tok_end2;
- int i;
- int instance;
- int targ;
- int done;
- char tok_list[] = {'.', ',', '{', '}', '\0'};
- /* All options use a ':' name/arg separator */
- if (*opt_arg != ':')
- return (opt_arg);
- opt_arg++;
- instance = -1;
- targ = -1;
- done = FALSE;
- /*
- * Restore separator that may be in
- * the middle of our option argument.
- */
- tok_end = strchr(opt_arg, '\0');
- if (tok_end < end)
- *tok_end = ',';
- while (!done) {
- switch (*opt_arg) {
- case '{':
- if (instance == -1) {
- instance = 0;
- } else {
- if (depth > 1) {
- if (targ == -1)
- targ = 0;
- } else {
- printf("Malformed Option %s\n",
- opt_name);
- done = TRUE;
- }
- }
- opt_arg++;
- break;
- case '}':
- if (targ != -1)
- targ = -1;
- else if (instance != -1)
- instance = -1;
- opt_arg++;
- break;
- case ',':
- case '.':
- if (instance == -1)
- done = TRUE;
- else if (targ >= 0)
- targ++;
- else if (instance >= 0)
- instance++;
- opt_arg++;
- break;
- case '\0':
- done = TRUE;
- break;
- default:
- tok_end = end;
- for (i = 0; tok_list[i]; i++) {
- tok_end2 = strchr(opt_arg, tok_list[i]);
- if ((tok_end2) && (tok_end2 < tok_end))
- tok_end = tok_end2;
- }
- callback(callback_arg, instance, targ,
- simple_strtol(opt_arg, NULL, 0));
- opt_arg = tok_end;
- break;
- }
- }
- return (opt_arg);
-}
diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h
index bfe6f95..3bfbf0f 100644
--- a/drivers/scsi/aic7xxx/aiclib.h
+++ b/drivers/scsi/aic7xxx/aiclib.h
@@ -57,121 +57,6 @@
#ifndef _AICLIB_H
#define _AICLIB_H
-/*
- * Linux Interrupt Support.
- */
-#ifndef IRQ_RETVAL
-typedef void irqreturn_t;
-#define IRQ_RETVAL(x)
-#endif
-
-/*
- * SCSI command format
- */
-
-/*
- * Define dome bits that are in ALL (or a lot of) scsi commands
- */
-#define SCSI_CTL_LINK 0x01
-#define SCSI_CTL_FLAG 0x02
-#define SCSI_CTL_VENDOR 0xC0
-#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */
-#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */
-
-#define SCSI_MAX_CDBLEN 16 /*
- * 16 byte commands are in the
- * SCSI-3 spec
- */
-/* 6byte CDBs special case 0 length to be 256 */
-#define SCSI_CDB6_LEN(len) ((len) == 0 ? 256 : len)
-
-/*
- * This type defines actions to be taken when a particular sense code is
- * received. Right now, these flags are only defined to take up 16 bits,
- * but can be expanded in the future if necessary.
- */
-typedef enum {
- SS_NOP = 0x000000, /* Do nothing */
- SS_RETRY = 0x010000, /* Retry the command */
- SS_FAIL = 0x020000, /* Bail out */
- SS_START = 0x030000, /* Send a Start Unit command to the device,
- * then retry the original command.
- */
- SS_TUR = 0x040000, /* Send a Test Unit Ready command to the
- * device, then retry the original command.
- */
- SS_REQSENSE = 0x050000, /* Send a RequestSense command to the
- * device, then retry the original command.
- */
- SS_INQ_REFRESH = 0x060000,
- SS_MASK = 0xff0000
-} aic_sense_action;
-
-typedef enum {
- SSQ_NONE = 0x0000,
- SSQ_DECREMENT_COUNT = 0x0100, /* Decrement the retry count */
- SSQ_MANY = 0x0200, /* send lots of recovery commands */
- SSQ_RANGE = 0x0400, /*
- * This table entry represents the
- * end of a range of ASCQs that
- * have identical error actions
- * and text.
- */
- SSQ_PRINT_SENSE = 0x0800,
- SSQ_DELAY = 0x1000, /* Delay before retry. */
- SSQ_DELAY_RANDOM = 0x2000, /* Randomized delay before retry. */
- SSQ_FALLBACK = 0x4000, /* Do a speed fallback to recover */
- SSQ_MASK = 0xff00
-} aic_sense_action_qualifier;
-
-/* Mask for error status values */
-#define SS_ERRMASK 0xff
-
-/* The default, retyable, error action */
-#define SS_RDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO
-
-/* The retyable, error action, with table specified error code */
-#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
-
-/* Fatal error action, with table specified error code */
-#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE
-
-struct scsi_generic
-{
- uint8_t opcode;
- uint8_t bytes[11];
-};
-
-struct scsi_request_sense
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused[2];
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_test_unit_ready
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused[3];
- uint8_t control;
-};
-
-struct scsi_send_diag
-{
- uint8_t opcode;
- uint8_t byte2;
-#define SSD_UOL 0x01
-#define SSD_DOL 0x02
-#define SSD_SELFTEST 0x04
-#define SSD_PF 0x10
- uint8_t unused[1];
- uint8_t paramlen[2];
- uint8_t control;
-};
-
struct scsi_sense
{
uint8_t opcode;
@@ -181,537 +66,12 @@
uint8_t control;
};
-struct scsi_inquiry
-{
- uint8_t opcode;
- uint8_t byte2;
-#define SI_EVPD 0x01
- uint8_t page_code;
- uint8_t reserved;
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_mode_sense_6
-{
- uint8_t opcode;
- uint8_t byte2;
-#define SMS_DBD 0x08
- uint8_t page;
-#define SMS_PAGE_CODE 0x3F
-#define SMS_VENDOR_SPECIFIC_PAGE 0x00
-#define SMS_DISCONNECT_RECONNECT_PAGE 0x02
-#define SMS_PERIPHERAL_DEVICE_PAGE 0x09
-#define SMS_CONTROL_MODE_PAGE 0x0A
-#define SMS_ALL_PAGES_PAGE 0x3F
-#define SMS_PAGE_CTRL_MASK 0xC0
-#define SMS_PAGE_CTRL_CURRENT 0x00
-#define SMS_PAGE_CTRL_CHANGEABLE 0x40
-#define SMS_PAGE_CTRL_DEFAULT 0x80
-#define SMS_PAGE_CTRL_SAVED 0xC0
- uint8_t unused;
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_mode_sense_10
-{
- uint8_t opcode;
- uint8_t byte2; /* same bits as small version */
- uint8_t page; /* same bits as small version */
- uint8_t unused[4];
- uint8_t length[2];
- uint8_t control;
-};
-
-struct scsi_mode_select_6
-{
- uint8_t opcode;
- uint8_t byte2;
-#define SMS_SP 0x01
-#define SMS_PF 0x10
- uint8_t unused[2];
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_mode_select_10
-{
- uint8_t opcode;
- uint8_t byte2; /* same bits as small version */
- uint8_t unused[5];
- uint8_t length[2];
- uint8_t control;
-};
-
-/*
- * When sending a mode select to a tape drive, the medium type must be 0.
- */
-struct scsi_mode_hdr_6
-{
- uint8_t datalen;
- uint8_t medium_type;
- uint8_t dev_specific;
- uint8_t block_descr_len;
-};
-
-struct scsi_mode_hdr_10
-{
- uint8_t datalen[2];
- uint8_t medium_type;
- uint8_t dev_specific;
- uint8_t reserved[2];
- uint8_t block_descr_len[2];
-};
-
-struct scsi_mode_block_descr
-{
- uint8_t density_code;
- uint8_t num_blocks[3];
- uint8_t reserved;
- uint8_t block_len[3];
-};
-
-struct scsi_log_sense
-{
- uint8_t opcode;
- uint8_t byte2;
-#define SLS_SP 0x01
-#define SLS_PPC 0x02
- uint8_t page;
-#define SLS_PAGE_CODE 0x3F
-#define SLS_ALL_PAGES_PAGE 0x00
-#define SLS_OVERRUN_PAGE 0x01
-#define SLS_ERROR_WRITE_PAGE 0x02
-#define SLS_ERROR_READ_PAGE 0x03
-#define SLS_ERROR_READREVERSE_PAGE 0x04
-#define SLS_ERROR_VERIFY_PAGE 0x05
-#define SLS_ERROR_NONMEDIUM_PAGE 0x06
-#define SLS_ERROR_LASTN_PAGE 0x07
-#define SLS_PAGE_CTRL_MASK 0xC0
-#define SLS_PAGE_CTRL_THRESHOLD 0x00
-#define SLS_PAGE_CTRL_CUMULATIVE 0x40
-#define SLS_PAGE_CTRL_THRESH_DEFAULT 0x80
-#define SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0
- uint8_t reserved[2];
- uint8_t paramptr[2];
- uint8_t length[2];
- uint8_t control;
-};
-
-struct scsi_log_select
-{
- uint8_t opcode;
- uint8_t byte2;
-/* SLS_SP 0x01 */
-#define SLS_PCR 0x02
- uint8_t page;
-/* SLS_PAGE_CTRL_MASK 0xC0 */
-/* SLS_PAGE_CTRL_THRESHOLD 0x00 */
-/* SLS_PAGE_CTRL_CUMULATIVE 0x40 */
-/* SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 */
-/* SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 */
- uint8_t reserved[4];
- uint8_t length[2];
- uint8_t control;
-};
-
-struct scsi_log_header
-{
- uint8_t page;
- uint8_t reserved;
- uint8_t datalen[2];
-};
-
-struct scsi_log_param_header {
- uint8_t param_code[2];
- uint8_t param_control;
-#define SLP_LP 0x01
-#define SLP_LBIN 0x02
-#define SLP_TMC_MASK 0x0C
-#define SLP_TMC_ALWAYS 0x00
-#define SLP_TMC_EQUAL 0x04
-#define SLP_TMC_NOTEQUAL 0x08
-#define SLP_TMC_GREATER 0x0C
-#define SLP_ETC 0x10
-#define SLP_TSD 0x20
-#define SLP_DS 0x40
-#define SLP_DU 0x80
- uint8_t param_len;
-};
-
-struct scsi_control_page {
- uint8_t page_code;
- uint8_t page_length;
- uint8_t rlec;
-#define SCB_RLEC 0x01 /*Report Log Exception Cond*/
- uint8_t queue_flags;
-#define SCP_QUEUE_ALG_MASK 0xF0
-#define SCP_QUEUE_ALG_RESTRICTED 0x00
-#define SCP_QUEUE_ALG_UNRESTRICTED 0x10
-#define SCP_QUEUE_ERR 0x02 /*Queued I/O aborted for CACs*/
-#define SCP_QUEUE_DQUE 0x01 /*Queued I/O disabled*/
- uint8_t eca_and_aen;
-#define SCP_EECA 0x80 /*Enable Extended CA*/
-#define SCP_RAENP 0x04 /*Ready AEN Permission*/
-#define SCP_UAAENP 0x02 /*UA AEN Permission*/
-#define SCP_EAENP 0x01 /*Error AEN Permission*/
- uint8_t reserved;
- uint8_t aen_holdoff_period[2];
-};
-
-struct scsi_reserve
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused[2];
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_release
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused[2];
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_prevent
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused[2];
- uint8_t how;
- uint8_t control;
-};
-#define PR_PREVENT 0x01
-#define PR_ALLOW 0x00
-
-struct scsi_sync_cache
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t begin_lba[4];
- uint8_t reserved;
- uint8_t lb_count[2];
- uint8_t control;
-};
-
-
-struct scsi_changedef
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused1;
- uint8_t how;
- uint8_t unused[4];
- uint8_t datalen;
- uint8_t control;
-};
-
-struct scsi_read_buffer
-{
- uint8_t opcode;
- uint8_t byte2;
-#define RWB_MODE 0x07
-#define RWB_MODE_HDR_DATA 0x00
-#define RWB_MODE_DATA 0x02
-#define RWB_MODE_DOWNLOAD 0x04
-#define RWB_MODE_DOWNLOAD_SAVE 0x05
- uint8_t buffer_id;
- uint8_t offset[3];
- uint8_t length[3];
- uint8_t control;
-};
-
-struct scsi_write_buffer
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t buffer_id;
- uint8_t offset[3];
- uint8_t length[3];
- uint8_t control;
-};
-
-struct scsi_rw_6
-{
- uint8_t opcode;
- uint8_t addr[3];
-/* only 5 bits are valid in the MSB address byte */
-#define SRW_TOPADDR 0x1F
- uint8_t length;
- uint8_t control;
-};
-
-struct scsi_rw_10
-{
- uint8_t opcode;
-#define SRW10_RELADDR 0x01
-#define SRW10_FUA 0x08
-#define SRW10_DPO 0x10
- uint8_t byte2;
- uint8_t addr[4];
- uint8_t reserved;
- uint8_t length[2];
- uint8_t control;
-};
-
-struct scsi_rw_12
-{
- uint8_t opcode;
-#define SRW12_RELADDR 0x01
-#define SRW12_FUA 0x08
-#define SRW12_DPO 0x10
- uint8_t byte2;
- uint8_t addr[4];
- uint8_t length[4];
- uint8_t reserved;
- uint8_t control;
-};
-
-struct scsi_start_stop_unit
-{
- uint8_t opcode;
- uint8_t byte2;
-#define SSS_IMMED 0x01
- uint8_t reserved[2];
- uint8_t how;
-#define SSS_START 0x01
-#define SSS_LOEJ 0x02
- uint8_t control;
-};
-
-#define SC_SCSI_1 0x01
-#define SC_SCSI_2 0x03
-
-/*
- * Opcodes
- */
-
-#define TEST_UNIT_READY 0x00
-#define REQUEST_SENSE 0x03
-#define READ_6 0x08
-#define WRITE_6 0x0a
-#define INQUIRY 0x12
-#define MODE_SELECT_6 0x15
-#define MODE_SENSE_6 0x1a
-#define START_STOP_UNIT 0x1b
-#define START_STOP 0x1b
-#define RESERVE 0x16
-#define RELEASE 0x17
-#define RECEIVE_DIAGNOSTIC 0x1c
-#define SEND_DIAGNOSTIC 0x1d
-#define PREVENT_ALLOW 0x1e
-#define READ_CAPACITY 0x25
-#define READ_10 0x28
-#define WRITE_10 0x2a
-#define POSITION_TO_ELEMENT 0x2b
-#define SYNCHRONIZE_CACHE 0x35
-#define WRITE_BUFFER 0x3b
-#define READ_BUFFER 0x3c
-#define CHANGE_DEFINITION 0x40
-#define LOG_SELECT 0x4c
-#define LOG_SENSE 0x4d
-#ifdef XXXCAM
-#define MODE_SENSE_10 0x5A
-#endif
-#define MODE_SELECT_10 0x55
-#define MOVE_MEDIUM 0xa5
-#define READ_12 0xa8
-#define WRITE_12 0xaa
-#define READ_ELEMENT_STATUS 0xb8
-
-
-/*
- * Device Types
- */
-#define T_DIRECT 0x00
-#define T_SEQUENTIAL 0x01
-#define T_PRINTER 0x02
-#define T_PROCESSOR 0x03
-#define T_WORM 0x04
-#define T_CDROM 0x05
-#define T_SCANNER 0x06
-#define T_OPTICAL 0x07
-#define T_CHANGER 0x08
-#define T_COMM 0x09
-#define T_ASC0 0x0a
-#define T_ASC1 0x0b
-#define T_STORARRAY 0x0c
-#define T_ENCLOSURE 0x0d
-#define T_RBC 0x0e
-#define T_OCRW 0x0f
-#define T_NODEVICE 0x1F
-#define T_ANY 0xFF /* Used in Quirk table matches */
-
-#define T_REMOV 1
-#define T_FIXED 0
-
-/*
- * This length is the initial inquiry length used by the probe code, as
- * well as the legnth necessary for aic_print_inquiry() to function
- * correctly. If either use requires a different length in the future,
- * the two values should be de-coupled.
- */
-#define SHORT_INQUIRY_LENGTH 36
-
-struct scsi_inquiry_data
-{
- uint8_t device;
-#define SID_TYPE(inq_data) ((inq_data)->device & 0x1f)
-#define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5)
-#define SID_QUAL_LU_CONNECTED 0x00 /*
- * The specified peripheral device
- * type is currently connected to
- * logical unit. If the target cannot
- * determine whether or not a physical
- * device is currently connected, it
- * shall also use this peripheral
- * qualifier when returning the INQUIRY
- * data. This peripheral qualifier
- * does not mean that the device is
- * ready for access by the initiator.
- */
-#define SID_QUAL_LU_OFFLINE 0x01 /*
- * The target is capable of supporting
- * the specified peripheral device type
- * on this logical unit; however, the
- * physical device is not currently
- * connected to this logical unit.
- */
-#define SID_QUAL_RSVD 0x02
-#define SID_QUAL_BAD_LU 0x03 /*
- * The target is not capable of
- * supporting a physical device on
- * this logical unit. For this
- * peripheral qualifier the peripheral
- * device type shall be set to 1Fh to
- * provide compatibility with previous
- * versions of SCSI. All other
- * peripheral device type values are
- * reserved for this peripheral
- * qualifier.
- */
-#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0)
- uint8_t dev_qual2;
-#define SID_QUAL2 0x7F
-#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0)
- uint8_t version;
-#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07)
#define SCSI_REV_0 0
#define SCSI_REV_CCS 1
#define SCSI_REV_2 2
#define SCSI_REV_SPC 3
#define SCSI_REV_SPC2 4
-#define SID_ECMA 0x38
-#define SID_ISO 0xC0
- uint8_t response_format;
-#define SID_AENC 0x80
-#define SID_TrmIOP 0x40
- uint8_t additional_length;
- uint8_t reserved[2];
- uint8_t flags;
-#define SID_SftRe 0x01
-#define SID_CmdQue 0x02
-#define SID_Linked 0x08
-#define SID_Sync 0x10
-#define SID_WBus16 0x20
-#define SID_WBus32 0x40
-#define SID_RelAdr 0x80
-#define SID_VENDOR_SIZE 8
- char vendor[SID_VENDOR_SIZE];
-#define SID_PRODUCT_SIZE 16
- char product[SID_PRODUCT_SIZE];
-#define SID_REVISION_SIZE 4
- char revision[SID_REVISION_SIZE];
- /*
- * The following fields were taken from SCSI Primary Commands - 2
- * (SPC-2) Revision 14, Dated 11 November 1999
- */
-#define SID_VENDOR_SPECIFIC_0_SIZE 20
- uint8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE];
- /*
- * An extension of SCSI Parallel Specific Values
- */
-#define SID_SPI_IUS 0x01
-#define SID_SPI_QAS 0x02
-#define SID_SPI_CLOCK_ST 0x00
-#define SID_SPI_CLOCK_DT 0x04
-#define SID_SPI_CLOCK_DT_ST 0x0C
-#define SID_SPI_MASK 0x0F
- uint8_t spi3data;
- uint8_t reserved2;
- /*
- * Version Descriptors, stored 2 byte values.
- */
- uint8_t version1[2];
- uint8_t version2[2];
- uint8_t version3[2];
- uint8_t version4[2];
- uint8_t version5[2];
- uint8_t version6[2];
- uint8_t version7[2];
- uint8_t version8[2];
-
- uint8_t reserved3[22];
-
-#define SID_VENDOR_SPECIFIC_1_SIZE 160
- uint8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE];
-};
-
-struct scsi_vpd_unit_serial_number
-{
- uint8_t device;
- uint8_t page_code;
-#define SVPD_UNIT_SERIAL_NUMBER 0x80
- uint8_t reserved;
- uint8_t length; /* serial number length */
-#define SVPD_SERIAL_NUM_SIZE 251
- uint8_t serial_num[SVPD_SERIAL_NUM_SIZE];
-};
-
-struct scsi_read_capacity
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t addr[4];
- uint8_t unused[3];
- uint8_t control;
-};
-
-struct scsi_read_capacity_data
-{
- uint8_t addr[4];
- uint8_t length[4];
-};
-
-struct scsi_report_luns
-{
- uint8_t opcode;
- uint8_t byte2;
- uint8_t unused[3];
- uint8_t addr[4];
- uint8_t control;
-};
-
-struct scsi_report_luns_data {
- uint8_t length[4]; /* length of LUN inventory, in bytes */
- uint8_t reserved[4]; /* unused */
- /*
- * LUN inventory- we only support the type zero form for now.
- */
- struct {
- uint8_t lundata[8];
- } luns[1];
-};
-#define RPL_LUNDATA_ATYP_MASK 0xc0 /* MBZ for type 0 lun */
-#define RPL_LUNDATA_T0LUN 1 /* @ lundata[1] */
-
-
struct scsi_sense_data
{
uint8_t error_code;
@@ -757,41 +117,6 @@
#define SSD_FULL_SIZE sizeof(struct scsi_sense_data)
};
-struct scsi_mode_header_6
-{
- uint8_t data_length; /* Sense data length */
- uint8_t medium_type;
- uint8_t dev_spec;
- uint8_t blk_desc_len;
-};
-
-struct scsi_mode_header_10
-{
- uint8_t data_length[2];/* Sense data length */
- uint8_t medium_type;
- uint8_t dev_spec;
- uint8_t unused[2];
- uint8_t blk_desc_len[2];
-};
-
-struct scsi_mode_page_header
-{
- uint8_t page_code;
- uint8_t page_length;
-};
-
-struct scsi_mode_blk_desc
-{
- uint8_t density;
- uint8_t nblocks[3];
- uint8_t reserved;
- uint8_t blklen[3];
-};
-
-#define SCSI_DEFAULT_DENSITY 0x00 /* use 'default' density */
-#define SCSI_SAME_DENSITY 0x7f /* use 'same' density- >= SCSI-2 only */
-
-
/*
* Status Byte
*/
@@ -807,76 +132,7 @@
#define SCSI_STATUS_ACA_ACTIVE 0x30
#define SCSI_STATUS_TASK_ABORTED 0x40
-struct scsi_inquiry_pattern {
- uint8_t type;
- uint8_t media_type;
-#define SIP_MEDIA_REMOVABLE 0x01
-#define SIP_MEDIA_FIXED 0x02
- const char *vendor;
- const char *product;
- const char *revision;
-};
-
-struct scsi_static_inquiry_pattern {
- uint8_t type;
- uint8_t media_type;
- char vendor[SID_VENDOR_SIZE+1];
- char product[SID_PRODUCT_SIZE+1];
- char revision[SID_REVISION_SIZE+1];
-};
-
-struct scsi_sense_quirk_entry {
- struct scsi_inquiry_pattern inq_pat;
- int num_sense_keys;
- int num_ascs;
- struct sense_key_table_entry *sense_key_info;
- struct asc_table_entry *asc_info;
-};
-
-struct sense_key_table_entry {
- uint8_t sense_key;
- uint32_t action;
- const char *desc;
-};
-
-struct asc_table_entry {
- uint8_t asc;
- uint8_t ascq;
- uint32_t action;
- const char *desc;
-};
-
-struct op_table_entry {
- uint8_t opcode;
- uint16_t opmask;
- const char *desc;
-};
-
-struct scsi_op_quirk_entry {
- struct scsi_inquiry_pattern inq_pat;
- int num_ops;
- struct op_table_entry *op_table;
-};
-
-typedef enum {
- SSS_FLAG_NONE = 0x00,
- SSS_FLAG_PRINT_COMMAND = 0x01
-} scsi_sense_string_flags;
-
-extern const char *scsi_sense_key_text[];
-
/************************* Large Disk Handling ********************************/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static __inline int aic_sector_div(u_long capacity, int heads, int sectors);
-
-static __inline int
-aic_sector_div(u_long capacity, int heads, int sectors)
-{
- return (capacity / (heads * sectors));
-}
-#else
-static __inline int aic_sector_div(sector_t capacity, int heads, int sectors);
-
static __inline int
aic_sector_div(sector_t capacity, int heads, int sectors)
{
@@ -884,152 +140,6 @@
sector_div(capacity, (heads * sectors));
return (int)capacity;
}
-#endif
-
-/**************************** Module Library Hack *****************************/
-/*
- * What we'd like to do is have a single "scsi library" module that both the
- * aic7xxx and aic79xx drivers could load and depend on. A cursory examination
- * of implementing module dependencies in Linux (handling the install and
- * initrd cases) does not look promissing. For now, we just duplicate this
- * code in both drivers using a simple symbol renaming scheme that hides this
- * hack from the drivers.
- */
-#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x
-#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix)
-#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX)
-
-#define aic_sense_desc AIC_LIB_ENTRY(_sense_desc)
-#define aic_sense_error_action AIC_LIB_ENTRY(_sense_error_action)
-#define aic_error_action AIC_LIB_ENTRY(_error_action)
-#define aic_op_desc AIC_LIB_ENTRY(_op_desc)
-#define aic_cdb_string AIC_LIB_ENTRY(_cdb_string)
-#define aic_print_inquiry AIC_LIB_ENTRY(_print_inquiry)
-#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate)
-#define aic_calc_syncparam AIC_LIB_ENTRY(_calc_syncparam)
-#define aic_calc_speed AIC_LIB_ENTRY(_calc_speed)
-#define aic_inquiry_match AIC_LIB_ENTRY(_inquiry_match)
-#define aic_static_inquiry_match AIC_LIB_ENTRY(_static_inquiry_match)
-#define aic_parse_brace_option AIC_LIB_ENTRY(_parse_brace_option)
-
-/******************************************************************************/
-
-void aic_sense_desc(int /*sense_key*/, int /*asc*/,
- int /*ascq*/, struct scsi_inquiry_data*,
- const char** /*sense_key_desc*/,
- const char** /*asc_desc*/);
-aic_sense_action aic_sense_error_action(struct scsi_sense_data*,
- struct scsi_inquiry_data*,
- uint32_t /*sense_flags*/);
-uint32_t aic_error_action(struct scsi_cmnd *,
- struct scsi_inquiry_data *,
- cam_status, u_int);
-
-#define SF_RETRY_UA 0x01
-#define SF_NO_PRINT 0x02
-#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */
-#define SF_PRINT_ALWAYS 0x08
-
-
-const char * aic_op_desc(uint16_t /*opcode*/, struct scsi_inquiry_data*);
-char * aic_cdb_string(uint8_t* /*cdb_ptr*/, char* /*cdb_string*/,
- size_t /*len*/);
-void aic_print_inquiry(struct scsi_inquiry_data*);
-
-u_int aic_calc_syncsrate(u_int /*period_factor*/);
-u_int aic_calc_syncparam(u_int /*period*/);
-u_int aic_calc_speed(u_int width, u_int period, u_int offset,
- u_int min_rate);
-
-int aic_inquiry_match(caddr_t /*inqbuffer*/,
- caddr_t /*table_entry*/);
-int aic_static_inquiry_match(caddr_t /*inqbuffer*/,
- caddr_t /*table_entry*/);
-
-typedef void aic_option_callback_t(u_long, int, int, int32_t);
-char * aic_parse_brace_option(char *opt_name, char *opt_arg,
- char *end, int depth,
- aic_option_callback_t *, u_long);
-
-static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
- int *error_code, int *sense_key,
- int *asc, int *ascq);
-static __inline void scsi_ulto2b(uint32_t val, uint8_t *bytes);
-static __inline void scsi_ulto3b(uint32_t val, uint8_t *bytes);
-static __inline void scsi_ulto4b(uint32_t val, uint8_t *bytes);
-static __inline uint32_t scsi_2btoul(uint8_t *bytes);
-static __inline uint32_t scsi_3btoul(uint8_t *bytes);
-static __inline int32_t scsi_3btol(uint8_t *bytes);
-static __inline uint32_t scsi_4btoul(uint8_t *bytes);
-
-static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
- int *error_code, int *sense_key,
- int *asc, int *ascq)
-{
- *error_code = sense->error_code & SSD_ERRCODE;
- *sense_key = sense->flags & SSD_KEY;
- *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
- *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
-}
-
-static __inline void
-scsi_ulto2b(uint32_t val, uint8_t *bytes)
-{
-
- bytes[0] = (val >> 8) & 0xff;
- bytes[1] = val & 0xff;
-}
-
-static __inline void
-scsi_ulto3b(uint32_t val, uint8_t *bytes)
-{
-
- bytes[0] = (val >> 16) & 0xff;
- bytes[1] = (val >> 8) & 0xff;
- bytes[2] = val & 0xff;
-}
-
-static __inline void
-scsi_ulto4b(uint32_t val, uint8_t *bytes)
-{
-
- bytes[0] = (val >> 24) & 0xff;
- bytes[1] = (val >> 16) & 0xff;
- bytes[2] = (val >> 8) & 0xff;
- bytes[3] = val & 0xff;
-}
-
-static __inline uint32_t
-scsi_2btoul(uint8_t *bytes)
-{
- uint32_t rv;
-
- rv = (bytes[0] << 8) |
- bytes[1];
- return (rv);
-}
-
-static __inline uint32_t
-scsi_3btoul(uint8_t *bytes)
-{
- uint32_t rv;
-
- rv = (bytes[0] << 16) |
- (bytes[1] << 8) |
- bytes[2];
- return (rv);
-}
-
-static __inline int32_t
-scsi_3btol(uint8_t *bytes)
-{
- uint32_t rc = scsi_3btoul(bytes);
-
- if (rc & 0x00800000)
- rc |= 0xff000000;
-
- return (int32_t) rc;
-}
static __inline uint32_t
scsi_4btoul(uint8_t *bytes)
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index fb28c12..deec0ce 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -583,8 +583,7 @@
#define AHCI_ENABLE (1 << 31)
static int piix_disable_ahci(struct pci_dev *pdev)
{
- void *mmio;
- unsigned long addr;
+ void __iomem *mmio;
u32 tmp;
int rc = 0;
@@ -592,11 +591,11 @@
* works because this device is usually set up by BIOS.
*/
- addr = pci_resource_start(pdev, AHCI_PCI_BAR);
- if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR))
+ if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
+ !pci_resource_len(pdev, AHCI_PCI_BAR))
return 0;
- mmio = ioremap(addr, 64);
+ mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
if (!mmio)
return -ENOMEM;
@@ -610,7 +609,7 @@
rc = -EIO;
}
- iounmap(mmio);
+ pci_iounmap(pdev, mmio);
return rc;
}
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 3900e28..bd0e1b6 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -20,7 +20,6 @@
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/chio.h> /* here are all the ioctls */
@@ -31,7 +30,7 @@
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
-#include <scsi/scsi_request.h>
+#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
#define CH_DT_MAX 16
@@ -181,17 +180,17 @@
/* ------------------------------------------------------------------- */
-static int ch_find_errno(unsigned char *sense_buffer)
+static int ch_find_errno(struct scsi_sense_hdr *sshdr)
{
int i,errno = 0;
/* Check to see if additional sense information is available */
- if (sense_buffer[7] > 5 &&
- sense_buffer[12] != 0) {
+ if (scsi_sense_valid(sshdr) &&
+ sshdr->asc != 0) {
for (i = 0; err[i].errno != 0; i++) {
- if (err[i].sense == sense_buffer[ 2] &&
- err[i].asc == sense_buffer[12] &&
- err[i].ascq == sense_buffer[13]) {
+ if (err[i].sense == sshdr->sense_key &&
+ err[i].asc == sshdr->asc &&
+ err[i].ascq == sshdr->ascq) {
errno = -err[i].errno;
break;
}
@@ -207,13 +206,9 @@
void *buffer, unsigned buflength,
enum dma_data_direction direction)
{
- int errno, retries = 0, timeout;
- struct scsi_request *sr;
+ int errno, retries = 0, timeout, result;
+ struct scsi_sense_hdr sshdr;
- sr = scsi_allocate_request(ch->device, GFP_KERNEL);
- if (NULL == sr)
- return -ENOMEM;
-
timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
? timeout_init : timeout_move;
@@ -224,16 +219,17 @@
__scsi_print_command(cmd);
}
- scsi_wait_req(sr, cmd, buffer, buflength,
- timeout * HZ, MAX_RETRIES);
+ result = scsi_execute_req(ch->device, cmd, direction, buffer,
+ buflength, &sshdr, timeout * HZ,
+ MAX_RETRIES);
- dprintk("result: 0x%x\n",sr->sr_result);
- if (driver_byte(sr->sr_result) & DRIVER_SENSE) {
+ dprintk("result: 0x%x\n",result);
+ if (driver_byte(result) & DRIVER_SENSE) {
if (debug)
- scsi_print_req_sense(ch->name, sr);
- errno = ch_find_errno(sr->sr_sense_buffer);
+ scsi_print_sense_hdr(ch->name, &sshdr);
+ errno = ch_find_errno(&sshdr);
- switch(sr->sr_sense_buffer[2] & 0xf) {
+ switch(sshdr.sense_key) {
case UNIT_ATTENTION:
ch->unit_attention = 1;
if (retries++ < 3)
@@ -241,7 +237,6 @@
break;
}
}
- scsi_release_request(sr);
return errno;
}
@@ -940,8 +935,6 @@
if (init)
ch_init_elem(ch);
- devfs_mk_cdev(MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
- S_IFCHR | S_IRUGO | S_IWUGO, ch->name);
class_device_create(ch_sysfs_class,
MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
dev, "s%s", ch->name);
@@ -974,7 +967,6 @@
class_device_destroy(ch_sysfs_class,
MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
- devfs_remove(ch->name);
kfree(ch->dt);
kfree(ch);
ch_devcount--;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index ec16173..f6be2c1 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -17,6 +17,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dbg.h>
@@ -1155,6 +1156,31 @@
}
}
+void
+scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+{
+ const char *sense_txt;
+ /* An example of deferred is when an earlier write to disk cache
+ * succeeded, but now the disk discovers that it cannot write the
+ * data to the magnetic media.
+ */
+ const char *error = scsi_sense_is_deferred(sshdr) ?
+ "<<DEFERRED>>" : "Current";
+ printk(KERN_INFO "%s: %s", name, error);
+ if (sshdr->response_code >= 0x72)
+ printk(" [descriptor]");
+
+ sense_txt = scsi_sense_key_string(sshdr->sense_key);
+ if (sense_txt)
+ printk(": sense key: %s\n", sense_txt);
+ else
+ printk(": sense key=0x%x\n", sshdr->sense_key);
+ printk(KERN_INFO " ");
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+ printk("\n");
+}
+EXPORT_SYMBOL(scsi_print_sense_hdr);
+
/* Print sense information */
void
__scsi_print_sense(const char *name, const unsigned char *sense_buffer,
@@ -1162,8 +1188,6 @@
{
int k, num, res;
unsigned int info;
- const char *error;
- const char *sense_txt;
struct scsi_sense_hdr ssh;
res = scsi_normalize_sense(sense_buffer, sense_len, &ssh);
@@ -1181,26 +1205,7 @@
printk("\n");
return;
}
-
- /* An example of deferred is when an earlier write to disk cache
- * succeeded, but now the disk discovers that it cannot write the
- * data to the magnetic media.
- */
- error = scsi_sense_is_deferred(&ssh) ?
- "<<DEFERRED>>" : "Current";
- printk(KERN_INFO "%s: %s", name, error);
- if (ssh.response_code >= 0x72)
- printk(" [descriptor]");
-
- sense_txt = scsi_sense_key_string(ssh.sense_key);
- if (sense_txt)
- printk(": sense key: %s\n", sense_txt);
- else
- printk(": sense key=0x%x\n", ssh.sense_key);
- printk(KERN_INFO " ");
- scsi_show_extd_sense(ssh.asc, ssh.ascq);
- printk("\n");
-
+ scsi_print_sense_hdr(name, &ssh);
if (ssh.response_code < 0x72) {
/* only decode extras for "fixed" format now */
char buff[80];
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 5feb886..85503fa 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/init.h>
@@ -52,21 +53,80 @@
};
/**
- * scsi_host_cancel - cancel outstanding IO to this host
- * @shost: pointer to struct Scsi_Host
- * recovery: recovery requested to run.
+ * scsi_host_set_state - Take the given host through the host
+ * state model.
+ * @shost: scsi host to change the state of.
+ * @state: state to change to.
+ *
+ * Returns zero if unsuccessful or an error if the requested
+ * transition is illegal.
**/
-static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
+int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
{
- struct scsi_device *sdev;
+ enum scsi_host_state oldstate = shost->shost_state;
- set_bit(SHOST_CANCEL, &shost->shost_state);
- shost_for_each_device(sdev, shost) {
- scsi_device_cancel(sdev, recovery);
+ if (state == oldstate)
+ return 0;
+
+ switch (state) {
+ case SHOST_CREATED:
+ /* There are no legal states that come back to
+ * created. This is the manually initialised start
+ * state */
+ goto illegal;
+
+ case SHOST_RUNNING:
+ switch (oldstate) {
+ case SHOST_CREATED:
+ case SHOST_RECOVERY:
+ break;
+ default:
+ goto illegal;
+ }
+ break;
+
+ case SHOST_RECOVERY:
+ switch (oldstate) {
+ case SHOST_RUNNING:
+ break;
+ default:
+ goto illegal;
+ }
+ break;
+
+ case SHOST_CANCEL:
+ switch (oldstate) {
+ case SHOST_CREATED:
+ case SHOST_RUNNING:
+ break;
+ default:
+ goto illegal;
+ }
+ break;
+
+ case SHOST_DEL:
+ switch (oldstate) {
+ case SHOST_CANCEL:
+ break;
+ default:
+ goto illegal;
+ }
+ break;
+
}
- wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY,
- &shost->shost_state)));
+ shost->shost_state = state;
+ return 0;
+
+ illegal:
+ SCSI_LOG_ERROR_RECOVERY(1,
+ dev_printk(KERN_ERR, &shost->shost_gendev,
+ "Illegal host state transition"
+ "%s->%s\n",
+ scsi_host_state_name(oldstate),
+ scsi_host_state_name(state)));
+ return -EINVAL;
}
+EXPORT_SYMBOL(scsi_host_set_state);
/**
* scsi_remove_host - remove a scsi host
@@ -74,11 +134,13 @@
**/
void scsi_remove_host(struct Scsi_Host *shost)
{
+ down(&shost->scan_mutex);
+ scsi_host_set_state(shost, SHOST_CANCEL);
+ up(&shost->scan_mutex);
scsi_forget_host(shost);
- scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost);
- set_bit(SHOST_DEL, &shost->shost_state);
+ scsi_host_set_state(shost, SHOST_DEL);
transport_unregister_device(&shost->shost_gendev);
class_device_unregister(&shost->shost_classdev);
@@ -115,7 +177,7 @@
if (error)
goto out;
- set_bit(SHOST_ADD, &shost->shost_state);
+ scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev);
@@ -164,15 +226,8 @@
struct Scsi_Host *shost = dev_to_shost(dev);
struct device *parent = dev->parent;
- if (shost->ehandler) {
- DECLARE_COMPLETION(sem);
- shost->eh_notify = &sem;
- shost->eh_kill = 1;
- up(shost->eh_wait);
- wait_for_completion(&sem);
- shost->eh_notify = NULL;
- }
-
+ if (shost->ehandler)
+ kthread_stop(shost->ehandler);
if (shost->work_q)
destroy_workqueue(shost->work_q);
@@ -202,7 +257,6 @@
{
struct Scsi_Host *shost;
int gfp_mask = GFP_KERNEL, rval;
- DECLARE_COMPLETION(complete);
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
@@ -226,6 +280,7 @@
spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock);
+ shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets);
INIT_LIST_HEAD(&shost->eh_cmd_q);
@@ -307,12 +362,12 @@
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
- shost->eh_notify = &complete;
- rval = kernel_thread(scsi_error_handler, shost, 0);
- if (rval < 0)
+ shost->ehandler = kthread_run(scsi_error_handler, shost,
+ "scsi_eh_%d", shost->host_no);
+ if (IS_ERR(shost->ehandler)) {
+ rval = PTR_ERR(shost->ehandler);
goto fail_destroy_freelist;
- wait_for_completion(&complete);
- shost->eh_notify = NULL;
+ }
scsi_proc_hostdir_add(shost->hostt);
return shost;
@@ -382,7 +437,7 @@
**/
struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
{
- if (test_bit(SHOST_DEL, &shost->shost_state) ||
+ if ((shost->shost_state == SHOST_DEL) ||
!get_device(&shost->shost_gendev))
return NULL;
return shost;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 2cb3c83..5b14934 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -87,7 +87,7 @@
static int init_timeout = 5;
static int max_requests = 50;
-#define IBMVSCSI_VERSION "1.5.6"
+#define IBMVSCSI_VERSION "1.5.7"
MODULE_DESCRIPTION("IBM Virtual SCSI");
MODULE_AUTHOR("Dave Boutcher");
@@ -145,6 +145,8 @@
sizeof(*evt->xfer_iu) * i;
evt->xfer_iu = pool->iu_storage + i;
evt->hostdata = hostdata;
+ evt->ext_list = NULL;
+ evt->ext_list_token = 0;
}
return 0;
@@ -161,9 +163,16 @@
struct ibmvscsi_host_data *hostdata)
{
int i, in_use = 0;
- for (i = 0; i < pool->size; ++i)
+ for (i = 0; i < pool->size; ++i) {
if (atomic_read(&pool->events[i].free) != 1)
++in_use;
+ if (pool->events[i].ext_list) {
+ dma_free_coherent(hostdata->dev,
+ SG_ALL * sizeof(struct memory_descriptor),
+ pool->events[i].ext_list,
+ pool->events[i].ext_list_token);
+ }
+ }
if (in_use)
printk(KERN_WARNING
"ibmvscsi: releasing event pool with %d "
@@ -286,24 +295,41 @@
} else {
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
srp_cmd->data_out_format = SRP_INDIRECT_BUFFER;
- srp_cmd->data_out_count = numbuf;
+ srp_cmd->data_out_count =
+ numbuf < MAX_INDIRECT_BUFS ?
+ numbuf: MAX_INDIRECT_BUFS;
} else {
srp_cmd->data_in_format = SRP_INDIRECT_BUFFER;
- srp_cmd->data_in_count = numbuf;
+ srp_cmd->data_in_count =
+ numbuf < MAX_INDIRECT_BUFS ?
+ numbuf: MAX_INDIRECT_BUFS;
}
}
}
+static void unmap_sg_list(int num_entries,
+ struct device *dev,
+ struct memory_descriptor *md)
+{
+ int i;
+
+ for (i = 0; i < num_entries; ++i) {
+ dma_unmap_single(dev,
+ md[i].virtual_address,
+ md[i].length, DMA_BIDIRECTIONAL);
+ }
+}
+
/**
* unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
* @cmd: srp_cmd whose additional_data member will be unmapped
* @dev: device for which the memory is mapped
*
*/
-static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev)
+static void unmap_cmd_data(struct srp_cmd *cmd,
+ struct srp_event_struct *evt_struct,
+ struct device *dev)
{
- int i;
-
if ((cmd->data_out_format == SRP_NO_BUFFER) &&
(cmd->data_in_format == SRP_NO_BUFFER))
return;
@@ -318,15 +344,34 @@
(struct indirect_descriptor *)cmd->additional_data;
int num_mapped = indirect->head.length /
sizeof(indirect->list[0]);
- for (i = 0; i < num_mapped; ++i) {
- struct memory_descriptor *data = &indirect->list[i];
- dma_unmap_single(dev,
- data->virtual_address,
- data->length, DMA_BIDIRECTIONAL);
+
+ if (num_mapped <= MAX_INDIRECT_BUFS) {
+ unmap_sg_list(num_mapped, dev, &indirect->list[0]);
+ return;
}
+
+ unmap_sg_list(num_mapped, dev, evt_struct->ext_list);
}
}
+static int map_sg_list(int num_entries,
+ struct scatterlist *sg,
+ struct memory_descriptor *md)
+{
+ int i;
+ u64 total_length = 0;
+
+ for (i = 0; i < num_entries; ++i) {
+ struct memory_descriptor *descr = md + i;
+ struct scatterlist *sg_entry = &sg[i];
+ descr->virtual_address = sg_dma_address(sg_entry);
+ descr->length = sg_dma_len(sg_entry);
+ descr->memory_handle = 0;
+ total_length += sg_dma_len(sg_entry);
+ }
+ return total_length;
+}
+
/**
* map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields
* @cmd: Scsi_Cmnd with the scatterlist
@@ -337,10 +382,11 @@
* Returns 1 on success.
*/
static int map_sg_data(struct scsi_cmnd *cmd,
+ struct srp_event_struct *evt_struct,
struct srp_cmd *srp_cmd, struct device *dev)
{
- int i, sg_mapped;
+ int sg_mapped;
u64 total_length = 0;
struct scatterlist *sg = cmd->request_buffer;
struct memory_descriptor *data =
@@ -363,27 +409,46 @@
return 1;
}
- if (sg_mapped > MAX_INDIRECT_BUFS) {
+ if (sg_mapped > SG_ALL) {
printk(KERN_ERR
"ibmvscsi: More than %d mapped sg entries, got %d\n",
- MAX_INDIRECT_BUFS, sg_mapped);
+ SG_ALL, sg_mapped);
return 0;
}
indirect->head.virtual_address = 0;
indirect->head.length = sg_mapped * sizeof(indirect->list[0]);
indirect->head.memory_handle = 0;
- for (i = 0; i < sg_mapped; ++i) {
- struct memory_descriptor *descr = &indirect->list[i];
- struct scatterlist *sg_entry = &sg[i];
- descr->virtual_address = sg_dma_address(sg_entry);
- descr->length = sg_dma_len(sg_entry);
- descr->memory_handle = 0;
- total_length += sg_dma_len(sg_entry);
- }
- indirect->total_length = total_length;
- return 1;
+ if (sg_mapped <= MAX_INDIRECT_BUFS) {
+ total_length = map_sg_list(sg_mapped, sg, &indirect->list[0]);
+ indirect->total_length = total_length;
+ return 1;
+ }
+
+ /* get indirect table */
+ if (!evt_struct->ext_list) {
+ evt_struct->ext_list =(struct memory_descriptor*)
+ dma_alloc_coherent(dev,
+ SG_ALL * sizeof(struct memory_descriptor),
+ &evt_struct->ext_list_token, 0);
+ if (!evt_struct->ext_list) {
+ printk(KERN_ERR
+ "ibmvscsi: Can't allocate memory for indirect table\n");
+ return 0;
+
+ }
+ }
+
+ total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list);
+
+ indirect->total_length = total_length;
+ indirect->head.virtual_address = evt_struct->ext_list_token;
+ indirect->head.length = sg_mapped * sizeof(indirect->list[0]);
+ memcpy(indirect->list, evt_struct->ext_list,
+ MAX_INDIRECT_BUFS * sizeof(struct memory_descriptor));
+
+ return 1;
}
/**
@@ -428,6 +493,7 @@
* Returns 1 on success.
*/
static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
+ struct srp_event_struct *evt_struct,
struct srp_cmd *srp_cmd, struct device *dev)
{
switch (cmd->sc_data_direction) {
@@ -450,7 +516,7 @@
if (!cmd->request_buffer)
return 1;
if (cmd->use_sg)
- return map_sg_data(cmd, srp_cmd, dev);
+ return map_sg_data(cmd, evt_struct, srp_cmd, dev);
return map_single_data(cmd, srp_cmd, dev);
}
@@ -486,6 +552,7 @@
printk(KERN_WARNING
"ibmvscsi: Warning, request_limit exceeded\n");
unmap_cmd_data(&evt_struct->iu.srp.cmd,
+ evt_struct,
hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
@@ -513,7 +580,7 @@
return 0;
send_error:
- unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev);
+ unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
if ((cmnd = evt_struct->cmnd) != NULL) {
cmnd->result = DID_ERROR << 16;
@@ -551,6 +618,7 @@
rsp->sense_and_response_data,
rsp->sense_data_list_length);
unmap_cmd_data(&evt_struct->iu.srp.cmd,
+ evt_struct,
evt_struct->hostdata->dev);
if (rsp->doover)
@@ -583,6 +651,7 @@
{
struct srp_cmd *srp_cmd;
struct srp_event_struct *evt_struct;
+ struct indirect_descriptor *indirect;
struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
u16 lun = lun_from_dev(cmnd->device);
@@ -591,14 +660,6 @@
if (!evt_struct)
return SCSI_MLQUEUE_HOST_BUSY;
- init_event_struct(evt_struct,
- handle_cmd_rsp,
- VIOSRP_SRP_FORMAT,
- cmnd->timeout);
-
- evt_struct->cmnd = cmnd;
- evt_struct->cmnd_done = done;
-
/* Set up the actual SRP IU */
srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, sizeof(*srp_cmd));
@@ -606,17 +667,25 @@
memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
srp_cmd->lun = ((u64) lun) << 48;
- if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) {
+ if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
}
+ init_event_struct(evt_struct,
+ handle_cmd_rsp,
+ VIOSRP_SRP_FORMAT,
+ cmnd->timeout_per_command/HZ);
+
+ evt_struct->cmnd = cmnd;
+ evt_struct->cmnd_done = done;
+
/* Fix up dma address of the buffer itself */
- if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) ||
- (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) {
- struct indirect_descriptor *indirect =
- (struct indirect_descriptor *)srp_cmd->additional_data;
+ indirect = (struct indirect_descriptor *)srp_cmd->additional_data;
+ if (((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) ||
+ (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) &&
+ (indirect->head.virtual_address == 0)) {
indirect->head.virtual_address = evt_struct->crq.IU_data_ptr +
offsetof(struct srp_cmd, additional_data) +
offsetof(struct indirect_descriptor, list);
@@ -826,11 +895,13 @@
struct srp_event_struct *tmp_evt, *found_evt;
union viosrp_iu srp_rsp;
int rsp_rc;
+ unsigned long flags;
u16 lun = lun_from_dev(cmd->device);
/* First, find this command in our sent list so we can figure
* out the correct tag
*/
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
found_evt = NULL;
list_for_each_entry(tmp_evt, &hostdata->sent, list) {
if (tmp_evt->cmnd == cmd) {
@@ -839,11 +910,14 @@
}
}
- if (!found_evt)
+ if (!found_evt) {
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
return FAILED;
+ }
evt = get_event_struct(&hostdata->pool);
if (evt == NULL) {
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n");
return FAILED;
}
@@ -867,7 +941,9 @@
evt->sync_srp = &srp_rsp;
init_completion(&evt->comp);
- if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
+ rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+ if (rsp_rc != 0) {
printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
return FAILED;
}
@@ -901,6 +977,7 @@
* The event is no longer in our list. Make sure it didn't
* complete while we were aborting
*/
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
found_evt = NULL;
list_for_each_entry(tmp_evt, &hostdata->sent, list) {
if (tmp_evt->cmnd == cmd) {
@@ -910,6 +987,7 @@
}
if (found_evt == NULL) {
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
printk(KERN_INFO
"ibmvscsi: aborted task tag 0x%lx completed\n",
tsk_mgmt->managed_task_tag);
@@ -922,8 +1000,10 @@
cmd->result = (DID_ABORT << 16);
list_del(&found_evt->list);
- unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev);
+ unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt,
+ found_evt->hostdata->dev);
free_event_struct(&found_evt->hostdata->pool, found_evt);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
atomic_inc(&hostdata->request_limit);
return SUCCESS;
}
@@ -943,10 +1023,13 @@
struct srp_event_struct *tmp_evt, *pos;
union viosrp_iu srp_rsp;
int rsp_rc;
+ unsigned long flags;
u16 lun = lun_from_dev(cmd->device);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
evt = get_event_struct(&hostdata->pool);
if (evt == NULL) {
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n");
return FAILED;
}
@@ -969,7 +1052,9 @@
evt->sync_srp = &srp_rsp;
init_completion(&evt->comp);
- if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
+ rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+ if (rsp_rc != 0) {
printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
return FAILED;
}
@@ -1002,12 +1087,14 @@
/* We need to find all commands for this LUN that have not yet been
* responded to, and fail them with DID_RESET
*/
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
if (tmp_evt->cmnd)
tmp_evt->cmnd->result = (DID_RESET << 16);
list_del(&tmp_evt->list);
- unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev);
+ unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt,
+ tmp_evt->hostdata->dev);
free_event_struct(&tmp_evt->hostdata->pool,
tmp_evt);
atomic_inc(&hostdata->request_limit);
@@ -1017,6 +1104,7 @@
tmp_evt->done(tmp_evt);
}
}
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
return SUCCESS;
}
@@ -1035,6 +1123,7 @@
if (tmp_evt->cmnd) {
tmp_evt->cmnd->result = (DID_ERROR << 16);
unmap_cmd_data(&tmp_evt->iu.srp.cmd,
+ tmp_evt,
tmp_evt->hostdata->dev);
if (tmp_evt->cmnd_done)
tmp_evt->cmnd_done(tmp_evt->cmnd);
@@ -1339,7 +1428,7 @@
.cmd_per_lun = 16,
.can_queue = 1, /* Updated after SRP_LOGIN */
.this_id = -1,
- .sg_tablesize = MAX_INDIRECT_BUFS,
+ .sg_tablesize = SG_ALL,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = ibmvscsi_attrs,
};
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 1030b70..8bec043 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -68,6 +68,8 @@
void (*cmnd_done) (struct scsi_cmnd *);
struct completion comp;
union viosrp_iu *sync_srp;
+ struct memory_descriptor *ext_list;
+ dma_addr_t ext_list_token;
};
/* a pool of event structs for use */
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index a872fad..62095bd 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -76,6 +76,10 @@
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
+int atapi_enabled = 0;
+module_param(atapi_enabled, int, 0444);
+MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
MODULE_LICENSE("GPL");
@@ -2613,7 +2617,7 @@
* @ap: port to read/write
* @buf: data buffer
* @buflen: buffer length
- * @do_write: read/write
+ * @write_data: read/write
*
* Transfer data from/to the device data register by MMIO.
*
@@ -2659,7 +2663,7 @@
* @ap: port to read/write
* @buf: data buffer
* @buflen: buffer length
- * @do_write: read/write
+ * @write_data: read/write
*
* Transfer data from/to the device data register by PIO.
*
@@ -4290,6 +4294,15 @@
+#ifdef CONFIG_PCI
+
+void ata_pci_host_stop (struct ata_host_set *host_set)
+{
+ struct pci_dev *pdev = to_pci_dev(host_set->dev);
+
+ pci_iounmap(pdev, host_set->mmio_base);
+}
+
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
@@ -4302,7 +4315,6 @@
* ata_probe_ent structure should then be freed with kfree().
*/
-#ifdef CONFIG_PCI
struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
{
@@ -4685,6 +4697,7 @@
#ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
+EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index f8ddc2a..03b7a6d 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1537,10 +1537,10 @@
if (unlikely(!ata_dev_present(dev)))
return NULL;
-#ifndef ATA_ENABLE_ATAPI
- if (unlikely(dev->class == ATA_DEV_ATAPI))
- return NULL;
-#endif
+ if (!atapi_enabled) {
+ if (unlikely(dev->class == ATA_DEV_ATAPI))
+ return NULL;
+ }
return dev;
}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 809c634a..d608b3a 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -38,6 +38,7 @@
};
/* libata-core.c */
+extern int atapi_enabled;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
extern void ata_qc_free(struct ata_queued_cmd *qc);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 3bb82aa..adb9567 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -342,9 +342,6 @@
#define VPD_MASK 0xf /* mask for any vpd data */
struct timer_list els_tmofunc;
-
- void *link_stats;
-
/*
* stat counters
*/
@@ -370,6 +367,8 @@
struct list_head freebufList;
struct list_head ctrspbuflist;
struct list_head rnidrspbuflist;
+
+ struct fc_host_statistics link_stats;
};
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 3cea928..0e089a4 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -23,6 +23,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
@@ -988,8 +989,7 @@
{
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
struct lpfc_sli *psli = &phba->sli;
- struct fc_host_statistics *hs =
- (struct fc_host_statistics *)phba->link_stats;
+ struct fc_host_statistics *hs = &phba->link_stats;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
int rc=0;
@@ -1020,6 +1020,8 @@
return NULL;
}
+ memset(hs, 0, sizeof (struct fc_host_statistics));
+
hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt;
hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256);
hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt;
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 78adee4..1280f0e 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -27,8 +27,10 @@
#include <linux/interrupt.h>
#include <linux/utsname.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
#include "lpfc_hw.h"
#include "lpfc_sli.h"
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 2b1c957..63caf7f 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -23,6 +23,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 233901e..0a8269d 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -24,6 +24,7 @@
#include <linux/kthread.h>
#include <linux/interrupt.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
@@ -1135,6 +1136,8 @@
switch(list) {
case NLP_NO_LIST: /* No list, just remove it */
lpfc_nlp_remove(phba, nlp);
+ /* as node removed - stop further transport calls */
+ rport_del = none;
break;
case NLP_UNUSED_LIST:
spin_lock_irq(phba->host->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 34d416d..6f3cb59 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
@@ -1339,14 +1340,12 @@
if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
goto out_disable_device;
- host = scsi_host_alloc(&lpfc_template,
- sizeof (struct lpfc_hba) + sizeof (unsigned long));
+ host = scsi_host_alloc(&lpfc_template, sizeof (struct lpfc_hba));
if (!host)
goto out_release_regions;
phba = (struct lpfc_hba*)host->hostdata;
memset(phba, 0, sizeof (struct lpfc_hba));
- phba->link_stats = (void *)&phba[1];
phba->host = host;
phba->fc_flag |= FC_LOADING;
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index c27cf94..73eb89f 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -23,6 +23,11 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include <scsi/scsi.h>
+
#include "lpfc_hw.h"
#include "lpfc_sli.h"
#include "lpfc_disc.h"
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index a5cfb64..0aba13c 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -23,6 +23,11 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include <scsi/scsi.h>
+
#include "lpfc_hw.h"
#include "lpfc_sli.h"
#include "lpfc_disc.h"
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 45dc021..9b35eaa 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -23,6 +23,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 17e4974..b5ad187 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -40,11 +40,6 @@
#define LPFC_RESET_WAIT 2
#define LPFC_ABORT_WAIT 2
-static inline void lpfc_put_lun(struct fcp_cmnd *fcmd, unsigned int lun)
-{
- fcmd->fcpLunLsl = 0;
- fcmd->fcpLunMsl = swab16((uint16_t)lun);
-}
/*
* This routine allocates a scsi buffer, which contains all the necessary
@@ -238,6 +233,8 @@
bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen;
if (datadir == DMA_TO_DEVICE)
bpl->tus.f.bdeFlags = 0;
+ else
+ bpl->tus.f.bdeFlags = BUFF_USE_RCV;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
num_bde = 1;
bpl++;
@@ -245,8 +242,11 @@
/*
* Finish initializing those IOCB fields that are dependent on the
- * scsi_cmnd request_buffer
+ * scsi_cmnd request_buffer. Note that the bdeSize is explicitly
+ * reinitialized since all iocb memory resources are used many times
+ * for transmit, receive, and continuation bpl's.
*/
+ iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
iocb_cmd->un.fcpi64.bdl.bdeSize +=
(num_bde * sizeof (struct ulp_bde64));
iocb_cmd->ulpBdeCount = 1;
@@ -445,8 +445,11 @@
int datadir = scsi_cmnd->sc_data_direction;
lpfc_cmd->fcp_rsp->rspSnsLen = 0;
+ /* clear task management bits */
+ lpfc_cmd->fcp_cmnd->fcpCntl2 = 0;
- lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun);
+ int_to_scsilun(lpfc_cmd->pCmd->device->lun,
+ &lpfc_cmd->fcp_cmnd->fcp_lun);
memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16);
@@ -545,7 +548,8 @@
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
- lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun);
+ int_to_scsilun(lpfc_cmd->pCmd->device->lun,
+ &lpfc_cmd->fcp_cmnd->fcp_lun);
fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
piocb->ulpCommand = CMD_FCP_ICMND64_CR;
@@ -746,6 +750,10 @@
cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
goto out_fail_command;
}
+ else if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+ cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
+ goto out_fail_command;
+ }
/*
* The device is most likely recovered and the driver
* needs a bit more time to finish. Ask the midlayer
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 0fd9ba1..acd64c4 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -78,18 +78,7 @@
};
struct fcp_cmnd {
- uint32_t fcpLunMsl; /* most significant lun word (32 bits) */
- uint32_t fcpLunLsl; /* least significant lun word (32 bits) */
- /* # of bits to shift lun id to end up in right
- * payload word, little endian = 8, big = 16.
- */
-#ifdef __BIG_ENDIAN
-#define FC_LUN_SHIFT 16
-#define FC_ADDR_MODE_SHIFT 24
-#else /* __LITTLE_ENDIAN */
-#define FC_LUN_SHIFT 8
-#define FC_ADDR_MODE_SHIFT 0
-#endif
+ struct scsi_lun fcp_lun;
uint8_t fcpCntl0; /* FCP_CNTL byte 0 (reserved) */
uint8_t fcpCntl1; /* FCP_CNTL byte 1 task codes */
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 1775508..e74e224 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -24,9 +24,11 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
#include "lpfc_hw.h"
#include "lpfc_sli.h"
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 47dea48..7e6747b 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.0.29"
+#define LPFC_DRIVER_VERSION "8.0.30"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index ff19332..a4857db 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1766,7 +1766,7 @@
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
unsigned long flags;
- if (state == mdev->ofdev.dev.power.power_state || state < 2)
+ if (state.event == mdev->ofdev.dev.power.power_state.event || state.event < 2)
return 0;
scsi_block_requests(ms->host);
@@ -1791,7 +1791,7 @@
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
unsigned long flags;
- if (mdev->ofdev.dev.power.power_state == 0)
+ if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
return 0;
set_mesh_power(ms, 1);
@@ -1802,7 +1802,7 @@
enable_irq(ms->meshintr);
scsi_unblock_requests(ms->host);
- mdev->ofdev.dev.power.power_state = 0;
+ mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
return 0;
}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index b993652..637fb65 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -996,7 +996,6 @@
break;
case ABORT_DEVICE:
- ha->flags.in_reset = 1;
if (qla1280_verbose)
printk(KERN_INFO
"scsi(%ld:%d:%d:%d): Queueing abort device "
@@ -1010,7 +1009,6 @@
printk(KERN_INFO
"scsi(%ld:%d:%d:%d): Queueing device reset "
"command.\n", ha->host_no, bus, target, lun);
- ha->flags.in_reset = 1;
if (qla1280_device_reset(ha, bus, target) == 0)
result = SUCCESS;
break;
@@ -1019,7 +1017,6 @@
if (qla1280_verbose)
printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS "
"DEVICE RESET\n", ha->host_no, bus);
- ha->flags.in_reset = 1;
if (qla1280_bus_reset(ha, bus == 0))
result = SUCCESS;
@@ -1047,7 +1044,6 @@
if (!list_empty(&ha->done_q))
qla1280_done(ha);
- ha->flags.in_reset = 0;
/* If we didn't manage to issue the action, or we have no
* command to wait for, exit here */
@@ -1269,6 +1265,22 @@
return qla1280_biosparam(disk->device, NULL, disk->capacity, geom);
}
#endif
+
+/* disable risc and host interrupts */
+static inline void
+qla1280_disable_intrs(struct scsi_qla_host *ha)
+{
+ WRT_REG_WORD(&ha->iobase->ictrl, 0);
+ RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */
+}
+
+/* enable risc and host interrupts */
+static inline void
+qla1280_enable_intrs(struct scsi_qla_host *ha)
+{
+ WRT_REG_WORD(&ha->iobase->ictrl, (ISP_EN_INT | ISP_EN_RISC));
+ RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */
+}
/**************************************************************************
* qla1280_intr_handler
@@ -1290,7 +1302,7 @@
ha->isr_count++;
reg = ha->iobase;
- WRT_REG_WORD(®->ictrl, 0); /* disable our interrupt. */
+ qla1280_disable_intrs(ha);
data = qla1280_debounce_register(®->istatus);
/* Check for pending interrupts. */
@@ -1303,8 +1315,7 @@
spin_unlock(HOST_LOCK);
- /* enable our interrupt. */
- WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC));
+ qla1280_enable_intrs(ha);
LEAVE_INTR("qla1280_intr_handler");
return IRQ_RETVAL(handled);
@@ -1317,7 +1328,7 @@
uint8_t mr;
uint16_t mb[MAILBOX_REGISTER_COUNT];
struct nvram *nv;
- int status;
+ int status, lun;
nv = &ha->nvram;
@@ -1325,24 +1336,38 @@
/* Set Target Parameters. */
mb[0] = MBC_SET_TARGET_PARAMETERS;
- mb[1] = (uint16_t) (bus ? target | BIT_7 : target);
- mb[1] <<= 8;
-
- mb[2] = (nv->bus[bus].target[target].parameter.c << 8);
+ mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8);
+ mb[2] = nv->bus[bus].target[target].parameter.renegotiate_on_error << 8;
+ mb[2] |= nv->bus[bus].target[target].parameter.stop_queue_on_check << 9;
+ mb[2] |= nv->bus[bus].target[target].parameter.auto_request_sense << 10;
+ mb[2] |= nv->bus[bus].target[target].parameter.tag_queuing << 11;
+ mb[2] |= nv->bus[bus].target[target].parameter.enable_sync << 12;
+ mb[2] |= nv->bus[bus].target[target].parameter.enable_wide << 13;
+ mb[2] |= nv->bus[bus].target[target].parameter.parity_checking << 14;
+ mb[2] |= nv->bus[bus].target[target].parameter.disconnect_allowed << 15;
if (IS_ISP1x160(ha)) {
mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5;
- mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) |
- nv->bus[bus].target[target].sync_period;
+ mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8);
mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) |
nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width;
mr |= BIT_6;
} else {
- mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) |
- nv->bus[bus].target[target].sync_period;
+ mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8);
}
+ mb[3] |= nv->bus[bus].target[target].sync_period;
- status = qla1280_mailbox_command(ha, mr, &mb[0]);
+ status = qla1280_mailbox_command(ha, mr, mb);
+
+ /* Set Device Queue Parameters. */
+ for (lun = 0; lun < MAX_LUNS; lun++) {
+ mb[0] = MBC_SET_DEVICE_QUEUE;
+ mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8);
+ mb[1] |= lun;
+ mb[2] = nv->bus[bus].max_queue_depth;
+ mb[3] = nv->bus[bus].target[target].execution_throttle;
+ status |= qla1280_mailbox_command(ha, 0x0f, mb);
+ }
if (status)
printk(KERN_WARNING "scsi(%ld:%i:%i): "
@@ -1389,19 +1414,19 @@
}
#if LINUX_VERSION_CODE > 0x020500
- nv->bus[bus].target[target].parameter.f.enable_sync = device->sdtr;
- nv->bus[bus].target[target].parameter.f.enable_wide = device->wdtr;
+ nv->bus[bus].target[target].parameter.enable_sync = device->sdtr;
+ nv->bus[bus].target[target].parameter.enable_wide = device->wdtr;
nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr;
#endif
if (driver_setup.no_sync ||
(driver_setup.sync_mask &&
(~driver_setup.sync_mask & (1 << target))))
- nv->bus[bus].target[target].parameter.f.enable_sync = 0;
+ nv->bus[bus].target[target].parameter.enable_sync = 0;
if (driver_setup.no_wide ||
(driver_setup.wide_mask &&
(~driver_setup.wide_mask & (1 << target))))
- nv->bus[bus].target[target].parameter.f.enable_wide = 0;
+ nv->bus[bus].target[target].parameter.enable_wide = 0;
if (IS_ISP1x160(ha)) {
if (driver_setup.no_ppr ||
(driver_setup.ppr_mask &&
@@ -1410,7 +1435,7 @@
}
spin_lock_irqsave(HOST_LOCK, flags);
- if (nv->bus[bus].target[target].parameter.f.enable_sync)
+ if (nv->bus[bus].target[target].parameter.enable_sync)
status = qla1280_set_target_parameters(ha, bus, target);
qla1280_get_target_parameters(ha, device);
spin_unlock_irqrestore(HOST_LOCK, flags);
@@ -1448,7 +1473,6 @@
*
* Input:
* ha = adapter block pointer.
- * done_q = done queue.
*/
static void
qla1280_done(struct scsi_qla_host *ha)
@@ -1522,7 +1546,7 @@
int host_status = DID_ERROR;
uint16_t comp_status = le16_to_cpu(sts->comp_status);
uint16_t state_flags = le16_to_cpu(sts->state_flags);
- uint16_t residual_length = le16_to_cpu(sts->residual_length);
+ uint16_t residual_length = le32_to_cpu(sts->residual_length);
uint16_t scsi_status = le16_to_cpu(sts->scsi_status);
#if DEBUG_QLA1280_INTR
static char *reason[] = {
@@ -1582,7 +1606,7 @@
case CS_DATA_OVERRUN:
dprintk(2, "Data overrun 0x%x\n", residual_length);
- dprintk(2, "qla1280_isr: response packet data\n");
+ dprintk(2, "qla1280_return_status: response packet data\n");
qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE);
host_status = DID_ERROR;
break;
@@ -1617,40 +1641,6 @@
/* QLogic ISP1280 Hardware Support Functions. */
/****************************************************************************/
- /*
- * qla2100_enable_intrs
- * qla2100_disable_intrs
- *
- * Input:
- * ha = adapter block pointer.
- *
- * Returns:
- * None
- */
-static inline void
-qla1280_enable_intrs(struct scsi_qla_host *ha)
-{
- struct device_reg __iomem *reg;
-
- reg = ha->iobase;
- /* enable risc and host interrupts */
- WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC));
- RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */
- ha->flags.ints_enabled = 1;
-}
-
-static inline void
-qla1280_disable_intrs(struct scsi_qla_host *ha)
-{
- struct device_reg __iomem *reg;
-
- reg = ha->iobase;
- /* disable risc and host interrupts */
- WRT_REG_WORD(®->ictrl, 0);
- RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */
- ha->flags.ints_enabled = 0;
-}
-
/*
* qla1280_initialize_adapter
* Initialize board.
@@ -1679,7 +1669,6 @@
ha->flags.reset_active = 0;
ha->flags.abort_isp_active = 0;
- ha->flags.ints_enabled = 0;
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
if (ia64_platform_is("sn2")) {
printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
@@ -1758,69 +1747,6 @@
return status;
}
-
-/*
- * ISP Firmware Test
- * Checks if present version of RISC firmware is older than
- * driver firmware.
- *
- * Input:
- * ha = adapter block pointer.
- *
- * Returns:
- * 0 = firmware does not need to be loaded.
- */
-static int
-qla1280_isp_firmware(struct scsi_qla_host *ha)
-{
- struct nvram *nv = (struct nvram *) ha->response_ring;
- int status = 0; /* dg 2/27 always loads RISC */
- uint16_t mb[MAILBOX_REGISTER_COUNT];
-
- ENTER("qla1280_isp_firmware");
-
- dprintk(1, "scsi(%li): Determining if RISC is loaded\n", ha->host_no);
-
- /* Bad NVRAM data, load RISC code. */
- if (!ha->nvram_valid) {
- ha->flags.disable_risc_code_load = 0;
- } else
- ha->flags.disable_risc_code_load =
- nv->cntr_flags_1.disable_loading_risc_code;
-
- if (ha->flags.disable_risc_code_load) {
- dprintk(3, "qla1280_isp_firmware: Telling RISC to verify "
- "checksum of loaded BIOS code.\n");
-
- /* Verify checksum of loaded RISC code. */
- mb[0] = MBC_VERIFY_CHECKSUM;
- /* mb[1] = ql12_risc_code_addr01; */
- mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
-
- if (!(status =
- qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) {
- /* Start firmware execution. */
- dprintk(3, "qla1280_isp_firmware: Startng F/W "
- "execution.\n");
-
- mb[0] = MBC_EXECUTE_FIRMWARE;
- /* mb[1] = ql12_risc_code_addr01; */
- mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
- qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
- } else
- printk(KERN_INFO "qla1280: RISC checksum failed.\n");
- } else {
- dprintk(1, "qla1280: NVRAM configured to load RISC load.\n");
- status = 1;
- }
-
- if (status)
- dprintk(2, "qla1280_isp_firmware: **** Load RISC code ****\n");
-
- LEAVE("qla1280_isp_firmware");
- return status;
-}
-
/*
* Chip diagnostics
* Test chip for proper operation.
@@ -2006,7 +1932,7 @@
"%d,%d(0x%x)\n",
risc_code_address, cnt, num, risc_address);
for(i = 0; i < cnt; i++)
- ((uint16_t *)ha->request_ring)[i] =
+ ((__le16 *)ha->request_ring)[i] =
cpu_to_le16(risc_code_address[i]);
mb[0] = MBC_LOAD_RAM;
@@ -2085,7 +2011,7 @@
mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
if (err) {
- printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no);
+ printk(KERN_ERR "scsi(%li): RISC checksum failed.\n", ha->host_no);
return err;
}
@@ -2105,14 +2031,7 @@
static int
qla1280_load_firmware(struct scsi_qla_host *ha)
{
- int err = -ENODEV;
-
- /* If firmware needs to be loaded */
- if (!qla1280_isp_firmware(ha)) {
- printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n",
- ha->host_no);
- goto out;
- }
+ int err;
err = qla1280_chip_diag(ha);
if (err)
@@ -2246,17 +2165,17 @@
{
struct nvram *nv = &ha->nvram;
- nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1;
- nv->bus[bus].target[target].parameter.f.auto_request_sense = 1;
- nv->bus[bus].target[target].parameter.f.tag_queuing = 1;
- nv->bus[bus].target[target].parameter.f.enable_sync = 1;
+ nv->bus[bus].target[target].parameter.renegotiate_on_error = 1;
+ nv->bus[bus].target[target].parameter.auto_request_sense = 1;
+ nv->bus[bus].target[target].parameter.tag_queuing = 1;
+ nv->bus[bus].target[target].parameter.enable_sync = 1;
#if 1 /* Some SCSI Processors do not seem to like this */
- nv->bus[bus].target[target].parameter.f.enable_wide = 1;
+ nv->bus[bus].target[target].parameter.enable_wide = 1;
#endif
- nv->bus[bus].target[target].parameter.f.parity_checking = 1;
- nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1;
nv->bus[bus].target[target].execution_throttle =
nv->bus[bus].max_queue_depth - 1;
+ nv->bus[bus].target[target].parameter.parity_checking = 1;
+ nv->bus[bus].target[target].parameter.disconnect_allowed = 1;
if (IS_ISP1x160(ha)) {
nv->bus[bus].target[target].flags.flags1x160.device_enable = 1;
@@ -2284,9 +2203,9 @@
/* nv->cntr_flags_1.disable_loading_risc_code = 1; */
nv->firmware_feature.f.enable_fast_posting = 1;
nv->firmware_feature.f.disable_synchronous_backoff = 1;
- nv->termination.f.scsi_bus_0_control = 3;
- nv->termination.f.scsi_bus_1_control = 3;
- nv->termination.f.auto_term_support = 1;
+ nv->termination.scsi_bus_0_control = 3;
+ nv->termination.scsi_bus_1_control = 3;
+ nv->termination.auto_term_support = 1;
/*
* Set default FIFO magic - What appropriate values would be here
@@ -2296,7 +2215,12 @@
* header file provided by QLogic seems to be bogus or incomplete
* at best.
*/
- nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128;
+ nv->isp_config.burst_enable = 1;
+ if (IS_ISP1040(ha))
+ nv->isp_config.fifo_threshold |= 3;
+ else
+ nv->isp_config.fifo_threshold |= 4;
+
if (IS_ISP1x160(ha))
nv->isp_parameter = 0x01; /* fast memory enable */
@@ -2327,66 +2251,53 @@
struct nvram *nv = &ha->nvram;
uint16_t mb[MAILBOX_REGISTER_COUNT];
int status, lun;
+ uint16_t flag;
/* Set Target Parameters. */
mb[0] = MBC_SET_TARGET_PARAMETERS;
- mb[1] = (uint16_t) (bus ? target | BIT_7 : target);
- mb[1] <<= 8;
+ mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8);
/*
- * Do not enable wide, sync, and ppr for the initial
- * INQUIRY run. We enable this later if we determine
- * the target actually supports it.
+ * Do not enable sync and ppr for the initial INQUIRY run. We
+ * enable this later if we determine the target actually
+ * supports it.
*/
- nv->bus[bus].target[target].parameter.f.
- auto_request_sense = 1;
- nv->bus[bus].target[target].parameter.f.
- stop_queue_on_check = 0;
-
- if (IS_ISP1x160(ha))
- nv->bus[bus].target[target].ppr_1x160.
- flags.enable_ppr = 0;
-
- /*
- * No sync, wide, etc. while probing
- */
- mb[2] = (nv->bus[bus].target[target].parameter.c << 8) &
- ~(TP_SYNC /*| TP_WIDE | TP_PPR*/);
+ mb[2] = (TP_RENEGOTIATE | TP_AUTO_REQUEST_SENSE | TP_TAGGED_QUEUE
+ | TP_WIDE | TP_PARITY | TP_DISCONNECT);
if (IS_ISP1x160(ha))
mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8;
else
mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8;
mb[3] |= nv->bus[bus].target[target].sync_period;
-
- status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]);
+ status = qla1280_mailbox_command(ha, 0x0f, mb);
/* Save Tag queuing enable flag. */
- mb[0] = BIT_0 << target;
- if (nv->bus[bus].target[target].parameter.f.tag_queuing)
- ha->bus_settings[bus].qtag_enables |= mb[0];
+ flag = (BIT_0 << target) & mb[0];
+ if (nv->bus[bus].target[target].parameter.tag_queuing)
+ ha->bus_settings[bus].qtag_enables |= flag;
/* Save Device enable flag. */
if (IS_ISP1x160(ha)) {
if (nv->bus[bus].target[target].flags.flags1x160.device_enable)
- ha->bus_settings[bus].device_enables |= mb[0];
+ ha->bus_settings[bus].device_enables |= flag;
ha->bus_settings[bus].lun_disables |= 0;
} else {
if (nv->bus[bus].target[target].flags.flags1x80.device_enable)
- ha->bus_settings[bus].device_enables |= mb[0];
+ ha->bus_settings[bus].device_enables |= flag;
/* Save LUN disable flag. */
if (nv->bus[bus].target[target].flags.flags1x80.lun_disable)
- ha->bus_settings[bus].lun_disables |= mb[0];
+ ha->bus_settings[bus].lun_disables |= flag;
}
/* Set Device Queue Parameters. */
for (lun = 0; lun < MAX_LUNS; lun++) {
mb[0] = MBC_SET_DEVICE_QUEUE;
- mb[1] = (uint16_t)(bus ? target | BIT_7 : target);
- mb[1] = mb[1] << 8 | lun;
+ mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8);
+ mb[1] |= lun;
mb[2] = nv->bus[bus].max_queue_depth;
mb[3] = nv->bus[bus].target[target].execution_throttle;
- status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]);
+ status |= qla1280_mailbox_command(ha, 0x0f, mb);
}
return status;
@@ -2431,7 +2342,6 @@
struct nvram *nv = &ha->nvram;
int bus, target, status = 0;
uint16_t mb[MAILBOX_REGISTER_COUNT];
- uint16_t mask;
ENTER("qla1280_nvram_config");
@@ -2439,7 +2349,7 @@
/* Always force AUTO sense for LINUX SCSI */
for (bus = 0; bus < MAX_BUSES; bus++)
for (target = 0; target < MAX_TARGETS; target++) {
- nv->bus[bus].target[target].parameter.f.
+ nv->bus[bus].target[target].parameter.
auto_request_sense = 1;
}
} else {
@@ -2457,31 +2367,40 @@
hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK;
- cfg1 = RD_REG_WORD(®->cfg_1);
+ cfg1 = RD_REG_WORD(®->cfg_1) & ~(BIT_4 | BIT_5 | BIT_6);
cdma_conf = RD_REG_WORD(®->cdma_cfg);
ddma_conf = RD_REG_WORD(®->ddma_cfg);
/* Busted fifo, says mjacob. */
- if (hwrev == ISP_CFG0_1040A)
- WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64);
- else
- WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB);
+ if (hwrev != ISP_CFG0_1040A)
+ cfg1 |= nv->isp_config.fifo_threshold << 4;
+
+ cfg1 |= nv->isp_config.burst_enable << 2;
+ WRT_REG_WORD(®->cfg_1, cfg1);
WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB);
WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB);
} else {
+ uint16_t cfg1, term;
+
/* Set ISP hardware DMA burst */
- mb[0] = nv->isp_config.c;
+ cfg1 = nv->isp_config.fifo_threshold << 4;
+ cfg1 |= nv->isp_config.burst_enable << 2;
/* Enable DMA arbitration on dual channel controllers */
if (ha->ports > 1)
- mb[0] |= BIT_13;
- WRT_REG_WORD(®->cfg_1, mb[0]);
+ cfg1 |= BIT_13;
+ WRT_REG_WORD(®->cfg_1, cfg1);
/* Set SCSI termination. */
- WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0));
- mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0);
- WRT_REG_WORD(®->gpio_data, mb[0]);
+ WRT_REG_WORD(®->gpio_enable,
+ BIT_7 | BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ term = nv->termination.scsi_bus_1_control;
+ term |= nv->termination.scsi_bus_0_control << 2;
+ term |= nv->termination.auto_term_support << 7;
+ RD_REG_WORD(®->id_l); /* Flush PCI write */
+ WRT_REG_WORD(®->gpio_data, term);
}
+ RD_REG_WORD(®->id_l); /* Flush PCI write */
/* ISP parameter word. */
mb[0] = MBC_SET_SYSTEM_PARAMETER;
@@ -2497,16 +2416,17 @@
/* Firmware feature word. */
mb[0] = MBC_SET_FIRMWARE_FEATURES;
- mask = BIT_5 | BIT_1 | BIT_0;
- mb[1] = le16_to_cpu(nv->firmware_feature.w) & (mask);
+ mb[1] = nv->firmware_feature.f.enable_fast_posting;
+ mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1;
+ mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5;
#if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2)
if (ia64_platform_is("sn2")) {
printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
"workaround\n", ha->host_no);
- mb[1] |= BIT_9;
+ mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */
}
#endif
- status |= qla1280_mailbox_command(ha, mask, &mb[0]);
+ status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
/* Retry count and delay. */
mb[0] = MBC_SET_RETRY_COUNT;
@@ -2535,27 +2455,27 @@
mb[2] |= BIT_5;
if (nv->bus[1].config_2.data_line_active_negation)
mb[2] |= BIT_4;
- status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+ status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb);
mb[0] = MBC_SET_DATA_OVERRUN_RECOVERY;
mb[1] = 2; /* Reset SCSI bus and return all outstanding IO */
- status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+ status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
/* thingy */
mb[0] = MBC_SET_PCI_CONTROL;
- mb[1] = 2; /* Data DMA Channel Burst Enable */
- mb[2] = 2; /* Command DMA Channel Burst Enable */
- status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+ mb[1] = BIT_1; /* Data DMA Channel Burst Enable */
+ mb[2] = BIT_1; /* Command DMA Channel Burst Enable */
+ status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb);
mb[0] = MBC_SET_TAG_AGE_LIMIT;
mb[1] = 8;
- status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+ status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
/* Selection timeout. */
mb[0] = MBC_SET_SELECTION_TIMEOUT;
mb[1] = nv->bus[0].selection_timeout;
mb[2] = nv->bus[1].selection_timeout;
- status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+ status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb);
for (bus = 0; bus < ha->ports; bus++)
status |= qla1280_config_bus(ha, bus);
@@ -3066,7 +2986,7 @@
struct scsi_cmnd *cmd = sp->cmd;
cmd_a64_entry_t *pkt;
struct scatterlist *sg = NULL;
- u32 *dword_ptr;
+ __le32 *dword_ptr;
dma_addr_t dma_handle;
int status = 0;
int cnt;
@@ -3104,10 +3024,13 @@
REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt);
}
+ dprintk(3, "Number of free entries=(%d) seg_cnt=0x%x\n",
+ ha->req_q_cnt, seg_cnt);
+
/* If room for request in request ring. */
if ((req_cnt + 2) >= ha->req_q_cnt) {
status = 1;
- dprintk(2, "qla1280_64bit_start_scsi: in-ptr=0x%x req_q_cnt="
+ dprintk(2, "qla1280_start_scsi: in-ptr=0x%x req_q_cnt="
"0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt,
req_cnt);
goto out;
@@ -3119,7 +3042,7 @@
if (cnt >= MAX_OUTSTANDING_COMMANDS) {
status = 1;
- dprintk(2, "qla1280_64bit_start_scsi: NO ROOM IN "
+ dprintk(2, "qla1280_start_scsi: NO ROOM IN "
"OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt);
goto out;
}
@@ -3128,7 +3051,7 @@
ha->req_q_cnt -= req_cnt;
CMD_HANDLE(sp->cmd) = (unsigned char *)(unsigned long)(cnt + 1);
- dprintk(2, "64bit_start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp,
+ dprintk(2, "start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp,
cmd->cmnd[0], (long)CMD_HANDLE(sp->cmd));
dprintk(2, " bus %i, target %i, lun %i\n",
SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd));
@@ -3350,7 +3273,7 @@
struct scsi_cmnd *cmd = sp->cmd;
struct cmd_entry *pkt;
struct scatterlist *sg = NULL;
- uint32_t *dword_ptr;
+ __le32 *dword_ptr;
int status = 0;
int cnt;
int req_cnt;
@@ -3993,21 +3916,21 @@
result = cmd->request_buffer;
n = &ha->nvram;
- n->bus[bus].target[target].parameter.f.enable_wide = 0;
- n->bus[bus].target[target].parameter.f.enable_sync = 0;
+ n->bus[bus].target[target].parameter.enable_wide = 0;
+ n->bus[bus].target[target].parameter.enable_sync = 0;
n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0;
if (result[7] & 0x60)
- n->bus[bus].target[target].parameter.f.enable_wide = 1;
+ n->bus[bus].target[target].parameter.enable_wide = 1;
if (result[7] & 0x10)
- n->bus[bus].target[target].parameter.f.enable_sync = 1;
+ n->bus[bus].target[target].parameter.enable_sync = 1;
if ((result[2] >= 3) && (result[4] + 5 > 56) &&
(result[56] & 0x4))
n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1;
dprintk(2, "get_target_options(): wide %i, sync %i, ppr %i\n",
- n->bus[bus].target[target].parameter.f.enable_wide,
- n->bus[bus].target[target].parameter.f.enable_sync,
+ n->bus[bus].target[target].parameter.enable_wide,
+ n->bus[bus].target[target].parameter.enable_sync,
n->bus[bus].target[target].ppr_1x160.flags.enable_ppr);
}
#endif
@@ -4071,7 +3994,7 @@
/* Save ISP completion status */
CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd);
- if (scsi_status & SS_CHECK_CONDITION) {
+ if (scsi_status & SAM_STAT_CHECK_CONDITION) {
if (comp_status != CS_ARS_FAILED) {
uint16_t req_sense_length =
le16_to_cpu(pkt->req_sense_length);
@@ -4650,7 +4573,7 @@
if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
if (pci_set_dma_mask(ha->pdev, 0xffffffff)) {
printk(KERN_WARNING "scsi(%li): Unable to set a "
- " suitable DMA mask - aboring\n", ha->host_no);
+ "suitable DMA mask - aborting\n", ha->host_no);
error = -ENODEV;
goto error_free_irq;
}
@@ -4660,14 +4583,14 @@
#else
if (pci_set_dma_mask(ha->pdev, 0xffffffff)) {
printk(KERN_WARNING "scsi(%li): Unable to set a "
- " suitable DMA mask - aboring\n", ha->host_no);
+ "suitable DMA mask - aborting\n", ha->host_no);
error = -ENODEV;
goto error_free_irq;
}
#endif
ha->request_ring = pci_alloc_consistent(ha->pdev,
- ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))),
+ ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)),
&ha->request_dma);
if (!ha->request_ring) {
printk(KERN_INFO "qla1280: Failed to get request memory\n");
@@ -4675,7 +4598,7 @@
}
ha->response_ring = pci_alloc_consistent(ha->pdev,
- ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))),
+ ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)),
&ha->response_dma);
if (!ha->response_ring) {
printk(KERN_INFO "qla1280: Failed to get response memory\n");
@@ -4758,7 +4681,7 @@
#if LINUX_VERSION_CODE >= 0x020600
error_disable_adapter:
- WRT_REG_WORD(&ha->iobase->ictrl, 0);
+ qla1280_disable_intrs(ha);
#endif
error_free_irq:
free_irq(pdev->irq, ha);
@@ -4770,11 +4693,11 @@
#endif
error_free_response_ring:
pci_free_consistent(ha->pdev,
- ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))),
+ ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)),
ha->response_ring, ha->response_dma);
error_free_request_ring:
pci_free_consistent(ha->pdev,
- ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))),
+ ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)),
ha->request_ring, ha->request_dma);
error_put_host:
scsi_host_put(host);
@@ -4795,7 +4718,7 @@
scsi_remove_host(host);
#endif
- WRT_REG_WORD(&ha->iobase->ictrl, 0);
+ qla1280_disable_intrs(ha);
free_irq(pdev->irq, ha);
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index d245ae0..59915fb 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -94,9 +94,6 @@
#define REQUEST_ENTRY_CNT 256 /* Number of request entries. */
#define RESPONSE_ENTRY_CNT 16 /* Number of response entries. */
-/* Number of segments 1 - 65535 */
-#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */
-
/*
* SCSI Request Block structure (sp) that is placed
* on cmd->SCp location of every I/O
@@ -378,29 +375,23 @@
uint16_t unused_12; /* 12, 13 */
uint16_t unused_14; /* 14, 15 */
- union {
- uint8_t c;
- struct {
- uint8_t reserved:2;
- uint8_t burst_enable:1;
- uint8_t reserved_1:1;
- uint8_t fifo_threshold:4;
- } f;
+ struct {
+ uint8_t reserved:2;
+ uint8_t burst_enable:1;
+ uint8_t reserved_1:1;
+ uint8_t fifo_threshold:4;
} isp_config; /* 16 */
/* Termination
* 0 = Disable, 1 = high only, 3 = Auto term
*/
- union {
- uint8_t c;
- struct {
- uint8_t scsi_bus_1_control:2;
- uint8_t scsi_bus_0_control:2;
- uint8_t unused_0:1;
- uint8_t unused_1:1;
- uint8_t unused_2:1;
- uint8_t auto_term_support:1;
- } f;
+ struct {
+ uint8_t scsi_bus_1_control:2;
+ uint8_t scsi_bus_0_control:2;
+ uint8_t unused_0:1;
+ uint8_t unused_1:1;
+ uint8_t unused_2:1;
+ uint8_t auto_term_support:1;
} termination; /* 17 */
uint16_t isp_parameter; /* 18, 19 */
@@ -460,18 +451,15 @@
uint16_t unused_38; /* 38, 39 */
struct {
- union {
- uint8_t c;
- struct {
- uint8_t renegotiate_on_error:1;
- uint8_t stop_queue_on_check:1;
- uint8_t auto_request_sense:1;
- uint8_t tag_queuing:1;
- uint8_t enable_sync:1;
- uint8_t enable_wide:1;
- uint8_t parity_checking:1;
- uint8_t disconnect_allowed:1;
- } f;
+ struct {
+ uint8_t renegotiate_on_error:1;
+ uint8_t stop_queue_on_check:1;
+ uint8_t auto_request_sense:1;
+ uint8_t tag_queuing:1;
+ uint8_t enable_sync:1;
+ uint8_t enable_wide:1;
+ uint8_t parity_checking:1;
+ uint8_t disconnect_allowed:1;
} parameter; /* 40 */
uint8_t execution_throttle; /* 41 */
@@ -528,23 +516,23 @@
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t handle; /* System handle. */
+ __le32 handle; /* System handle. */
uint8_t lun; /* SCSI LUN */
uint8_t target; /* SCSI ID */
- uint16_t cdb_len; /* SCSI command length. */
- uint16_t control_flags; /* Control flags. */
- uint16_t reserved;
- uint16_t timeout; /* Command timeout. */
- uint16_t dseg_count; /* Data segment count. */
+ __le16 cdb_len; /* SCSI command length. */
+ __le16 control_flags; /* Control flags. */
+ __le16 reserved;
+ __le16 timeout; /* Command timeout. */
+ __le16 dseg_count; /* Data segment count. */
uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
- uint32_t dseg_3_address; /* Data segment 3 address. */
- uint32_t dseg_3_length; /* Data segment 3 length. */
+ __le32 dseg_0_address; /* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address; /* Data segment 1 address. */
+ __le32 dseg_1_length; /* Data segment 1 length. */
+ __le32 dseg_2_address; /* Data segment 2 address. */
+ __le32 dseg_2_length; /* Data segment 2 length. */
+ __le32 dseg_3_address; /* Data segment 3 address. */
+ __le32 dseg_3_length; /* Data segment 3 length. */
};
/*
@@ -556,21 +544,21 @@
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved; /* Reserved */
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
- uint32_t dseg_3_address; /* Data segment 3 address. */
- uint32_t dseg_3_length; /* Data segment 3 length. */
- uint32_t dseg_4_address; /* Data segment 4 address. */
- uint32_t dseg_4_length; /* Data segment 4 length. */
- uint32_t dseg_5_address; /* Data segment 5 address. */
- uint32_t dseg_5_length; /* Data segment 5 length. */
- uint32_t dseg_6_address; /* Data segment 6 address. */
- uint32_t dseg_6_length; /* Data segment 6 length. */
+ __le32 reserved; /* Reserved */
+ __le32 dseg_0_address; /* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address; /* Data segment 1 address. */
+ __le32 dseg_1_length; /* Data segment 1 length. */
+ __le32 dseg_2_address; /* Data segment 2 address. */
+ __le32 dseg_2_length; /* Data segment 2 length. */
+ __le32 dseg_3_address; /* Data segment 3 address. */
+ __le32 dseg_3_length; /* Data segment 3 length. */
+ __le32 dseg_4_address; /* Data segment 4 address. */
+ __le32 dseg_4_length; /* Data segment 4 length. */
+ __le32 dseg_5_address; /* Data segment 5 address. */
+ __le32 dseg_5_length; /* Data segment 5 length. */
+ __le32 dseg_6_address; /* Data segment 6 address. */
+ __le32 dseg_6_length; /* Data segment 6 length. */
};
/*
@@ -586,22 +574,22 @@
#define RF_FULL BIT_1 /* Full */
#define RF_BAD_HEADER BIT_2 /* Bad header. */
#define RF_BAD_PAYLOAD BIT_3 /* Bad payload. */
- uint32_t handle; /* System handle. */
- uint16_t scsi_status; /* SCSI status. */
- uint16_t comp_status; /* Completion status. */
- uint16_t state_flags; /* State flags. */
-#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */
-#define SF_GOT_SENSE BIT_13 /* Got Sense */
-#define SF_GOT_STATUS BIT_12 /* Got Status */
-#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */
-#define SF_SENT_CDB BIT_10 /* Send CDB */
-#define SF_GOT_TARGET BIT_9 /* */
-#define SF_GOT_BUS BIT_8 /* */
- uint16_t status_flags; /* Status flags. */
- uint16_t time; /* Time. */
- uint16_t req_sense_length; /* Request sense data length. */
- uint32_t residual_length; /* Residual transfer length. */
- uint16_t reserved[4];
+ __le32 handle; /* System handle. */
+ __le16 scsi_status; /* SCSI status. */
+ __le16 comp_status; /* Completion status. */
+ __le16 state_flags; /* State flags. */
+#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */
+#define SF_GOT_SENSE BIT_13 /* Got Sense */
+#define SF_GOT_STATUS BIT_12 /* Got Status */
+#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */
+#define SF_SENT_CDB BIT_10 /* Send CDB */
+#define SF_GOT_TARGET BIT_9 /* */
+#define SF_GOT_BUS BIT_8 /* */
+ __le16 status_flags; /* Status flags. */
+ __le16 time; /* Time. */
+ __le16 req_sense_length;/* Request sense data length. */
+ __le32 residual_length; /* Residual transfer length. */
+ __le16 reserved[4];
uint8_t req_sense_data[32]; /* Request sense data. */
};
@@ -614,7 +602,7 @@
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved;
+ __le32 reserved;
uint8_t lun; /* SCSI LUN */
uint8_t target; /* SCSI ID */
uint8_t modifier; /* Modifier (7-0). */
@@ -638,11 +626,11 @@
uint32_t handle; /* System handle. */
uint8_t lun; /* SCSI LUN */
uint8_t target; /* SCSI ID */
- uint16_t cdb_len; /* SCSI command length. */
- uint16_t control_flags; /* Control flags. */
- uint16_t reserved;
- uint16_t timeout; /* Command timeout. */
- uint16_t dseg_count; /* Data segment count. */
+ __le16 cdb_len; /* SCSI command length. */
+ __le16 control_flags; /* Control flags. */
+ __le16 reserved;
+ __le16 timeout; /* Command timeout. */
+ __le16 dseg_count; /* Data segment count. */
uint8_t scsi_cdb[88]; /* SCSI command words. */
};
@@ -655,20 +643,20 @@
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t handle; /* System handle. */
+ __le32 handle; /* System handle. */
uint8_t lun; /* SCSI LUN */
uint8_t target; /* SCSI ID */
- uint16_t cdb_len; /* SCSI command length. */
- uint16_t control_flags; /* Control flags. */
- uint16_t reserved;
- uint16_t timeout; /* Command timeout. */
- uint16_t dseg_count; /* Data segment count. */
+ __le16 cdb_len; /* SCSI command length. */
+ __le16 control_flags; /* Control flags. */
+ __le16 reserved;
+ __le16 timeout; /* Command timeout. */
+ __le16 dseg_count; /* Data segment count. */
uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */
- uint32_t reserved_1[2]; /* unused */
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address[2]; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
+ __le32 reserved_1[2]; /* unused */
+ __le32 dseg_0_address[2]; /* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address[2]; /* Data segment 1 address. */
+ __le32 dseg_1_length; /* Data segment 1 length. */
} cmd_a64_entry_t, request_t;
/*
@@ -680,16 +668,16 @@
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address[2]; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address[2]; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
- uint32_t dseg_3_address[2]; /* Data segment 3 address. */
- uint32_t dseg_3_length; /* Data segment 3 length. */
- uint32_t dseg_4_address[2]; /* Data segment 4 address. */
- uint32_t dseg_4_length; /* Data segment 4 length. */
+ __le32 dseg_0_address[2]; /* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address[2]; /* Data segment 1 address. */
+ __le32 dseg_1_length; /* Data segment 1 length. */
+ __le32 dseg_2_address[2]; /* Data segment 2 address. */
+ __le32 dseg_2_length; /* Data segment 2 length. */
+ __le32 dseg_3_address[2]; /* Data segment 3 address. */
+ __le32 dseg_3_length; /* Data segment 3 length. */
+ __le32 dseg_4_address[2]; /* Data segment 4 address. */
+ __le32 dseg_4_length; /* Data segment 4 length. */
};
/*
@@ -701,10 +689,10 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status not used. */
- uint32_t reserved_2;
- uint16_t lun; /* Bit 15 is bus number. */
- uint16_t reserved_4;
- uint32_t option_flags;
+ __le32 reserved_2;
+ __le16 lun; /* Bit 15 is bus number. */
+ __le16 reserved_4;
+ __le32 option_flags;
uint8_t status;
uint8_t reserved_5;
uint8_t command_count; /* Number of ATIOs allocated. */
@@ -714,8 +702,8 @@
/* commands (2-26). */
uint8_t group_7_length; /* SCSI CDB length for group 7 */
/* commands (2-26). */
- uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
- uint16_t reserved_6[20];
+ __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */
+ __le16 reserved_6[20];
};
/*
@@ -729,20 +717,20 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun; /* SCSI LUN */
uint8_t reserved_3;
uint8_t operators;
uint8_t reserved_4;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t reserved_5;
uint8_t command_count; /* Number of ATIOs allocated. */
uint8_t immed_notify_count; /* Number of Immediate Notify */
/* entries allocated. */
- uint16_t reserved_6;
- uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
- uint16_t reserved_7[20];
+ __le16 reserved_6;
+ __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */
+ __le16 reserved_7[20];
};
/*
@@ -754,20 +742,20 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun;
uint8_t initiator_id;
uint8_t reserved_3;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t reserved_4;
uint8_t tag_value; /* Received queue tag message value */
uint8_t tag_type; /* Received queue tag message type */
/* entries allocated. */
- uint16_t seq_id;
+ __le16 seq_id;
uint8_t scsi_msg[8]; /* SCSI message not handled by ISP */
- uint16_t reserved_5[8];
+ __le16 reserved_5[8];
uint8_t sense_data[18];
};
@@ -780,16 +768,16 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun;
uint8_t initiator_id;
uint8_t reserved_3;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t event;
- uint16_t seq_id;
- uint16_t reserved_4[22];
+ __le16 seq_id;
+ __le16 reserved_4[22];
};
/*
@@ -801,12 +789,12 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun;
uint8_t initiator_id;
uint8_t cdb_len;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t scsi_status;
uint8_t tag_value; /* Received queue tag message value */
@@ -824,28 +812,28 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun; /* SCSI LUN */
uint8_t initiator_id;
uint8_t reserved_3;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t scsi_status;
uint8_t tag_value; /* Received queue tag message value */
uint8_t tag_type; /* Received queue tag message type */
- uint32_t transfer_length;
- uint32_t residual;
- uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
- uint16_t dseg_count; /* Data segment count. */
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
- uint32_t dseg_3_address; /* Data segment 3 address. */
- uint32_t dseg_3_length; /* Data segment 3 length. */
+ __le32 transfer_length;
+ __le32 residual;
+ __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */
+ __le16 dseg_count; /* Data segment count. */
+ __le32 dseg_0_address; /* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address; /* Data segment 1 address. */
+ __le32 dseg_1_length; /* Data segment 1 length. */
+ __le32 dseg_2_address; /* Data segment 2 address. */
+ __le32 dseg_2_length; /* Data segment 2 length. */
+ __le32 dseg_3_address; /* Data segment 3 address. */
+ __le32 dseg_3_length; /* Data segment 3 length. */
};
/*
@@ -857,24 +845,24 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun; /* SCSI LUN */
uint8_t initiator_id;
uint8_t reserved_3;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t scsi_status;
uint8_t tag_value; /* Received queue tag message value */
uint8_t tag_type; /* Received queue tag message type */
- uint32_t transfer_length;
- uint32_t residual;
- uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
- uint16_t dseg_count; /* Data segment count. */
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint16_t dseg_1_length; /* Data segment 1 length. */
+ __le32 transfer_length;
+ __le32 residual;
+ __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */
+ __le16 dseg_count; /* Data segment count. */
+ __le32 dseg_0_address; /* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address; /* Data segment 1 address. */
+ __le16 dseg_1_length; /* Data segment 1 length. */
uint8_t sense_data[18];
};
@@ -887,25 +875,25 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun; /* SCSI LUN */
uint8_t initiator_id;
uint8_t reserved_3;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t scsi_status;
uint8_t tag_value; /* Received queue tag message value */
uint8_t tag_type; /* Received queue tag message type */
- uint32_t transfer_length;
- uint32_t residual;
- uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
- uint16_t dseg_count; /* Data segment count. */
- uint32_t reserved_4[2];
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address[2]; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
+ __le32 transfer_length;
+ __le32 residual;
+ __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */
+ __le16 dseg_count; /* Data segment count. */
+ __le32 reserved_4[2];
+ __le32 dseg_0_address[2];/* Data segment 0 address. */
+ __le32 dseg_0_length; /* Data segment 0 length. */
+ __le32 dseg_1_address[2];/* Data segment 1 address. */
+ __le32 dseg_1_length; /* Data segment 1 length. */
};
/*
@@ -917,21 +905,21 @@
uint8_t entry_count; /* Entry count. */
uint8_t reserved_1;
uint8_t entry_status; /* Entry Status. */
- uint32_t reserved_2;
+ __le32 reserved_2;
uint8_t lun; /* SCSI LUN */
uint8_t initiator_id;
uint8_t reserved_3;
uint8_t target_id;
- uint32_t option_flags;
+ __le32 option_flags;
uint8_t status;
uint8_t scsi_status;
uint8_t tag_value; /* Received queue tag message value */
uint8_t tag_type; /* Received queue tag message type */
- uint32_t transfer_length;
- uint32_t residual;
- uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
- uint16_t dseg_count; /* Data segment count. */
- uint16_t reserved_4[7];
+ __le32 transfer_length;
+ __le32 residual;
+ __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */
+ __le16 dseg_count; /* Data segment count. */
+ __le16 reserved_4[7];
uint8_t sense_data[18];
};
@@ -979,14 +967,6 @@
#define CS_RETRY 0x82 /* Driver defined */
/*
- * ISP status entry - SCSI status byte bit definitions.
- */
-#define SS_CHECK_CONDITION BIT_1
-#define SS_CONDITION_MET BIT_2
-#define SS_BUSY_CONDITION BIT_3
-#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3)
-
-/*
* ISP target entries - Option flags bit definitions.
*/
#define OF_ENABLE_TAG BIT_1 /* Tagged queue action enable */
@@ -1082,10 +1062,6 @@
uint32_t reset_active:1; /* 3 */
uint32_t abort_isp_active:1; /* 4 */
uint32_t disable_risc_code_load:1; /* 5 */
- uint32_t enable_64bit_addressing:1; /* 6 */
- uint32_t in_reset:1; /* 7 */
- uint32_t ints_enabled:1;
- uint32_t ignore_nvram:1;
#ifdef __ia64__
uint32_t use_pci_vchannel:1;
#endif
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 659a5d6..fe0fce7 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -211,6 +211,138 @@
sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
}
+/* Scsi_Host attributes. */
+
+static ssize_t
+qla2x00_drvr_version_show(struct class_device *cdev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
+}
+
+static ssize_t
+qla2x00_fw_version_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ char fw_str[30];
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ha->isp_ops.fw_version_str(ha, fw_str));
+}
+
+static ssize_t
+qla2x00_serial_num_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ uint32_t sn;
+
+ sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
+ return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
+ sn % 100000);
+}
+
+static ssize_t
+qla2x00_isp_name_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name);
+}
+
+static ssize_t
+qla2x00_isp_id_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
+ ha->product_id[0], ha->product_id[1], ha->product_id[2],
+ ha->product_id[3]);
+}
+
+static ssize_t
+qla2x00_model_name_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
+}
+
+static ssize_t
+qla2x00_model_desc_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ha->model_desc ? ha->model_desc: "");
+}
+
+static ssize_t
+qla2x00_pci_info_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ char pci_info[30];
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ha->isp_ops.pci_info_str(ha, pci_info));
+}
+
+static ssize_t
+qla2x00_state_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ int len = 0;
+
+ if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+ atomic_read(&ha->loop_state) == LOOP_DEAD)
+ len = snprintf(buf, PAGE_SIZE, "Link Down\n");
+ else if (atomic_read(&ha->loop_state) != LOOP_READY ||
+ test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
+ test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags))
+ len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n");
+ else {
+ len = snprintf(buf, PAGE_SIZE, "Link Up - ");
+
+ switch (ha->current_topology) {
+ case ISP_CFG_NL:
+ len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
+ break;
+ case ISP_CFG_FL:
+ len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
+ break;
+ case ISP_CFG_N:
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "N_Port to N_Port\n");
+ break;
+ case ISP_CFG_F:
+ len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
+ break;
+ default:
+ len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
+ break;
+ }
+ }
+ return len;
+}
+
+static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
+ NULL);
+static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
+static CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
+static CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
+static CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
+static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
+static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
+static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
+static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
+
+struct class_device_attribute *qla2x00_host_attrs[] = {
+ &class_device_attr_driver_version,
+ &class_device_attr_fw_version,
+ &class_device_attr_serial_num,
+ &class_device_attr_isp_name,
+ &class_device_attr_isp_id,
+ &class_device_attr_model_name,
+ &class_device_attr_model_desc,
+ &class_device_attr_pci_info,
+ &class_device_attr_state,
+ NULL,
+};
+
/* Host attributes. */
static void
@@ -304,10 +436,13 @@
.show_host_node_name = 1,
.show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+
.get_host_port_id = qla2x00_get_host_port_id,
.show_host_port_id = 1,
.dd_fcrport_size = sizeof(struct fc_port *),
+ .show_rport_supported_classes = 1,
.get_starget_node_name = qla2x00_get_starget_node_name,
.show_starget_node_name = 1,
@@ -329,4 +464,5 @@
be64_to_cpu(*(uint64_t *)ha->init_cb->node_name);
fc_host_port_name(ha->host) =
be64_to_cpu(*(uint64_t *)ha->init_cb->port_name);
+ fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index b8d90e9..9684e7a 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -81,6 +81,7 @@
#define DEBUG2_3_11(x) do {x;} while (0);
#define DEBUG2_9_10(x) do {x;} while (0);
#define DEBUG2_11(x) do {x;} while (0);
+#define DEBUG2_13(x) do {x;} while (0);
#else
#define DEBUG2(x) do {} while (0);
#endif
@@ -169,8 +170,14 @@
#if defined(QL_DEBUG_LEVEL_13)
#define DEBUG13(x) do {x;} while (0)
+#if !defined(DEBUG2_13)
+#define DEBUG2_13(x) do {x;} while(0)
+#endif
#else
#define DEBUG13(x) do {} while (0)
+#if !defined(QL_DEBUG_LEVEL_2)
+#define DEBUG2_13(x) do {} while(0)
+#endif
#endif
#if defined(QL_DEBUG_LEVEL_14)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1c6d366..b455c31 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -214,6 +214,7 @@
* valid range of an N-PORT id is 0 through 0x7ef.
*/
#define NPH_LAST_HANDLE 0x7ef
+#define NPH_MGMT_SERVER 0x7fa /* FFFFFA */
#define NPH_SNS 0x7fc /* FFFFFC */
#define NPH_FABRIC_CONTROLLER 0x7fd /* FFFFFD */
#define NPH_F_PORT 0x7fe /* FFFFFE */
@@ -630,6 +631,7 @@
#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */
#define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */
#define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */
+#define MBC_STOP_FIRMWARE 0x14 /* Stop firmware. */
#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */
#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */
#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */
@@ -913,7 +915,7 @@
* MSB BIT 1 =
* MSB BIT 2 =
* MSB BIT 3 =
- * MSB BIT 4 =
+ * MSB BIT 4 = LED mode
* MSB BIT 5 = enable 50 ohm termination
* MSB BIT 6 = Data Rate (2300 only)
* MSB BIT 7 = Data Rate (2300 only)
@@ -1035,7 +1037,7 @@
* MSB BIT 1 =
* MSB BIT 2 =
* MSB BIT 3 =
- * MSB BIT 4 =
+ * MSB BIT 4 = LED mode
* MSB BIT 5 = enable 50 ohm termination
* MSB BIT 6 = Data Rate (2300 only)
* MSB BIT 7 = Data Rate (2300 only)
@@ -1131,10 +1133,7 @@
uint8_t link_down_timeout;
- uint8_t adapter_id_0[4];
- uint8_t adapter_id_1[4];
- uint8_t adapter_id_2[4];
- uint8_t adapter_id_3[4];
+ uint8_t adapter_id[16];
uint8_t alt1_boot_node_name[WWN_SIZE];
uint16_t alt1_boot_lun_number;
@@ -1673,6 +1672,7 @@
uint8_t cur_path; /* current path id */
struct fc_rport *rport;
+ u32 supported_classes;
} fc_port_t;
/*
@@ -1727,6 +1727,8 @@
#define CT_REJECT_RESPONSE 0x8001
#define CT_ACCEPT_RESPONSE 0x8002
+#define CT_REASON_CANNOT_PERFORM 0x09
+#define CT_EXPL_ALREADY_REGISTERED 0x10
#define NS_N_PORT_TYPE 0x01
#define NS_NL_PORT_TYPE 0x02
@@ -1768,6 +1770,100 @@
#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
#define RSNN_NN_RSP_SIZE 16
+/*
+ * HBA attribute types.
+ */
+#define FDMI_HBA_ATTR_COUNT 9
+#define FDMI_HBA_NODE_NAME 1
+#define FDMI_HBA_MANUFACTURER 2
+#define FDMI_HBA_SERIAL_NUMBER 3
+#define FDMI_HBA_MODEL 4
+#define FDMI_HBA_MODEL_DESCRIPTION 5
+#define FDMI_HBA_HARDWARE_VERSION 6
+#define FDMI_HBA_DRIVER_VERSION 7
+#define FDMI_HBA_OPTION_ROM_VERSION 8
+#define FDMI_HBA_FIRMWARE_VERSION 9
+#define FDMI_HBA_OS_NAME_AND_VERSION 0xa
+#define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb
+
+struct ct_fdmi_hba_attr {
+ uint16_t type;
+ uint16_t len;
+ union {
+ uint8_t node_name[WWN_SIZE];
+ uint8_t manufacturer[32];
+ uint8_t serial_num[8];
+ uint8_t model[16];
+ uint8_t model_desc[80];
+ uint8_t hw_version[16];
+ uint8_t driver_version[32];
+ uint8_t orom_version[16];
+ uint8_t fw_version[16];
+ uint8_t os_version[128];
+ uint8_t max_ct_len[4];
+ } a;
+};
+
+struct ct_fdmi_hba_attributes {
+ uint32_t count;
+ struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT];
+};
+
+/*
+ * Port attribute types.
+ */
+#define FDMI_PORT_ATTR_COUNT 5
+#define FDMI_PORT_FC4_TYPES 1
+#define FDMI_PORT_SUPPORT_SPEED 2
+#define FDMI_PORT_CURRENT_SPEED 3
+#define FDMI_PORT_MAX_FRAME_SIZE 4
+#define FDMI_PORT_OS_DEVICE_NAME 5
+#define FDMI_PORT_HOST_NAME 6
+
+struct ct_fdmi_port_attr {
+ uint16_t type;
+ uint16_t len;
+ union {
+ uint8_t fc4_types[32];
+ uint32_t sup_speed;
+ uint32_t cur_speed;
+ uint32_t max_frame_size;
+ uint8_t os_dev_name[32];
+ uint8_t host_name[32];
+ } a;
+};
+
+/*
+ * Port Attribute Block.
+ */
+struct ct_fdmi_port_attributes {
+ uint32_t count;
+ struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT];
+};
+
+/* FDMI definitions. */
+#define GRHL_CMD 0x100
+#define GHAT_CMD 0x101
+#define GRPL_CMD 0x102
+#define GPAT_CMD 0x110
+
+#define RHBA_CMD 0x200
+#define RHBA_RSP_SIZE 16
+
+#define RHAT_CMD 0x201
+#define RPRT_CMD 0x210
+
+#define RPA_CMD 0x211
+#define RPA_RSP_SIZE 16
+
+#define DHBA_CMD 0x300
+#define DHBA_REQ_SIZE (16 + 8)
+#define DHBA_RSP_SIZE 16
+
+#define DHAT_CMD 0x301
+#define DPRT_CMD 0x310
+#define DPA_CMD 0x311
+
/* CT command header -- request/response common fields */
struct ct_cmd_hdr {
uint8_t revision;
@@ -1825,6 +1921,43 @@
uint8_t name_len;
uint8_t sym_node_name[255];
} rsnn_nn;
+
+ struct {
+ uint8_t hba_indentifier[8];
+ } ghat;
+
+ struct {
+ uint8_t hba_identifier[8];
+ uint32_t entry_count;
+ uint8_t port_name[8];
+ struct ct_fdmi_hba_attributes attrs;
+ } rhba;
+
+ struct {
+ uint8_t hba_identifier[8];
+ struct ct_fdmi_hba_attributes attrs;
+ } rhat;
+
+ struct {
+ uint8_t port_name[8];
+ struct ct_fdmi_port_attributes attrs;
+ } rpa;
+
+ struct {
+ uint8_t port_name[8];
+ } dhba;
+
+ struct {
+ uint8_t port_name[8];
+ } dhat;
+
+ struct {
+ uint8_t port_name[8];
+ } dprt;
+
+ struct {
+ uint8_t port_name[8];
+ } dpa;
} req;
};
@@ -1882,6 +2015,12 @@
struct {
uint8_t fc4_types[32];
} gft_id;
+
+ struct {
+ uint32_t entry_count;
+ uint8_t port_name[8];
+ struct ct_fdmi_hba_attributes attrs;
+ } ghat;
} rsp;
};
@@ -2032,6 +2171,8 @@
uint16_t (*calc_req_entries) (uint16_t);
void (*build_iocbs) (srb_t *, cmd_entry_t *, uint16_t);
void * (*prep_ms_iocb) (struct scsi_qla_host *, uint32_t, uint32_t);
+ void * (*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t,
+ uint32_t);
uint8_t * (*read_nvram) (struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
@@ -2111,6 +2252,7 @@
#define IOCTL_ERROR_RECOVERY 23
#define LOOP_RESET_NEEDED 24
#define BEACON_BLINK_NEEDED 25
+#define REGISTER_FDMI_NEEDED 26
uint32_t device_flags;
#define DFLG_LOCAL_DEVICES BIT_0
@@ -2204,6 +2346,7 @@
int port_down_retry_count;
uint8_t mbx_count;
uint16_t last_loop_id;
+ uint16_t mgmt_svr_loop_id;
uint32_t login_retry_count;
@@ -2318,6 +2461,7 @@
uint8_t model_number[16+1];
#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
char *model_desc;
+ uint8_t adapter_id[16+1];
uint8_t *node_name;
uint8_t *port_name;
@@ -2377,6 +2521,7 @@
#define QLA_SUSPENDED 0x106
#define QLA_BUSY 0x107
#define QLA_RSCNS_HANDLED 0x108
+#define QLA_ALREADY_REGISTERED 0x109
/*
* Stat info for all adpaters
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 665c203..1ed32e7 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -79,6 +79,7 @@
extern int ql2xenablezio;
extern int ql2xintrdelaytimer;
extern int ql2xloginretrycount;
+extern int ql2xfdmienable;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -147,9 +148,6 @@
#endif
extern int
-qla2x00_target_reset(scsi_qla_host_t *, struct fc_port *);
-
-extern int
qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
uint8_t *, uint16_t *);
@@ -215,6 +213,9 @@
extern int
qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
+extern int
+qla2x00_stop_firmware(scsi_qla_host_t *);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
@@ -269,6 +270,9 @@
extern int qla2x00_rff_id(scsi_qla_host_t *);
extern int qla2x00_rnn_id(scsi_qla_host_t *);
extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
+extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
+extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
+extern int qla2x00_fdmi_register(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_rscn.c source file.
@@ -289,6 +293,8 @@
/*
* Global Function Prototypes in qla_attr.c source file.
*/
+struct class_device_attribute;
+extern struct class_device_attribute *qla2x00_host_attrs[];
struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 31ce4f6..e7b138c 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1099,3 +1099,567 @@
return (rval);
}
+
+/**
+ * qla2x00_mgmt_svr_login() - Login to fabric Managment Service.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_mgmt_svr_login(scsi_qla_host_t *ha)
+{
+ int ret;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ ret = QLA_SUCCESS;
+ if (ha->flags.management_server_logged_in)
+ return ret;
+
+ ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
+ mb, BIT_1);
+ if (mb[0] != MBS_COMMAND_COMPLETE) {
+ DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
+ "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n",
+ __func__, ha->host_no, ha->mgmt_svr_loop_id, mb[0], mb[1],
+ mb[2], mb[6], mb[7]));
+ ret = QLA_FUNCTION_FAILED;
+ } else
+ ha->flags.management_server_logged_in = 1;
+
+ return ret;
+}
+
+/**
+ * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
+ * @ha: HA context
+ * @req_size: request size in bytes
+ * @rsp_size: response size in bytes
+ *
+ * Returns a pointer to the @ha's ms_iocb.
+ */
+void *
+qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
+ uint32_t rsp_size)
+{
+ ms_iocb_entry_t *ms_pkt;
+
+ ms_pkt = ha->ms_iocb;
+ memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));
+
+ ms_pkt->entry_type = MS_IOCB_TYPE;
+ ms_pkt->entry_count = 1;
+ SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id);
+ ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
+ ms_pkt->timeout = __constant_cpu_to_le16(59);
+ ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
+ ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
+ ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
+ ms_pkt->req_bytecount = cpu_to_le32(req_size);
+
+ ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+
+ ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
+
+ return ms_pkt;
+}
+
+/**
+ * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
+ * @ha: HA context
+ * @req_size: request size in bytes
+ * @rsp_size: response size in bytes
+ *
+ * Returns a pointer to the @ha's ms_iocb.
+ */
+void *
+qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
+ uint32_t rsp_size)
+{
+ struct ct_entry_24xx *ct_pkt;
+
+ ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
+ memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+
+ ct_pkt->entry_type = CT_IOCB_TYPE;
+ ct_pkt->entry_count = 1;
+ ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
+ ct_pkt->timeout = __constant_cpu_to_le16(59);
+ ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
+ ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
+ ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
+ ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+
+ ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+
+ ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+
+ return ct_pkt;
+}
+
+static inline ms_iocb_entry_t *
+qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size)
+{
+ ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
+ struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
+
+ if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+ ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+ ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+ } else {
+ ms_pkt->req_bytecount = cpu_to_le32(req_size);
+ ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+ }
+
+ return ms_pkt;
+}
+
+/**
+ * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
+ * @ct_req: CT request buffer
+ * @cmd: GS command
+ * @rsp_size: response size in bytes
+ *
+ * Returns a pointer to the intitialized @ct_req.
+ */
+static inline struct ct_sns_req *
+qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd,
+ uint16_t rsp_size)
+{
+ memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+
+ ct_req->header.revision = 0x01;
+ ct_req->header.gs_type = 0xFA;
+ ct_req->header.gs_subtype = 0x10;
+ ct_req->command = cpu_to_be16(cmd);
+ ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+
+ return ct_req;
+}
+
+/**
+ * qla2x00_fdmi_rhba() -
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_fdmi_rhba(scsi_qla_host_t *ha)
+{
+ int rval, alen;
+ uint32_t size, sn;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+ uint8_t *entries;
+ struct ct_fdmi_hba_attr *eiter;
+
+ /* Issue RHBA */
+ /* Prepare common MS IOCB */
+ /* Request size adjusted after CT preparation */
+ ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
+ RHBA_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare FDMI command arguments -- attribute block, attributes. */
+ memcpy(ct_req->req.rhba.hba_identifier, ha->port_name, WWN_SIZE);
+ ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1);
+ memcpy(ct_req->req.rhba.port_name, ha->port_name, WWN_SIZE);
+ size = 2 * WWN_SIZE + 4 + 4;
+
+ /* Attributes */
+ ct_req->req.rhba.attrs.count =
+ __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT);
+ entries = ct_req->req.rhba.hba_identifier;
+
+ /* Nodename. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME);
+ eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE);
+ memcpy(eiter->a.node_name, ha->node_name, WWN_SIZE);
+ size += 4 + WWN_SIZE;
+
+ DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n",
+ __func__, ha->host_no,
+ eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2],
+ eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5],
+ eiter->a.node_name[6], eiter->a.node_name[7]));
+
+ /* Manufacturer. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER);
+ strcpy(eiter->a.manufacturer, "QLogic Corporation");
+ alen = strlen(eiter->a.manufacturer);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, ha->host_no,
+ eiter->a.manufacturer));
+
+ /* Serial number. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER);
+ sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
+ sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000);
+ alen = strlen(eiter->a.serial_num);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, ha->host_no,
+ eiter->a.serial_num));
+
+ /* Model name. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL);
+ strcpy(eiter->a.model, ha->model_number);
+ alen = strlen(eiter->a.model);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, ha->host_no,
+ eiter->a.model));
+
+ /* Model description. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION);
+ if (ha->model_desc)
+ strncpy(eiter->a.model_desc, ha->model_desc, 80);
+ alen = strlen(eiter->a.model_desc);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, ha->host_no,
+ eiter->a.model_desc));
+
+ /* Hardware version. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION);
+ strcpy(eiter->a.hw_version, ha->adapter_id);
+ alen = strlen(eiter->a.hw_version);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, ha->host_no,
+ eiter->a.hw_version));
+
+ /* Driver version. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION);
+ strcpy(eiter->a.driver_version, qla2x00_version_str);
+ alen = strlen(eiter->a.driver_version);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, ha->host_no,
+ eiter->a.driver_version));
+
+ /* Option ROM version. */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION);
+ strcpy(eiter->a.orom_version, "0.00");
+ alen = strlen(eiter->a.orom_version);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, ha->host_no,
+ eiter->a.orom_version));
+
+ /* Firmware version */
+ eiter = (struct ct_fdmi_hba_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION);
+ ha->isp_ops.fw_version_str(ha, eiter->a.fw_version);
+ alen = strlen(eiter->a.fw_version);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, ha->host_no,
+ eiter->a.fw_version));
+
+ /* Update MS request size. */
+ qla2x00_update_ms_fdmi_iocb(ha, size + 16);
+
+ DEBUG13(printk("%s(%ld): RHBA identifier="
+ "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
+ ha->host_no, ct_req->req.rhba.hba_identifier[0],
+ ct_req->req.rhba.hba_identifier[1],
+ ct_req->req.rhba.hba_identifier[2],
+ ct_req->req.rhba.hba_identifier[3],
+ ct_req->req.rhba.hba_identifier[4],
+ ct_req->req.rhba.hba_identifier[5],
+ ct_req->req.rhba.hba_identifier[6],
+ ct_req->req.rhba.hba_identifier[7], size));
+ DEBUG13(qla2x00_dump_buffer(entries, size));
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n",
+ ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RHBA") !=
+ QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM &&
+ ct_rsp->header.explanation_code ==
+ CT_EXPL_ALREADY_REGISTERED) {
+ DEBUG2_13(printk("%s(%ld): HBA already registered.\n",
+ __func__, ha->host_no));
+ rval = QLA_ALREADY_REGISTERED;
+ }
+ } else {
+ DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n",
+ ha->host_no));
+ }
+
+ return rval;
+}
+
+/**
+ * qla2x00_fdmi_dhba() -
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_fdmi_dhba(scsi_qla_host_t *ha)
+{
+ int rval;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+
+ /* Issue RPA */
+ /* Prepare common MS IOCB */
+ ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
+ DHBA_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD,
+ DHBA_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare FDMI command arguments -- portname. */
+ memcpy(ct_req->req.dhba.port_name, ha->port_name, WWN_SIZE);
+
+ DEBUG13(printk("%s(%ld): DHBA portname="
+ "%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, ha->host_no,
+ ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
+ ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
+ ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
+ ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]));
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n",
+ ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "DHBA") !=
+ QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n",
+ ha->host_no));
+ }
+
+ return rval;
+}
+
+/**
+ * qla2x00_fdmi_rpa() -
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
+{
+ int rval, alen;
+ uint32_t size, max_frame_size;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+ uint8_t *entries;
+ struct ct_fdmi_port_attr *eiter;
+ struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb;
+
+ /* Issue RPA */
+ /* Prepare common MS IOCB */
+ /* Request size adjusted after CT preparation */
+ ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
+ RPA_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare FDMI command arguments -- attribute block, attributes. */
+ memcpy(ct_req->req.rpa.port_name, ha->port_name, WWN_SIZE);
+ size = WWN_SIZE + 4;
+
+ /* Attributes */
+ ct_req->req.rpa.attrs.count =
+ __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
+ entries = ct_req->req.rpa.port_name;
+
+ /* FC4 types. */
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES);
+ eiter->len = __constant_cpu_to_be16(4 + 32);
+ eiter->a.fc4_types[2] = 0x01;
+ size += 4 + 32;
+
+ DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__, ha->host_no,
+ eiter->a.fc4_types[2], eiter->a.fc4_types[1]));
+
+ /* Supported speed. */
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
+ eiter->len = __constant_cpu_to_be16(4 + 4);
+ if (IS_QLA25XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(4);
+ else if (IS_QLA24XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(8);
+ else if (IS_QLA23XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(2);
+ else
+ eiter->a.sup_speed = __constant_cpu_to_be32(1);
+ size += 4 + 4;
+
+ DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no,
+ eiter->a.sup_speed));
+
+ /* Current speed. */
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED);
+ eiter->len = __constant_cpu_to_be16(4 + 4);
+ switch (ha->link_data_rate) {
+ case 0:
+ eiter->a.cur_speed = __constant_cpu_to_be32(1);
+ break;
+ case 1:
+ eiter->a.cur_speed = __constant_cpu_to_be32(2);
+ break;
+ case 3:
+ eiter->a.cur_speed = __constant_cpu_to_be32(8);
+ break;
+ case 4:
+ eiter->a.cur_speed = __constant_cpu_to_be32(4);
+ break;
+ }
+ size += 4 + 4;
+
+ DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, ha->host_no,
+ eiter->a.cur_speed));
+
+ /* Max frame size. */
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
+ eiter->len = __constant_cpu_to_be16(4 + 4);
+ max_frame_size = IS_QLA24XX(ha) || IS_QLA25XX(ha) ?
+ (uint32_t) icb24->frame_payload_size:
+ (uint32_t) ha->init_cb->frame_payload_size;
+ eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
+ size += 4 + 4;
+
+ DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, ha->host_no,
+ eiter->a.max_frame_size));
+
+ /* OS device name. */
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME);
+ sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no);
+ alen = strlen(eiter->a.os_dev_name);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
+ eiter->a.os_dev_name));
+
+ /* Update MS request size. */
+ qla2x00_update_ms_fdmi_iocb(ha, size + 16);
+
+ DEBUG13(printk("%s(%ld): RPA portname="
+ "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
+ ha->host_no, ct_req->req.rpa.port_name[0],
+ ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2],
+ ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4],
+ ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6],
+ ct_req->req.rpa.port_name[7], size));
+ DEBUG13(qla2x00_dump_buffer(entries, size));
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n",
+ ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RPA") !=
+ QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ DEBUG2(printk("scsi(%ld): RPA exiting normally.\n",
+ ha->host_no));
+ }
+
+ return rval;
+}
+
+/**
+ * qla2x00_fdmi_register() -
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_fdmi_register(scsi_qla_host_t *ha)
+{
+ int rval;
+
+ rval = qla2x00_mgmt_svr_login(ha);
+ if (rval)
+ return rval;
+
+ rval = qla2x00_fdmi_rhba(ha);
+ if (rval) {
+ if (rval != QLA_ALREADY_REGISTERED)
+ return rval;
+
+ rval = qla2x00_fdmi_dhba(ha);
+ if (rval)
+ return rval;
+
+ rval = qla2x00_fdmi_rhba(ha);
+ if (rval)
+ return rval;
+ }
+ rval = qla2x00_fdmi_rpa(ha);
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index a6d2559..c619583 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -88,6 +88,7 @@
ha->mbx_flags = 0;
ha->isp_abort_cnt = 0;
ha->beacon_blink_led = 0;
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
rval = ha->isp_ops.pci_config(ha);
@@ -1563,7 +1564,7 @@
ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
- ha->flags.enable_led_scheme = ((nv->efi_parameters & BIT_3) ? 1 : 0);
+ ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
ha->operating_mode =
(icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -1697,6 +1698,7 @@
fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
atomic_set(&fcport->state, FCS_UNCONFIGURED);
fcport->flags = FCF_RLC_SUPPORT;
+ fcport->supported_classes = FC_COS_UNSPECIFIED;
return (fcport);
}
@@ -1898,7 +1900,8 @@
continue;
/* Bypass if not same domain and area of adapter. */
- if (area != ha->d_id.b.area || domain != ha->d_id.b.domain)
+ if (area && domain &&
+ (area != ha->d_id.b.area || domain != ha->d_id.b.domain))
continue;
/* Bypass invalid local loop ID. */
@@ -2075,6 +2078,7 @@
return;
}
rport->dd_data = fcport;
+ rport->supported_classes = fcport->supported_classes;
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
if (fcport->port_type == FCT_INITIATOR)
@@ -2130,6 +2134,11 @@
return (QLA_SUCCESS);
}
do {
+ /* FDMI support. */
+ if (ql2xfdmienable &&
+ test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags))
+ qla2x00_fdmi_register(ha);
+
/* Ensure we are logged into the SNS. */
if (IS_QLA24XX(ha) || IS_QLA25XX(ha))
loop_id = NPH_SNS;
@@ -2392,6 +2401,12 @@
if (new_fcport->d_id.b24 == ha->d_id.b24)
continue;
+ /* Bypass if same domain and area of adapter. */
+ if (((new_fcport->d_id.b24 & 0xffff00) ==
+ (ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
+ ISP_CFG_FL)
+ continue;
+
/* Bypass reserved domain fields. */
if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
continue;
@@ -2794,6 +2809,11 @@
}
}
+ if (mb[10] & BIT_0)
+ fcport->supported_classes |= FC_COS_CLASS2;
+ if (mb[10] & BIT_1)
+ fcport->supported_classes |= FC_COS_CLASS3;
+
rval = QLA_SUCCESS;
break;
} else if (mb[0] == MBS_LOOP_ID_USED) {
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index ebdc3c5..37f82e2 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -810,12 +810,8 @@
ha->req_q_cnt = ha->request_q_length -
(ha->req_ring_index - cnt);
}
- if (ha->req_q_cnt < (req_cnt + 2)) {
- if (cmd->use_sg)
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
+ if (ha->req_q_cnt < (req_cnt + 2))
goto queuing_error;
- }
/* Build command packet. */
ha->current_outstanding_cmd = handle;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index f910de6..c255bb0 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -451,6 +451,8 @@
ha->flags.management_server_logged_in = 0;
ha->link_data_rate = 0;
+ if (ql2xfdmienable)
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
/* Update AEN queue. */
qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 409ea0a..13e1c90 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -19,6 +19,7 @@
#include "qla_def.h"
#include <linux/delay.h>
+#include <scsi/scsi_transport_fc.h>
static void
qla2x00_mbx_sem_timeout(unsigned long data)
@@ -251,7 +252,7 @@
mb0 = RD_REG_WORD(®->isp24.mailbox0);
ictrl = RD_REG_DWORD(®->isp24.ictrl);
} else {
- mb0 = RD_MAILBOX_REG(ha, reg->isp, 0);
+ mb0 = RD_MAILBOX_REG(ha, ®->isp, 0);
ictrl = RD_REG_WORD(®->isp.ictrl);
}
printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n",
@@ -983,58 +984,6 @@
#endif
/*
- * qla2x00_target_reset
- * Issue target reset mailbox command.
- *
- * Input:
- * ha = adapter block pointer.
- * TARGET_QUEUE_LOCK must be released.
- * ADAPTER_STATE_LOCK must be released.
- *
- * Returns:
- * qla2x00 local function return status code.
- *
- * Context:
- * Kernel context.
- */
-int
-qla2x00_target_reset(scsi_qla_host_t *ha, struct fc_port *fcport)
-{
- int rval;
- mbx_cmd_t mc;
- mbx_cmd_t *mcp = &mc;
-
- DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);)
-
- if (atomic_read(&fcport->state) != FCS_ONLINE)
- return 0;
-
- mcp->mb[0] = MBC_TARGET_RESET;
- if (HAS_EXTENDED_IDS(ha))
- mcp->mb[1] = fcport->loop_id;
- else
- mcp->mb[1] = fcport->loop_id << 8;
- mcp->mb[2] = ha->loop_reset_delay;
- mcp->out_mb = MBX_2|MBX_1|MBX_0;
- mcp->in_mb = MBX_0;
- mcp->tov = 30;
- mcp->flags = 0;
- rval = qla2x00_mailbox_command(ha, mcp);
-
- if (rval != QLA_SUCCESS) {
- /*EMPTY*/
- DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n",
- ha->host_no, rval);)
- } else {
- /*EMPTY*/
- DEBUG11(printk("qla2x00_target_reset(%ld): done.\n",
- ha->host_no);)
- }
-
- return rval;
-}
-
-/*
* qla2x00_get_adapter_id
* Get adapter ID and topology.
*
@@ -1326,6 +1275,10 @@
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
+
+ /* Passback COS information. */
+ fcport->supported_classes = (pd->options & BIT_4) ?
+ FC_COS_CLASS2: FC_COS_CLASS3;
}
gpd_error_out:
@@ -1661,6 +1614,13 @@
mb[1] |= BIT_1;
} else
mb[1] = BIT_0;
+
+ /* Passback COS information. */
+ mb[10] = 0;
+ if (lg->io_parameter[7] || lg->io_parameter[8])
+ mb[10] |= BIT_0; /* Class 2. */
+ if (lg->io_parameter[9] || lg->io_parameter[10])
+ mb[10] |= BIT_1; /* Class 3. */
}
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
@@ -1723,6 +1683,8 @@
mb[2] = mcp->mb[2];
mb[6] = mcp->mb[6];
mb[7] = mcp->mb[7];
+ /* COS retrieved from Get-Port-Database mailbox command. */
+ mb[10] = 0;
}
if (rval != QLA_SUCCESS) {
@@ -2465,3 +2427,32 @@
return rval;
}
+
+int
+qla2x00_stop_firmware(scsi_qla_host_t *ha)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_STOP_FIRMWARE;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = 5;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ ha->host_no, rval));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 9000659..8982978 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -79,7 +79,7 @@
MODULE_PARM_DESC(ql2xloginretrycount,
"Specify an alternate value for the NVRAM login retry count.");
-int ql2xfwloadbin;
+int ql2xfwloadbin=1;
module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xfwloadbin,
"Load ISP2xxx firmware image via hotplug.");
@@ -88,6 +88,12 @@
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
+int ql2xfdmienable;
+module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xfdmienable,
+ "Enables FDMI registratons "
+ "Default is 0 - no FDMI. 1 - perfom FDMI.");
+
/*
* SCSI host template entry points
*/
@@ -105,6 +111,9 @@
static int qla2x00_loop_reset(scsi_qla_host_t *ha);
static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
+static int qla2x00_change_queue_depth(struct scsi_device *, int);
+static int qla2x00_change_queue_type(struct scsi_device *, int);
+
static struct scsi_host_template qla2x00_driver_template = {
.module = THIS_MODULE,
.name = "qla2xxx",
@@ -119,6 +128,8 @@
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .change_queue_depth = qla2x00_change_queue_depth,
+ .change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
@@ -129,6 +140,7 @@
* which equates to 0x800000 sectors.
*/
.max_sectors = 0xFFFF,
+ .shost_attrs = qla2x00_host_attrs,
};
static struct scsi_host_template qla24xx_driver_template = {
@@ -145,12 +157,15 @@
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .change_queue_depth = qla2x00_change_queue_depth,
+ .change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
+ .shost_attrs = qla2x00_host_attrs,
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
@@ -487,14 +502,13 @@
static int
qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
{
-#define ABORT_POLLING_PERIOD HZ
-#define ABORT_WAIT_ITER ((10 * HZ) / (ABORT_POLLING_PERIOD))
+#define ABORT_POLLING_PERIOD 1000
+#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD))
unsigned long wait_iter = ABORT_WAIT_ITER;
int ret = QLA_SUCCESS;
while (CMD_SP(cmd)) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(ABORT_POLLING_PERIOD);
+ msleep(ABORT_POLLING_PERIOD);
if (--wait_iter)
break;
@@ -1016,7 +1030,7 @@
if (fcport->port_type != FCT_TARGET)
continue;
- status = qla2x00_target_reset(ha, fcport);
+ status = qla2x00_device_reset(ha, fcport);
if (status != QLA_SUCCESS)
break;
}
@@ -1103,6 +1117,28 @@
sdev->hostdata = NULL;
}
+static int
+qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ return sdev->queue_depth;
+}
+
+static int
+qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
+{
+ if (sdev->tagged_supported) {
+ scsi_set_tag_type(sdev, tag_type);
+ if (tag_type)
+ scsi_activate_tcq(sdev, sdev->queue_depth);
+ else
+ scsi_deactivate_tcq(sdev, sdev->queue_depth);
+ } else
+ tag_type = 0;
+
+ return tag_type;
+}
+
/**
* qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
* @ha: HA context
@@ -1113,36 +1149,23 @@
static void
qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
{
- /* Assume 32bit DMA address */
+ /* Assume a 32bit DMA mask. */
ha->flags.enable_64bit_addressing = 0;
- /*
- * Given the two variants pci_set_dma_mask(), allow the compiler to
- * assist in setting the proper dma mask.
- */
- if (sizeof(dma_addr_t) > 4) {
- if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {
+ if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) {
+ /* Any upper-dword bits set? */
+ if (MSD(dma_get_required_mask(&ha->pdev->dev)) &&
+ !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
+ /* Ok, a 64bit DMA mask is applicable. */
ha->flags.enable_64bit_addressing = 1;
ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64;
ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64;
-
- if (pci_set_consistent_dma_mask(ha->pdev,
- DMA_64BIT_MASK)) {
- qla_printk(KERN_DEBUG, ha,
- "Failed to set 64 bit PCI consistent mask; "
- "using 32 bit.\n");
- pci_set_consistent_dma_mask(ha->pdev,
- DMA_32BIT_MASK);
- }
- } else {
- qla_printk(KERN_DEBUG, ha,
- "Failed to set 64 bit PCI DMA mask, falling back "
- "to 32 bit MASK.\n");
- pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
+ return;
}
- } else {
- pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
}
+
+ dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK);
+ pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
}
static int
@@ -1316,6 +1339,7 @@
ha->prev_topology = 0;
ha->ports = MAX_BUSES;
ha->init_cb_size = sizeof(init_cb_t);
+ ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
/* Assign ISP specific operations. */
ha->isp_ops.pci_config = qla2100_pci_config;
@@ -1338,6 +1362,7 @@
ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32;
ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32;
ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb;
+ ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb;
ha->isp_ops.read_nvram = qla2x00_read_nvram_data;
ha->isp_ops.write_nvram = qla2x00_write_nvram_data;
ha->isp_ops.fw_dump = qla2100_fw_dump;
@@ -1375,6 +1400,7 @@
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct init_cb_24xx);
+ ha->mgmt_svr_loop_id = 10;
ha->isp_ops.pci_config = qla24xx_pci_config;
ha->isp_ops.reset_chip = qla24xx_reset_chip;
ha->isp_ops.chip_diag = qla24xx_chip_diag;
@@ -1395,6 +1421,7 @@
ha->isp_ops.fabric_login = qla24xx_login_fabric;
ha->isp_ops.fabric_logout = qla24xx_fabric_logout;
ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb;
+ ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb;
ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
ha->isp_ops.fw_dump = qla24xx_fw_dump;
@@ -1558,8 +1585,6 @@
return 0;
probe_failed:
- fc_remove_host(ha->host);
-
qla2x00_free_device(ha);
scsi_host_put(host);
@@ -1601,10 +1626,6 @@
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
qla2x00_cancel_io_descriptors(ha);
- /* turn-off interrupts on the card */
- if (ha->interrupts_on)
- ha->isp_ops.disable_intrs(ha);
-
/* Disable timer */
if (ha->timer_active)
qla2x00_stop_timer(ha);
@@ -1624,8 +1645,14 @@
}
}
- qla2x00_mem_free(ha);
+ /* Stop currently executing firmware. */
+ qla2x00_stop_firmware(ha);
+ /* turn-off interrupts on the card */
+ if (ha->interrupts_on)
+ ha->isp_ops.disable_intrs(ha);
+
+ qla2x00_mem_free(ha);
ha->flags.online = 0;
@@ -1934,7 +1961,7 @@
{
struct list_head *fcpl, *fcptemp;
fc_port_t *fcport;
- unsigned long wtime;/* max wait time if mbx cmd is busy. */
+ unsigned int wtime;/* max wait time if mbx cmd is busy. */
if (ha == NULL) {
/* error */
@@ -1943,11 +1970,9 @@
}
/* Make sure all other threads are stopped. */
- wtime = 60 * HZ;
- while (ha->dpc_wait && wtime) {
- set_current_state(TASK_INTERRUPTIBLE);
- wtime = schedule_timeout(wtime);
- }
+ wtime = 60 * 1000;
+ while (ha->dpc_wait && wtime)
+ wtime = msleep_interruptible(wtime);
/* free ioctl memory */
qla2x00_free_ioctl_mem(ha);
@@ -2478,15 +2503,15 @@
int
qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
{
- const unsigned int step = HZ/10;
+ const unsigned int step = 100; /* msecs */
+ unsigned int iterations = jiffies_to_msecs(timeout)/100;
do {
if (!down_trylock(sema))
return 0;
- set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout(step))
+ if (msleep_interruptible(step))
break;
- } while ((timeout -= step) > 0);
+ } while (--iterations >= 0);
return -ETIMEDOUT;
}
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index d7f5c60..c14abf7 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -468,21 +468,12 @@
uint32_t dwords)
{
uint32_t i;
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
- /* Pause RISC. */
- WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
/* Dword reads to flash. */
for (i = 0; i < dwords; i++, faddr++)
dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
flash_data_to_access_addr(faddr)));
- /* Release RISC pause. */
- WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
-
return dwptr;
}
@@ -532,10 +523,6 @@
ret = QLA_SUCCESS;
- /* Pause RISC. */
- WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
-
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,
ha->host_no, man_id, flash_id));
@@ -599,10 +586,6 @@
RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
- /* Release RISC pause. */
- WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
-
return ret;
}
@@ -630,11 +613,6 @@
{
uint32_t i;
uint32_t *dwptr;
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
- /* Pause RISC. */
- WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
/* Dword reads to flash. */
dwptr = (uint32_t *)buf;
@@ -642,10 +620,6 @@
dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
nvram_data_to_access_addr(naddr)));
- /* Release RISC pause. */
- WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
-
return buf;
}
@@ -690,10 +664,6 @@
ret = QLA_SUCCESS;
- /* Pause RISC. */
- WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
-
/* Enable flash write. */
WRT_REG_DWORD(®->ctrl_status,
RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE);
@@ -728,9 +698,5 @@
RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
- /* Release RISC pause. */
- WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
- RD_REG_DWORD(®->hccr); /* PCI Posting. */
-
return ret;
}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index e3cd361..eae7d6e 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -19,9 +19,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.00b5-k"
+#define QLA2XXX_VERSION "8.01.00-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
#define QLA_DRIVER_PATCH_VER 0
-#define QLA_DRIVER_BETA_VER 5
+#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
new file mode 100644
index 0000000..f1ea502
--- /dev/null
+++ b/drivers/scsi/raid_class.c
@@ -0,0 +1,250 @@
+/*
+ * RAID Attributes
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/raid_class.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#define RAID_NUM_ATTRS 3
+
+struct raid_internal {
+ struct raid_template r;
+ struct raid_function_template *f;
+ /* The actual attributes */
+ struct class_device_attribute private_attrs[RAID_NUM_ATTRS];
+ /* The array of null terminated pointers to attributes
+ * needed by scsi_sysfs.c */
+ struct class_device_attribute *attrs[RAID_NUM_ATTRS + 1];
+};
+
+struct raid_component {
+ struct list_head node;
+ struct device *dev;
+ int num;
+};
+
+#define to_raid_internal(tmpl) container_of(tmpl, struct raid_internal, r)
+
+#define tc_to_raid_internal(tcont) ({ \
+ struct raid_template *r = \
+ container_of(tcont, struct raid_template, raid_attrs); \
+ to_raid_internal(r); \
+})
+
+#define ac_to_raid_internal(acont) ({ \
+ struct transport_container *tc = \
+ container_of(acont, struct transport_container, ac); \
+ tc_to_raid_internal(tc); \
+})
+
+#define class_device_to_raid_internal(cdev) ({ \
+ struct attribute_container *ac = \
+ attribute_container_classdev_to_container(cdev); \
+ ac_to_raid_internal(ac); \
+})
+
+
+static int raid_match(struct attribute_container *cont, struct device *dev)
+{
+ /* We have to look for every subsystem that could house
+ * emulated RAID devices, so start with SCSI */
+ struct raid_internal *i = ac_to_raid_internal(cont);
+
+ if (scsi_is_sdev_device(dev)) {
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (i->f->cookie != sdev->host->hostt)
+ return 0;
+
+ return i->f->is_raid(dev);
+ }
+ /* FIXME: look at other subsystems too */
+ return 0;
+}
+
+static int raid_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
+{
+ struct raid_data *rd;
+
+ BUG_ON(class_get_devdata(cdev));
+
+ rd = kmalloc(sizeof(*rd), GFP_KERNEL);
+ if (!rd)
+ return -ENOMEM;
+
+ memset(rd, 0, sizeof(*rd));
+ INIT_LIST_HEAD(&rd->component_list);
+ class_set_devdata(cdev, rd);
+
+ return 0;
+}
+
+static int raid_remove(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
+{
+ struct raid_data *rd = class_get_devdata(cdev);
+ struct raid_component *rc, *next;
+ class_set_devdata(cdev, NULL);
+ list_for_each_entry_safe(rc, next, &rd->component_list, node) {
+ char buf[40];
+ snprintf(buf, sizeof(buf), "component-%d", rc->num);
+ list_del(&rc->node);
+ sysfs_remove_link(&cdev->kobj, buf);
+ kfree(rc);
+ }
+ kfree(class_get_devdata(cdev));
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(raid_class,
+ "raid_devices",
+ raid_setup,
+ raid_remove,
+ NULL);
+
+static struct {
+ enum raid_state value;
+ char *name;
+} raid_states[] = {
+ { RAID_ACTIVE, "active" },
+ { RAID_DEGRADED, "degraded" },
+ { RAID_RESYNCING, "resyncing" },
+ { RAID_OFFLINE, "offline" },
+};
+
+static const char *raid_state_name(enum raid_state state)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < sizeof(raid_states)/sizeof(raid_states[0]); i++) {
+ if (raid_states[i].value == state) {
+ name = raid_states[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
+
+#define raid_attr_show_internal(attr, fmt, var, code) \
+static ssize_t raid_show_##attr(struct class_device *cdev, char *buf) \
+{ \
+ struct raid_data *rd = class_get_devdata(cdev); \
+ code \
+ return snprintf(buf, 20, #fmt "\n", var); \
+}
+
+#define raid_attr_ro_states(attr, states, code) \
+raid_attr_show_internal(attr, %s, name, \
+ const char *name; \
+ code \
+ name = raid_##states##_name(rd->attr); \
+) \
+static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL)
+
+
+#define raid_attr_ro_internal(attr, code) \
+raid_attr_show_internal(attr, %d, rd->attr, code) \
+static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL)
+
+#define ATTR_CODE(attr) \
+ struct raid_internal *i = class_device_to_raid_internal(cdev); \
+ if (i->f->get_##attr) \
+ i->f->get_##attr(cdev->dev);
+
+#define raid_attr_ro(attr) raid_attr_ro_internal(attr, )
+#define raid_attr_ro_fn(attr) raid_attr_ro_internal(attr, ATTR_CODE(attr))
+#define raid_attr_ro_state(attr) raid_attr_ro_states(attr, attr, ATTR_CODE(attr))
+
+raid_attr_ro(level);
+raid_attr_ro_fn(resync);
+raid_attr_ro_state(state);
+
+void raid_component_add(struct raid_template *r,struct device *raid_dev,
+ struct device *component_dev)
+{
+ struct class_device *cdev =
+ attribute_container_find_class_device(&r->raid_attrs.ac,
+ raid_dev);
+ struct raid_component *rc;
+ struct raid_data *rd = class_get_devdata(cdev);
+ char buf[40];
+
+ rc = kmalloc(sizeof(*rc), GFP_KERNEL);
+ if (!rc)
+ return;
+
+ INIT_LIST_HEAD(&rc->node);
+ rc->dev = component_dev;
+ rc->num = rd->component_count++;
+
+ snprintf(buf, sizeof(buf), "component-%d", rc->num);
+ list_add_tail(&rc->node, &rd->component_list);
+ sysfs_create_link(&cdev->kobj, &component_dev->kobj, buf);
+}
+EXPORT_SYMBOL(raid_component_add);
+
+struct raid_template *
+raid_class_attach(struct raid_function_template *ft)
+{
+ struct raid_internal *i = kmalloc(sizeof(struct raid_internal),
+ GFP_KERNEL);
+ int count = 0;
+
+ if (unlikely(!i))
+ return NULL;
+
+ memset(i, 0, sizeof(*i));
+
+ i->f = ft;
+
+ i->r.raid_attrs.ac.class = &raid_class.class;
+ i->r.raid_attrs.ac.match = raid_match;
+ i->r.raid_attrs.ac.attrs = &i->attrs[0];
+
+ attribute_container_register(&i->r.raid_attrs.ac);
+
+ i->attrs[count++] = &class_device_attr_level;
+ i->attrs[count++] = &class_device_attr_resync;
+ i->attrs[count++] = &class_device_attr_state;
+
+ i->attrs[count] = NULL;
+ BUG_ON(count > RAID_NUM_ATTRS);
+
+ return &i->r;
+}
+EXPORT_SYMBOL(raid_class_attach);
+
+void
+raid_class_release(struct raid_template *r)
+{
+ struct raid_internal *i = to_raid_internal(r);
+
+ attribute_container_unregister(&i->r.raid_attrs.ac);
+
+ kfree(i);
+}
+EXPORT_SYMBOL(raid_class_release);
+
+static __init int raid_init(void)
+{
+ return transport_class_register(&raid_class);
+}
+
+static __exit void raid_exit(void)
+{
+ transport_class_unregister(&raid_class);
+}
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("RAID device class");
+MODULE_LICENSE("GPL");
+
+module_init(raid_init);
+module_exit(raid_exit);
+
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
new file mode 100644
index 0000000..f97e3af
--- /dev/null
+++ b/drivers/scsi/sata_mv.c
@@ -0,0 +1,843 @@
+/*
+ * sata_mv.c - Marvell SATA support
+ *
+ * Copyright 2005: EMC Corporation, all rights reserved.
+ *
+ * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "sata_mv"
+#define DRV_VERSION "0.12"
+
+enum {
+ /* BAR's are enumerated in terms of pci_resource_start() terms */
+ MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */
+ MV_IO_BAR = 2, /* offset 0x18: IO space */
+ MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */
+
+ MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
+ MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
+
+ MV_PCI_REG_BASE = 0,
+ MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
+ MV_SATAHC0_REG_BASE = 0x20000,
+
+ MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
+ MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
+ MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
+ MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
+
+ MV_Q_CT = 32,
+ MV_CRQB_SZ = 32,
+ MV_CRPB_SZ = 8,
+
+ MV_DMA_BOUNDARY = 0xffffffffU,
+ SATAHC_MASK = (~(MV_SATAHC_REG_SZ - 1)),
+
+ MV_PORTS_PER_HC = 4,
+ /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+ MV_PORT_HC_SHIFT = 2,
+ /* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */
+ MV_PORT_MASK = 3,
+
+ /* Host Flags */
+ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
+ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
+ MV_FLAG_BDMA = (1 << 28), /* Basic DMA */
+
+ chip_504x = 0,
+ chip_508x = 1,
+ chip_604x = 2,
+ chip_608x = 3,
+
+ /* PCI interface registers */
+
+ PCI_MAIN_CMD_STS_OFS = 0xd30,
+ STOP_PCI_MASTER = (1 << 2),
+ PCI_MASTER_EMPTY = (1 << 3),
+ GLOB_SFT_RST = (1 << 4),
+
+ PCI_IRQ_CAUSE_OFS = 0x1d58,
+ PCI_IRQ_MASK_OFS = 0x1d5c,
+ PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
+
+ HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
+ HC_MAIN_IRQ_MASK_OFS = 0x1d64,
+ PORT0_ERR = (1 << 0), /* shift by port # */
+ PORT0_DONE = (1 << 1), /* shift by port # */
+ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
+ HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
+ PCI_ERR = (1 << 18),
+ TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
+ TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
+ PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
+ GPIO_INT = (1 << 22),
+ SELF_INT = (1 << 23),
+ TWSI_INT = (1 << 24),
+ HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
+ HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
+ PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
+ HC_MAIN_RSVD),
+
+ /* SATAHC registers */
+ HC_CFG_OFS = 0,
+
+ HC_IRQ_CAUSE_OFS = 0x14,
+ CRBP_DMA_DONE = (1 << 0), /* shift by port # */
+ HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
+ DEV_IRQ = (1 << 8), /* shift by port # */
+
+ /* Shadow block registers */
+ SHD_PIO_DATA_OFS = 0x100,
+ SHD_FEA_ERR_OFS = 0x104,
+ SHD_SECT_CNT_OFS = 0x108,
+ SHD_LBA_L_OFS = 0x10C,
+ SHD_LBA_M_OFS = 0x110,
+ SHD_LBA_H_OFS = 0x114,
+ SHD_DEV_HD_OFS = 0x118,
+ SHD_CMD_STA_OFS = 0x11C,
+ SHD_CTL_AST_OFS = 0x120,
+
+ /* SATA registers */
+ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
+ SATA_ACTIVE_OFS = 0x350,
+
+ /* Port registers */
+ EDMA_CFG_OFS = 0,
+
+ EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
+ EDMA_ERR_IRQ_MASK_OFS = 0xc,
+ EDMA_ERR_D_PAR = (1 << 0),
+ EDMA_ERR_PRD_PAR = (1 << 1),
+ EDMA_ERR_DEV = (1 << 2),
+ EDMA_ERR_DEV_DCON = (1 << 3),
+ EDMA_ERR_DEV_CON = (1 << 4),
+ EDMA_ERR_SERR = (1 << 5),
+ EDMA_ERR_SELF_DIS = (1 << 7),
+ EDMA_ERR_BIST_ASYNC = (1 << 8),
+ EDMA_ERR_CRBQ_PAR = (1 << 9),
+ EDMA_ERR_CRPB_PAR = (1 << 10),
+ EDMA_ERR_INTRL_PAR = (1 << 11),
+ EDMA_ERR_IORDY = (1 << 12),
+ EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
+ EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
+ EDMA_ERR_LNK_DATA_RX = (0xf << 17),
+ EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
+ EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
+ EDMA_ERR_TRANS_PROTO = (1 << 31),
+ EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
+ EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
+ EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
+ EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
+ EDMA_ERR_LNK_DATA_RX |
+ EDMA_ERR_LNK_DATA_TX |
+ EDMA_ERR_TRANS_PROTO),
+
+ EDMA_CMD_OFS = 0x28,
+ EDMA_EN = (1 << 0),
+ EDMA_DS = (1 << 1),
+ ATA_RST = (1 << 2),
+
+ /* BDMA is 6xxx part only */
+ BDMA_CMD_OFS = 0x224,
+ BDMA_START = (1 << 0),
+
+ MV_UNDEF = 0,
+};
+
+struct mv_port_priv {
+
+};
+
+struct mv_host_priv {
+
+};
+
+static void mv_irq_clear(struct ata_port *ap);
+static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
+static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static void mv_phy_reset(struct ata_port *ap);
+static int mv_master_reset(void __iomem *mmio_base);
+static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static Scsi_Host_Template mv_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .eh_strategy_handler = ata_scsi_error,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = MV_UNDEF,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = MV_UNDEF,
+ .proc_name = DRV_NAME,
+ .dma_boundary = MV_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+ .ordered_flush = 1,
+};
+
+static struct ata_port_operations mv_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = mv_phy_reset,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .eng_timeout = ata_eng_timeout,
+
+ .irq_handler = mv_interrupt,
+ .irq_clear = mv_irq_clear,
+
+ .scr_read = mv_scr_read,
+ .scr_write = mv_scr_write,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static struct ata_port_info mv_port_info[] = {
+ { /* chip_504x */
+ .sht = &mv_sht,
+ .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO),
+ .pio_mask = 0x1f, /* pio4-0 */
+ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
+ .port_ops = &mv_ops,
+ },
+ { /* chip_508x */
+ .sht = &mv_sht,
+ .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ MV_FLAG_DUAL_HC),
+ .pio_mask = 0x1f, /* pio4-0 */
+ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
+ .port_ops = &mv_ops,
+ },
+ { /* chip_604x */
+ .sht = &mv_sht,
+ .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA),
+ .pio_mask = 0x1f, /* pio4-0 */
+ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
+ .port_ops = &mv_ops,
+ },
+ { /* chip_608x */
+ .sht = &mv_sht,
+ .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC |
+ MV_FLAG_BDMA),
+ .pio_mask = 0x1f, /* pio4-0 */
+ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */
+ .port_ops = &mv_ops,
+ },
+};
+
+static struct pci_device_id mv_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_508x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
+
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+ {} /* terminate list */
+};
+
+static struct pci_driver mv_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = mv_pci_tbl,
+ .probe = mv_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+/*
+ * Functions
+ */
+
+static inline void writelfl(unsigned long data, void __iomem *addr)
+{
+ writel(data, addr);
+ (void) readl(addr); /* flush to avoid PCI posted write */
+}
+
+static inline void __iomem *mv_port_addr_to_hc_base(void __iomem *port_mmio)
+{
+ return ((void __iomem *)((unsigned long)port_mmio &
+ (unsigned long)SATAHC_MASK));
+}
+
+static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
+{
+ return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
+}
+
+static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
+{
+ return (mv_hc_base(base, port >> MV_PORT_HC_SHIFT) +
+ MV_SATAHC_ARBTR_REG_SZ +
+ ((port & MV_PORT_MASK) * MV_PORT_REG_SZ));
+}
+
+static inline void __iomem *mv_ap_base(struct ata_port *ap)
+{
+ return mv_port_base(ap->host_set->mmio_base, ap->port_no);
+}
+
+static inline int mv_get_hc_count(unsigned long flags)
+{
+ return ((flags & MV_FLAG_DUAL_HC) ? 2 : 1);
+}
+
+static inline int mv_is_edma_active(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ return (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
+}
+
+static inline int mv_port_bdma_capable(struct ata_port *ap)
+{
+ return (ap->flags & MV_FLAG_BDMA);
+}
+
+static void mv_irq_clear(struct ata_port *ap)
+{
+}
+
+static unsigned int mv_scr_offset(unsigned int sc_reg_in)
+{
+ unsigned int ofs;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ case SCR_CONTROL:
+ case SCR_ERROR:
+ ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
+ break;
+ case SCR_ACTIVE:
+ ofs = SATA_ACTIVE_OFS; /* active is not with the others */
+ break;
+ default:
+ ofs = 0xffffffffU;
+ break;
+ }
+ return ofs;
+}
+
+static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+{
+ unsigned int ofs = mv_scr_offset(sc_reg_in);
+
+ if (0xffffffffU != ofs) {
+ return readl(mv_ap_base(ap) + ofs);
+ } else {
+ return (u32) ofs;
+ }
+}
+
+static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+{
+ unsigned int ofs = mv_scr_offset(sc_reg_in);
+
+ if (0xffffffffU != ofs) {
+ writelfl(val, mv_ap_base(ap) + ofs);
+ }
+}
+
+static int mv_master_reset(void __iomem *mmio_base)
+{
+ void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS;
+ int i, rc = 0;
+ u32 t;
+
+ VPRINTK("ENTER\n");
+
+ /* Following procedure defined in PCI "main command and status
+ * register" table.
+ */
+ t = readl(reg);
+ writel(t | STOP_PCI_MASTER, reg);
+
+ for (i = 0; i < 100; i++) {
+ msleep(10);
+ t = readl(reg);
+ if (PCI_MASTER_EMPTY & t) {
+ break;
+ }
+ }
+ if (!(PCI_MASTER_EMPTY & t)) {
+ printk(KERN_ERR DRV_NAME "PCI master won't flush\n");
+ rc = 1; /* broken HW? */
+ goto done;
+ }
+
+ /* set reset */
+ i = 5;
+ do {
+ writel(t | GLOB_SFT_RST, reg);
+ t = readl(reg);
+ udelay(1);
+ } while (!(GLOB_SFT_RST & t) && (i-- > 0));
+
+ if (!(GLOB_SFT_RST & t)) {
+ printk(KERN_ERR DRV_NAME "can't set global reset\n");
+ rc = 1; /* broken HW? */
+ goto done;
+ }
+
+ /* clear reset */
+ i = 5;
+ do {
+ writel(t & ~GLOB_SFT_RST, reg);
+ t = readl(reg);
+ udelay(1);
+ } while ((GLOB_SFT_RST & t) && (i-- > 0));
+
+ if (GLOB_SFT_RST & t) {
+ printk(KERN_ERR DRV_NAME "can't clear global reset\n");
+ rc = 1; /* broken HW? */
+ }
+
+ done:
+ VPRINTK("EXIT, rc = %i\n", rc);
+ return rc;
+}
+
+static void mv_err_intr(struct ata_port *ap)
+{
+ void __iomem *port_mmio;
+ u32 edma_err_cause, serr = 0;
+
+ /* bug here b/c we got an err int on a port we don't know about,
+ * so there's no way to clear it
+ */
+ BUG_ON(NULL == ap);
+ port_mmio = mv_ap_base(ap);
+
+ edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ if (EDMA_ERR_SERR & edma_err_cause) {
+ serr = scr_read(ap, SCR_ERROR);
+ scr_write_flush(ap, SCR_ERROR, serr);
+ }
+ DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n",
+ ap->port_no, edma_err_cause, serr);
+
+ /* Clear EDMA now that SERR cleanup done */
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ /* check for fatal here and recover if needed */
+ if (EDMA_ERR_FATAL & edma_err_cause) {
+ mv_phy_reset(ap);
+ }
+}
+
+/* Handle any outstanding interrupts in a single SATAHC
+ */
+static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
+ unsigned int hc)
+{
+ void __iomem *mmio = host_set->mmio_base;
+ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ u32 hc_irq_cause;
+ int shift, port, port0, hard_port;
+ u8 ata_status;
+
+ if (hc == 0) {
+ port0 = 0;
+ } else {
+ port0 = MV_PORTS_PER_HC;
+ }
+
+ /* we'll need the HC success int register in most cases */
+ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+ if (hc_irq_cause) {
+ writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
+ }
+
+ VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
+ hc,relevant,hc_irq_cause);
+
+ for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+ ap = host_set->ports[port];
+ hard_port = port & MV_PORT_MASK; /* range 0-3 */
+ ata_status = 0xffU;
+
+ if (((CRBP_DMA_DONE | DEV_IRQ) << hard_port) & hc_irq_cause) {
+ BUG_ON(NULL == ap);
+ /* rcv'd new resp, basic DMA complete, or ATA IRQ */
+ /* This is needed to clear the ATA INTRQ.
+ * FIXME: don't read the status reg in EDMA mode!
+ */
+ ata_status = readb((void __iomem *)
+ ap->ioaddr.status_addr);
+ }
+
+ shift = port * 2;
+ if (port >= MV_PORTS_PER_HC) {
+ shift++; /* skip bit 8 in the HC Main IRQ reg */
+ }
+ if ((PORT0_ERR << shift) & relevant) {
+ mv_err_intr(ap);
+ /* FIXME: smart to OR in ATA_ERR? */
+ ata_status = readb((void __iomem *)
+ ap->ioaddr.status_addr) | ATA_ERR;
+ }
+
+ if (ap) {
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (NULL != qc) {
+ VPRINTK("port %u IRQ found for qc, "
+ "ata_status 0x%x\n", port,ata_status);
+ BUG_ON(0xffU == ata_status);
+ /* mark qc status appropriately */
+ ata_qc_complete(qc, ata_status);
+ }
+ }
+ }
+ VPRINTK("EXIT\n");
+}
+
+static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host_set *host_set = dev_instance;
+ unsigned int hc, handled = 0, n_hcs;
+ void __iomem *mmio;
+ u32 irq_stat;
+
+ mmio = host_set->mmio_base;
+ irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
+ n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
+
+ /* check the cases where we either have nothing pending or have read
+ * a bogus register value which can indicate HW removal or PCI fault
+ */
+ if (!irq_stat || (0xffffffffU == irq_stat)) {
+ return IRQ_NONE;
+ }
+
+ spin_lock(&host_set->lock);
+
+ for (hc = 0; hc < n_hcs; hc++) {
+ u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
+ if (relevant) {
+ mv_host_intr(host_set, relevant, hc);
+ handled = 1;
+ }
+ }
+ if (PCI_ERR & irq_stat) {
+ /* FIXME: these are all masked by default, but still need
+ * to recover from them properly.
+ */
+ }
+
+ spin_unlock(&host_set->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void mv_phy_reset(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct ata_taskfile tf;
+ struct ata_device *dev = &ap->device[0];
+ u32 edma = 0, bdma;
+
+ VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
+
+ edma = readl(port_mmio + EDMA_CMD_OFS);
+ if (EDMA_EN & edma) {
+ /* disable EDMA if active */
+ edma &= ~EDMA_EN;
+ writelfl(edma | EDMA_DS, port_mmio + EDMA_CMD_OFS);
+ udelay(1);
+ } else if (mv_port_bdma_capable(ap) &&
+ (bdma = readl(port_mmio + BDMA_CMD_OFS)) & BDMA_START) {
+ /* disable BDMA if active */
+ writelfl(bdma & ~BDMA_START, port_mmio + BDMA_CMD_OFS);
+ }
+
+ writelfl(edma | ATA_RST, port_mmio + EDMA_CMD_OFS);
+ udelay(25); /* allow reset propagation */
+
+ /* Spec never mentions clearing the bit. Marvell's driver does
+ * clear the bit, however.
+ */
+ writelfl(edma & ~ATA_RST, port_mmio + EDMA_CMD_OFS);
+
+ VPRINTK("Done. Now calling __sata_phy_reset()\n");
+
+ /* proceed to init communications via the scr_control reg */
+ __sata_phy_reset(ap);
+
+ if (ap->flags & ATA_FLAG_PORT_DISABLED) {
+ VPRINTK("Port disabled pre-sig. Exiting.\n");
+ return;
+ }
+
+ tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
+ tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
+ tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
+ tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
+
+ dev->class = ata_dev_classify(&tf);
+ if (!ata_dev_present(dev)) {
+ VPRINTK("Port disabled post-sig: No device present.\n");
+ ata_port_disable(ap);
+ }
+ VPRINTK("EXIT\n");
+}
+
+static void mv_port_init(struct ata_ioports *port, unsigned long base)
+{
+ /* PIO related setup */
+ port->data_addr = base + SHD_PIO_DATA_OFS;
+ port->error_addr = port->feature_addr = base + SHD_FEA_ERR_OFS;
+ port->nsect_addr = base + SHD_SECT_CNT_OFS;
+ port->lbal_addr = base + SHD_LBA_L_OFS;
+ port->lbam_addr = base + SHD_LBA_M_OFS;
+ port->lbah_addr = base + SHD_LBA_H_OFS;
+ port->device_addr = base + SHD_DEV_HD_OFS;
+ port->status_addr = port->command_addr = base + SHD_CMD_STA_OFS;
+ port->altstatus_addr = port->ctl_addr = base + SHD_CTL_AST_OFS;
+ /* unused */
+ port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+
+ /* unmask all EDMA error interrupts */
+ writel(~0, (void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS);
+
+ VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
+ readl((void __iomem *)base + EDMA_CFG_OFS),
+ readl((void __iomem *)base + EDMA_ERR_IRQ_CAUSE_OFS),
+ readl((void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS));
+}
+
+static int mv_host_init(struct ata_probe_ent *probe_ent)
+{
+ int rc = 0, n_hc, port, hc;
+ void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *port_mmio;
+
+ if (mv_master_reset(probe_ent->mmio_base)) {
+ rc = 1;
+ goto done;
+ }
+
+ n_hc = mv_get_hc_count(probe_ent->host_flags);
+ probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+
+ for (port = 0; port < probe_ent->n_ports; port++) {
+ port_mmio = mv_port_base(mmio, port);
+ mv_port_init(&probe_ent->port[port], (unsigned long)port_mmio);
+ }
+
+ for (hc = 0; hc < n_hc; hc++) {
+ VPRINTK("HC%i: HC config=0x%08x HC IRQ cause=0x%08x\n", hc,
+ readl(mv_hc_base(mmio, hc) + HC_CFG_OFS),
+ readl(mv_hc_base(mmio, hc) + HC_IRQ_CAUSE_OFS));
+ }
+
+ writel(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+ writel(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
+
+ VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+ "PCI int cause/mask=0x%08x/0x%08x\n",
+ readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
+ readl(mmio + HC_MAIN_IRQ_MASK_OFS),
+ readl(mmio + PCI_IRQ_CAUSE_OFS),
+ readl(mmio + PCI_IRQ_MASK_OFS));
+
+ done:
+ return rc;
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_intx(struct pci_dev *pdev, int enable)
+{
+ u16 pci_command, new;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+
+ if (enable)
+ new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
+ else
+ new = pci_command | PCI_COMMAND_INTX_DISABLE;
+
+ if (new != pci_command)
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+}
+
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version = 0;
+ struct ata_probe_ent *probe_ent = NULL;
+ struct mv_host_priv *hpriv;
+ unsigned int board_idx = (unsigned int)ent->driver_data;
+ void __iomem *mmio_base;
+ int pci_dev_busy = 0;
+ int rc;
+
+ if (!printed_version++) {
+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+ }
+
+ VPRINTK("ENTER for PCI Bus:Slot.Func=%u:%u.%u\n", pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ return rc;
+ }
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ pci_intx(pdev, 1);
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = ioremap_nocache(pci_resource_start(pdev, MV_PRIMARY_BAR),
+ pci_resource_len(pdev, MV_PRIMARY_BAR));
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+ memset(hpriv, 0, sizeof(*hpriv));
+
+ probe_ent->sht = mv_port_info[board_idx].sht;
+ probe_ent->host_flags = mv_port_info[board_idx].host_flags;
+ probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
+ probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = mv_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->mmio_base = mmio_base;
+ probe_ent->private_data = hpriv;
+
+ /* initialize adapter */
+ rc = mv_host_init(probe_ent);
+ if (rc) {
+ goto err_out_hpriv;
+ }
+/* mv_print_info(probe_ent); */
+
+ {
+ int b, w;
+ u32 dw[4]; /* hold a line of 16b */
+ VPRINTK("PCI config space:\n");
+ for (b = 0; b < 0x40; ) {
+ for (w = 0; w < 4; w++) {
+ (void) pci_read_config_dword(pdev,b,&dw[w]);
+ b += sizeof(*dw);
+ }
+ VPRINTK("%08x %08x %08x %08x\n",
+ dw[0],dw[1],dw[2],dw[3]);
+ }
+ }
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+ err_out_hpriv:
+ kfree(hpriv);
+ err_out_iounmap:
+ iounmap(mmio_base);
+ err_out_free_ent:
+ kfree(probe_ent);
+ err_out_regions:
+ pci_release_regions(pdev);
+ err_out:
+ if (!pci_dev_busy) {
+ pci_disable_device(pdev);
+ }
+
+ return rc;
+}
+
+static int __init mv_init(void)
+{
+ return pci_module_init(&mv_pci_driver);
+}
+
+static void __exit mv_exit(void)
+{
+ pci_unregister_driver(&mv_pci_driver);
+}
+
+MODULE_AUTHOR("Brett Russ");
+MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(mv_init);
+module_exit(mv_exit);
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 03d9bc6..a1d62de 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -351,6 +351,7 @@
static void nv_host_stop (struct ata_host_set *host_set)
{
struct nv_host *host = host_set->private_data;
+ struct pci_dev *pdev = to_pci_dev(host_set->dev);
// Disable hotplug event interrupts.
if (host->host_desc->disable_hotplug)
@@ -358,7 +359,8 @@
kfree(host);
- ata_host_stop(host_set);
+ if (host_set->mmio_base)
+ pci_iounmap(pdev, host_set->mmio_base);
}
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -420,8 +422,7 @@
if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
unsigned long base;
- probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5),
- pci_resource_len(pdev, 5));
+ probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
if (probe_ent->mmio_base == NULL) {
rc = -EIO;
goto err_out_free_host;
@@ -457,7 +458,7 @@
err_out_iounmap:
if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
- iounmap(probe_ent->mmio_base);
+ pci_iounmap(pdev, probe_ent->mmio_base);
err_out_free_host:
kfree(host);
err_out_free_ent:
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 7c4f6ec..538ad72 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -92,6 +92,7 @@
static void pdc_irq_clear(struct ata_port *ap);
static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+
static Scsi_Host_Template pdc_ata_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -132,7 +133,7 @@
.scr_write = pdc_sata_scr_write,
.port_start = pdc_port_start,
.port_stop = pdc_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = ata_pci_host_stop,
};
static struct ata_port_operations pdc_pata_ops = {
@@ -153,7 +154,7 @@
.port_start = pdc_port_start,
.port_stop = pdc_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = ata_pci_host_stop,
};
static struct ata_port_info pdc_port_info[] = {
@@ -282,7 +283,7 @@
static void pdc_reset_port(struct ata_port *ap)
{
- void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
@@ -418,7 +419,7 @@
u8 status;
unsigned int handled = 0, have_err = 0;
u32 tmp;
- void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
tmp = readl(mmio);
if (tmp & PDC_ERR_MASK) {
@@ -447,7 +448,7 @@
static void pdc_irq_clear(struct ata_port *ap)
{
struct ata_host_set *host_set = ap->host_set;
- void *mmio = host_set->mmio_base;
+ void __iomem *mmio = host_set->mmio_base;
readl(mmio + PDC_INT_SEQMASK);
}
@@ -459,7 +460,7 @@
u32 mask = 0;
unsigned int i, tmp;
unsigned int handled = 0;
- void *mmio_base;
+ void __iomem *mmio_base;
VPRINTK("ENTER\n");
@@ -581,7 +582,7 @@
static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
u32 tmp;
/*
@@ -624,7 +625,7 @@
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
unsigned long base;
- void *mmio_base;
+ void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
int rc;
@@ -663,8 +664,7 @@
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = ioremap(pci_resource_start(pdev, 3),
- pci_resource_len(pdev, 3));
+ mmio_base = pci_iomap(pdev, 3, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 9c99ab4..ffcdeb6 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -494,7 +494,7 @@
if (rc)
return rc;
qs_enter_reg_mode(ap);
- pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
if (!pp) {
rc = -ENOMEM;
goto err_out;
@@ -538,11 +538,12 @@
static void qs_host_stop(struct ata_host_set *host_set)
{
void __iomem *mmio_base = host_set->mmio_base;
+ struct pci_dev *pdev = to_pci_dev(host_set->dev);
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
- ata_host_stop(host_set);
+ pci_iounmap(pdev, mmio_base);
}
static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
@@ -646,8 +647,7 @@
goto err_out_regions;
}
- mmio_base = ioremap(pci_resource_start(pdev, 4),
- pci_resource_len(pdev, 4));
+ mmio_base = pci_iomap(pdev, 4, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_regions;
@@ -697,7 +697,7 @@
return 0;
err_out_iounmap:
- iounmap(mmio_base);
+ pci_iounmap(pdev, mmio_base);
err_out_regions:
pci_release_regions(pdev);
err_out:
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 71d4954..ba98a17 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -86,6 +86,7 @@
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void sil_post_set_mode (struct ata_port *ap);
+
static struct pci_device_id sil_pci_tbl[] = {
{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
@@ -172,7 +173,7 @@
.scr_write = sil_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = ata_pci_host_stop,
};
static struct ata_port_info sil_port_info[] = {
@@ -231,6 +232,7 @@
MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
MODULE_VERSION(DRV_VERSION);
+
static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
{
u8 cache_line = 0;
@@ -242,7 +244,8 @@
{
struct ata_host_set *host_set = ap->host_set;
struct ata_device *dev;
- void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+ void __iomem *addr =
+ host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
u32 tmp, dev_mode[2];
unsigned int i;
@@ -375,7 +378,7 @@
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
unsigned long base;
- void *mmio_base;
+ void __iomem *mmio_base;
int rc;
unsigned int i;
int pci_dev_busy = 0;
@@ -425,8 +428,7 @@
probe_ent->irq_flags = SA_SHIRQ;
probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
- mmio_base = ioremap(pci_resource_start(pdev, 5),
- pci_resource_len(pdev, 5));
+ mmio_base = pci_iomap(pdev, 5, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index 19d3bb3..d89d968 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -318,7 +318,7 @@
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = ata_pci_host_stop,
};
static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -346,7 +346,7 @@
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
unsigned long base;
- void *mmio_base;
+ void __iomem *mmio_base;
int pci_dev_busy = 0;
int rc;
int i;
@@ -392,8 +392,7 @@
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = ioremap(pci_resource_start(pdev, 5),
- pci_resource_len(pdev, 5));
+ mmio_base = pci_iomap(pdev, 5, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index c72fcc4..540a851 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -245,13 +245,14 @@
static void pdc20621_host_stop(struct ata_host_set *host_set)
{
+ struct pci_dev *pdev = to_pci_dev(host_set->dev);
struct pdc_host_priv *hpriv = host_set->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
- iounmap(dimm_mmio);
+ pci_iounmap(pdev, dimm_mmio);
kfree(hpriv);
- ata_host_stop(host_set);
+ pci_iounmap(pdev, host_set->mmio_base);
}
static int pdc_port_start(struct ata_port *ap)
@@ -451,9 +452,9 @@
struct scatterlist *sg = qc->sg;
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void *mmio = ap->host_set->mmio_base;
+ void __iomem *mmio = ap->host_set->mmio_base;
struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
unsigned int portno = ap->port_no;
unsigned int i, last, idx, total_len = 0, sgt_len;
u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
@@ -513,9 +514,9 @@
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void *mmio = ap->host_set->mmio_base;
+ void __iomem *mmio = ap->host_set->mmio_base;
struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
unsigned int portno = ap->port_no;
unsigned int i;
@@ -565,7 +566,7 @@
{
struct ata_port *ap = qc->ap;
struct ata_host_set *host_set = ap->host_set;
- void *mmio = host_set->mmio_base;
+ void __iomem *mmio = host_set->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -639,7 +640,7 @@
struct ata_port *ap = qc->ap;
struct ata_host_set *host_set = ap->host_set;
unsigned int port_no = ap->port_no;
- void *mmio = host_set->mmio_base;
+ void __iomem *mmio = host_set->mmio_base;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 seq = (u8) (port_no + 1);
unsigned int port_ofs;
@@ -699,7 +700,7 @@
static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
struct ata_queued_cmd *qc,
unsigned int doing_hdma,
- void *mmio)
+ void __iomem *mmio)
{
unsigned int port_no = ap->port_no;
unsigned int port_ofs =
@@ -778,7 +779,7 @@
static void pdc20621_irq_clear(struct ata_port *ap)
{
struct ata_host_set *host_set = ap->host_set;
- void *mmio = host_set->mmio_base;
+ void __iomem *mmio = host_set->mmio_base;
mmio += PDC_CHIP0_OFS;
@@ -792,7 +793,7 @@
u32 mask = 0;
unsigned int i, tmp, port_no;
unsigned int handled = 0;
- void *mmio_base;
+ void __iomem *mmio_base;
VPRINTK("ENTER\n");
@@ -940,9 +941,9 @@
u16 idx;
u8 page_mask;
long dist;
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
struct pdc_host_priv *hpriv = pe->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -996,9 +997,9 @@
u16 idx;
u8 page_mask;
long dist;
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
struct pdc_host_priv *hpriv = pe->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1044,7 +1045,7 @@
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
u32 subaddr, u32 *pdata)
{
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
u32 i2creg = 0;
u32 status;
u32 count =0;
@@ -1103,7 +1104,7 @@
u32 data = 0;
int size, i;
u8 bdimmsize;
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
static const struct {
unsigned int reg;
unsigned int ofs;
@@ -1166,7 +1167,7 @@
{
u32 data, spd0;
int error, i;
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1220,7 +1221,7 @@
u32 ticks=0;
u32 clock=0;
u32 fparam=0;
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1344,7 +1345,7 @@
static void pdc_20621_init(struct ata_probe_ent *pe)
{
u32 tmp;
- void *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1377,7 +1378,8 @@
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
unsigned long base;
- void *mmio_base, *dimm_mmio = NULL;
+ void __iomem *mmio_base;
+ void __iomem *dimm_mmio = NULL;
struct pdc_host_priv *hpriv = NULL;
unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
@@ -1417,8 +1419,7 @@
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = ioremap(pci_resource_start(pdev, 3),
- pci_resource_len(pdev, 3));
+ mmio_base = pci_iomap(pdev, 3, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
@@ -1432,8 +1433,7 @@
}
memset(hpriv, 0, sizeof(*hpriv));
- dimm_mmio = ioremap(pci_resource_start(pdev, 4),
- pci_resource_len(pdev, 4));
+ dimm_mmio = pci_iomap(pdev, 4, 0);
if (!dimm_mmio) {
kfree(hpriv);
rc = -ENOMEM;
@@ -1480,9 +1480,9 @@
err_out_iounmap_dimm: /* only get to this label if 20621 */
kfree(hpriv);
- iounmap(dimm_mmio);
+ pci_iounmap(pdev, dimm_mmio);
err_out_iounmap:
- iounmap(mmio_base);
+ pci_iounmap(pdev, mmio_base);
err_out_free_ent:
kfree(probe_ent);
err_out_regions:
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 1566886..42e13ed 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -125,8 +125,8 @@
.sht = &uli_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x03, //support pio mode 4 (FIXME)
- .udma_mask = 0x7f, //support udma mode 6
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
.port_ops = &uli_ops,
};
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 3985f344..cf94e01 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -252,7 +252,7 @@
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = ata_pci_host_stop,
};
static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -326,8 +326,7 @@
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ mmio_base = pci_iomap(pdev, 0, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d14523d..a780546 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -268,6 +268,7 @@
} else
put_device(&dev->sdev_gendev);
+ cmd->jiffies_at_alloc = jiffies;
return cmd;
}
EXPORT_SYMBOL(scsi_get_command);
@@ -627,7 +628,7 @@
spin_lock_irqsave(host->host_lock, flags);
scsi_cmd_get_serial(host, cmd);
- if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
+ if (unlikely(host->shost_state == SHOST_DEL)) {
cmd->result = (DID_NO_CONNECT << 16);
scsi_done(cmd);
} else {
@@ -798,9 +799,23 @@
while (!list_empty(&local_q)) {
struct scsi_cmnd *cmd = list_entry(local_q.next,
struct scsi_cmnd, eh_entry);
+ /* The longest time any command should be outstanding is the
+ * per command timeout multiplied by the number of retries.
+ *
+ * For a typical command, this is 2.5 minutes */
+ unsigned long wait_for
+ = cmd->allowed * cmd->timeout_per_command;
list_del_init(&cmd->eh_entry);
disposition = scsi_decide_disposition(cmd);
+ if (disposition != SUCCESS &&
+ time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+ dev_printk(KERN_ERR, &cmd->device->sdev_gendev,
+ "timing out command, waited %lus\n",
+ wait_for/HZ);
+ disposition = SUCCESS;
+ }
+
scsi_log_completion(cmd, disposition);
switch (disposition) {
case SUCCESS:
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 6121dc1..07b554a 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -114,6 +114,7 @@
{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */
{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */
{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */
+ {"", "Scanner", "1.80", BLIST_NOLUN}, /* responds to all lun */
/*
* Other types of devices that have special flags.
@@ -135,7 +136,7 @@
{"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
{"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
{"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
- {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+ {"DEC", "HSG80", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
{"DELL", "PV660F", NULL, BLIST_SPARSELUN},
{"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN},
{"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */
@@ -191,6 +192,7 @@
{"SGI", "RAID5", "*", BLIST_SPARSELUN},
{"SGI", "TP9100", "*", BLIST_REPORTLUN2},
{"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
+ {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
{"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
{"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 0fc8b48..895c945 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -20,6 +20,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -75,7 +76,7 @@
scmd->eh_eflags |= eh_flag;
list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
- set_bit(SHOST_RECOVERY, &shost->shost_state);
+ scsi_host_set_state(shost, SHOST_RECOVERY);
shost->host_failed++;
scsi_eh_wakeup(shost);
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -115,7 +116,6 @@
add_timer(&scmd->eh_timeout);
}
-EXPORT_SYMBOL(scsi_add_timer);
/**
* scsi_delete_timer - Delete/cancel timer for a given function.
@@ -143,7 +143,6 @@
return rtn;
}
-EXPORT_SYMBOL(scsi_delete_timer);
/**
* scsi_times_out - Timeout function for normal scsi commands.
@@ -197,7 +196,8 @@
{
int online;
- wait_event(sdev->host->host_wait, (!test_bit(SHOST_RECOVERY, &sdev->host->shost_state)));
+ wait_event(sdev->host->host_wait, (sdev->host->shost_state !=
+ SHOST_RECOVERY));
online = scsi_device_online(sdev);
@@ -775,9 +775,11 @@
__FUNCTION__, scmd, rtn));
if (rtn == SUCCESS)
return 0;
- else if (rtn == NEEDS_RETRY)
+ else if (rtn == NEEDS_RETRY) {
if (retry_cnt--)
goto retry_tur;
+ return 0;
+ }
return 1;
}
@@ -1458,7 +1460,7 @@
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
__FUNCTION__));
- clear_bit(SHOST_RECOVERY, &shost->shost_state);
+ scsi_host_set_state(shost, SHOST_RUNNING);
wake_up(&shost->host_wait);
@@ -1582,16 +1584,8 @@
int rtn;
DECLARE_MUTEX_LOCKED(sem);
- /*
- * Flush resources
- */
-
- daemonize("scsi_eh_%d", shost->host_no);
-
current->flags |= PF_NOFREEZE;
-
shost->eh_wait = &sem;
- shost->ehandler = current;
/*
* Wake up the thread that created us.
@@ -1599,8 +1593,6 @@
SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of"
" scsi_eh_%d\n",shost->host_no));
- complete(shost->eh_notify);
-
while (1) {
/*
* If we get a signal, it means we are supposed to go
@@ -1621,7 +1613,7 @@
* semaphores isn't unreasonable.
*/
down_interruptible(&sem);
- if (shost->eh_kill)
+ if (kthread_should_stop())
break;
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
@@ -1660,22 +1652,6 @@
* Make sure that nobody tries to wake us up again.
*/
shost->eh_wait = NULL;
-
- /*
- * Knock this down too. From this point on, the host is flying
- * without a pilot. If this is because the module is being unloaded,
- * that's fine. If the user sent a signal to this thing, we are
- * potentially in real danger.
- */
- shost->eh_active = 0;
- shost->ehandler = NULL;
-
- /*
- * If anyone is waiting for us to exit (i.e. someone trying to unload
- * a driver), then wake up that process to let them know we are on
- * the way out the door.
- */
- complete_and_exit(shost->eh_notify, 0);
return 0;
}
@@ -1846,12 +1822,16 @@
int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
struct scsi_sense_hdr *sshdr)
{
- if (!sense_buffer || !sb_len || (sense_buffer[0] & 0x70) != 0x70)
+ if (!sense_buffer || !sb_len)
return 0;
memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
sshdr->response_code = (sense_buffer[0] & 0x7f);
+
+ if (!scsi_sense_valid(sshdr))
+ return 0;
+
if (sshdr->response_code >= 0x72) {
/*
* descriptor format
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 7a6b530..b7fddac 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -30,20 +30,20 @@
#define MAX_BUF PAGE_SIZE
-/*
- * If we are told to probe a host, we will return 0 if the host is not
- * present, 1 if the host is present, and will return an identifying
- * string at *arg, if arg is non null, filling to the length stored at
- * (int *) arg
+/**
+ * ioctl_probe -- return host identification
+ * @host: host to identify
+ * @buffer: userspace buffer for identification
+ *
+ * Return an identifying string at @buffer, if @buffer is non-NULL, filling
+ * to the length stored at * (int *) @buffer.
*/
-
static int ioctl_probe(struct Scsi_Host *host, void __user *buffer)
{
unsigned int len, slen;
const char *string;
- int temp = host->hostt->present;
- if (temp && buffer) {
+ if (buffer) {
if (get_user(len, (unsigned int __user *) buffer))
return -EFAULT;
@@ -59,7 +59,7 @@
return -EFAULT;
}
}
- return temp;
+ return 1;
}
/*
@@ -88,25 +88,18 @@
static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
int timeout, int retries)
{
- struct scsi_request *sreq;
int result;
struct scsi_sense_hdr sshdr;
SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd));
- sreq = scsi_allocate_request(sdev, GFP_KERNEL);
- if (!sreq) {
- printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n");
- return -ENOMEM;
- }
+ result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0,
+ &sshdr, timeout, retries);
- sreq->sr_data_direction = DMA_NONE;
- scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries);
+ SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result));
- SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result));
-
- if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
- (scsi_request_normalize_sense(sreq, &sshdr))) {
+ if ((driver_byte(result) & DRIVER_SENSE) &&
+ (scsi_sense_valid(&sshdr))) {
switch (sshdr.sense_key) {
case ILLEGAL_REQUEST:
if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
@@ -125,7 +118,7 @@
case UNIT_ATTENTION:
if (sdev->removable) {
sdev->changed = 1;
- sreq->sr_result = 0; /* This is no longer considered an error */
+ result = 0; /* This is no longer considered an error */
break;
}
default: /* Fall through for non-removable media */
@@ -135,15 +128,13 @@
sdev->channel,
sdev->id,
sdev->lun,
- sreq->sr_result);
- scsi_print_req_sense(" ", sreq);
+ result);
+ scsi_print_sense_hdr(" ", &sshdr);
break;
}
}
- result = sreq->sr_result;
SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
- scsi_release_request(sreq);
return result;
}
@@ -208,8 +199,8 @@
{
char *buf;
unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
char __user *cmd_in;
- struct scsi_request *sreq;
unsigned char opcode;
unsigned int inlen, outlen, cmdlen;
unsigned int needed, buf_needed;
@@ -321,31 +312,23 @@
break;
}
- sreq = scsi_allocate_request(sdev, GFP_KERNEL);
- if (!sreq) {
- result = -EINTR;
- goto error;
- }
-
- sreq->sr_data_direction = data_direction;
- scsi_wait_req(sreq, cmd, buf, needed, timeout, retries);
+ result = scsi_execute(sdev, cmd, data_direction, buf, needed,
+ sense, timeout, retries, 0);
/*
* If there was an error condition, pass the info back to the user.
*/
- result = sreq->sr_result;
if (result) {
- int sb_len = sizeof(sreq->sr_sense_buffer);
+ int sb_len = sizeof(*sense);
sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
- if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len))
+ if (copy_to_user(cmd_in, sense, sb_len))
result = -EFAULT;
} else {
if (copy_to_user(cmd_in, buf, outlen))
result = -EFAULT;
}
- scsi_release_request(sreq);
error:
kfree(buf);
return result;
@@ -475,8 +458,7 @@
* error processing, as long as the device was opened
* non-blocking */
if (filp && filp->f_flags & O_NONBLOCK) {
- if (test_bit(SHOST_RECOVERY,
- &sdev->host->shost_state))
+ if (sdev->host->shost_state == SHOST_RECOVERY)
return -ENODEV;
} else if (!scsi_block_when_processing_errors(sdev))
return -ENODEV;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7a91ca3..77f2d44 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -232,23 +232,6 @@
}
EXPORT_SYMBOL(scsi_do_req);
-static void scsi_wait_done(struct scsi_cmnd *cmd)
-{
- struct request *req = cmd->request;
- struct request_queue *q = cmd->device->request_queue;
- unsigned long flags;
-
- req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-
- spin_lock_irqsave(q->queue_lock, flags);
- if (blk_rq_tagged(req))
- blk_queue_end_tag(q, req);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (req->waiting)
- complete(req->waiting);
-}
-
/* This is the end routine we get to if a command was never attached
* to the request. Simply complete the request without changing
* rq_status; this will cause a DRIVER_ERROR. */
@@ -263,21 +246,114 @@
unsigned bufflen, int timeout, int retries)
{
DECLARE_COMPLETION(wait);
-
- sreq->sr_request->waiting = &wait;
- sreq->sr_request->rq_status = RQ_SCSI_BUSY;
- sreq->sr_request->end_io = scsi_wait_req_end_io;
- scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
- timeout, retries);
+ int write = (sreq->sr_data_direction == DMA_TO_DEVICE);
+ struct request *req;
+
+ req = blk_get_request(sreq->sr_device->request_queue, write,
+ __GFP_WAIT);
+ if (bufflen && blk_rq_map_kern(sreq->sr_device->request_queue, req,
+ buffer, bufflen, __GFP_WAIT)) {
+ sreq->sr_result = DRIVER_ERROR << 24;
+ blk_put_request(req);
+ return;
+ }
+
+ req->flags |= REQ_NOMERGE;
+ req->waiting = &wait;
+ req->end_io = scsi_wait_req_end_io;
+ req->cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]);
+ req->sense = sreq->sr_sense_buffer;
+ req->sense_len = 0;
+ memcpy(req->cmd, cmnd, req->cmd_len);
+ req->timeout = timeout;
+ req->flags |= REQ_BLOCK_PC;
+ req->rq_disk = NULL;
+ blk_insert_request(sreq->sr_device->request_queue, req,
+ sreq->sr_data_direction == DMA_TO_DEVICE, NULL);
wait_for_completion(&wait);
sreq->sr_request->waiting = NULL;
- if (sreq->sr_request->rq_status != RQ_SCSI_DONE)
+ sreq->sr_result = req->errors;
+ if (req->errors)
sreq->sr_result |= (DRIVER_ERROR << 24);
- __scsi_release_request(sreq);
+ blk_put_request(req);
}
+
EXPORT_SYMBOL(scsi_wait_req);
+/**
+ * scsi_execute - insert request and wait for the result
+ * @sdev: scsi device
+ * @cmd: scsi command
+ * @data_direction: data direction
+ * @buffer: data buffer
+ * @bufflen: len of buffer
+ * @sense: optional sense buffer
+ * @timeout: request timeout in seconds
+ * @retries: number of times to retry request
+ * @flags: or into request flags;
+ *
+ * returns the req->errors value which is the the scsi_cmnd result
+ * field.
+ **/
+int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ unsigned char *sense, int timeout, int retries, int flags)
+{
+ struct request *req;
+ int write = (data_direction == DMA_TO_DEVICE);
+ int ret = DRIVER_ERROR << 24;
+
+ req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
+
+ if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
+ buffer, bufflen, __GFP_WAIT))
+ goto out;
+
+ req->cmd_len = COMMAND_SIZE(cmd[0]);
+ memcpy(req->cmd, cmd, req->cmd_len);
+ req->sense = sense;
+ req->sense_len = 0;
+ req->timeout = timeout;
+ req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET;
+
+ /*
+ * head injection *required* here otherwise quiesce won't work
+ */
+ blk_execute_rq(req->q, NULL, req, 1);
+
+ ret = req->errors;
+ out:
+ blk_put_request(req);
+
+ return ret;
+}
+EXPORT_SYMBOL(scsi_execute);
+
+
+int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ struct scsi_sense_hdr *sshdr, int timeout, int retries)
+{
+ char *sense = NULL;
+ int result;
+
+ if (sshdr) {
+ sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+ if (!sense)
+ return DRIVER_ERROR << 24;
+ memset(sense, 0, SCSI_SENSE_BUFFERSIZE);
+ }
+ result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
+ sense, timeout, retries, 0);
+ if (sshdr)
+ scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
+
+ kfree(sense);
+ return result;
+}
+EXPORT_SYMBOL(scsi_execute_req);
+
/*
* Function: scsi_init_cmd_errh()
*
@@ -348,7 +424,7 @@
spin_lock_irqsave(shost->host_lock, flags);
shost->host_busy--;
- if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) &&
+ if (unlikely((shost->shost_state == SHOST_RECOVERY) &&
shost->host_failed))
scsi_eh_wakeup(shost);
spin_unlock(shost->host_lock);
@@ -851,17 +927,20 @@
scsi_requeue_command(q, cmd);
return;
}
- printk(KERN_INFO "Device %s not ready.\n",
- req->rq_disk ? req->rq_disk->disk_name : "");
+ if (!(req->flags & REQ_QUIET))
+ dev_printk(KERN_INFO,
+ &cmd->device->sdev_gendev,
+ "Device not ready.\n");
cmd = scsi_end_request(cmd, 0, this_count, 1);
return;
case VOLUME_OVERFLOW:
- printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ",
- cmd->device->host->host_no,
- (int)cmd->device->channel,
- (int)cmd->device->id, (int)cmd->device->lun);
- __scsi_print_command(cmd->data_cmnd);
- scsi_print_sense("", cmd);
+ if (!(req->flags & REQ_QUIET)) {
+ dev_printk(KERN_INFO,
+ &cmd->device->sdev_gendev,
+ "Volume overflow, CDB: ");
+ __scsi_print_command(cmd->data_cmnd);
+ scsi_print_sense("", cmd);
+ }
cmd = scsi_end_request(cmd, 0, block_bytes, 1);
return;
default:
@@ -878,14 +957,13 @@
return;
}
if (result) {
- printk(KERN_INFO "SCSI error : <%d %d %d %d> return code "
- "= 0x%x\n", cmd->device->host->host_no,
- cmd->device->channel,
- cmd->device->id,
- cmd->device->lun, result);
+ if (!(req->flags & REQ_QUIET)) {
+ dev_printk(KERN_INFO, &cmd->device->sdev_gendev,
+ "SCSI error: return code = 0x%x\n", result);
- if (driver_byte(result) & DRIVER_SENSE)
- scsi_print_sense("", cmd);
+ if (driver_byte(result) & DRIVER_SENSE)
+ scsi_print_sense("", cmd);
+ }
/*
* Mark a single buffer as not uptodate. Queue the remainder.
* We sometimes get this cruft in the event that a medium error
@@ -1020,6 +1098,12 @@
return -EOPNOTSUPP;
}
+static void scsi_generic_done(struct scsi_cmnd *cmd)
+{
+ BUG_ON(!blk_pc_request(cmd->request));
+ scsi_io_completion(cmd, cmd->result == 0 ? cmd->bufflen : 0, 0);
+}
+
static int scsi_prep_fn(struct request_queue *q, struct request *req)
{
struct scsi_device *sdev = q->queuedata;
@@ -1061,7 +1145,7 @@
* these two cases differently. We differentiate by looking
* at request->cmd, as this tells us the real story.
*/
- if (req->flags & REQ_SPECIAL) {
+ if (req->flags & REQ_SPECIAL && req->special) {
struct scsi_request *sreq = req->special;
if (sreq->sr_magic == SCSI_REQ_MAGIC) {
@@ -1073,7 +1157,7 @@
cmd = req->special;
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
- if(unlikely(specials_only)) {
+ if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) {
if(specials_only == SDEV_QUIESCE ||
specials_only == SDEV_BLOCK)
return BLKPREP_DEFER;
@@ -1142,11 +1226,26 @@
/*
* Initialize the actual SCSI command for this request.
*/
- drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- return BLKPREP_KILL;
+ if (req->rq_disk) {
+ drv = *(struct scsi_driver **)req->rq_disk->private_data;
+ if (unlikely(!drv->init_command(cmd))) {
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ return BLKPREP_KILL;
+ }
+ } else {
+ memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
+ if (rq_data_dir(req) == WRITE)
+ cmd->sc_data_direction = DMA_TO_DEVICE;
+ else if (req->data_len)
+ cmd->sc_data_direction = DMA_FROM_DEVICE;
+ else
+ cmd->sc_data_direction = DMA_NONE;
+
+ cmd->transfersize = req->data_len;
+ cmd->allowed = 3;
+ cmd->timeout_per_command = req->timeout;
+ cmd->done = scsi_generic_done;
}
}
@@ -1207,7 +1306,7 @@
struct Scsi_Host *shost,
struct scsi_device *sdev)
{
- if (test_bit(SHOST_RECOVERY, &shost->shost_state))
+ if (shost->shost_state == SHOST_RECOVERY)
return 0;
if (shost->host_busy == 0 && shost->host_blocked) {
/*
@@ -1539,9 +1638,9 @@
}
}
/**
- * __scsi_mode_sense - issue a mode sense, falling back from 10 to
+ * scsi_mode_sense - issue a mode sense, falling back from 10 to
* six bytes if necessary.
- * @sreq: SCSI request to fill in with the MODE_SENSE
+ * @sdev: SCSI device to be queried
* @dbd: set if mode sense will allow block descriptors to be returned
* @modepage: mode page being requested
* @buffer: request buffer (may not be smaller than eight bytes)
@@ -1549,26 +1648,34 @@
* @timeout: command timeout
* @retries: number of retries before failing
* @data: returns a structure abstracting the mode header data
+ * @sense: place to put sense data (or NULL if no sense to be collected).
+ * must be SCSI_SENSE_BUFFERSIZE big.
*
* Returns zero if unsuccessful, or the header offset (either 4
* or 8 depending on whether a six or ten byte command was
* issued) if successful.
**/
int
-__scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage,
+scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
unsigned char *buffer, int len, int timeout, int retries,
- struct scsi_mode_data *data) {
+ struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) {
unsigned char cmd[12];
int use_10_for_ms;
int header_length;
+ int result;
+ struct scsi_sense_hdr my_sshdr;
memset(data, 0, sizeof(*data));
memset(&cmd[0], 0, 12);
cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */
cmd[2] = modepage;
+ /* caller might not be interested in sense, but we need it */
+ if (!sshdr)
+ sshdr = &my_sshdr;
+
retry:
- use_10_for_ms = sreq->sr_device->use_10_for_ms;
+ use_10_for_ms = sdev->use_10_for_ms;
if (use_10_for_ms) {
if (len < 8)
@@ -1586,36 +1693,31 @@
header_length = 4;
}
- sreq->sr_cmd_len = 0;
- memset(sreq->sr_sense_buffer, 0, sizeof(sreq->sr_sense_buffer));
- sreq->sr_data_direction = DMA_FROM_DEVICE;
-
memset(buffer, 0, len);
- scsi_wait_req(sreq, cmd, buffer, len, timeout, retries);
+ result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
+ sshdr, timeout, retries);
/* This code looks awful: what it's doing is making sure an
* ILLEGAL REQUEST sense return identifies the actual command
* byte as the problem. MODE_SENSE commands can return
* ILLEGAL REQUEST if the code page isn't supported */
- if (use_10_for_ms && !scsi_status_is_good(sreq->sr_result) &&
- (driver_byte(sreq->sr_result) & DRIVER_SENSE)) {
- struct scsi_sense_hdr sshdr;
-
- if (scsi_request_normalize_sense(sreq, &sshdr)) {
- if ((sshdr.sense_key == ILLEGAL_REQUEST) &&
- (sshdr.asc == 0x20) && (sshdr.ascq == 0)) {
+ if (use_10_for_ms && !scsi_status_is_good(result) &&
+ (driver_byte(result) & DRIVER_SENSE)) {
+ if (scsi_sense_valid(sshdr)) {
+ if ((sshdr->sense_key == ILLEGAL_REQUEST) &&
+ (sshdr->asc == 0x20) && (sshdr->ascq == 0)) {
/*
* Invalid command operation code
*/
- sreq->sr_device->use_10_for_ms = 0;
+ sdev->use_10_for_ms = 0;
goto retry;
}
}
}
- if(scsi_status_is_good(sreq->sr_result)) {
+ if(scsi_status_is_good(result)) {
data->header_length = header_length;
if(use_10_for_ms) {
data->length = buffer[0]*256 + buffer[1] + 2;
@@ -1632,73 +1734,31 @@
}
}
- return sreq->sr_result;
-}
-EXPORT_SYMBOL(__scsi_mode_sense);
-
-/**
- * scsi_mode_sense - issue a mode sense, falling back from 10 to
- * six bytes if necessary.
- * @sdev: scsi device to send command to.
- * @dbd: set if mode sense will disable block descriptors in the return
- * @modepage: mode page being requested
- * @buffer: request buffer (may not be smaller than eight bytes)
- * @len: length of request buffer.
- * @timeout: command timeout
- * @retries: number of retries before failing
- *
- * Returns zero if unsuccessful, or the header offset (either 4
- * or 8 depending on whether a six or ten byte command was
- * issued) if successful.
- **/
-int
-scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
- unsigned char *buffer, int len, int timeout, int retries,
- struct scsi_mode_data *data)
-{
- struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
- int ret;
-
- if (!sreq)
- return -1;
-
- ret = __scsi_mode_sense(sreq, dbd, modepage, buffer, len,
- timeout, retries, data);
-
- scsi_release_request(sreq);
-
- return ret;
+ return result;
}
EXPORT_SYMBOL(scsi_mode_sense);
int
scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
{
- struct scsi_request *sreq;
char cmd[] = {
TEST_UNIT_READY, 0, 0, 0, 0, 0,
};
+ struct scsi_sense_hdr sshdr;
int result;
- sreq = scsi_allocate_request(sdev, GFP_KERNEL);
- if (!sreq)
- return -ENOMEM;
+ result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
+ timeout, retries);
- sreq->sr_data_direction = DMA_NONE;
- scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries);
+ if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
- if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) {
- struct scsi_sense_hdr sshdr;
-
- if ((scsi_request_normalize_sense(sreq, &sshdr)) &&
+ if ((scsi_sense_valid(&sshdr)) &&
((sshdr.sense_key == UNIT_ATTENTION) ||
(sshdr.sense_key == NOT_READY))) {
sdev->changed = 1;
- sreq->sr_result = 0;
+ result = 0;
}
}
- result = sreq->sr_result;
- scsi_release_request(sreq);
return result;
}
EXPORT_SYMBOL(scsi_test_unit_ready);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index d30d7f4..ee6de17 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -63,6 +63,9 @@
extern void scsi_exit_devinfo(void);
/* scsi_error.c */
+extern void scsi_add_timer(struct scsi_cmnd *, int,
+ void (*)(struct scsi_cmnd *));
+extern int scsi_delete_timer(struct scsi_cmnd *);
extern void scsi_times_out(struct scsi_cmnd *cmd);
extern int scsi_error_handler(void *host);
extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 48edd67..19c9a23 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -111,15 +111,14 @@
/**
* scsi_unlock_floptical - unlock device via a special MODE SENSE command
- * @sreq: used to send the command
+ * @sdev: scsi device to send command to
* @result: area to store the result of the MODE SENSE
*
* Description:
- * Send a vendor specific MODE SENSE (not a MODE SELECT) command using
- * @sreq to unlock a device, storing the (unused) results into result.
+ * Send a vendor specific MODE SENSE (not a MODE SELECT) command.
* Called for BLIST_KEY devices.
**/
-static void scsi_unlock_floptical(struct scsi_request *sreq,
+static void scsi_unlock_floptical(struct scsi_device *sdev,
unsigned char *result)
{
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -129,11 +128,10 @@
scsi_cmd[1] = 0;
scsi_cmd[2] = 0x2e;
scsi_cmd[3] = 0;
- scsi_cmd[4] = 0x2a; /* size */
+ scsi_cmd[4] = 0x2a; /* size */
scsi_cmd[5] = 0;
- sreq->sr_cmd_len = 0;
- sreq->sr_data_direction = DMA_FROM_DEVICE;
- scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3);
+ scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,
+ SCSI_TIMEOUT, 3);
}
/**
@@ -433,26 +431,25 @@
/**
* scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
- * @sreq: used to send the INQUIRY
+ * @sdev: scsi_device to probe
* @inq_result: area to store the INQUIRY result
+ * @result_len: len of inq_result
* @bflags: store any bflags found here
*
* Description:
- * Probe the lun associated with @sreq using a standard SCSI INQUIRY;
+ * Probe the lun associated with @req using a standard SCSI INQUIRY;
*
- * If the INQUIRY is successful, sreq->sr_result is zero and: the
+ * If the INQUIRY is successful, zero is returned and the
* INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
- * are copied to the Scsi_Device at @sreq->sr_device (sdev);
- * any flags value is stored in *@bflags.
+ * are copied to the Scsi_Device any flags value is stored in *@bflags.
**/
-static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
- int *bflags)
+static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
+ int result_len, int *bflags)
{
- struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
int first_inquiry_len, try_inquiry_len, next_inquiry_len;
int response_len = 0;
- int pass, count;
+ int pass, count, result;
struct scsi_sense_hdr sshdr;
*bflags = 0;
@@ -475,28 +472,26 @@
memset(scsi_cmd, 0, 6);
scsi_cmd[0] = INQUIRY;
scsi_cmd[4] = (unsigned char) try_inquiry_len;
- sreq->sr_cmd_len = 0;
- sreq->sr_data_direction = DMA_FROM_DEVICE;
memset(inq_result, 0, try_inquiry_len);
- scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result,
- try_inquiry_len,
- HZ/2 + HZ*scsi_inq_timeout, 3);
+
+ result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
+ inq_result, try_inquiry_len, &sshdr,
+ HZ / 2 + HZ * scsi_inq_timeout, 3);
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s "
"with code 0x%x\n",
- sreq->sr_result ? "failed" : "successful",
- sreq->sr_result));
+ result ? "failed" : "successful", result));
- if (sreq->sr_result) {
+ if (result) {
/*
* not-ready to ready transition [asc/ascq=0x28/0x0]
* or power-on, reset [asc/ascq=0x29/0x0], continue.
* INQUIRY should not yield UNIT_ATTENTION
* but many buggy devices do so anyway.
*/
- if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
- scsi_request_normalize_sense(sreq, &sshdr)) {
+ if ((driver_byte(result) & DRIVER_SENSE) &&
+ scsi_sense_valid(&sshdr)) {
if ((sshdr.sense_key == UNIT_ATTENTION) &&
((sshdr.asc == 0x28) ||
(sshdr.asc == 0x29)) &&
@@ -507,7 +502,7 @@
break;
}
- if (sreq->sr_result == 0) {
+ if (result == 0) {
response_len = (unsigned char) inq_result[4] + 5;
if (response_len > 255)
response_len = first_inquiry_len; /* sanity */
@@ -556,8 +551,8 @@
/* If the last transfer attempt got an error, assume the
* peripheral doesn't exist or is dead. */
- if (sreq->sr_result)
- return;
+ if (result)
+ return -EIO;
/* Don't report any more data than the device says is valid */
sdev->inquiry_len = min(try_inquiry_len, response_len);
@@ -593,7 +588,7 @@
(sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
sdev->scsi_level++;
- return;
+ return 0;
}
/**
@@ -800,9 +795,8 @@
void *hostdata)
{
struct scsi_device *sdev;
- struct scsi_request *sreq;
unsigned char *result;
- int bflags, res = SCSI_SCAN_NO_RESPONSE;
+ int bflags, res = SCSI_SCAN_NO_RESPONSE, result_len = 256;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
/*
@@ -831,16 +825,13 @@
sdev = scsi_alloc_sdev(starget, lun, hostdata);
if (!sdev)
goto out;
- sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
- if (!sreq)
- goto out_free_sdev;
- result = kmalloc(256, GFP_ATOMIC |
+
+ result = kmalloc(result_len, GFP_ATOMIC |
((shost->unchecked_isa_dma) ? __GFP_DMA : 0));
if (!result)
- goto out_free_sreq;
+ goto out_free_sdev;
- scsi_probe_lun(sreq, result, &bflags);
- if (sreq->sr_result)
+ if (scsi_probe_lun(sdev, result, result_len, &bflags))
goto out_free_result;
/*
@@ -868,7 +859,7 @@
if (res == SCSI_SCAN_LUN_PRESENT) {
if (bflags & BLIST_KEY) {
sdev->lockable = 0;
- scsi_unlock_floptical(sreq, result);
+ scsi_unlock_floptical(sdev, result);
}
if (bflagsp)
*bflagsp = bflags;
@@ -876,8 +867,6 @@
out_free_result:
kfree(result);
- out_free_sreq:
- scsi_release_request(sreq);
out_free_sdev:
if (res == SCSI_SCAN_LUN_PRESENT) {
if (sdevp) {
@@ -1070,8 +1059,8 @@
unsigned int lun;
unsigned int num_luns;
unsigned int retries;
+ int result;
struct scsi_lun *lunp, *lun_data;
- struct scsi_request *sreq;
u8 *data;
struct scsi_sense_hdr sshdr;
struct scsi_target *starget = scsi_target(sdev);
@@ -1089,10 +1078,6 @@
if (bflags & BLIST_NOLUN)
return 0;
- sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
- if (!sreq)
- goto out;
-
sprintf(devname, "host %d channel %d id %d",
sdev->host->host_no, sdev->channel, sdev->id);
@@ -1110,7 +1095,7 @@
lun_data = kmalloc(length, GFP_ATOMIC |
(sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
if (!lun_data)
- goto out_release_request;
+ goto out;
scsi_cmd[0] = REPORT_LUNS;
@@ -1129,8 +1114,6 @@
scsi_cmd[10] = 0; /* reserved */
scsi_cmd[11] = 0; /* control */
- sreq->sr_cmd_len = 0;
- sreq->sr_data_direction = DMA_FROM_DEVICE;
/*
* We can get a UNIT ATTENTION, for example a power on/reset, so
@@ -1146,29 +1129,29 @@
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending"
" REPORT LUNS to %s (try %d)\n", devname,
retries));
- scsi_wait_req(sreq, scsi_cmd, lun_data, length,
- SCSI_TIMEOUT + 4*HZ, 3);
+
+ result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
+ lun_data, length, &sshdr,
+ SCSI_TIMEOUT + 4 * HZ, 3);
+
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS"
- " %s (try %d) result 0x%x\n", sreq->sr_result
- ? "failed" : "successful", retries,
- sreq->sr_result));
- if (sreq->sr_result == 0)
+ " %s (try %d) result 0x%x\n", result
+ ? "failed" : "successful", retries, result));
+ if (result == 0)
break;
- else if (scsi_request_normalize_sense(sreq, &sshdr)) {
+ else if (scsi_sense_valid(&sshdr)) {
if (sshdr.sense_key != UNIT_ATTENTION)
break;
}
}
- if (sreq->sr_result) {
+ if (result) {
/*
* The device probably does not support a REPORT LUN command
*/
kfree(lun_data);
- scsi_release_request(sreq);
return 1;
}
- scsi_release_request(sreq);
/*
* Get the length from the first four bytes of lun_data.
@@ -1242,8 +1225,6 @@
kfree(lun_data);
return 0;
- out_release_request:
- scsi_release_request(sreq);
out:
/*
* We are out of memory, don't try scanning any further.
@@ -1265,9 +1246,12 @@
get_device(&starget->dev);
down(&shost->scan_mutex);
- res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
- if (res != SCSI_SCAN_LUN_PRESENT)
- sdev = ERR_PTR(-ENODEV);
+ if (scsi_host_scan_allowed(shost)) {
+ res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
+ hostdata);
+ if (res != SCSI_SCAN_LUN_PRESENT)
+ sdev = ERR_PTR(-ENODEV);
+ }
up(&shost->scan_mutex);
scsi_target_reap(starget);
put_device(&starget->dev);
@@ -1417,11 +1401,15 @@
return -EINVAL;
down(&shost->scan_mutex);
- if (channel == SCAN_WILD_CARD)
- for (channel = 0; channel <= shost->max_channel; channel++)
+ if (scsi_host_scan_allowed(shost)) {
+ if (channel == SCAN_WILD_CARD)
+ for (channel = 0; channel <= shost->max_channel;
+ channel++)
+ scsi_scan_channel(shost, channel, id, lun,
+ rescan);
+ else
scsi_scan_channel(shost, channel, id, lun, rescan);
- else
- scsi_scan_channel(shost, channel, id, lun, rescan);
+ }
up(&shost->scan_mutex);
return 0;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index beed7fb..dae59d1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -48,6 +48,30 @@
return name;
}
+static struct {
+ enum scsi_host_state value;
+ char *name;
+} shost_states[] = {
+ { SHOST_CREATED, "created" },
+ { SHOST_RUNNING, "running" },
+ { SHOST_CANCEL, "cancel" },
+ { SHOST_DEL, "deleted" },
+ { SHOST_RECOVERY, "recovery" },
+};
+const char *scsi_host_state_name(enum scsi_host_state state)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) {
+ if (shost_states[i].value == state) {
+ name = shost_states[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
static int check_set(unsigned int *val, char *src)
{
char *last;
@@ -124,6 +148,43 @@
};
static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
+static ssize_t
+store_shost_state(struct class_device *class_dev, const char *buf, size_t count)
+{
+ int i;
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+ enum scsi_host_state state = 0;
+
+ for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) {
+ const int len = strlen(shost_states[i].name);
+ if (strncmp(shost_states[i].name, buf, len) == 0 &&
+ buf[len] == '\n') {
+ state = shost_states[i].value;
+ break;
+ }
+ }
+ if (!state)
+ return -EINVAL;
+
+ if (scsi_host_set_state(shost, state))
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t
+show_shost_state(struct class_device *class_dev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+ const char *name = scsi_host_state_name(shost->shost_state);
+
+ if (!name)
+ return -EINVAL;
+
+ return snprintf(buf, 20, "%s\n", name);
+}
+
+static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state);
+
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
@@ -139,6 +200,7 @@
&class_device_attr_unchecked_isa_dma,
&class_device_attr_proc_name,
&class_device_attr_scan,
+ &class_device_attr_state,
NULL
};
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index e6412fc..2cab556 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -252,7 +252,8 @@
#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
-static int fc_target_setup(struct device *dev)
+static int fc_target_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
{
struct scsi_target *starget = to_scsi_target(dev);
struct fc_rport *rport = starget_to_rport(starget);
@@ -281,7 +282,8 @@
NULL,
NULL);
-static int fc_host_setup(struct device *dev)
+static int fc_host_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 7670919..ef577c8 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -28,14 +28,14 @@
#include "scsi_priv.h"
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
-#include <scsi/scsi_request.h>
+#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>
#define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a)
-#define SPI_NUM_ATTRS 13 /* increase this if you add attributes */
+#define SPI_NUM_ATTRS 14 /* increase this if you add attributes */
#define SPI_OTHER_ATTRS 1 /* Increase this if you add "always
* on" attributes */
#define SPI_HOST_ATTRS 1
@@ -106,27 +106,31 @@
return result;
}
-/* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions
- * resulting from (likely) bus and device resets */
-static void spi_wait_req(struct scsi_request *sreq, const void *cmd,
- void *buffer, unsigned bufflen)
+static int spi_execute(struct scsi_device *sdev, const void *cmd,
+ enum dma_data_direction dir,
+ void *buffer, unsigned bufflen,
+ struct scsi_sense_hdr *sshdr)
{
- int i;
+ int i, result;
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
for(i = 0; i < DV_RETRIES; i++) {
- sreq->sr_request->flags |= REQ_FAILFAST;
+ result = scsi_execute(sdev, cmd, dir, buffer, bufflen,
+ sense, DV_TIMEOUT, /* retries */ 1,
+ REQ_FAILFAST);
+ if (result & DRIVER_SENSE) {
+ struct scsi_sense_hdr sshdr_tmp;
+ if (!sshdr)
+ sshdr = &sshdr_tmp;
- scsi_wait_req(sreq, cmd, buffer, bufflen,
- DV_TIMEOUT, /* retries */ 1);
- if (sreq->sr_result & DRIVER_SENSE) {
- struct scsi_sense_hdr sshdr;
-
- if (scsi_request_normalize_sense(sreq, &sshdr)
- && sshdr.sense_key == UNIT_ATTENTION)
+ if (scsi_normalize_sense(sense, sizeof(*sense),
+ sshdr)
+ && sshdr->sense_key == UNIT_ATTENTION)
continue;
}
break;
}
+ return result;
}
static struct {
@@ -162,7 +166,8 @@
return SPI_SIGNAL_UNKNOWN;
}
-static int spi_host_setup(struct device *dev)
+static int spi_host_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
@@ -196,7 +201,9 @@
return &i->t.host_attrs.ac == cont;
}
-static int spi_device_configure(struct device *dev)
+static int spi_device_configure(struct transport_container *tc,
+ struct device *dev,
+ struct class_device *cdev)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_target *starget = sdev->sdev_target;
@@ -214,7 +221,9 @@
return 0;
}
-static int spi_setup_transport_attrs(struct device *dev)
+static int spi_setup_transport_attrs(struct transport_container *tc,
+ struct device *dev,
+ struct class_device *cdev)
{
struct scsi_target *starget = to_scsi_target(dev);
@@ -231,6 +240,7 @@
spi_rd_strm(starget) = 0;
spi_rti(starget) = 0;
spi_pcomp_en(starget) = 0;
+ spi_hold_mcs(starget) = 0;
spi_dv_pending(starget) = 0;
spi_initial_dv(starget) = 0;
init_MUTEX(&spi_dv_sem(starget));
@@ -347,6 +357,7 @@
spi_transport_rd_attr(rd_strm, "%d\n");
spi_transport_rd_attr(rti, "%d\n");
spi_transport_rd_attr(pcomp_en, "%d\n");
+spi_transport_rd_attr(hold_mcs, "%d\n");
/* we only care about the first child device so we return 1 */
static int child_iter(struct device *dev, void *data)
@@ -539,13 +550,13 @@
/* This is for read/write Domain Validation: If the device supports
* an echo buffer, we do read/write tests to it */
static enum spi_compare_returns
-spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
+spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer,
u8 *ptr, const int retries)
{
- struct scsi_device *sdev = sreq->sr_device;
int len = ptr - buffer;
- int j, k, r;
+ int j, k, r, result;
unsigned int pattern = 0x0000ffff;
+ struct scsi_sense_hdr sshdr;
const char spi_write_buffer[] = {
WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
@@ -590,14 +601,12 @@
}
for (r = 0; r < retries; r++) {
- sreq->sr_cmd_len = 0; /* wait_req to fill in */
- sreq->sr_data_direction = DMA_TO_DEVICE;
- spi_wait_req(sreq, spi_write_buffer, buffer, len);
- if(sreq->sr_result || !scsi_device_online(sdev)) {
- struct scsi_sense_hdr sshdr;
+ result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE,
+ buffer, len, &sshdr);
+ if(result || !scsi_device_online(sdev)) {
scsi_device_set_state(sdev, SDEV_QUIESCE);
- if (scsi_request_normalize_sense(sreq, &sshdr)
+ if (scsi_sense_valid(&sshdr)
&& sshdr.sense_key == ILLEGAL_REQUEST
/* INVALID FIELD IN CDB */
&& sshdr.asc == 0x24 && sshdr.ascq == 0x00)
@@ -609,14 +618,13 @@
return SPI_COMPARE_SKIP_TEST;
- SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result);
+ SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", result);
return SPI_COMPARE_FAILURE;
}
memset(ptr, 0, len);
- sreq->sr_cmd_len = 0; /* wait_req to fill in */
- sreq->sr_data_direction = DMA_FROM_DEVICE;
- spi_wait_req(sreq, spi_read_buffer, ptr, len);
+ spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE,
+ ptr, len, NULL);
scsi_device_set_state(sdev, SDEV_QUIESCE);
if (memcmp(buffer, ptr, len) != 0)
@@ -628,25 +636,22 @@
/* This is for the simplest form of Domain Validation: a read test
* on the inquiry data from the device */
static enum spi_compare_returns
-spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer,
+spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer,
u8 *ptr, const int retries)
{
- int r;
- const int len = sreq->sr_device->inquiry_len;
- struct scsi_device *sdev = sreq->sr_device;
+ int r, result;
+ const int len = sdev->inquiry_len;
const char spi_inquiry[] = {
INQUIRY, 0, 0, 0, len, 0
};
for (r = 0; r < retries; r++) {
- sreq->sr_cmd_len = 0; /* wait_req to fill in */
- sreq->sr_data_direction = DMA_FROM_DEVICE;
-
memset(ptr, 0, len);
- spi_wait_req(sreq, spi_inquiry, ptr, len);
+ result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE,
+ ptr, len, NULL);
- if(sreq->sr_result || !scsi_device_online(sdev)) {
+ if(result || !scsi_device_online(sdev)) {
scsi_device_set_state(sdev, SDEV_QUIESCE);
return SPI_COMPARE_FAILURE;
}
@@ -667,12 +672,11 @@
}
static enum spi_compare_returns
-spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,
+spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr,
enum spi_compare_returns
- (*compare_fn)(struct scsi_request *, u8 *, u8 *, int))
+ (*compare_fn)(struct scsi_device *, u8 *, u8 *, int))
{
- struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
- struct scsi_device *sdev = sreq->sr_device;
+ struct spi_internal *i = to_spi_internal(sdev->host->transportt);
struct scsi_target *starget = sdev->sdev_target;
int period = 0, prevperiod = 0;
enum spi_compare_returns retval;
@@ -680,7 +684,7 @@
for (;;) {
int newperiod;
- retval = compare_fn(sreq, buffer, ptr, DV_LOOPS);
+ retval = compare_fn(sdev, buffer, ptr, DV_LOOPS);
if (retval == SPI_COMPARE_SUCCESS
|| retval == SPI_COMPARE_SKIP_TEST)
@@ -726,9 +730,9 @@
}
static int
-spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
+spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer)
{
- int l;
+ int l, result;
/* first off do a test unit ready. This can error out
* because of reservations or some other reason. If it
@@ -744,18 +748,16 @@
};
- sreq->sr_cmd_len = 0;
- sreq->sr_data_direction = DMA_NONE;
-
/* We send a set of three TURs to clear any outstanding
* unit attention conditions if they exist (Otherwise the
* buffer tests won't be happy). If the TUR still fails
* (reservation conflict, device not ready, etc) just
* skip the write tests */
for (l = 0; ; l++) {
- spi_wait_req(sreq, spi_test_unit_ready, NULL, 0);
+ result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE,
+ NULL, 0, NULL);
- if(sreq->sr_result) {
+ if(result) {
if(l >= 3)
return 0;
} else {
@@ -764,12 +766,10 @@
}
}
- sreq->sr_cmd_len = 0;
- sreq->sr_data_direction = DMA_FROM_DEVICE;
+ result = spi_execute(sdev, spi_read_buffer_descriptor,
+ DMA_FROM_DEVICE, buffer, 4, NULL);
- spi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4);
-
- if (sreq->sr_result)
+ if (result)
/* Device has no echo buffer */
return 0;
@@ -777,17 +777,16 @@
}
static void
-spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
+spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
{
- struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
- struct scsi_device *sdev = sreq->sr_device;
+ struct spi_internal *i = to_spi_internal(sdev->host->transportt);
struct scsi_target *starget = sdev->sdev_target;
int len = sdev->inquiry_len;
/* first set us up for narrow async */
DV_SET(offset, 0);
DV_SET(width, 0);
- if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)
+ if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
!= SPI_COMPARE_SUCCESS) {
SPI_PRINTK(starget, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
/* FIXME: should probably offline the device here? */
@@ -799,7 +798,7 @@
scsi_device_wide(sdev)) {
i->f->set_width(starget, 1);
- if (spi_dv_device_compare_inquiry(sreq, buffer,
+ if (spi_dv_device_compare_inquiry(sdev, buffer,
buffer + len,
DV_LOOPS)
!= SPI_COMPARE_SUCCESS) {
@@ -820,7 +819,7 @@
len = 0;
if (scsi_device_dt(sdev))
- len = spi_dv_device_get_echo_buffer(sreq, buffer);
+ len = spi_dv_device_get_echo_buffer(sdev, buffer);
retry:
@@ -846,7 +845,7 @@
if (len == 0) {
SPI_PRINTK(starget, KERN_INFO, "Domain Validation skipping write tests\n");
- spi_dv_retrain(sreq, buffer, buffer + len,
+ spi_dv_retrain(sdev, buffer, buffer + len,
spi_dv_device_compare_inquiry);
return;
}
@@ -856,7 +855,7 @@
len = SPI_MAX_ECHO_BUFFER_SIZE;
}
- if (spi_dv_retrain(sreq, buffer, buffer + len,
+ if (spi_dv_retrain(sdev, buffer, buffer + len,
spi_dv_device_echo_buffer)
== SPI_COMPARE_SKIP_TEST) {
/* OK, the stupid drive can't do a write echo buffer
@@ -879,16 +878,12 @@
void
spi_dv_device(struct scsi_device *sdev)
{
- struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
struct scsi_target *starget = sdev->sdev_target;
u8 *buffer;
const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
- if (unlikely(!sreq))
- return;
-
if (unlikely(scsi_device_get(sdev)))
- goto out_free_req;
+ return;
buffer = kmalloc(len, GFP_KERNEL);
@@ -909,7 +904,7 @@
SPI_PRINTK(starget, KERN_INFO, "Beginning Domain Validation\n");
- spi_dv_device_internal(sreq, buffer);
+ spi_dv_device_internal(sdev, buffer);
SPI_PRINTK(starget, KERN_INFO, "Ending Domain Validation\n");
@@ -924,8 +919,6 @@
kfree(buffer);
out_put:
scsi_device_put(sdev);
- out_free_req:
- scsi_release_request(sreq);
}
EXPORT_SYMBOL(spi_dv_device);
@@ -1028,10 +1021,17 @@
sprint_frac(tmp, picosec, 1000);
dev_info(&starget->dev,
- "%s %sSCSI %d.%d MB/s %s%s%s (%s ns, offset %d)\n",
- scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
- tp->dt ? "DT" : "ST", tp->iu ? " IU" : "",
- tp->qas ? " QAS" : "", tmp, tp->offset);
+ "%s %sSCSI %d.%d MB/s %s%s%s%s%s%s%s%s (%s ns, offset %d)\n",
+ scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
+ tp->dt ? "DT" : "ST",
+ tp->iu ? " IU" : "",
+ tp->qas ? " QAS" : "",
+ tp->rd_strm ? " RDSTRM" : "",
+ tp->rti ? " RTI" : "",
+ tp->wr_flow ? " WRFLOW" : "",
+ tp->pcomp_en ? " PCOMP" : "",
+ tp->hold_mcs ? " HMCS" : "",
+ tmp, tp->offset);
} else {
dev_info(&starget->dev, "%sasynchronous.\n",
tp->width ? "wide " : "");
@@ -1073,6 +1073,7 @@
{
struct scsi_device *sdev;
struct Scsi_Host *shost;
+ struct spi_internal *i;
if (!scsi_is_sdev_device(dev))
return 0;
@@ -1085,6 +1086,9 @@
/* Note: this class has no device attributes, so it has
* no per-HBA allocation and thus we don't need to distinguish
* the attribute containers for the device */
+ i = to_spi_internal(shost->transportt);
+ if (i->f->deny_binding && i->f->deny_binding(sdev->sdev_target))
+ return 0;
return 1;
}
@@ -1092,6 +1096,7 @@
struct device *dev)
{
struct Scsi_Host *shost;
+ struct scsi_target *starget;
struct spi_internal *i;
if (!scsi_is_target_device(dev))
@@ -1103,7 +1108,11 @@
return 0;
i = to_spi_internal(shost->transportt);
-
+ starget = to_scsi_target(dev);
+
+ if (i->f->deny_binding && i->f->deny_binding(starget))
+ return 0;
+
return &i->t.target_attrs.ac == cont;
}
@@ -1154,6 +1163,7 @@
SETUP_ATTRIBUTE(rd_strm);
SETUP_ATTRIBUTE(rti);
SETUP_ATTRIBUTE(pcomp_en);
+ SETUP_ATTRIBUTE(hold_mcs);
/* if you add an attribute but forget to increase SPI_NUM_ATTRS
* this bug will trigger */
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 0410e1b..de564b3 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -59,7 +59,6 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
-#include <scsi/scsi_request.h>
#include <scsi/scsicam.h>
#include "scsi_logging.h"
@@ -125,7 +124,7 @@
static void sd_end_flush(request_queue_t *, struct request *);
static int sd_prepare_flush(request_queue_t *, struct request *);
static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer);
+ unsigned char *buffer);
static struct scsi_driver sd_template = {
.owner = THIS_MODULE,
@@ -682,19 +681,13 @@
static int sd_sync_cache(struct scsi_device *sdp)
{
- struct scsi_request *sreq;
int retries, res;
+ struct scsi_sense_hdr sshdr;
if (!scsi_device_online(sdp))
return -ENODEV;
- sreq = scsi_allocate_request(sdp, GFP_KERNEL);
- if (!sreq) {
- printk("FAILED\n No memory for request\n");
- return -ENOMEM;
- }
- sreq->sr_data_direction = DMA_NONE;
for (retries = 3; retries > 0; --retries) {
unsigned char cmd[10] = { 0 };
@@ -703,22 +696,20 @@
* Leave the rest of the command zero to indicate
* flush everything.
*/
- scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
- if (sreq->sr_result == 0)
+ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
+ if (res == 0)
break;
}
- res = sreq->sr_result;
- if (res) {
- printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
+ if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
"host = %d, driver = %02x\n ",
status_byte(res), msg_byte(res),
host_byte(res), driver_byte(res));
if (driver_byte(res) & DRIVER_SENSE)
- scsi_print_req_sense("sd", sreq);
+ scsi_print_sense_hdr("sd", &sshdr);
}
- scsi_release_request(sreq);
return res;
}
@@ -957,22 +948,19 @@
scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
}
-static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
+static int media_not_present(struct scsi_disk *sdkp,
+ struct scsi_sense_hdr *sshdr)
{
- struct scsi_sense_hdr sshdr;
- if (!srp->sr_result)
- return 0;
- if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))
+ if (!scsi_sense_valid(sshdr))
return 0;
/* not invoked for commands that could return deferred errors */
- if (scsi_request_normalize_sense(srp, &sshdr)) {
- if (sshdr.sense_key != NOT_READY &&
- sshdr.sense_key != UNIT_ATTENTION)
- return 0;
- if (sshdr.asc != 0x3A) /* medium not present */
- return 0;
- }
+ if (sshdr->sense_key != NOT_READY &&
+ sshdr->sense_key != UNIT_ATTENTION)
+ return 0;
+ if (sshdr->asc != 0x3A) /* medium not present */
+ return 0;
+
set_media_not_present(sdkp);
return 1;
}
@@ -981,10 +969,10 @@
* spinup disk - called only in sd_revalidate_disk()
*/
static void
-sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer) {
+sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
+{
unsigned char cmd[10];
- unsigned long spintime_value = 0;
+ unsigned long spintime_expire = 0;
int retries, spintime;
unsigned int the_result;
struct scsi_sense_hdr sshdr;
@@ -1001,18 +989,13 @@
cmd[0] = TEST_UNIT_READY;
memset((void *) &cmd[1], 0, 9);
- SRpnt->sr_cmd_len = 0;
- memset(SRpnt->sr_sense_buffer, 0,
- SCSI_SENSE_BUFFERSIZE);
- SRpnt->sr_data_direction = DMA_NONE;
+ the_result = scsi_execute_req(sdkp->device, cmd,
+ DMA_NONE, NULL, 0,
+ &sshdr, SD_TIMEOUT,
+ SD_MAX_RETRIES);
- scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
- 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);
-
- the_result = SRpnt->sr_result;
if (the_result)
- sense_valid = scsi_request_normalize_sense(
- SRpnt, &sshdr);
+ sense_valid = scsi_sense_valid(&sshdr);
retries++;
} while (retries < 3 &&
(!scsi_status_is_good(the_result) ||
@@ -1024,7 +1007,7 @@
* any media in it, don't bother with any of the rest of
* this crap.
*/
- if (media_not_present(sdkp, SRpnt))
+ if (media_not_present(sdkp, &sshdr))
return;
if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
@@ -1063,33 +1046,42 @@
cmd[1] = 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
- SRpnt->sr_cmd_len = 0;
- memset(SRpnt->sr_sense_buffer, 0,
- SCSI_SENSE_BUFFERSIZE);
-
- SRpnt->sr_data_direction = DMA_NONE;
- scsi_wait_req(SRpnt, (void *)cmd,
- (void *) buffer, 0/*512*/,
- SD_TIMEOUT, SD_MAX_RETRIES);
- spintime_value = jiffies;
+ scsi_execute_req(sdkp->device, cmd, DMA_NONE,
+ NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
+ spintime_expire = jiffies + 100 * HZ;
+ spintime = 1;
}
- spintime = 1;
/* Wait 1 second for next try */
msleep(1000);
printk(".");
+
+ /*
+ * Wait for USB flash devices with slow firmware.
+ * Yes, this sense key/ASC combination shouldn't
+ * occur here. It's characteristic of these devices.
+ */
+ } else if (sense_valid &&
+ sshdr.sense_key == UNIT_ATTENTION &&
+ sshdr.asc == 0x28) {
+ if (!spintime) {
+ spintime_expire = jiffies + 5 * HZ;
+ spintime = 1;
+ }
+ /* Wait 1 second for next try */
+ msleep(1000);
} else {
/* we don't understand the sense code, so it's
* probably pointless to loop */
if(!spintime) {
printk(KERN_NOTICE "%s: Unit Not Ready, "
"sense:\n", diskname);
- scsi_print_req_sense("", SRpnt);
+ scsi_print_sense_hdr("", &sshdr);
}
break;
}
- } while (spintime &&
- time_after(spintime_value + 100 * HZ, jiffies));
+ } while (spintime && time_before_eq(jiffies, spintime_expire));
if (spintime) {
if (scsi_status_is_good(the_result))
@@ -1104,14 +1096,15 @@
*/
static void
sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer) {
+ unsigned char *buffer)
+{
unsigned char cmd[16];
- struct scsi_device *sdp = sdkp->device;
int the_result, retries;
int sector_size = 0;
int longrc = 0;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
+ struct scsi_device *sdp = sdkp->device;
repeat:
retries = 3;
@@ -1128,20 +1121,15 @@
memset((void *) buffer, 0, 8);
}
- SRpnt->sr_cmd_len = 0;
- memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- SRpnt->sr_data_direction = DMA_FROM_DEVICE;
+ the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
+ buffer, longrc ? 12 : 8, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
- scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES);
-
- if (media_not_present(sdkp, SRpnt))
+ if (media_not_present(sdkp, &sshdr))
return;
- the_result = SRpnt->sr_result;
if (the_result)
- sense_valid = scsi_request_normalize_sense(SRpnt,
- &sshdr);
+ sense_valid = scsi_sense_valid(&sshdr);
retries--;
} while (the_result && retries);
@@ -1156,7 +1144,7 @@
driver_byte(the_result));
if (driver_byte(the_result) & DRIVER_SENSE)
- scsi_print_req_sense("sd", SRpnt);
+ scsi_print_sense_hdr("sd", &sshdr);
else
printk("%s : sense not available. \n", diskname);
@@ -1296,11 +1284,13 @@
/* called with buffer of length 512 */
static inline int
-sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage,
- unsigned char *buffer, int len, struct scsi_mode_data *data)
+sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage,
+ unsigned char *buffer, int len, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *sshdr)
{
- return __scsi_mode_sense(SRpnt, dbd, modepage, buffer, len,
- SD_TIMEOUT, SD_MAX_RETRIES, data);
+ return scsi_mode_sense(sdp, dbd, modepage, buffer, len,
+ SD_TIMEOUT, SD_MAX_RETRIES, data,
+ sshdr);
}
/*
@@ -1309,25 +1299,27 @@
*/
static void
sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer) {
+ unsigned char *buffer)
+{
int res;
+ struct scsi_device *sdp = sdkp->device;
struct scsi_mode_data data;
set_disk_ro(sdkp->disk, 0);
- if (sdkp->device->skip_ms_page_3f) {
+ if (sdp->skip_ms_page_3f) {
printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
return;
}
- if (sdkp->device->use_192_bytes_for_3f) {
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 192, &data);
+ if (sdp->use_192_bytes_for_3f) {
+ res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 192, &data, NULL);
} else {
/*
* First attempt: ask for all pages (0x3F), but only 4 bytes.
* We have to start carefully: some devices hang if we ask
* for more than is available.
*/
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data);
+ res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 4, &data, NULL);
/*
* Second attempt: ask for page 0 When only page 0 is
@@ -1336,14 +1328,14 @@
* CDB.
*/
if (!scsi_status_is_good(res))
- res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data);
+ res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL);
/*
* Third attempt: ask 255 bytes, as we did earlier.
*/
if (!scsi_status_is_good(res))
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255,
- &data);
+ res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255,
+ &data, NULL);
}
if (!scsi_status_is_good(res)) {
@@ -1365,19 +1357,20 @@
*/
static void
sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer)
+ unsigned char *buffer)
{
int len = 0, res;
+ struct scsi_device *sdp = sdkp->device;
int dbd;
int modepage;
struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
- if (sdkp->device->skip_ms_page_8)
+ if (sdp->skip_ms_page_8)
goto defaults;
- if (sdkp->device->type == TYPE_RBC) {
+ if (sdp->type == TYPE_RBC) {
modepage = 6;
dbd = 8;
} else {
@@ -1386,7 +1379,7 @@
}
/* cautiously ask */
- res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data);
+ res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr);
if (!scsi_status_is_good(res))
goto bad_sense;
@@ -1407,7 +1400,7 @@
len += data.header_length + data.block_descriptor_length;
/* Get the data */
- res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data);
+ res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
if (scsi_status_is_good(res)) {
const char *types[] = {
@@ -1439,7 +1432,7 @@
}
bad_sense:
- if (scsi_request_normalize_sense(SRpnt, &sshdr) &&
+ if (scsi_sense_valid(&sshdr) &&
sshdr.sense_key == ILLEGAL_REQUEST &&
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
printk(KERN_NOTICE "%s: cache data unavailable\n",
@@ -1464,7 +1457,6 @@
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
- struct scsi_request *sreq;
unsigned char *buffer;
SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
@@ -1476,18 +1468,11 @@
if (!scsi_device_online(sdp))
goto out;
- sreq = scsi_allocate_request(sdp, GFP_KERNEL);
- if (!sreq) {
- printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation "
- "failure.\n");
- goto out;
- }
-
buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA);
if (!buffer) {
printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
"failure.\n");
- goto out_release_request;
+ goto out;
}
/* defaults, until the device tells us otherwise */
@@ -1498,25 +1483,23 @@
sdkp->WCE = 0;
sdkp->RCD = 0;
- sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer);
+ sd_spinup_disk(sdkp, disk->disk_name);
/*
* Without media there is no reason to ask; moreover, some devices
* react badly if we do.
*/
if (sdkp->media_present) {
- sd_read_capacity(sdkp, disk->disk_name, sreq, buffer);
+ sd_read_capacity(sdkp, disk->disk_name, buffer);
if (sdp->removable)
sd_read_write_protect_flag(sdkp, disk->disk_name,
- sreq, buffer);
- sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer);
+ buffer);
+ sd_read_cache_type(sdkp, disk->disk_name, buffer);
}
set_capacity(disk, sdkp->capacity);
kfree(buffer);
- out_release_request:
- scsi_release_request(sreq);
out:
return 0;
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index e822ca0..b1b69d7 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -61,7 +61,7 @@
#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
-static char *sg_version_date = "20050328";
+static char *sg_version_date = "20050901";
static int sg_proc_init(void);
static void sg_proc_cleanup(void);
@@ -1027,8 +1027,7 @@
if (sdp->detached)
return -ENODEV;
if (filp->f_flags & O_NONBLOCK) {
- if (test_bit(SHOST_RECOVERY,
- &sdp->device->host->shost_state))
+ if (sdp->device->host->shost_state == SHOST_RECOVERY)
return -EBUSY;
} else if (!scsi_block_when_processing_errors(sdp->device))
return -EBUSY;
@@ -1795,12 +1794,12 @@
unsigned long uaddr, size_t count, int rw,
unsigned long max_pfn)
{
+ unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = uaddr >> PAGE_SHIFT;
+ const int nr_pages = end - start;
int res, i, j;
- unsigned int nr_pages;
struct page **pages;
- nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
-
/* User attempted Overflow! */
if ((uaddr + count) < uaddr)
return -EINVAL;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 2f259f2..ce63fc8 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -50,10 +50,10 @@
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h>
+#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h> /* For the door lock/unlock commands */
-#include <scsi/scsi_request.h>
#include "scsi_logging.h"
#include "sr.h"
@@ -199,15 +199,7 @@
/* check multisession offset etc */
sr_cd_check(cdi);
- /*
- * If the disk changed, the capacity will now be different,
- * so we force a re-read of this information
- * Force 2048 for the sector size so that filesystems won't
- * be trying to use something that is too small if the disc
- * has changed.
- */
- cd->needs_sector_size = 1;
- cd->device->sector_size = 2048;
+ get_sectorsize(cd);
}
return retval;
}
@@ -538,13 +530,6 @@
if (!scsi_block_when_processing_errors(sdev))
goto error_out;
- /*
- * If this device did not have media in the drive at boot time, then
- * we would have been unable to get the sector size. Check to see if
- * this is the case, and try again.
- */
- if (cd->needs_sector_size)
- get_sectorsize(cd);
return 0;
error_out:
@@ -604,7 +589,6 @@
cd->driver = &sr_template;
cd->disk = disk;
cd->capacity = 0x1fffff;
- cd->needs_sector_size = 1;
cd->device->changed = 1; /* force recheck CD type */
cd->use = 1;
cd->readcd_known = 0;
@@ -658,43 +642,30 @@
unsigned char *buffer;
int the_result, retries = 3;
int sector_size;
- struct scsi_request *SRpnt = NULL;
request_queue_t *queue;
buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer)
goto Enomem;
- SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL);
- if (!SRpnt)
- goto Enomem;
do {
cmd[0] = READ_CAPACITY;
memset((void *) &cmd[1], 0, 9);
- /* Mark as really busy */
- SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
- SRpnt->sr_cmd_len = 0;
-
memset(buffer, 0, 8);
/* Do the command and wait.. */
- SRpnt->sr_data_direction = DMA_FROM_DEVICE;
- scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- 8, SR_TIMEOUT, MAX_RETRIES);
+ the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE,
+ buffer, 8, NULL, SR_TIMEOUT,
+ MAX_RETRIES);
- the_result = SRpnt->sr_result;
retries--;
} while (the_result && retries);
- scsi_release_request(SRpnt);
- SRpnt = NULL;
-
if (the_result) {
cd->capacity = 0x1fffff;
sector_size = 2048; /* A guess, just in case */
- cd->needs_sector_size = 1;
} else {
#if 0
if (cdrom_get_last_written(&cd->cdi,
@@ -727,7 +698,6 @@
printk("%s: unsupported sector size %d.\n",
cd->cdi.name, sector_size);
cd->capacity = 0;
- cd->needs_sector_size = 1;
}
cd->device->sector_size = sector_size;
@@ -736,7 +706,6 @@
* Add this so that we have the ability to correctly gauge
* what the device is capable of.
*/
- cd->needs_sector_size = 0;
set_capacity(cd->disk, cd->capacity);
}
@@ -748,10 +717,7 @@
Enomem:
cd->capacity = 0x1fffff;
- sector_size = 2048; /* A guess, just in case */
- cd->needs_sector_size = 1;
- if (SRpnt)
- scsi_release_request(SRpnt);
+ cd->device->sector_size = 2048; /* A guess, just in case */
goto out;
}
@@ -759,8 +725,8 @@
{
unsigned char *buffer;
struct scsi_mode_data data;
- struct scsi_request *SRpnt;
unsigned char cmd[MAX_COMMAND_SIZE];
+ struct scsi_sense_hdr sshdr;
unsigned int the_result;
int retries, rc, n;
@@ -776,19 +742,11 @@
""
};
- /* allocate a request for the TEST_UNIT_READY */
- SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL);
- if (!SRpnt) {
- printk(KERN_WARNING "(get_capabilities:) Request allocation "
- "failure.\n");
- return;
- }
/* allocate transfer buffer */
buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer) {
printk(KERN_ERR "sr: out of memory.\n");
- scsi_release_request(SRpnt);
return;
}
@@ -800,24 +758,19 @@
memset((void *)cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
- SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
- SRpnt->sr_data_direction = DMA_NONE;
+ the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL,
+ 0, &sshdr, SR_TIMEOUT,
+ MAX_RETRIES);
- scsi_wait_req (SRpnt, (void *) cmd, buffer,
- 0, SR_TIMEOUT, MAX_RETRIES);
-
- the_result = SRpnt->sr_result;
retries++;
} while (retries < 5 &&
(!scsi_status_is_good(the_result) ||
- ((driver_byte(the_result) & DRIVER_SENSE) &&
- SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));
+ (scsi_sense_valid(&sshdr) &&
+ sshdr.sense_key == UNIT_ATTENTION)));
/* ask for mode page 0x2a */
rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
- SR_TIMEOUT, 3, &data);
+ SR_TIMEOUT, 3, &data, NULL);
if (!scsi_status_is_good(rc)) {
/* failed, drive doesn't have capabilities mode page */
@@ -825,7 +778,6 @@
cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
CDC_DVD | CDC_DVD_RAM |
CDC_SELECT_DISC | CDC_SELECT_SPEED);
- scsi_release_request(SRpnt);
kfree(buffer);
printk("%s: scsi-1 drive\n", cd->cdi.name);
return;
@@ -885,7 +837,6 @@
cd->device->writeable = 1;
}
- scsi_release_request(SRpnt);
kfree(buffer);
}
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index 0b31780..d2bcd99 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -33,7 +33,6 @@
struct scsi_device *device;
unsigned int vendor; /* vendor code, see sr_vendor.c */
unsigned long ms_offset; /* for reading multisession-CD's */
- unsigned needs_sector_size:1; /* needs to get sector size */
unsigned use:1; /* is this device still supportable */
unsigned xa_flag:1; /* CD has XA sectors ? */
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 82d68fd..6e45ac3 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -17,7 +17,7 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
-#include <scsi/scsi_request.h>
+#include <scsi/scsi_cmnd.h>
#include "sr.h"
@@ -84,41 +84,37 @@
int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
{
- struct scsi_request *SRpnt;
struct scsi_device *SDev;
- struct request *req;
+ struct scsi_sense_hdr sshdr;
int result, err = 0, retries = 0;
+ struct request_sense *sense = cgc->sense;
SDev = cd->device;
- SRpnt = scsi_allocate_request(SDev, GFP_KERNEL);
- if (!SRpnt) {
- printk(KERN_ERR "Unable to allocate SCSI request in sr_do_ioctl");
- err = -ENOMEM;
- goto out;
- }
- SRpnt->sr_data_direction = cgc->data_direction;
+
+ if (!sense) {
+ sense = kmalloc(sizeof(*sense), GFP_KERNEL);
+ if (!sense) {
+ err = -ENOMEM;
+ goto out;
+ }
+ }
retry:
if (!scsi_block_when_processing_errors(SDev)) {
err = -ENODEV;
- goto out_free;
+ goto out;
}
- scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen,
- cgc->timeout, IOCTL_RETRIES);
+ memset(sense, 0, sizeof(*sense));
+ result = scsi_execute(SDev, cgc->cmd, cgc->data_direction,
+ cgc->buffer, cgc->buflen, (char *)sense,
+ cgc->timeout, IOCTL_RETRIES, 0);
- req = SRpnt->sr_request;
- if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
- memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen);
- kfree(SRpnt->sr_buffer);
- SRpnt->sr_buffer = req->buffer;
- }
-
- result = SRpnt->sr_result;
+ scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr);
/* Minimal error checking. Ignore cases we know about, and report the rest. */
if (driver_byte(result) != 0) {
- switch (SRpnt->sr_sense_buffer[2] & 0xf) {
+ switch (sshdr.sense_key) {
case UNIT_ATTENTION:
SDev->changed = 1;
if (!cgc->quiet)
@@ -128,8 +124,8 @@
err = -ENOMEDIUM;
break;
case NOT_READY: /* This happens if there is no disc in drive */
- if (SRpnt->sr_sense_buffer[12] == 0x04 &&
- SRpnt->sr_sense_buffer[13] == 0x01) {
+ if (sshdr.asc == 0x04 &&
+ sshdr.ascq == 0x01) {
/* sense: Logical unit is in process of becoming ready */
if (!cgc->quiet)
printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name);
@@ -146,37 +142,33 @@
if (!cgc->quiet)
printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name);
#ifdef DEBUG
- scsi_print_req_sense("sr", SRpnt);
+ scsi_print_sense_hdr("sr", &sshdr);
#endif
err = -ENOMEDIUM;
break;
case ILLEGAL_REQUEST:
err = -EIO;
- if (SRpnt->sr_sense_buffer[12] == 0x20 &&
- SRpnt->sr_sense_buffer[13] == 0x00)
+ if (sshdr.asc == 0x20 &&
+ sshdr.ascq == 0x00)
/* sense: Invalid command operation code */
err = -EDRIVE_CANT_DO_THIS;
#ifdef DEBUG
__scsi_print_command(cgc->cmd);
- scsi_print_req_sense("sr", SRpnt);
+ scsi_print_sense_hdr("sr", &sshdr);
#endif
break;
default:
printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name);
__scsi_print_command(cgc->cmd);
- scsi_print_req_sense("sr", SRpnt);
+ scsi_print_sense_hdr("sr", &sshdr);
err = -EIO;
}
}
- if (cgc->sense)
- memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense));
-
/* Wake up a process waiting for device */
- out_free:
- scsi_release_request(SRpnt);
- SRpnt = NULL;
out:
+ if (!cgc->sense)
+ kfree(sense);
cgc->stat = err;
return err;
}
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 0a7839d..a93308a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static char *verstr = "20050501";
+static char *verstr = "20050830";
#include <linux/module.h>
@@ -219,6 +219,12 @@
static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long);
+static void scsi_tape_release(struct kref *);
+
+#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref)
+
+static DECLARE_MUTEX(st_ref_sem);
+
#include "osst_detect.h"
#ifndef SIGS_FROM_OSST
@@ -230,6 +236,46 @@
{"OnStream", "FW-", "", "osst"}
#endif
+static struct scsi_tape *scsi_tape_get(int dev)
+{
+ struct scsi_tape *STp = NULL;
+
+ down(&st_ref_sem);
+ write_lock(&st_dev_arr_lock);
+
+ if (dev < st_dev_max && scsi_tapes != NULL)
+ STp = scsi_tapes[dev];
+ if (!STp) goto out;
+
+ kref_get(&STp->kref);
+
+ if (!STp->device)
+ goto out_put;
+
+ if (scsi_device_get(STp->device))
+ goto out_put;
+
+ goto out;
+
+out_put:
+ kref_put(&STp->kref, scsi_tape_release);
+ STp = NULL;
+out:
+ write_unlock(&st_dev_arr_lock);
+ up(&st_ref_sem);
+ return STp;
+}
+
+static void scsi_tape_put(struct scsi_tape *STp)
+{
+ struct scsi_device *sdev = STp->device;
+
+ down(&st_ref_sem);
+ kref_put(&STp->kref, scsi_tape_release);
+ scsi_device_put(sdev);
+ up(&st_ref_sem);
+}
+
struct st_reject_data {
char *vendor;
char *model;
@@ -311,7 +357,7 @@
return 0;
cmdstatp = &STp->buffer->cmdstat;
- st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp);
+ st_analyze_sense(SRpnt, cmdstatp);
if (cmdstatp->have_sense)
scode = STp->buffer->cmdstat.sense_hdr.sense_key;
@@ -399,10 +445,10 @@
(STp->buffer)->cmdstat.midlevel_result = SCpnt->result;
SCpnt->request->rq_status = RQ_SCSI_DONE;
- (STp->buffer)->last_SRpnt = SCpnt->sc_request;
DEB( STp->write_pending = 0; )
- complete(SCpnt->request->waiting);
+ if (SCpnt->request->waiting)
+ complete(SCpnt->request->waiting);
}
/* Do the scsi command. Waits until command performed if do_wait is true.
@@ -412,8 +458,20 @@
st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd,
int bytes, int direction, int timeout, int retries, int do_wait)
{
+ struct completion *waiting;
unsigned char *bp;
+ /* if async, make sure there's no command outstanding */
+ if (!do_wait && ((STp->buffer)->last_SRpnt)) {
+ printk(KERN_ERR "%s: Async command already active.\n",
+ tape_name(STp));
+ if (signal_pending(current))
+ (STp->buffer)->syscall_result = (-EINTR);
+ else
+ (STp->buffer)->syscall_result = (-EBUSY);
+ return NULL;
+ }
+
if (SRpnt == NULL) {
SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC);
if (SRpnt == NULL) {
@@ -427,7 +485,13 @@
}
}
- init_completion(&STp->wait);
+ /* If async IO, set last_SRpnt. This ptr tells write_behind_check
+ which IO is outstanding. It's nulled out when the IO completes. */
+ if (!do_wait)
+ (STp->buffer)->last_SRpnt = SRpnt;
+
+ waiting = &STp->wait;
+ init_completion(waiting);
SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length);
if (SRpnt->sr_use_sg) {
if (!STp->buffer->do_dio)
@@ -438,17 +502,20 @@
bp = (STp->buffer)->b_data;
SRpnt->sr_data_direction = direction;
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_request->waiting = &(STp->wait);
+ SRpnt->sr_request->waiting = waiting;
SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
SRpnt->sr_request->rq_disk = STp->disk;
+ SRpnt->sr_request->end_io = blk_end_sync_rq;
STp->buffer->cmdstat.have_sense = 0;
scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
st_sleep_done, timeout, retries);
if (do_wait) {
- wait_for_completion(SRpnt->sr_request->waiting);
+ wait_for_completion(waiting);
SRpnt->sr_request->waiting = NULL;
+ if (SRpnt->sr_request->rq_status != RQ_SCSI_DONE)
+ SRpnt->sr_result |= (DRIVER_ERROR << 24);
(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
}
return SRpnt;
@@ -465,6 +532,7 @@
struct st_buffer *STbuffer;
struct st_partstat *STps;
struct st_cmdstatus *cmdstatp;
+ struct scsi_request *SRpnt;
STbuffer = STp->buffer;
if (!STbuffer->writing)
@@ -478,10 +546,14 @@
) /* end DEB */
wait_for_completion(&(STp->wait));
- (STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
+ SRpnt = STbuffer->last_SRpnt;
+ STbuffer->last_SRpnt = NULL;
+ SRpnt->sr_request->waiting = NULL;
+ if (SRpnt->sr_request->rq_status != RQ_SCSI_DONE)
+ SRpnt->sr_result |= (DRIVER_ERROR << 24);
- (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
- scsi_release_request((STp->buffer)->last_SRpnt);
+ (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
+ scsi_release_request(SRpnt);
STbuffer->buffer_bytes -= STbuffer->writing;
STps = &(STp->ps[STp->partition]);
@@ -1055,25 +1127,20 @@
*/
filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+ if (!(STp = scsi_tape_get(dev)))
+ return -ENXIO;
+
write_lock(&st_dev_arr_lock);
- if (dev >= st_dev_max || scsi_tapes == NULL ||
- ((STp = scsi_tapes[dev]) == NULL)) {
- write_unlock(&st_dev_arr_lock);
- return (-ENXIO);
- }
filp->private_data = STp;
name = tape_name(STp);
if (STp->in_use) {
write_unlock(&st_dev_arr_lock);
+ scsi_tape_put(STp);
DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
return (-EBUSY);
}
- if(scsi_device_get(STp->device)) {
- write_unlock(&st_dev_arr_lock);
- return (-ENXIO);
- }
STp->in_use = 1;
write_unlock(&st_dev_arr_lock);
STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
@@ -1118,7 +1185,7 @@
err_out:
normalize_buffer(STp->buffer);
STp->in_use = 0;
- scsi_device_put(STp->device);
+ scsi_tape_put(STp);
return retval;
}
@@ -1250,7 +1317,7 @@
write_lock(&st_dev_arr_lock);
STp->in_use = 0;
write_unlock(&st_dev_arr_lock);
- scsi_device_put(STp->device);
+ scsi_tape_put(STp);
return result;
}
@@ -3887,6 +3954,7 @@
goto out_put_disk;
}
memset(tpnt, 0, sizeof(struct scsi_tape));
+ kref_init(&tpnt->kref);
tpnt->disk = disk;
sprintf(disk->disk_name, "st%d", i);
disk->private_data = &tpnt->driver;
@@ -3902,6 +3970,7 @@
tpnt->tape_type = MT_ISSCSI2;
tpnt->buffer = buffer;
+ tpnt->buffer->last_SRpnt = NULL;
tpnt->inited = 0;
tpnt->dirty = 0;
@@ -4076,15 +4145,10 @@
tpnt->modes[mode].cdevs[j] = NULL;
}
}
- tpnt->device = NULL;
- if (tpnt->buffer) {
- tpnt->buffer->orig_frp_segs = 0;
- normalize_buffer(tpnt->buffer);
- kfree(tpnt->buffer);
- }
- put_disk(tpnt->disk);
- kfree(tpnt);
+ down(&st_ref_sem);
+ kref_put(&tpnt->kref, scsi_tape_release);
+ up(&st_ref_sem);
return 0;
}
}
@@ -4093,6 +4157,34 @@
return 0;
}
+/**
+ * scsi_tape_release - Called to free the Scsi_Tape structure
+ * @kref: pointer to embedded kref
+ *
+ * st_ref_sem must be held entering this routine. Because it is
+ * called on last put, you should always use the scsi_tape_get()
+ * scsi_tape_put() helpers which manipulate the semaphore directly
+ * and never do a direct kref_put().
+ **/
+static void scsi_tape_release(struct kref *kref)
+{
+ struct scsi_tape *tpnt = to_scsi_tape(kref);
+ struct gendisk *disk = tpnt->disk;
+
+ tpnt->device = NULL;
+
+ if (tpnt->buffer) {
+ tpnt->buffer->orig_frp_segs = 0;
+ normalize_buffer(tpnt->buffer);
+ kfree(tpnt->buffer);
+ }
+
+ disk->private_data = NULL;
+ put_disk(disk);
+ kfree(tpnt);
+ return;
+}
+
static void st_intr(struct scsi_cmnd *SCpnt)
{
scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1);
@@ -4348,12 +4440,12 @@
static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
unsigned long uaddr, size_t count, int rw)
{
+ unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = uaddr >> PAGE_SHIFT;
+ const int nr_pages = end - start;
int res, i, j;
- unsigned int nr_pages;
struct page **pages;
- nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
-
/* User attempted Overflow! */
if ((uaddr + count) < uaddr)
return -EINVAL;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 061da11..790acac 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -3,7 +3,7 @@
#define _ST_H
#include <linux/completion.h>
-
+#include <linux/kref.h>
/* Descriptor for analyzed sense data */
struct st_cmdstatus {
@@ -156,6 +156,7 @@
unsigned char last_sense[16];
#endif
struct gendisk *disk;
+ struct kref kref;
};
/* Bit masks for use_pf */
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index 0b10169..aec39fb 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -58,8 +58,7 @@
* int((BAUD_BASE - (baud >> 1)) / baud)
*/
-static void
-serial21285_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial21285_stop_tx(struct uart_port *port)
{
if (tx_enabled(port)) {
disable_irq(IRQ_CONTX);
@@ -67,8 +66,7 @@
}
}
-static void
-serial21285_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial21285_start_tx(struct uart_port *port)
{
if (!tx_enabled(port)) {
enable_irq(IRQ_CONTX);
@@ -148,7 +146,7 @@
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- serial21285_stop_tx(port, 0);
+ serial21285_stop_tx(port);
goto out;
}
@@ -164,7 +162,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- serial21285_stop_tx(port, 0);
+ serial21285_stop_tx(port);
out:
return IRQ_HANDLED;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 9097f2f..2efb317 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -40,7 +40,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index b116122..170c9d2 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -2474,8 +2474,7 @@
.tiocmset = rs_360_tiocmset,
};
-/* int __init rs_360_init(void) */
-int rs_360_init(void)
+static int __init rs_360_init(void)
{
struct serial_state * state;
ser_info_t *info;
@@ -2827,10 +2826,7 @@
return 0;
}
-
-
-
-
+module_init(rs_360_init);
/* This must always be called before the rs_360_init() function, otherwise
* it blows away the port control information.
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 7e8fc7c..30a0a3d 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1001,7 +1001,7 @@
}
}
-static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1018,7 +1018,7 @@
static void transmit_chars(struct uart_8250_port *up);
-static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1158,7 +1158,11 @@
up->port.x_char = 0;
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ if (uart_tx_stopped(&up->port)) {
+ serial8250_stop_tx(&up->port);
+ return;
+ }
+ if (uart_circ_empty(xmit)) {
__stop_tx(up);
return;
}
@@ -2586,82 +2590,3 @@
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
#endif
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
-
-/**
- * register_serial - configure a 16x50 serial port at runtime
- * @req: request structure
- *
- * Configure the serial port specified by the request. If the
- * port exists and is in use an error is returned. If the port
- * is not currently in the table it is added.
- *
- * The port is then probed and if necessary the IRQ is autodetected
- * If this fails an error is returned.
- *
- * On success the port is ready to use and the line number is returned.
- *
- * Note: this function is deprecated - use serial8250_register_port
- * instead.
- */
-int register_serial(struct serial_struct *req)
-{
- struct uart_port port;
-
- port.iobase = req->port;
- port.membase = req->iomem_base;
- port.irq = req->irq;
- port.uartclk = req->baud_base * 16;
- port.fifosize = req->xmit_fifo_size;
- port.regshift = req->iomem_reg_shift;
- port.iotype = req->io_type;
- port.flags = req->flags | UPF_BOOT_AUTOCONF;
- port.mapbase = req->iomap_base;
- port.dev = NULL;
-
- if (share_irqs)
- port.flags |= UPF_SHARE_IRQ;
-
- if (HIGH_BITS_OFFSET)
- port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
-
- /*
- * If a clock rate wasn't specified by the low level driver, then
- * default to the standard clock rate. This should be 115200 (*16)
- * and should not depend on the architecture's BASE_BAUD definition.
- * However, since this API will be deprecated, it's probably a
- * better idea to convert the drivers to use the new API
- * (serial8250_register_port and serial8250_unregister_port).
- */
- if (port.uartclk == 0) {
- printk(KERN_WARNING
- "Serial: registering port at [%08x,%08lx,%p] irq %d with zero baud_base\n",
- port.iobase, port.mapbase, port.membase, port.irq);
- printk(KERN_WARNING "Serial: see %s:%d for more information\n",
- __FILE__, __LINE__);
- dump_stack();
-
- /*
- * Fix it up for now, but this is only a temporary measure.
- */
- port.uartclk = BASE_BAUD * 16;
- }
-
- return serial8250_register_port(&port);
-}
-EXPORT_SYMBOL(register_serial);
-
-/**
- * unregister_serial - remove a 16x50 serial port at runtime
- * @line: serial line number
- *
- * Remove one serial port. This may not be called from interrupt
- * context. We hand the port back to our local PM control.
- *
- * Note: this function is deprecated - use serial8250_unregister_port
- * instead.
- */
-void unregister_serial(int line)
-{
- serial8250_unregister_port(line);
-}
-EXPORT_SYMBOL(unregister_serial);
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 9225c82..b1b459e 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -16,11 +16,7 @@
*/
#include <linux/config.h>
-
-int serial8250_register_port(struct uart_port *);
-void serial8250_unregister_port(int line);
-void serial8250_suspend_port(int line);
-void serial8250_resume_port(int line);
+#include <linux/serial_8250.h>
struct old_serial_port {
unsigned int uart;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d579761..e39818a 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -308,7 +308,7 @@
config SERIAL_DZ
bool "DECstation DZ serial driver"
- depends on MACH_DECSTATION && MIPS32
+ depends on MACH_DECSTATION && 32BIT
select SERIAL_CORE
help
DZ11-family serial controllers for VAXstations, including the
@@ -830,7 +830,7 @@
config SERIAL_TXX9
bool "TMPTX39XX/49XX SIO support"
- depends HAS_TXX9_SERIAL
+ depends HAS_TXX9_SERIAL && BROKEN
select SERIAL_CORE
default y
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 2884b31..978e124 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -105,7 +105,7 @@
unsigned int old_status;
};
-static void pl010_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pl010_stop_tx(struct uart_port *port)
{
unsigned int cr;
@@ -114,7 +114,7 @@
UART_PUT_CR(port, cr);
}
-static void pl010_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pl010_start_tx(struct uart_port *port)
{
unsigned int cr;
@@ -219,7 +219,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- pl010_stop_tx(port, 0);
+ pl010_stop_tx(port);
return;
}
@@ -236,7 +236,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- pl010_stop_tx(port, 0);
+ pl010_stop_tx(port);
}
static void pl010_modem_status(struct uart_port *port)
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 7db88ee..5607130 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -74,7 +74,7 @@
unsigned int old_status;
};
-static void pl011_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -82,7 +82,7 @@
writew(uap->im, uap->port.membase + UART011_IMSC);
}
-static void pl011_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pl011_start_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -184,7 +184,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
- pl011_stop_tx(&uap->port, 0);
+ pl011_stop_tx(&uap->port);
return;
}
@@ -201,7 +201,7 @@
uart_write_wakeup(&uap->port);
if (uart_circ_empty(xmit))
- pl011_stop_tx(&uap->port, 0);
+ pl011_stop_tx(&uap->port);
}
static void pl011_modem_status(struct uart_amba_port *uap)
diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c
index 6104aee..a274ebf 100644
--- a/drivers/serial/au1x00_uart.c
+++ b/drivers/serial/au1x00_uart.c
@@ -200,7 +200,7 @@
DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
}
-static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -210,7 +210,7 @@
}
}
-static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -337,7 +337,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial8250_stop_tx(&up->port, 0);
+ serial8250_stop_tx(&up->port);
return;
}
@@ -356,7 +356,7 @@
DEBUG_INTR("THRE...");
if (uart_circ_empty(xmit))
- serial8250_stop_tx(&up->port, 0);
+ serial8250_stop_tx(&up->port);
}
static _INLINE_ void check_modem_status(struct uart_8250_port *up)
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
index e92522b..d822896 100644
--- a/drivers/serial/clps711x.c
+++ b/drivers/serial/clps711x.c
@@ -69,8 +69,7 @@
#define tx_enabled(port) ((port)->unused[0])
-static void
-clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void clps711xuart_stop_tx(struct uart_port *port)
{
if (tx_enabled(port)) {
disable_irq(TX_IRQ(port));
@@ -78,8 +77,7 @@
}
}
-static void
-clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start)
+static void clps711xuart_start_tx(struct uart_port *port)
{
if (!tx_enabled(port)) {
enable_irq(TX_IRQ(port));
@@ -165,7 +163,7 @@
return IRQ_HANDLED;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- clps711xuart_stop_tx(port, 0);
+ clps711xuart_stop_tx(port);
return IRQ_HANDLED;
}
@@ -182,7 +180,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- clps711xuart_stop_tx(port, 0);
+ clps711xuart_stop_tx(port);
return IRQ_HANDLED;
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index d639ac9..25825f2 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -124,7 +124,7 @@
/*
* Stop transmitter
*/
-static void cpm_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void cpm_uart_stop_tx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile smc_t *smcp = pinfo->smcp;
@@ -141,7 +141,7 @@
/*
* Start transmitter
*/
-static void cpm_uart_start_tx(struct uart_port *port, unsigned int tty_start)
+static void cpm_uart_start_tx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile smc_t *smcp = pinfo->smcp;
@@ -403,10 +403,8 @@
inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
{
- unsigned long target_jiffies = jiffies + pinfo->wait_closing;
-
- while (!time_after(jiffies, target_jiffies))
- schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(pinfo->wait_closing);
}
/*
@@ -425,9 +423,12 @@
/* If the port is not the console, disable Rx and Tx. */
if (!(pinfo->flags & FLAG_CONSOLE)) {
/* Wait for all the BDs marked sent */
- while(!cpm_uart_tx_empty(port))
+ while(!cpm_uart_tx_empty(port)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(2);
- if(pinfo->wait_closing)
+ }
+
+ if (pinfo->wait_closing)
cpm_uart_wait_until_send(pinfo);
/* Stop uarts */
@@ -623,7 +624,7 @@
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- cpm_uart_stop_tx(port, 0);
+ cpm_uart_stop_tx(port);
return 0;
}
@@ -656,7 +657,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) {
- cpm_uart_stop_tx(port, 0);
+ cpm_uart_stop_tx(port);
return 0;
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index c4c8f4b..15ad58d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -142,6 +142,14 @@
* be supported in a sane fashion.
*/
#ifndef CONFIG_STX_GP3
+#ifdef CONFIG_MPC8560_ADS
+ volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ io->iop_ppard |= 0x00000018;
+ io->iop_psord &= ~0x00000008; /* Rx */
+ io->iop_psord &= ~0x00000010; /* Tx */
+ io->iop_pdird &= ~0x00000008; /* Rx */
+ io->iop_pdird |= 0x00000010; /* Tx */
+#else
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
@@ -149,6 +157,7 @@
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
#endif
+#endif
cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
@@ -257,6 +266,7 @@
cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
+ *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
cpm_uart_ports[UART_SMC1].port.mapbase =
(unsigned long)&cpm2_immr->im_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
@@ -269,6 +279,7 @@
cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
cpm_uart_ports[UART_SMC2].smcup =
(smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
+ *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
cpm_uart_ports[UART_SMC2].port.mapbase =
(unsigned long)&cpm2_immr->im_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 23b8871..40d3e71 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -446,7 +446,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/bitops.h>
#include <linux/delay.h>
@@ -5041,17 +5040,3 @@
/* this makes sure that rs_init is called during kernel boot */
module_init(rs_init);
-
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-int
-register_serial(struct serial_struct *req)
-{
- return -1;
-}
-
-void unregister_serial(int line)
-{
-}
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index 97824ee..e63b9df 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -112,7 +112,7 @@
* ------------------------------------------------------------
*/
-static void dz_stop_tx(struct uart_port *uport, unsigned int tty_stop)
+static void dz_stop_tx(struct uart_port *uport)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned short tmp, mask = 1 << dport->port.line;
@@ -125,7 +125,7 @@
spin_unlock_irqrestore(&dport->port.lock, flags);
}
-static void dz_start_tx(struct uart_port *uport, unsigned int tty_start)
+static void dz_start_tx(struct uart_port *uport)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned short tmp, mask = 1 << dport->port.line;
@@ -290,7 +290,7 @@
}
/* if nothing to do or stopped or hardware stopped */
if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
- dz_stop_tx(&dport->port, 0);
+ dz_stop_tx(&dport->port);
return;
}
@@ -308,7 +308,7 @@
/* Are we done */
if (uart_circ_empty(xmit))
- dz_stop_tx(&dport->port, 0);
+ dz_stop_tx(&dport->port);
}
/*
@@ -440,7 +440,7 @@
*/
static void dz_shutdown(struct uart_port *uport)
{
- dz_stop_tx(uport, 0);
+ dz_stop_tx(uport);
}
/*
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index c112b32..eb31125 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -56,7 +56,6 @@
#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -989,18 +988,16 @@
return result;
}
-static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void icom_stop_tx(struct uart_port *port)
{
unsigned char cmdReg;
- if (tty_stop) {
- trace(ICOM_PORT, "STOP", 0);
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
- }
+ trace(ICOM_PORT, "STOP", 0);
+ cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+ writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
}
-static void icom_start_tx(struct uart_port *port, unsigned int tty_start)
+static void icom_start_tx(struct uart_port *port)
{
unsigned char cmdReg;
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 01a8726..4c985e6 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -124,7 +124,7 @@
/*
* interrupts disabled on entry
*/
-static void imx_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void imx_stop_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN;
@@ -165,13 +165,13 @@
} while (!(UTS((u32)sport->port.membase) & UTS_TXFULL));
if (uart_circ_empty(xmit))
- imx_stop_tx(&sport->port, 0);
+ imx_stop_tx(&sport->port);
}
/*
* interrupts disabled on entry
*/
-static void imx_start_tx(struct uart_port *port, unsigned int tty_start)
+static void imx_start_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -196,7 +196,7 @@
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
- imx_stop_tx(&sport->port, 0);
+ imx_stop_tx(&sport->port);
goto out;
}
@@ -291,13 +291,31 @@
return USR2((u32)sport->port.membase) & USR2_TXDC ? TIOCSER_TEMT : 0;
}
+/*
+ * We have a modem side uart, so the meanings of RTS and CTS are inverted.
+ */
static unsigned int imx_get_mctrl(struct uart_port *port)
{
- return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+ struct imx_port *sport = (struct imx_port *)port;
+ unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+
+ if (USR1((u32)sport->port.membase) & USR1_RTSS)
+ tmp |= TIOCM_CTS;
+
+ if (UCR2((u32)sport->port.membase) & UCR2_CTS)
+ tmp |= TIOCM_RTS;
+
+ return tmp;
}
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ struct imx_port *sport = (struct imx_port *)port;
+
+ if (mctrl & TIOCM_RTS)
+ UCR2((u32)sport->port.membase) |= UCR2_CTS;
+ else
+ UCR2((u32)sport->port.membase) &= ~UCR2_CTS;
}
/*
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 793c3a7..0c5c96a 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -2373,10 +2373,9 @@
/**
* ic4_stop_tx - stop the transmitter
* @port: Port to operate on
- * @tty_stop: Set to 1 if called via uart_stop
*
*/
-static void ic4_stop_tx(struct uart_port *the_port, unsigned int tty_stop)
+static void ic4_stop_tx(struct uart_port *the_port)
{
}
@@ -2471,10 +2470,9 @@
/**
* ic4_start_tx - Start transmitter, flush any output
* @port: Port to operate on
- * @tty_stop: Set to 1 if called via uart_start
*
*/
-static void ic4_start_tx(struct uart_port *the_port, unsigned int tty_stop)
+static void ic4_start_tx(struct uart_port *the_port)
{
struct ioc4_port *port = get_ioc4_port(the_port);
unsigned long flags;
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index ea5bf4d..ef13234 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -592,7 +592,7 @@
}
/* The port lock is held and interrupts are disabled. */
-static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void ip22zilog_stop_tx(struct uart_port *port)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
@@ -600,7 +600,7 @@
}
/* The port lock is held and interrupts are disabled. */
-static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void ip22zilog_start_tx(struct uart_port *port)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 98de225..6fa0d62 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -113,7 +113,7 @@
udelay(10);
}
-static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start)
+static void jsm_tty_start_tx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
@@ -125,7 +125,7 @@
jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
}
-static void jsm_tty_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void jsm_tty_stop_tx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 9b50560..b0ecc75 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -275,7 +275,7 @@
__sio_out(value, offset);
}
-static void m32r_sio_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void m32r_sio_stop_tx(struct uart_port *port)
{
struct uart_sio_port *up = (struct uart_sio_port *)port;
@@ -285,7 +285,7 @@
}
}
-static void m32r_sio_start_tx(struct uart_port *port, unsigned int tty_start)
+static void m32r_sio_start_tx(struct uart_port *port)
{
#ifdef CONFIG_SERIAL_M32R_PLDSIO
struct uart_sio_port *up = (struct uart_sio_port *)port;
@@ -425,7 +425,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- m32r_sio_stop_tx(&up->port, 0);
+ m32r_sio_stop_tx(&up->port);
return;
}
@@ -446,7 +446,7 @@
DEBUG_INTR("THRE...");
if (uart_circ_empty(xmit))
- m32r_sio_stop_tx(&up->port, 0);
+ m32r_sio_stop_tx(&up->port);
}
/*
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 8c40167..43b03c5 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -40,7 +40,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/semaphore.h>
#include <asm/delay.h>
#include <asm/coldfire.h>
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 2a5cf17..a3cd0ee 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -119,7 +119,7 @@
}
static void
-mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+mpc52xx_uart_stop_tx(struct uart_port *port)
{
/* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
@@ -127,7 +127,7 @@
}
static void
-mpc52xx_uart_start_tx(struct uart_port *port, unsigned int tty_start)
+mpc52xx_uart_start_tx(struct uart_port *port)
{
/* port->lock taken by caller */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
@@ -485,7 +485,7 @@
/* Nothing to do ? */
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- mpc52xx_uart_stop_tx(port,0);
+ mpc52xx_uart_stop_tx(port);
return 0;
}
@@ -504,7 +504,7 @@
/* Maybe we're done after all */
if (uart_circ_empty(xmit)) {
- mpc52xx_uart_stop_tx(port,0);
+ mpc52xx_uart_stop_tx(port);
return 0;
}
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index e43276c..efe79b1 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -1072,18 +1072,18 @@
}
static void
-mpsc_stop_tx(struct uart_port *port, uint tty_start)
+mpsc_stop_tx(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
- pr_debug("mpsc_stop_tx[%d]: tty_start: %d\n", port->line, tty_start);
+ pr_debug("mpsc_stop_tx[%d]\n", port->line);
mpsc_freeze(pi);
return;
}
static void
-mpsc_start_tx(struct uart_port *port, uint tty_start)
+mpsc_start_tx(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
@@ -1091,7 +1091,7 @@
mpsc_copy_tx_data(pi);
mpsc_sdma_start_tx(pi);
- pr_debug("mpsc_start_tx[%d]: tty_start: %d\n", port->line, tty_start);
+ pr_debug("mpsc_start_tx[%d]\n", port->line);
return;
}
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index dadd7e1..1890646 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -111,22 +111,20 @@
/**
* mux_stop_tx - Stop transmitting characters.
* @port: Ptr to the uart_port.
- * @tty_stop: tty layer issue this command?
*
* The Serial MUX does not support this function.
*/
-static void mux_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void mux_stop_tx(struct uart_port *port)
{
}
/**
* mux_start_tx - Start transmitting characters.
* @port: Ptr to the uart_port.
- * @tty_start: tty layer issue this command?
*
* The Serial Mux does not support this function.
*/
-static void mux_start_tx(struct uart_port *port, unsigned int tty_start)
+static void mux_start_tx(struct uart_port *port)
{
}
@@ -181,7 +179,7 @@
}
if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- mux_stop_tx(port, 0);
+ mux_stop_tx(port);
return;
}
@@ -202,7 +200,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- mux_stop_tx(port, 0);
+ mux_stop_tx(port);
}
/**
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 7db2f37..5ddd8ab 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -630,11 +630,10 @@
/*
* Stop TX side. Dealt like sunzilog at next Tx interrupt,
- * though for DMA, we will have to do a bit more. What is
- * the meaning of the tty_stop bit ? XXX
+ * though for DMA, we will have to do a bit more.
* The port lock is held and interrupts are disabled.
*/
-static void pmz_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pmz_stop_tx(struct uart_port *port)
{
to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
}
@@ -643,7 +642,7 @@
* Kick the Tx side.
* The port lock is held and interrupts are disabled.
*/
-static void pmz_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pmz_start_tx(struct uart_port *port)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned char status;
@@ -1601,7 +1600,7 @@
return 0;
}
- if (pm_state == mdev->ofdev.dev.power.power_state || pm_state < 2)
+ if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
return 0;
pmz_debug("suspend, switching to state %d\n", pm_state);
@@ -1661,7 +1660,7 @@
if (uap == NULL)
return 0;
- if (mdev->ofdev.dev.power.power_state == 0)
+ if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
return 0;
pmz_debug("resume, switching to state 0\n");
@@ -1714,7 +1713,7 @@
pmz_debug("resume, switching complete\n");
- mdev->ofdev.dev.power.power_state = 0;
+ mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
return 0;
}
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index 461c81c..eaa0af8 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -80,7 +80,7 @@
serial_out(up, UART_IER, up->ier);
}
-static void serial_pxa_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial_pxa_stop_tx(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
@@ -185,7 +185,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial_pxa_stop_tx(&up->port, 0);
+ serial_pxa_stop_tx(&up->port);
return;
}
@@ -203,10 +203,10 @@
if (uart_circ_empty(xmit))
- serial_pxa_stop_tx(&up->port, 0);
+ serial_pxa_stop_tx(&up->port);
}
-static void serial_pxa_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial_pxa_start_tx(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 7365d4b..c361c6f 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -246,8 +246,7 @@
spin_unlock_irqrestore(&port->lock, flags);
}
-static void
-s3c24xx_serial_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
if (tx_enabled(port)) {
disable_irq(TX_IRQ(port));
@@ -257,8 +256,7 @@
}
}
-static void
-s3c24xx_serial_start_tx(struct uart_port *port, unsigned int tty_start)
+static void s3c24xx_serial_start_tx(struct uart_port *port)
{
if (!tx_enabled(port)) {
if (port->flags & UPF_CONS_FLOW)
@@ -424,7 +422,7 @@
*/
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- s3c24xx_serial_stop_tx(port, 0);
+ s3c24xx_serial_stop_tx(port);
goto out;
}
@@ -443,7 +441,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- s3c24xx_serial_stop_tx(port, 0);
+ s3c24xx_serial_stop_tx(port);
out:
return IRQ_HANDLED;
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index 98641c3..1225b14 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -145,7 +145,7 @@
/*
* interrupts disabled on entry
*/
-static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sa1100_stop_tx(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
u32 utcr3;
@@ -158,7 +158,7 @@
/*
* interrupts may not be disabled on entry
*/
-static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sa1100_start_tx(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
@@ -264,7 +264,7 @@
sa1100_mctrl_check(sport);
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
- sa1100_stop_tx(&sport->port, 0);
+ sa1100_stop_tx(&sport->port);
return;
}
@@ -284,7 +284,7 @@
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit))
- sa1100_stop_tx(&sport->port, 0);
+ sa1100_stop_tx(&sport->port);
}
static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 54699c3..2d8622e 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -80,7 +80,7 @@
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- port->ops->stop_tx(port, 1);
+ port->ops->stop_tx(port);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -91,7 +91,7 @@
if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
!tty->stopped && !tty->hw_stopped)
- port->ops->start_tx(port, 1);
+ port->ops->start_tx(port);
}
static void uart_start(struct tty_struct *tty)
@@ -542,7 +542,7 @@
port->x_char = ch;
if (ch) {
spin_lock_irqsave(&port->lock, flags);
- port->ops->start_tx(port, 0);
+ port->ops->start_tx(port);
spin_unlock_irqrestore(&port->lock, flags);
}
}
@@ -1146,7 +1146,7 @@
spin_lock_irqsave(&state->port->lock, flags);
if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
tty->hw_stopped = 1;
- state->port->ops->stop_tx(state->port, 0);
+ state->port->ops->stop_tx(state->port);
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
@@ -1869,7 +1869,7 @@
struct uart_ops *ops = port->ops;
spin_lock_irq(&port->lock);
- ops->stop_tx(port, 0);
+ ops->stop_tx(port);
ops->set_mctrl(port, 0);
ops->stop_rx(port);
spin_unlock_irq(&port->lock);
@@ -1935,7 +1935,7 @@
uart_change_speed(state, NULL);
spin_lock_irq(&port->lock);
ops->set_mctrl(port, port->mctrl);
- ops->start_tx(port, 0);
+ ops->start_tx(port);
spin_unlock_irq(&port->lock);
}
@@ -1947,21 +1947,29 @@
static inline void
uart_report_port(struct uart_driver *drv, struct uart_port *port)
{
- printk("%s%d", drv->dev_name, port->line);
- printk(" at ");
+ char address[64];
+
switch (port->iotype) {
case UPIO_PORT:
- printk("I/O 0x%x", port->iobase);
+ snprintf(address, sizeof(address),
+ "I/O 0x%x", port->iobase);
break;
case UPIO_HUB6:
- printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+ snprintf(address, sizeof(address),
+ "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
case UPIO_MEM32:
- printk("MMIO 0x%lx", port->mapbase);
+ snprintf(address, sizeof(address),
+ "MMIO 0x%lx", port->mapbase);
+ break;
+ default:
+ strlcpy(address, "*unknown*", sizeof(address));
break;
}
- printk(" (irq = %d) is a %s\n", port->irq, uart_type(port));
+
+ printk(KERN_INFO "%s%d at %s (irq = %d) is a %s\n",
+ drv->dev_name, port->line, address, port->irq, uart_type(port));
}
static void
@@ -2289,143 +2297,11 @@
}
EXPORT_SYMBOL(uart_match_port);
-/*
- * Try to find an unused uart_state slot for a port.
- */
-static struct uart_state *
-uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port)
-{
- int i;
-
- /*
- * First, find a port entry which matches. Note: if we do
- * find a matching entry, and it has a non-zero use count,
- * then we can't register the port.
- */
- for (i = 0; i < drv->nr; i++)
- if (uart_match_port(drv->state[i].port, port))
- return &drv->state[i];
-
- /*
- * We didn't find a matching entry, so look for the first
- * free entry. We look for one which hasn't been previously
- * used (indicated by zero iobase).
- */
- for (i = 0; i < drv->nr; i++)
- if (drv->state[i].port->type == PORT_UNKNOWN &&
- drv->state[i].port->iobase == 0 &&
- drv->state[i].count == 0)
- return &drv->state[i];
-
- /*
- * That also failed. Last resort is to find any currently
- * entry which doesn't have a real port associated with it.
- */
- for (i = 0; i < drv->nr; i++)
- if (drv->state[i].port->type == PORT_UNKNOWN &&
- drv->state[i].count == 0)
- return &drv->state[i];
-
- return NULL;
-}
-
-/**
- * uart_register_port: register uart settings with a port
- * @drv: pointer to the uart low level driver structure for this port
- * @port: uart port structure describing the port
- *
- * Register UART settings with the specified low level driver. Detect
- * the type of the port if UPF_BOOT_AUTOCONF is set, and detect the
- * IRQ if UPF_AUTO_IRQ is set.
- *
- * We try to pick the same port for the same IO base address, so that
- * when a modem is plugged in, unplugged and plugged back in, it gets
- * allocated the same port.
- *
- * Returns negative error, or positive line number.
- */
-int uart_register_port(struct uart_driver *drv, struct uart_port *port)
-{
- struct uart_state *state;
- int ret;
-
- down(&port_sem);
-
- state = uart_find_match_or_unused(drv, port);
-
- if (state) {
- /*
- * Ok, we've found a line that we can use.
- *
- * If we find a port that matches this one, and it appears
- * to be in-use (even if it doesn't have a type) we shouldn't
- * alter it underneath itself - the port may be open and
- * trying to do useful work.
- */
- if (uart_users(state) != 0) {
- ret = -EBUSY;
- goto out;
- }
-
- /*
- * If the port is already initialised, don't touch it.
- */
- if (state->port->type == PORT_UNKNOWN) {
- state->port->iobase = port->iobase;
- state->port->membase = port->membase;
- state->port->irq = port->irq;
- state->port->uartclk = port->uartclk;
- state->port->fifosize = port->fifosize;
- state->port->regshift = port->regshift;
- state->port->iotype = port->iotype;
- state->port->flags = port->flags;
- state->port->line = state - drv->state;
- state->port->mapbase = port->mapbase;
-
- uart_configure_port(drv, state, state->port);
- }
-
- ret = state->port->line;
- } else
- ret = -ENOSPC;
- out:
- up(&port_sem);
- return ret;
-}
-
-/**
- * uart_unregister_port - de-allocate a port
- * @drv: pointer to the uart low level driver structure for this port
- * @line: line index previously returned from uart_register_port()
- *
- * Hang up the specified line associated with the low level driver,
- * and mark the port as unused.
- */
-void uart_unregister_port(struct uart_driver *drv, int line)
-{
- struct uart_state *state;
-
- if (line < 0 || line >= drv->nr) {
- printk(KERN_ERR "Attempt to unregister ");
- printk("%s%d", drv->dev_name, line);
- printk("\n");
- return;
- }
-
- state = drv->state + line;
-
- down(&port_sem);
- uart_unconfigure_port(drv, state);
- up(&port_sem);
-}
-
EXPORT_SYMBOL(uart_write_wakeup);
EXPORT_SYMBOL(uart_register_driver);
EXPORT_SYMBOL(uart_unregister_driver);
EXPORT_SYMBOL(uart_suspend_port);
EXPORT_SYMBOL(uart_resume_port);
-EXPORT_SYMBOL(uart_register_port);
-EXPORT_SYMBOL(uart_unregister_port);
EXPORT_SYMBOL(uart_add_one_port);
EXPORT_SYMBOL(uart_remove_one_port);
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index 56f269b..8302376 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -112,13 +112,12 @@
unsigned int statusPrev; /* Most recently read modem status */
};
-static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
+static void lh7a40xuart_stop_tx (struct uart_port* port)
{
BIT_CLR (port, UART_R_INTEN, TxInt);
}
-static void lh7a40xuart_start_tx (struct uart_port* port,
- unsigned int tty_start)
+static void lh7a40xuart_start_tx (struct uart_port* port)
{
BIT_SET (port, UART_R_INTEN, TxInt);
@@ -208,7 +207,7 @@
return;
}
if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
- lh7a40xuart_stop_tx (port, 0);
+ lh7a40xuart_stop_tx (port);
return;
}
@@ -230,7 +229,7 @@
uart_write_wakeup (port);
if (uart_circ_empty (xmit))
- lh7a40xuart_stop_tx (port, 0);
+ lh7a40xuart_stop_tx (port);
}
static void lh7a40xuart_modem_status (struct uart_port* port)
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index d085030..49afadb 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -253,7 +253,7 @@
sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
}
-static void serial_txx9_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void serial_txx9_stop_tx(struct uart_port *port)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned long flags;
@@ -263,7 +263,7 @@
spin_unlock_irqrestore(&up->port.lock, flags);
}
-static void serial_txx9_start_tx(struct uart_port *port, unsigned int tty_start)
+static void serial_txx9_start_tx(struct uart_port *port)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned long flags;
@@ -372,7 +372,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial_txx9_stop_tx(&up->port, 0);
+ serial_txx9_stop_tx(&up->port);
return;
}
@@ -389,7 +389,7 @@
uart_write_wakeup(&up->port);
if (uart_circ_empty(xmit))
- serial_txx9_stop_tx(&up->port, 0);
+ serial_txx9_stop_tx(&up->port);
}
static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index ad5b776..5122663 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -79,8 +79,8 @@
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
/* Function prototypes */
-static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop);
-static void sci_start_tx(struct uart_port *port, unsigned int tty_start);
+static void sci_stop_tx(struct uart_port *port);
+static void sci_start_tx(struct uart_port *port);
static void sci_start_rx(struct uart_port *port, unsigned int tty_start);
static void sci_stop_rx(struct uart_port *port);
static int sci_request_irq(struct sci_port *port);
@@ -455,7 +455,7 @@
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) {
- sci_stop_tx(port, 0);
+ sci_stop_tx(port);
} else {
local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
@@ -900,7 +900,7 @@
return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
}
-static void sci_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sci_start_tx(struct uart_port *port)
{
struct sci_port *s = &sci_ports[port->line];
@@ -909,7 +909,7 @@
enable_irq(s->irqs[SCIx_TXI_IRQ]);
}
-static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sci_stop_tx(struct uart_port *port)
{
unsigned long flags;
unsigned short ctrl;
@@ -978,7 +978,7 @@
struct sci_port *s = &sci_ports[port->line];
sci_stop_rx(port);
- sci_stop_tx(port, 1);
+ sci_stop_tx(port);
sci_free_irq(s);
#if defined(__H8300S__)
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 12d1f14..313f9df 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -259,10 +259,9 @@
/**
* snp_stop_tx - stop the transmitter - no-op for us
* @port: Port to operat eon - we ignore - no-op function
- * @tty_stop: Set to 1 if called via uart_stop
*
*/
-static void snp_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void snp_stop_tx(struct uart_port *port)
{
}
@@ -325,10 +324,9 @@
/**
* snp_start_tx - Start transmitter
* @port: Port to operate on
- * @tty_stop: Set to 1 if called via uart_start
*
*/
-static void snp_start_tx(struct uart_port *port, unsigned int tty_stop)
+static void snp_start_tx(struct uart_port *port)
{
if (sal_console_port.sc_ops->sal_wakeup_transmit)
sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
@@ -615,7 +613,7 @@
uart_write_wakeup(&port->sc_port);
if (uart_circ_empty(xmit))
- snp_stop_tx(&port->sc_port, 0); /* no-op for us */
+ snp_stop_tx(&port->sc_port); /* no-op for us */
}
/**
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 8d19888..e971156 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -245,7 +245,7 @@
return tty;
}
-static void sunsab_stop_tx(struct uart_port *, unsigned int);
+static void sunsab_stop_tx(struct uart_port *);
static void sunsab_tx_idle(struct uart_sunsab_port *);
static void transmit_chars(struct uart_sunsab_port *up,
@@ -301,7 +301,7 @@
uart_write_wakeup(&up->port);
if (uart_circ_empty(xmit))
- sunsab_stop_tx(&up->port, 0);
+ sunsab_stop_tx(&up->port);
}
static void check_status(struct uart_sunsab_port *up,
@@ -448,7 +448,7 @@
}
/* port->lock held by caller. */
-static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sunsab_stop_tx(struct uart_port *port)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
@@ -476,7 +476,7 @@
}
/* port->lock held by caller. */
-static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunsab_start_tx(struct uart_port *port)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
struct circ_buf *xmit = &up->port.info->xmit;
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index d57a355..5959e67 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -255,21 +255,30 @@
}
#endif /* CONFIG_SERIAL_8250_RSA */
-static void sunsu_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static inline void __stop_tx(struct uart_sunsu_port *p)
+{
+ if (p->ier & UART_IER_THRI) {
+ p->ier &= ~UART_IER_THRI;
+ serial_out(p, UART_IER, p->ier);
+ }
+}
+
+static void sunsu_stop_tx(struct uart_port *port)
{
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
- if (up->ier & UART_IER_THRI) {
- up->ier &= ~UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
- if (up->port.type == PORT_16C950 && tty_stop) {
+ __stop_tx(up);
+
+ /*
+ * We really want to stop the transmitter from sending.
+ */
+ if (up->port.type == PORT_16C950) {
up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
}
-static void sunsu_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunsu_start_tx(struct uart_port *port)
{
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
@@ -277,10 +286,11 @@
up->ier |= UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
+
/*
- * We only do this from uart_start
+ * Re-enable the transmitter if we disabled it.
*/
- if (tty_start && up->port.type == PORT_16C950) {
+ if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
up->acr &= ~UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
@@ -413,8 +423,12 @@
up->port.x_char = 0;
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- sunsu_stop_tx(&up->port, 0);
+ if (uart_tx_stopped(&up->port)) {
+ sunsu_stop_tx(&up->port);
+ return;
+ }
+ if (uart_circ_empty(xmit)) {
+ __stop_tx(up);
return;
}
@@ -431,7 +445,7 @@
uart_write_wakeup(&up->port);
if (uart_circ_empty(xmit))
- sunsu_stop_tx(&up->port, 0);
+ __stop_tx(up);
}
static _INLINE_ void check_modem_status(struct uart_sunsu_port *up)
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index bff42a7..d754457 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -684,7 +684,7 @@
}
/* The port lock is held and interrupts are disabled. */
-static void sunzilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void sunzilog_stop_tx(struct uart_port *port)
{
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
@@ -692,7 +692,7 @@
}
/* The port lock is held and interrupts are disabled. */
-static void sunzilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void sunzilog_start_tx(struct uart_port *port)
{
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
diff --git a/drivers/serial/uart00.c b/drivers/serial/uart00.c
index 186f130..47b504f 100644
--- a/drivers/serial/uart00.c
+++ b/drivers/serial/uart00.c
@@ -87,7 +87,7 @@
#define UART_TX_READY(s) (((s) & UART_TSR_TX_LEVEL_MSK) < 15)
//#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0)
-static void uart00_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void uart00_stop_tx(struct uart_port *port)
{
UART_PUT_IEC(port, UART_IEC_TIE_MSK);
}
@@ -199,7 +199,7 @@
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- uart00_stop_tx(port, 0);
+ uart00_stop_tx(port);
return;
}
@@ -218,10 +218,10 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- uart00_stop_tx(port, 0);
+ uart00_stop_tx(port);
}
-static void uart00_start_tx(struct uart_port *port, unsigned int tty_start)
+static void uart00_start_tx(struct uart_port *port)
{
UART_PUT_IES(port, UART_IES_TIE_MSK);
uart00_tx_chars(port);
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
index bb48278..9378895 100644
--- a/drivers/serial/v850e_uart.c
+++ b/drivers/serial/v850e_uart.c
@@ -240,7 +240,7 @@
/* TX/RX interrupt handlers. */
-static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop);
+static void v850e_uart_stop_tx (struct uart_port *port);
void v850e_uart_tx (struct uart_port *port)
{
@@ -339,14 +339,14 @@
return mctrl;
}
-static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start)
+static void v850e_uart_start_tx (struct uart_port *port)
{
v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
v850e_uart_tx (port);
v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line));
}
-static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop)
+static void v850e_uart_stop_tx (struct uart_port *port)
{
v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
}
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 1f98532..0c5d65a 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -284,7 +284,7 @@
return mctrl;
}
-static void siu_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void siu_stop_tx(struct uart_port *port)
{
unsigned long flags;
uint8_t ier;
@@ -298,7 +298,7 @@
spin_unlock_irqrestore(&port->lock, flags);
}
-static void siu_start_tx(struct uart_port *port, unsigned int tty_start)
+static void siu_start_tx(struct uart_port *port)
{
unsigned long flags;
uint8_t ier;
@@ -458,7 +458,7 @@
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- siu_stop_tx(port, 0);
+ siu_stop_tx(port);
return;
}
@@ -474,7 +474,7 @@
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- siu_stop_tx(port, 0);
+ siu_stop_tx(port);
}
static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index bb1db19..c466739 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -960,7 +960,7 @@
intf->altsetting->desc.bInterfaceNumber);
/* instance init */
- instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
+ instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
if (!instance) {
dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
return -ENOMEM;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 79422a3..12ecdb0 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -782,7 +782,7 @@
return -E2BIG;
}
- bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum);
+ bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb_host%d", busnum);
if (IS_ERR(bus->class_dev)) {
clear_bit(busnum, busmap.busmap);
up(&usb_bus_list_lock);
@@ -1669,7 +1669,7 @@
{
struct usb_hcd *hcd;
- hcd = kcalloc(1, sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
+ hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
if (!hcd) {
dev_dbg (dev, "hcd alloc failed\n");
return NULL;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c3e46d2..c9412da 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1570,7 +1570,7 @@
struct usb_driver *driver;
intf = udev->actconfig->interface[i];
- if (state <= intf->dev.power.power_state)
+ if (state.event <= intf->dev.power.power_state.event)
continue;
if (!intf->dev.driver)
continue;
@@ -1578,11 +1578,11 @@
if (driver->suspend) {
status = driver->suspend(intf, state);
- if (intf->dev.power.power_state != state
+ if (intf->dev.power.power_state.event != state.event
|| status)
dev_err(&intf->dev,
"suspend %d fail, code %d\n",
- state, status);
+ state.event, status);
}
/* only drivers with suspend() can ever resume();
@@ -1595,7 +1595,7 @@
* since we know every driver's probe/disconnect works
* even for drivers that can't suspend.
*/
- if (!driver->suspend || state > PM_SUSPEND_MEM) {
+ if (!driver->suspend || state.event > PM_EVENT_FREEZE) {
#if 1
dev_warn(&intf->dev, "resume is unsafe!\n");
#else
@@ -1616,7 +1616,7 @@
* policies (when HNP doesn't apply) once we have mechanisms to
* turn power back on! (Likely not before 2.7...)
*/
- if (state > PM_SUSPEND_MEM) {
+ if (state.event > PM_EVENT_FREEZE) {
dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
}
@@ -1733,7 +1733,7 @@
struct usb_driver *driver;
intf = udev->actconfig->interface[i];
- if (intf->dev.power.power_state == PMSG_ON)
+ if (intf->dev.power.power_state.event == PM_EVENT_ON)
continue;
if (!intf->dev.driver) {
/* FIXME maybe force to alt 0 */
@@ -1747,11 +1747,11 @@
/* can we do better than just logging errors? */
status = driver->resume(intf);
- if (intf->dev.power.power_state != PMSG_ON
+ if (intf->dev.power.power_state.event != PM_EVENT_ON
|| status)
dev_dbg(&intf->dev,
"resume fail, state %d code %d\n",
- intf->dev.power.power_state, status);
+ intf->dev.power.power_state.event, status);
}
status = 0;
@@ -1934,7 +1934,7 @@
unsigned port1;
int status;
- if (intf->dev.power.power_state == PM_SUSPEND_ON)
+ if (intf->dev.power.power_state.event == PM_EVENT_ON)
return 0;
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 99c85d2..2cddd8a 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1400,7 +1400,7 @@
driver = to_usb_driver(dev->driver);
/* there's only one USB suspend state */
- if (intf->dev.power.power_state)
+ if (intf->dev.power.power_state.event)
return 0;
if (driver->suspend)
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index b01efb6..65ac9fe 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -641,7 +641,7 @@
spin_lock_irqsave (&ehci->lock, flags);
- if (bus->controller->power.power_state) {
+ if (bus->controller->power.power_state.event) {
size = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index b56f258..4c972b5 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -638,7 +638,7 @@
{
struct ehci_iso_stream *stream;
- stream = kcalloc(1, sizeof *stream, mem_flags);
+ stream = kzalloc(sizeof *stream, mem_flags);
if (likely (stream != NULL)) {
INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_list);
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 76cb496..75128c3 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -717,7 +717,7 @@
}
/* avoid all allocations within spinlocks: request or endpoint */
if (!hep->hcpriv) {
- ep = kcalloc(1, sizeof *ep, mem_flags);
+ ep = kzalloc(sizeof *ep, mem_flags);
if (!ep)
return -ENOMEM;
}
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index c58408c..447f488 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -631,7 +631,7 @@
hcd->product_desc,
hcd_name);
- if (bus->controller->power.power_state) {
+ if (bus->controller->power.power_state.event) {
size -= scnprintf (next, size,
"SUSPENDED (no register access)\n");
goto done;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 7a890a6..d2a1fd4 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -835,7 +835,7 @@
/* avoid all allocations within spinlocks */
if (!hep->hcpriv)
- ep = kcalloc(1, sizeof *ep, mem_flags);
+ ep = kzalloc(sizeof *ep, mem_flags);
spin_lock_irqsave(&sl811->lock, flags);
@@ -1781,9 +1781,9 @@
if (phase != SUSPEND_POWER_DOWN)
return retval;
- if (state <= PM_SUSPEND_MEM)
+ if (state.event == PM_EVENT_FREEZE)
retval = sl811h_hub_suspend(hcd);
- else
+ else if (state.event == PM_EVENT_SUSPEND)
port_power(sl811, 0);
if (retval == 0)
dev->power.power_state = state;
@@ -1802,7 +1802,7 @@
/* with no "check to see if VBUS is still powered" board hook,
* let's assume it'd only be powered to enable remote wakeup.
*/
- if (dev->power.power_state > PM_SUSPEND_MEM
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND
|| !hcd->can_wakeup) {
sl811->port1 = 0;
port_power(sl811, 1);
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
index 13532f3..74f8760 100644
--- a/drivers/usb/input/acecad.c
+++ b/drivers/usb/input/acecad.c
@@ -152,7 +152,7 @@
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
+ acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
if (!acecad)
return -ENOMEM;
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
index 0dc439f..becb87e 100644
--- a/drivers/usb/input/itmtouch.c
+++ b/drivers/usb/input/itmtouch.c
@@ -166,7 +166,7 @@
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
- if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
+ if (!(itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
}
diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
index 2569638..acc71ec 100644
--- a/drivers/usb/input/pid.c
+++ b/drivers/usb/input/pid.c
@@ -263,7 +263,7 @@
struct hid_ff_pid *private;
struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
- private = hid->ff_private = kcalloc(1, sizeof(struct hid_ff_pid), GFP_KERNEL);
+ private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
if (!private)
return -ENOMEM;
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
index ca9f3a3..f36c0b6 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -1523,7 +1523,6 @@
static int w9968cf_i2c_attach_inform(struct i2c_client* client)
{
struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
- const char* clientname = i2c_clientname(client);
int id = client->driver->id, err = 0;
if (id == I2C_DRIVERID_OVCAMCHIP) {
@@ -1535,12 +1534,12 @@
}
} else {
DBG(4, "Rejected client [%s] with driver [%s]",
- clientname, client->driver->name)
+ client->name, client->driver->name)
return -EINVAL;
}
DBG(5, "I2C attach client [%s] with driver [%s]",
- clientname, client->driver->name)
+ client->name, client->driver->name)
return 0;
}
@@ -1549,12 +1548,11 @@
static int w9968cf_i2c_detach_inform(struct i2c_client* client)
{
struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
- const char* clientname = i2c_clientname(client);
if (cam->sensor_client == client)
cam->sensor_client = NULL;
- DBG(5, "I2C detach client [%s]", clientname)
+ DBG(5, "I2C detach client [%s]", client->name)
return 0;
}
@@ -1573,15 +1571,13 @@
int err = 0;
static struct i2c_algorithm algo = {
- .name = "W996[87]CF algorithm",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = w9968cf_i2c_smbus_xfer,
.algo_control = w9968cf_i2c_control,
.functionality = w9968cf_i2c_func,
};
static struct i2c_adapter adap = {
- .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF,
+ .id = I2C_HW_SMBUS_W9968CF,
.class = I2C_CLASS_CAM_DIGITAL,
.owner = THIS_MODULE,
.client_register = w9968cf_i2c_attach_inform,
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index cda7249..fd7fb98 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1533,7 +1533,7 @@
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
- if (intf->dev.power.power_state != PMSG_ON) {
+ if (intf->dev.power.power_state.event != PM_EVENT_ON) {
up (&dev->sem);
return -EHOSTUNREACH;
}
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index 16f3521..fe3fd41 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -8,5 +8,3 @@
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o
-
-CFLAGS_zd1201.o = -Idrivers/net/wireless/
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
index e32a80b..fc01397 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/usb/net/zd1201.c
@@ -21,7 +21,7 @@
#include <linux/string.h>
#include <linux/if_arp.h>
#include <linux/firmware.h>
-#include <ieee802_11.h>
+#include <net/ieee80211.h>
#include "zd1201.h"
static struct usb_device_id zd1201_table[] = {
@@ -338,24 +338,24 @@
goto resubmit;
}
- if ((seq & IEEE802_11_SCTL_FRAG) ||
- (fc & IEEE802_11_FCTL_MOREFRAGS)) {
+ if ((seq & IEEE80211_SCTL_FRAG) ||
+ (fc & IEEE80211_FCTL_MOREFRAGS)) {
struct zd1201_frag *frag = NULL;
char *ptr;
if (datalen<14)
goto resubmit;
- if ((seq & IEEE802_11_SCTL_FRAG) == 0) {
+ if ((seq & IEEE80211_SCTL_FRAG) == 0) {
frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
if (!frag)
goto resubmit;
- skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2);
+ skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
if (!skb) {
kfree(frag);
goto resubmit;
}
frag->skb = skb;
- frag->seq = seq & IEEE802_11_SCTL_SEQ;
+ frag->seq = seq & IEEE80211_SCTL_SEQ;
skb_reserve(skb, 2);
memcpy(skb_put(skb, 12), &data[datalen-14], 12);
memcpy(skb_put(skb, 2), &data[6], 2);
@@ -364,7 +364,7 @@
goto resubmit;
}
hlist_for_each_entry(frag, node, &zd->fraglist, fnode)
- if(frag->seq == (seq&IEEE802_11_SCTL_SEQ))
+ if(frag->seq == (seq&IEEE80211_SCTL_SEQ))
break;
if (!frag)
goto resubmit;
@@ -372,7 +372,7 @@
ptr = skb_put(skb, len);
if (ptr)
memcpy(ptr, data+8, len);
- if (fc & IEEE802_11_FCTL_MOREFRAGS)
+ if (fc & IEEE80211_FCTL_MOREFRAGS)
goto resubmit;
hlist_del_init(&frag->fnode);
kfree(frag);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 7bc1d44..b0eba3a 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -2323,17 +2323,16 @@
* can properly take care of D3 ? Also, with swsusp, we
* know we'll be rebooted, ...
*/
-#ifdef CONFIG_PPC_PMAC
+#ifndef CONFIG_PPC_PMAC
/* HACK ALERT ! Once I find a proper way to say to each driver
* individually what will happen with it's PCI slot, I'll change
* that. On laptops, the AGP slot is just unclocked, so D2 is
* expected, while on desktops, the card is powered off
*/
- if (state >= 3)
- state = 2;
+ return 0;
#endif /* CONFIG_PPC_PMAC */
- if (state != 2 || state == pdev->dev.power.power_state)
+ if (state.event == pdev->dev.power.power_state.event)
return 0;
printk(KERN_DEBUG "aty128fb: suspending...\n");
@@ -2367,7 +2366,7 @@
* used dummy fb ops, 2.5 need proper support for this at the
* fbdev level
*/
- if (state == 2)
+ if (state.event != PM_EVENT_ON)
aty128_set_suspend(par, 1);
release_console_sem();
@@ -2382,12 +2381,11 @@
struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par;
- if (pdev->dev.power.power_state == 0)
+ if (pdev->dev.power.power_state.event == PM_EVENT_ON)
return 0;
/* Wakeup chip */
- if (pdev->dev.power.power_state == 2)
- aty128_set_suspend(par, 0);
+ aty128_set_suspend(par, 0);
par->asleep = 0;
/* Restore display & engine */
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 8c42538..3e10bd8 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2022,17 +2022,16 @@
struct fb_info *info = pci_get_drvdata(pdev);
struct atyfb_par *par = (struct atyfb_par *) info->par;
-#ifdef CONFIG_PPC_PMAC
+#ifndef CONFIG_PPC_PMAC
/* HACK ALERT ! Once I find a proper way to say to each driver
* individually what will happen with it's PCI slot, I'll change
* that. On laptops, the AGP slot is just unclocked, so D2 is
* expected, while on desktops, the card is powered off
*/
- if (state >= 3)
- state = 2;
+ return 0;
#endif /* CONFIG_PPC_PMAC */
- if (state != 2 || state == pdev->dev.power.power_state)
+ if (state.event == pdev->dev.power.power_state.event)
return 0;
acquire_console_sem();
@@ -2071,12 +2070,12 @@
struct fb_info *info = pci_get_drvdata(pdev);
struct atyfb_par *par = (struct atyfb_par *) info->par;
- if (pdev->dev.power.power_state == 0)
+ if (pdev->dev.power.power_state.event == PM_EVENT_ON)
return 0;
acquire_console_sem();
- if (pdev->dev.power.power_state == 2)
+ if (pdev->dev.power.power_state.event == 2)
aty_power_mgmt(0, par);
par->asleep = 0;
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 7622441..a9d0414 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -75,7 +75,7 @@
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
- chan->adapter.id = I2C_ALGO_ATI;
+ chan->adapter.id = I2C_HW_B_RADEON;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->rinfo->pdev->dev;
chan->algo.setsda = radeon_gpio_setsda;
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 98352af..59a1b6f 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -2526,18 +2526,18 @@
struct radeonfb_info *rinfo = info->par;
int i;
- if (state == pdev->dev.power.power_state)
+ if (state.event == pdev->dev.power.power_state.event)
return 0;
printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
- pci_name(pdev), state);
+ pci_name(pdev), state.event);
/* For suspend-to-disk, we cheat here. We don't suspend anything and
* let fbcon continue drawing until we are all set. That shouldn't
* really cause any problem at this point, provided that the wakeup
* code knows that any state in memory may not match the HW
*/
- if (state != PM_SUSPEND_MEM)
+ if (state.event == PM_EVENT_FREEZE)
goto done;
acquire_console_sem();
@@ -2616,7 +2616,7 @@
struct radeonfb_info *rinfo = info->par;
int rc = 0;
- if (pdev->dev.power.power_state == 0)
+ if (pdev->dev.power.power_state.event == PM_EVENT_ON)
return 0;
if (rinfo->no_schedule) {
@@ -2626,7 +2626,7 @@
acquire_console_sem();
printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
- pci_name(pdev), pdev->dev.power.power_state);
+ pci_name(pdev), pdev->dev.power.power_state.event);
if (pci_enable_device(pdev)) {
@@ -2637,7 +2637,7 @@
}
pci_set_master(pdev);
- if (pdev->dev.power.power_state == PM_SUSPEND_MEM) {
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
/* Wakeup chip. Check from config space if we were powered off
* (todo: additionally, check CLK_PIN_CNTL too)
*/
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 9aae884..4af321f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
+obj-$(CONFIG_SHARP_LOCOMO) += locomolcd.o
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
new file mode 100644
index 0000000..ada6e75
--- /dev/null
+++ b/drivers/video/backlight/locomolcd.c
@@ -0,0 +1,157 @@
+/*
+ * Backlight control code for Sharp Zaurus SL-5500
+ *
+ * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
+ * Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
+ * GPL v2
+ *
+ * This driver assumes single CPU. That's okay, because collie is
+ * slightly old hardware, and noone is going to retrofit second CPU to
+ * old PDA.
+ */
+
+/* LCD power functions */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/hardware/locomo.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/collie.h>
+#else
+#include <asm/arch/poodle.h>
+#endif
+
+extern void (*sa1100fb_lcd_power)(int on);
+
+static struct locomo_dev *locomolcd_dev;
+
+static void locomolcd_on(int comadj)
+{
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
+ mdelay(2);
+
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
+ mdelay(2);
+
+ locomo_m62332_senddata(locomolcd_dev, comadj, 0);
+ mdelay(5);
+
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
+ mdelay(10);
+
+ /* TFTCRST | CPSOUT=0 | CPSEN */
+ locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC);
+
+ /* Set CPSD */
+ locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD);
+
+ /* TFTCRST | CPSOUT=0 | CPSEN */
+ locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
+ mdelay(10);
+
+ locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
+}
+
+static void locomolcd_off(int comadj)
+{
+ /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
+ locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
+ mdelay(1);
+
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ mdelay(110);
+
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ mdelay(700);
+
+ /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
+ locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+}
+
+void locomolcd_power(int on)
+{
+ int comadj = 118;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (!locomolcd_dev) {
+ local_irq_restore(flags);
+ return;
+ }
+
+ /* read comadj */
+#ifdef CONFIG_MACH_POODLE
+ comadj = 118;
+#else
+ comadj = 128;
+#endif
+
+ if (on)
+ locomolcd_on(comadj);
+ else
+ locomolcd_off(comadj);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(locomolcd_power);
+
+static int poodle_lcd_probe(struct locomo_dev *dev)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ locomolcd_dev = dev;
+
+ /* the poodle_lcd_power function is called for the first time
+ * from fs_initcall, which is before locomo is activated.
+ * We need to recall poodle_lcd_power here*/
+#ifdef CONFIG_MACH_POODLE
+ locomolcd_power(1);
+#endif
+ local_irq_restore(flags);
+ return 0;
+}
+
+static int poodle_lcd_remove(struct locomo_dev *dev)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ locomolcd_dev = NULL;
+ local_irq_restore(flags);
+ return 0;
+}
+
+static struct locomo_driver poodle_lcd_driver = {
+ .drv = {
+ .name = "locomo-backlight",
+ },
+ .devid = LOCOMO_DEVID_BACKLIGHT,
+ .probe = poodle_lcd_probe,
+ .remove = poodle_lcd_remove,
+};
+
+static int __init poodle_lcd_init(void)
+{
+ int ret = locomo_driver_register(&poodle_lcd_driver);
+ if (ret) return ret;
+
+#ifdef CONFIG_SA1100_COLLIE
+ sa1100fb_lcd_power = locomolcd_power;
+#endif
+ return 0;
+}
+device_initcall(poodle_lcd_init);
+
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index e75a965..4131243 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -462,9 +462,9 @@
{
struct fb_info *p = pci_get_drvdata(pdev);
- if (state == pdev->dev.power.power_state)
+ if (state.event == pdev->dev.power.power_state.event)
return 0;
- if (state != PM_SUSPEND_MEM)
+ if (state.event != PM_SUSPEND_MEM)
goto done;
acquire_console_sem();
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 7513fb9..6db1834 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1506,12 +1506,12 @@
struct i810fb_par *par = (struct i810fb_par *) info->par;
int blank = 0, prev_state = par->cur_state;
- if (state == prev_state)
+ if (state.event == prev_state)
return 0;
- par->cur_state = state;
+ par->cur_state = state.event;
- switch (state) {
+ switch (state.event) {
case 1:
blank = VESA_VSYNC_SUSPEND;
break;
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 67f8534..ad60bbb 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -1271,7 +1271,7 @@
}
static int maven_attach_adapter(struct i2c_adapter* adapter) {
- if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400))
+ if (adapter->id == I2C_HW_B_G400)
return i2c_probe(adapter, &addr_data, &maven_detect_client);
return 0;
}
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index 3757c14..1a91bff 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -90,14 +90,13 @@
return val;
}
-#define I2C_ALGO_NVIDIA 0x0e0000
static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
{
int rc;
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
- chan->adapter.id = I2C_ALGO_NVIDIA;
+ chan->adapter.id = I2C_HW_B_NVIDIA;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pci_dev->dev;
chan->algo.setsda = nvidia_gpio_setsda;
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index 3e00ad7..28d1fe5 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -413,7 +413,7 @@
static int __init init_one(int slot)
{
- unsigned long base_addr = get_tc_base_addr(slot);
+ unsigned long base_addr = CKSEG1ADDR(get_tc_base_addr(slot));
struct aafb_info *ip = &my_fb_info[slot];
memset(ip, 0, sizeof(struct aafb_info));
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index f809558..c98f1c8 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -1,57 +1,55 @@
/*
- * linux/drivers/video/pmag-ba-fb.c
+ * linux/drivers/video/pmag-ba-fb.c
*
- * PMAG-BA TurboChannel framebuffer card support ... derived from:
+ * PMAG-BA TURBOchannel Color Frame Buffer (CFB) card support,
+ * derived from:
* "HP300 Topcat framebuffer support (derived from macfb of all things)
* Phil Blundell <philb@gnu.org> 1998", the original code can be
- * found in the file hpfb.c in the same directory.
+ * found in the file hpfb.c in the same directory.
*
* Based on digital document:
* "PMAG-BA TURBOchannel Color Frame Buffer
* Functional Specification", Revision 1.2, August 27, 1990
*
- * DECstation related code Copyright (C) 1999, 2000, 2001 by
- * Michael Engel <engel@unix-ag.org>,
- * Karsten Merker <merker@linuxtag.org> and
+ * DECstation related code Copyright (C) 1999, 2000, 2001 by
+ * Michael Engel <engel@unix-ag.org>,
+ * Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * 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) 2005 Maciej W. Rozycki
*
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
+
+#include <linux/compiler.h>
#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/fb.h>
-#include <asm/bootinfo.h>
-#include <asm/dec/machtype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/bug.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
#include <asm/dec/tc.h>
+
#include <video/pmag-ba-fb.h>
-struct pmag_ba_ramdac_regs {
- unsigned char addr_low;
- unsigned char pad0[3];
- unsigned char addr_hi;
- unsigned char pad1[3];
- unsigned char data;
- unsigned char pad2[3];
- unsigned char cmap;
+
+struct pmagbafb_par {
+ struct fb_info *next;
+ volatile void __iomem *mmio;
+ volatile u32 __iomem *dac;
+ int slot;
};
-/*
- * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
- */
-static struct fb_info pmagba_fb_info[3];
-static struct fb_var_screeninfo pmagbafb_defined = {
+static struct fb_info *root_pmagbafb_dev;
+
+static struct fb_var_screeninfo pmagbafb_defined __initdata = {
.xres = 1024,
.yres = 864,
.xres_virtual = 1024,
@@ -61,58 +59,71 @@
.green.length = 8,
.blue.length = 8,
.activate = FB_ACTIVATE_NOW,
- .height = 274,
- .width = 195,
- .accel = FB_ACCEL_NONE,
+ .height = -1,
+ .width = -1,
+ .accel_flags = FB_ACCEL_NONE,
+ .pixclock = 14452,
+ .left_margin = 116,
+ .right_margin = 12,
+ .upper_margin = 34,
+ .lower_margin = 12,
+ .hsync_len = 128,
+ .vsync_len = 3,
+ .sync = FB_SYNC_ON_GREEN,
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo pmagbafb_fix = {
+static struct fb_fix_screeninfo pmagbafb_fix __initdata = {
.id = "PMAG-BA",
- .smem_len = (1024 * 864),
+ .smem_len = (1024 * 1024),
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.line_length = 1024,
+ .mmio_len = PMAG_BA_SIZE - PMAG_BA_BT459,
};
-/*
- * Turn hardware cursor off
- */
-void pmagbafb_erase_cursor(struct pmag_ba_ramdac_regs *bt459_regs)
+
+static inline void dac_write(struct pmagbafb_par *par, unsigned int reg, u8 v)
{
- bt459_regs->addr_low = 0;
- bt459_regs->addr_hi = 3;
- bt459_regs->data = 0;
+ writeb(v, par->dac + reg / 4);
}
-/*
- * Set the palette.
- */
-static int pmagbafb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
+static inline u8 dac_read(struct pmagbafb_par *par, unsigned int reg)
{
- struct pmag_ba_ramdac_regs *bt459_regs = (struct pmag_ba_ramdac_regs *) info->par;
+ return readb(par->dac + reg / 4);
+}
- if (regno >= info->cmap.len)
- return 1;
+
+/*
+ * Set the palette.
+ */
+static int pmagbafb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+{
+ struct pmagbafb_par *par = info->par;
+
+ BUG_ON(regno >= info->cmap.len);
red >>= 8; /* The cmap fields are 16 bits */
- green >>= 8; /* wide, but the harware colormap */
+ green >>= 8; /* wide, but the hardware colormap */
blue >>= 8; /* registers are only 8 bits wide */
- bt459_regs->addr_low = (__u8) regno;
- bt459_regs->addr_hi = 0;
- bt459_regs->cmap = red;
- bt459_regs->cmap = green;
- bt459_regs->cmap = blue;
+ mb();
+ dac_write(par, BT459_ADDR_LO, regno);
+ dac_write(par, BT459_ADDR_HI, 0x00);
+ wmb();
+ dac_write(par, BT459_CMAP, red);
+ wmb();
+ dac_write(par, BT459_CMAP, green);
+ wmb();
+ dac_write(par, BT459_CMAP, blue);
+
return 0;
}
static struct fb_ops pmagbafb_ops = {
.owner = THIS_MODULE,
- .fb_get_fix = gen_get_fix,
- .fb_get_var = gen_get_var,
.fb_setcolreg = pmagbafb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
@@ -120,63 +131,133 @@
.fb_cursor = soft_cursor,
};
-int __init pmagbafb_init_one(int slot)
+
+/*
+ * Turn the hardware cursor off.
+ */
+static void __init pmagbafb_erase_cursor(struct fb_info *info)
{
- unsigned long base_addr = get_tc_base_addr(slot);
- struct fb_info *info = &pmagba_fb_info[slot];
- struct display *disp = &pmagba_disp[slot];
+ struct pmagbafb_par *par = info->par;
- printk("PMAG-BA framebuffer in slot %d\n", slot);
- /*
- * Framebuffer display memory base address and friends
- */
- pmagbafb_fix.smem_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
- info->par = (base_addr + PMAG_BA_BT459_OFFSET);
+ mb();
+ dac_write(par, BT459_ADDR_LO, 0x00);
+ dac_write(par, BT459_ADDR_HI, 0x03);
+ wmb();
+ dac_write(par, BT459_DATA, 0x00);
+}
- /*
- * Configure the Bt459 RAM DAC
- */
- pmagbafb_erase_cursor((struct pmag_ba_ramdac_regs *) info->par);
- /*
- * Let there be consoles..
- */
+static int __init pmagbafb_init_one(int slot)
+{
+ struct fb_info *info;
+ struct pmagbafb_par *par;
+ unsigned long base_addr;
+
+ info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+ par->slot = slot;
+ claim_tc_card(par->slot);
+
+ base_addr = get_tc_base_addr(par->slot);
+
+ par->next = root_pmagbafb_dev;
+ root_pmagbafb_dev = info;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ goto err_alloc;
+
info->fbops = &pmagbafb_ops;
+ info->fix = pmagbafb_fix;
info->var = pmagbafb_defined;
- info->fix = pmagbafb_fix;
- info->screen_base = pmagbafb_fix.smem_start;
info->flags = FBINFO_DEFAULT;
- fb_alloc_cmap(&fb_info.cmap, 256, 0);
+ /* MMIO mapping setup. */
+ info->fix.mmio_start = base_addr;
+ par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
+ if (!par->mmio)
+ goto err_cmap;
+ par->dac = par->mmio + PMAG_BA_BT459;
+
+ /* Frame buffer mapping setup. */
+ info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
+ info->screen_base = ioremap_nocache(info->fix.smem_start,
+ info->fix.smem_len);
+ if (!info->screen_base)
+ goto err_mmio_map;
+ info->screen_size = info->fix.smem_len;
+
+ pmagbafb_erase_cursor(info);
if (register_framebuffer(info) < 0)
- return 1;
+ goto err_smem_map;
+
+ pr_info("fb%d: %s frame buffer device in slot %d\n",
+ info->node, info->fix.id, par->slot);
+
return 0;
+
+
+err_smem_map:
+ iounmap(info->screen_base);
+
+err_mmio_map:
+ iounmap(par->mmio);
+
+err_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+err_alloc:
+ root_pmagbafb_dev = par->next;
+ release_tc_card(par->slot);
+ framebuffer_release(info);
+ return -ENXIO;
}
-/*
- * Initialise the framebuffer
- */
-
-int __init pmagbafb_init(void)
+static void __exit pmagbafb_exit_one(void)
{
- int sid;
- int found = 0;
+ struct fb_info *info = root_pmagbafb_dev;
+ struct pmagbafb_par *par = info->par;
+
+ unregister_framebuffer(info);
+ iounmap(info->screen_base);
+ iounmap(par->mmio);
+ fb_dealloc_cmap(&info->cmap);
+ root_pmagbafb_dev = par->next;
+ release_tc_card(par->slot);
+ framebuffer_release(info);
+}
+
+
+/*
+ * Initialise the framebuffer.
+ */
+static int __init pmagbafb_init(void)
+{
+ int count = 0;
+ int slot;
if (fb_get_options("pmagbafb", NULL))
- return -ENODEV;
+ return -ENXIO;
- if (TURBOCHANNEL) {
- while ((sid = search_tc_card("PMAG-BA")) >= 0) {
- found = 1;
- claim_tc_card(sid);
- pmagbafb_init_one(sid);
- }
- return found ? 0 : -ENODEV;
- } else {
- return -ENODEV;
+ while ((slot = search_tc_card("PMAG-BA")) >= 0) {
+ if (pmagbafb_init_one(slot) < 0)
+ break;
+ count++;
}
+ return (count > 0) ? 0 : -ENXIO;
}
+static void __exit pmagbafb_exit(void)
+{
+ while (root_pmagbafb_dev)
+ pmagbafb_exit_one();
+}
+
+
module_init(pmagbafb_init);
+module_exit(pmagbafb_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index d14eaee..a483b13 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -1,114 +1,128 @@
/*
- * linux/drivers/video/pmagb-b-fb.c
+ * linux/drivers/video/pmagb-b-fb.c
*
- * PMAGB-B TurboChannel framebuffer card support ... derived from:
+ * PMAGB-B TURBOchannel Smart Frame Buffer (SFB) card support,
+ * derived from:
* "HP300 Topcat framebuffer support (derived from macfb of all things)
* Phil Blundell <philb@gnu.org> 1998", the original code can be
- * found in the file hpfb.c in the same directory.
+ * found in the file hpfb.c in the same directory.
*
- * DECstation related code Copyright (C) 1999, 2000, 2001 by
- * Michael Engel <engel@unix-ag.org>,
- * Karsten Merker <merker@linuxtag.org> and
+ * DECstation related code Copyright (C) 1999, 2000, 2001 by
+ * Michael Engel <engel@unix-ag.org>,
+ * Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * 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) 2005 Maciej W. Rozycki
*
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
*/
-/*
- * We currently only support the PMAGB-B in high resolution mode
- * as I know of no way to detect low resolution mode set via jumper.
- * KM, 2001/01/07
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
+#include <linux/compiler.h>
#include <linux/delay.h>
-#include <linux/init.h>
+#include <linux/errno.h>
#include <linux/fb.h>
-#include <asm/bootinfo.h>
-#include <asm/dec/machtype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/bug.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
#include <asm/dec/tc.h>
+
#include <video/pmagb-b-fb.h>
-struct pmagb_b_ramdac_regs {
- unsigned char addr_low;
- unsigned char pad0[3];
- unsigned char addr_hi;
- unsigned char pad1[3];
- unsigned char data;
- unsigned char pad2[3];
- unsigned char cmap;
+
+struct pmagbbfb_par {
+ struct fb_info *next;
+ volatile void __iomem *mmio;
+ volatile void __iomem *smem;
+ volatile u32 __iomem *sfb;
+ volatile u32 __iomem *dac;
+ unsigned int osc0;
+ unsigned int osc1;
+ int slot;
};
-/*
- * Max 3 TURBOchannel slots -> max 3 PMAGB-B :)
- */
-static struct fb_info pmagbb_fb_info[3];
-static struct fb_var_screeninfo pmagbbfb_defined = {
- .xres = 1280,
- .yres = 1024,
- .xres_virtual = 1280,
- .yres_virtual = 1024,
+static struct fb_info *root_pmagbbfb_dev;
+
+static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
.bits_per_pixel = 8,
.red.length = 8,
.green.length = 8,
.blue.length = 8,
.activate = FB_ACTIVATE_NOW,
- .height = 274,
- .width = 195,
+ .height = -1,
+ .width = -1,
.accel_flags = FB_ACCEL_NONE,
+ .sync = FB_SYNC_ON_GREEN,
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo pmagbafb_fix = {
+static struct fb_fix_screeninfo pmagbbfb_fix __initdata = {
.id = "PMAGB-BA",
- .smem_len = (1280 * 1024),
+ .smem_len = (2048 * 1024),
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
- .line_length = 1280,
+ .mmio_len = PMAGB_B_FBMEM,
+};
+
+
+static inline void sfb_write(struct pmagbbfb_par *par, unsigned int reg, u32 v)
+{
+ writel(v, par->sfb + reg / 4);
}
-/*
- * Turn hardware cursor off
- */
-void pmagbbfb_erase_cursor(struct pmagb_b_ramdac_regs *bt459_regs)
+static inline u32 sfb_read(struct pmagbbfb_par *par, unsigned int reg)
{
- bt459_regs->addr_low = 0;
- bt459_regs->addr_hi = 3;
- bt459_regs->data = 0;
+ return readl(par->sfb + reg / 4);
}
-/*
- * Set the palette.
- */
-static int pmagbbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
+static inline void dac_write(struct pmagbbfb_par *par, unsigned int reg, u8 v)
{
- struct pmagb_b_ramdac_regs *bt459_regs = (struct pmagb_b_ramdac_regs *) info->par;
-
- if (regno >= info->cmap.len)
- return 1;
+ writeb(v, par->dac + reg / 4);
+}
+
+static inline u8 dac_read(struct pmagbbfb_par *par, unsigned int reg)
+{
+ return readb(par->dac + reg / 4);
+}
+
+static inline void gp0_write(struct pmagbbfb_par *par, u32 v)
+{
+ writel(v, par->mmio + PMAGB_B_GP0);
+}
+
+
+/*
+ * Set the palette.
+ */
+static int pmagbbfb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+{
+ struct pmagbbfb_par *par = info->par;
+
+ BUG_ON(regno >= info->cmap.len);
red >>= 8; /* The cmap fields are 16 bits */
- green >>= 8; /* wide, but the harware colormap */
+ green >>= 8; /* wide, but the hardware colormap */
blue >>= 8; /* registers are only 8 bits wide */
- bt459_regs->addr_low = (__u8) regno;
- bt459_regs->addr_hi = 0;
- bt459_regs->cmap = red;
- bt459_regs->cmap = green;
- bt459_regs->cmap = blue;
+ mb();
+ dac_write(par, BT459_ADDR_LO, regno);
+ dac_write(par, BT459_ADDR_HI, 0x00);
+ wmb();
+ dac_write(par, BT459_CMAP, red);
+ wmb();
+ dac_write(par, BT459_CMAP, green);
+ wmb();
+ dac_write(par, BT459_CMAP, blue);
+
return 0;
}
@@ -121,62 +135,247 @@
.fb_cursor = soft_cursor,
};
-int __init pmagbbfb_init_one(int slot)
+
+/*
+ * Turn the hardware cursor off.
+ */
+static void __init pmagbbfb_erase_cursor(struct fb_info *info)
{
- unsigned long base_addr = get_tc_base_addr(slot);
- struct fb_info *info = &pmagbb_fb_info[slot];
+ struct pmagbbfb_par *par = info->par;
- printk("PMAGB-BA framebuffer in slot %d\n", slot);
- /*
- * Framebuffer display memory base address and friends
- */
- pmagbbfb_fix.smem_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET;
- info->par = (base_addr + PMAGB_B_BT459_OFFSET);
-
- /*
- * Configure the Bt459 RAM DAC
- */
- pmagbbfb_erase_cursor((struct pmagb_b_ramdac_regs *) info->par);
+ mb();
+ dac_write(par, BT459_ADDR_LO, 0x00);
+ dac_write(par, BT459_ADDR_HI, 0x03);
+ wmb();
+ dac_write(par, BT459_DATA, 0x00);
+}
- /*
- * Let there be consoles..
- */
+/*
+ * Set up screen parameters.
+ */
+static void __init pmagbbfb_screen_setup(struct fb_info *info)
+{
+ struct pmagbbfb_par *par = info->par;
+
+ info->var.xres = ((sfb_read(par, SFB_REG_VID_HOR) >>
+ SFB_VID_HOR_PIX_SHIFT) & SFB_VID_HOR_PIX_MASK) * 4;
+ info->var.xres_virtual = info->var.xres;
+ info->var.yres = (sfb_read(par, SFB_REG_VID_VER) >>
+ SFB_VID_VER_SL_SHIFT) & SFB_VID_VER_SL_MASK;
+ info->var.yres_virtual = info->var.yres;
+ info->var.left_margin = ((sfb_read(par, SFB_REG_VID_HOR) >>
+ SFB_VID_HOR_BP_SHIFT) &
+ SFB_VID_HOR_BP_MASK) * 4;
+ info->var.right_margin = ((sfb_read(par, SFB_REG_VID_HOR) >>
+ SFB_VID_HOR_FP_SHIFT) &
+ SFB_VID_HOR_FP_MASK) * 4;
+ info->var.upper_margin = (sfb_read(par, SFB_REG_VID_VER) >>
+ SFB_VID_VER_BP_SHIFT) & SFB_VID_VER_BP_MASK;
+ info->var.lower_margin = (sfb_read(par, SFB_REG_VID_VER) >>
+ SFB_VID_VER_FP_SHIFT) & SFB_VID_VER_FP_MASK;
+ info->var.hsync_len = ((sfb_read(par, SFB_REG_VID_HOR) >>
+ SFB_VID_HOR_SYN_SHIFT) &
+ SFB_VID_HOR_SYN_MASK) * 4;
+ info->var.vsync_len = (sfb_read(par, SFB_REG_VID_VER) >>
+ SFB_VID_VER_SYN_SHIFT) & SFB_VID_VER_SYN_MASK;
+
+ info->fix.line_length = info->var.xres;
+};
+
+/*
+ * Determine oscillator configuration.
+ */
+static void __init pmagbbfb_osc_setup(struct fb_info *info)
+{
+ static unsigned int pmagbbfb_freqs[] __initdata = {
+ 130808, 119843, 104000, 92980, 74367, 72800,
+ 69197, 66000, 65000, 50350, 36000, 32000, 25175
+ };
+ struct pmagbbfb_par *par = info->par;
+ u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
+ u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+ int i, j;
+
+ gp0_write(par, 0); /* select Osc0 */
+ for (j = 0; j < 16; j++) {
+ mb();
+ sfb_write(par, SFB_REG_TCCLK_COUNT, 0);
+ mb();
+ for (i = 0; i < 100; i++) { /* nominally max. 20.5us */
+ if (sfb_read(par, SFB_REG_TCCLK_COUNT) == 0)
+ break;
+ udelay(1);
+ }
+ count0 += sfb_read(par, SFB_REG_VIDCLK_COUNT);
+ }
+
+ gp0_write(par, 1); /* select Osc1 */
+ for (j = 0; j < 16; j++) {
+ mb();
+ sfb_write(par, SFB_REG_TCCLK_COUNT, 0);
+
+ for (i = 0; i < 100; i++) { /* nominally max. 20.5us */
+ if (sfb_read(par, SFB_REG_TCCLK_COUNT) == 0)
+ break;
+ udelay(1);
+ }
+ count1 += sfb_read(par, SFB_REG_VIDCLK_COUNT);
+ }
+
+ freq0 = (freqtc * count0 + counttc / 2) / counttc;
+ par->osc0 = freq0;
+ if (freq0 >= pmagbbfb_freqs[0] - (pmagbbfb_freqs[0] + 32) / 64 &&
+ freq0 <= pmagbbfb_freqs[0] + (pmagbbfb_freqs[0] + 32) / 64)
+ par->osc0 = pmagbbfb_freqs[0];
+
+ freq1 = (par->osc0 * count1 + count0 / 2) / count0;
+ par->osc1 = freq1;
+ for (i = 0; i < sizeof(pmagbbfb_freqs) / sizeof(*pmagbbfb_freqs); i++)
+ if (freq1 >= pmagbbfb_freqs[i] -
+ (pmagbbfb_freqs[i] + 128) / 256 &&
+ freq1 <= pmagbbfb_freqs[i] +
+ (pmagbbfb_freqs[i] + 128) / 256) {
+ par->osc1 = pmagbbfb_freqs[i];
+ break;
+ }
+
+ if (par->osc0 - par->osc1 <= (par->osc0 + par->osc1 + 256) / 512 ||
+ par->osc1 - par->osc0 <= (par->osc0 + par->osc1 + 256) / 512)
+ par->osc1 = 0;
+
+ gp0_write(par, par->osc1 != 0); /* reselect OscX */
+
+ info->var.pixclock = par->osc1 ?
+ (1000000000 + par->osc1 / 2) / par->osc1 :
+ (1000000000 + par->osc0 / 2) / par->osc0;
+};
+
+
+static int __init pmagbbfb_init_one(int slot)
+{
+ char freq0[12], freq1[12];
+ struct fb_info *info;
+ struct pmagbbfb_par *par;
+ unsigned long base_addr;
+ u32 vid_base;
+
+ info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+ par->slot = slot;
+ claim_tc_card(par->slot);
+
+ base_addr = get_tc_base_addr(par->slot);
+
+ par->next = root_pmagbbfb_dev;
+ root_pmagbbfb_dev = info;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ goto err_alloc;
+
info->fbops = &pmagbbfb_ops;
- info->var = pmagbbfb_defined;
info->fix = pmagbbfb_fix;
- info->screen_base = pmagbbfb_fix.smem_start;
+ info->var = pmagbbfb_defined;
info->flags = FBINFO_DEFAULT;
- fb_alloc_cmap(&fb_info.cmap, 256, 0);
+ /* MMIO mapping setup. */
+ info->fix.mmio_start = base_addr;
+ par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
+ if (!par->mmio)
+ goto err_cmap;
+ par->sfb = par->mmio + PMAGB_B_SFB;
+ par->dac = par->mmio + PMAGB_B_BT459;
+
+ /* Frame buffer mapping setup. */
+ info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
+ par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
+ if (!par->smem)
+ goto err_mmio_map;
+ vid_base = sfb_read(par, SFB_REG_VID_BASE);
+ info->screen_base = (void __iomem *)par->smem + vid_base * 0x1000;
+ info->screen_size = info->fix.smem_len - 2 * vid_base * 0x1000;
+
+ pmagbbfb_erase_cursor(info);
+ pmagbbfb_screen_setup(info);
+ pmagbbfb_osc_setup(info);
if (register_framebuffer(info) < 0)
- return 1;
+ goto err_smem_map;
+
+ snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
+ par->osc0 / 1000, par->osc0 % 1000);
+ snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
+ par->osc1 / 1000, par->osc1 % 1000);
+
+ pr_info("fb%d: %s frame buffer device in slot %d\n",
+ info->node, info->fix.id, par->slot);
+ pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
+ info->node, freq0, par->osc1 ? freq1 : "disabled",
+ par->osc1 != 0);
+
return 0;
+
+
+err_smem_map:
+ iounmap(par->smem);
+
+err_mmio_map:
+ iounmap(par->mmio);
+
+err_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+err_alloc:
+ root_pmagbbfb_dev = par->next;
+ release_tc_card(par->slot);
+ framebuffer_release(info);
+ return -ENXIO;
}
-/*
- * Initialise the framebuffer
- */
-
-int __init pmagbbfb_init(void)
+static void __exit pmagbbfb_exit_one(void)
{
- int sid;
- int found = 0;
+ struct fb_info *info = root_pmagbbfb_dev;
+ struct pmagbbfb_par *par = info->par;
+
+ unregister_framebuffer(info);
+ iounmap(par->smem);
+ iounmap(par->mmio);
+ fb_dealloc_cmap(&info->cmap);
+ root_pmagbbfb_dev = par->next;
+ release_tc_card(par->slot);
+ framebuffer_release(info);
+}
+
+
+/*
+ * Initialise the framebuffer.
+ */
+static int __init pmagbbfb_init(void)
+{
+ int count = 0;
+ int slot;
if (fb_get_options("pmagbbfb", NULL))
- return -ENODEV;
+ return -ENXIO;
- if (TURBOCHANNEL) {
- while ((sid = search_tc_card("PMAGB-BA")) >= 0) {
- found = 1;
- claim_tc_card(sid);
- pmagbbfb_init_one(sid);
- }
- return found ? 0 : -ENODEV;
- } else {
- return -ENODEV;
+ while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
+ if (pmagbbfb_init_one(slot) < 0)
+ break;
+ count++;
}
+ return (count > 0) ? 0 : -ENXIO;
}
+static void __exit pmagbbfb_exit(void)
+{
+ while (root_pmagbbfb_dev)
+ pmagbbfb_exit_one();
+}
+
+
module_init(pmagbbfb_init);
+module_exit(pmagbbfb_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index 71b69da..162012b 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -21,7 +21,6 @@
#include <asm/uaccess.h>
#include <asm/setup.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/q40_master.h>
#include <linux/fb.h>
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index da1334d..77151d8 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -92,14 +92,13 @@
return val;
}
-#define I2C_ALGO_RIVA 0x0e0000
static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name)
{
int rc;
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
- chan->adapter.id = I2C_ALGO_RIVA;
+ chan->adapter.id = I2C_HW_B_RIVA;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pdev->dev;
chan->algo.setsda = riva_gpio_setsda;
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 3848be2..fa98d91 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -655,7 +655,7 @@
}
#ifdef CONFIG_PM
-static int s1d13xxxfb_suspend(struct device *dev, u32 state, u32 level)
+static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state, u32 level)
{
struct fb_info *info = dev_get_drvdata(dev);
struct s1d13xxxfb_par *s1dfb = info->par;
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 024a0ce..847698b 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -137,7 +137,6 @@
return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
}
-#define I2C_ALGO_SAVAGE 0x0f0000
static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
const char *name)
{
@@ -147,7 +146,7 @@
if (add_bus && chan->par) {
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
- chan->adapter.id = I2C_ALGO_SAVAGE;
+ chan->adapter.id = I2C_HW_B_SAVAGE;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pcidev->dev;
chan->algo.udelay = 40;
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index f4633d1..117ad42 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2110,7 +2110,6 @@
struct savagefb_par *par = (struct savagefb_par *)info->par;
DBG("savagefb_suspend");
- printk(KERN_DEBUG "state: %u\n", state);
acquire_console_sem();
fb_set_suspend(info, pci_choose_state(dev, state));
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index adcda69..0030c07 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -5,9 +5,15 @@
*
* Copyright (C) 2002, ATI Corp.
* Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton
*
* Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
*
+ * Generic platform support by Ian Molton <spyro@f2s.com>
+ * and Richard Purdie <rpurdie@rpsys.net>
+ *
+ * w32xx support by Ian Molton
+ *
* 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.
@@ -21,7 +27,7 @@
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/string.h>
-#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <video/w100fb.h>
@@ -30,114 +36,78 @@
/*
* Prototypes
*/
-static void w100fb_save_buffer(void);
-static void w100fb_clear_buffer(void);
-static void w100fb_restore_buffer(void);
-static void w100fb_clear_screen(u32 mode, long int offset);
-static void w100_resume(void);
static void w100_suspend(u32 mode);
-static void w100_init_qvga_rotation(u16 deg);
-static void w100_init_vga_rotation(u16 deg);
static void w100_vsync(void);
-static void w100_init_sharp_lcd(u32 mode);
-static void w100_pwm_setup(void);
-static void w100_InitExtMem(u32 mode);
-static void w100_hw_init(void);
-static u16 w100_set_fastsysclk(u16 Freq);
-
-static void lcdtg_hw_init(u32 mode);
-static void lcdtg_lcd_change(u32 mode);
-static void lcdtg_resume(void);
-static void lcdtg_suspend(void);
-
-
-/* Register offsets & lengths */
-#define REMAPPED_FB_LEN 0x15ffff
-
-#define BITS_PER_PIXEL 16
+static void w100_hw_init(struct w100fb_par*);
+static void w100_pwm_setup(struct w100fb_par*);
+static void w100_init_clocks(struct w100fb_par*);
+static void w100_setup_memory(struct w100fb_par*);
+static void w100_init_lcd(struct w100fb_par*);
+static void w100_set_dispregs(struct w100fb_par*);
+static void w100_update_enable(void);
+static void w100_update_disable(void);
+static void calc_hsync(struct w100fb_par *par);
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
/* Pseudo palette size */
#define MAX_PALETTES 16
-/* for resolution change */
-#define LCD_MODE_INIT (-1)
-#define LCD_MODE_480 0
-#define LCD_MODE_320 1
-#define LCD_MODE_240 2
-#define LCD_MODE_640 3
-
-#define LCD_SHARP_QVGA 0
-#define LCD_SHARP_VGA 1
-
-#define LCD_MODE_PORTRAIT 0
-#define LCD_MODE_LANDSCAPE 1
-
#define W100_SUSPEND_EXTMEM 0
#define W100_SUSPEND_ALL 1
-/* General frame buffer data structures */
-struct w100fb_par {
- u32 xres;
- u32 yres;
- int fastsysclk_mode;
- int lcdMode;
- int rotation_flag;
- int blanking_flag;
- int comadj;
- int phadadj;
-};
-
-static struct w100fb_par *current_par;
+#define BITS_PER_PIXEL 16
/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
static void *remapped_base;
static void *remapped_regs;
static void *remapped_fbuf;
-/* External Function */
-static void(*w100fb_ssp_send)(u8 adrs, u8 data);
+#define REMAPPED_FB_LEN 0x15ffff
+
+/* This is the offset in the w100's address space we map the current
+ framebuffer memory to. We use the position of external memory as
+ we can remap internal memory to there if external isn't present. */
+#define W100_FB_BASE MEM_EXT_BASE_VALUE
+
/*
* Sysfs functions
*/
-
-static ssize_t rotation_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- return sprintf(buf, "%d\n",par->rotation_flag);
+ return sprintf(buf, "%d\n",par->flip);
}
-static ssize_t rotation_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned int rotate;
+ unsigned int flip;
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- rotate = simple_strtoul(buf, NULL, 10);
+ flip = simple_strtoul(buf, NULL, 10);
- if (rotate > 0) par->rotation_flag = 1;
- else par->rotation_flag = 0;
+ if (flip > 0)
+ par->flip = 1;
+ else
+ par->flip = 0;
- if (par->lcdMode == LCD_MODE_320)
- w100_init_qvga_rotation(par->rotation_flag ? 270 : 90);
- else if (par->lcdMode == LCD_MODE_240)
- w100_init_qvga_rotation(par->rotation_flag ? 180 : 0);
- else if (par->lcdMode == LCD_MODE_640)
- w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
- else if (par->lcdMode == LCD_MODE_480)
- w100_init_vga_rotation(par->rotation_flag ? 180 : 0);
+ w100_update_disable();
+ w100_set_dispregs(par);
+ w100_update_enable();
+
+ calc_hsync(par);
return count;
}
-static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store);
+static DEVICE_ATTR(flip, 0644, flip_show, flip_store);
static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned long param;
- unsigned long regs;
+ unsigned long regs, param;
regs = simple_strtoul(buf, NULL, 16);
param = readl(remapped_regs + regs);
printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
@@ -148,8 +118,7 @@
static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned long regs;
- unsigned long param;
+ unsigned long regs, param;
sscanf(buf, "%lx %lx", ®s, ¶m);
if (regs <= 0x2000) {
@@ -163,54 +132,56 @@
static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
-static ssize_t fastsysclk_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- return sprintf(buf, "%d\n",par->fastsysclk_mode);
+ return sprintf(buf, "%d\n",par->fastpll_mode);
}
-static ssize_t fastsysclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- int param;
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
- param = simple_strtoul(buf, NULL, 10);
-
- if (param == 75) {
- printk("Set fastsysclk %d\n", param);
- par->fastsysclk_mode = param;
- w100_set_fastsysclk(par->fastsysclk_mode);
- } else if (param == 100) {
- printk("Set fastsysclk %d\n", param);
- par->fastsysclk_mode = param;
- w100_set_fastsysclk(par->fastsysclk_mode);
+ if (simple_strtoul(buf, NULL, 10) > 0) {
+ par->fastpll_mode=1;
+ printk("w100fb: Using fast system clock (if possible)\n");
+ } else {
+ par->fastpll_mode=0;
+ printk("w100fb: Using normal system clock\n");
}
+
+ w100_init_clocks(par);
+ calc_hsync(par);
+
return count;
}
-static DEVICE_ATTR(fastsysclk, 0644, fastsysclk_show, fastsysclk_store);
+static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store);
/*
- * The touchscreen on this device needs certain information
- * from the video driver to function correctly. We export it here.
+ * Some touchscreens need hsync information from the video driver to
+ * function correctly. We export it here.
*/
-int w100fb_get_xres(void) {
- return current_par->xres;
-}
+unsigned long w100fb_get_hsynclen(struct device *dev)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct w100fb_par *par=info->par;
-int w100fb_get_blanking(void) {
- return current_par->blanking_flag;
+ /* If display is blanked/suspended, hsync isn't active */
+ if (par->blanked)
+ return 0;
+ else
+ return par->hsync_len;
}
+EXPORT_SYMBOL(w100fb_get_hsynclen);
-int w100fb_get_fastsysclk(void) {
- return current_par->fastsysclk_mode;
+static void w100fb_clear_screen(struct w100fb_par *par)
+{
+ memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
}
-EXPORT_SYMBOL(w100fb_get_xres);
-EXPORT_SYMBOL(w100fb_get_blanking);
-EXPORT_SYMBOL(w100fb_get_fastsysclk);
/*
@@ -234,7 +205,6 @@
* according to the RGB bitfield information.
*/
if (regno < MAX_PALETTES) {
-
u32 *pal = info->pseudo_palette;
val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
@@ -250,115 +220,90 @@
*/
static int w100fb_blank(int blank_mode, struct fb_info *info)
{
- struct w100fb_par *par;
- par=info->par;
+ struct w100fb_par *par = info->par;
+ struct w100_tg_info *tg = par->mach->tg;
switch(blank_mode) {
- case FB_BLANK_NORMAL: /* Normal blanking */
- case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
- case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
- case FB_BLANK_POWERDOWN: /* Poweroff */
- if (par->blanking_flag == 0) {
- w100fb_save_buffer();
- lcdtg_suspend();
- par->blanking_flag = 1;
+ case FB_BLANK_NORMAL: /* Normal blanking */
+ case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+ case FB_BLANK_POWERDOWN: /* Poweroff */
+ if (par->blanked == 0) {
+ if(tg && tg->suspend)
+ tg->suspend(par);
+ par->blanked = 1;
}
break;
case FB_BLANK_UNBLANK: /* Unblanking */
- if (par->blanking_flag != 0) {
- w100fb_restore_buffer();
- lcdtg_resume();
- par->blanking_flag = 0;
+ if (par->blanked != 0) {
+ if(tg && tg->resume)
+ tg->resume(par);
+ par->blanked = 0;
}
break;
}
return 0;
}
+
/*
* Change the resolution by calling the appropriate hardware functions
*/
-static void w100fb_changeres(int rotate_mode, u32 mode)
+static void w100fb_activate_var(struct w100fb_par *par)
{
- u16 rotation=0;
+ struct w100_tg_info *tg = par->mach->tg;
- switch(rotate_mode) {
- case LCD_MODE_LANDSCAPE:
- rotation=(current_par->rotation_flag ? 270 : 90);
- break;
- case LCD_MODE_PORTRAIT:
- rotation=(current_par->rotation_flag ? 180 : 0);
- break;
- }
+ w100_pwm_setup(par);
+ w100_setup_memory(par);
+ w100_init_clocks(par);
+ w100fb_clear_screen(par);
+ w100_vsync();
- w100_pwm_setup();
- switch(mode) {
- case LCD_SHARP_QVGA:
- w100_vsync();
- w100_suspend(W100_SUSPEND_EXTMEM);
- w100_init_sharp_lcd(LCD_SHARP_QVGA);
- w100_init_qvga_rotation(rotation);
- w100_InitExtMem(LCD_SHARP_QVGA);
- w100fb_clear_screen(LCD_SHARP_QVGA, 0);
- lcdtg_lcd_change(LCD_SHARP_QVGA);
- break;
- case LCD_SHARP_VGA:
- w100fb_clear_screen(LCD_SHARP_QVGA, 0);
- writel(0xBFFFA000, remapped_regs + mmMC_EXT_MEM_LOCATION);
- w100_InitExtMem(LCD_SHARP_VGA);
- w100fb_clear_screen(LCD_SHARP_VGA, 0x200000);
- w100_vsync();
- w100_init_sharp_lcd(LCD_SHARP_VGA);
- if (rotation != 0)
- w100_init_vga_rotation(rotation);
- lcdtg_lcd_change(LCD_SHARP_VGA);
- break;
- }
+ w100_update_disable();
+ w100_init_lcd(par);
+ w100_set_dispregs(par);
+ w100_update_enable();
+
+ calc_hsync(par);
+
+ if (!par->blanked && tg && tg->change)
+ tg->change(par);
}
-/*
- * Set up the display for the fb subsystem
+
+/* Select the smallest mode that allows the desired resolution to be
+ * displayed. If desired, the x and y parameters can be rounded up to
+ * match the selected mode.
*/
-static void w100fb_activate_var(struct fb_info *info)
+static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
{
- u32 temp32;
- struct w100fb_par *par=info->par;
- struct fb_var_screeninfo *var = &info->var;
+ struct w100_mode *mode = NULL;
+ struct w100_mode *modelist = par->mach->modelist;
+ unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
+ unsigned int i;
- /* Set the hardware to 565 */
- temp32 = readl(remapped_regs + mmDISP_DEBUG2);
- temp32 &= 0xff7fffff;
- temp32 |= 0x00800000;
- writel(temp32, remapped_regs + mmDISP_DEBUG2);
+ for (i = 0 ; i < par->mach->num_modes ; i++) {
+ if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
+ modelist[i].xres < best_x && modelist[i].yres < best_y) {
+ best_x = modelist[i].xres;
+ best_y = modelist[i].yres;
+ mode = &modelist[i];
+ } else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
+ modelist[i].xres < best_y && modelist[i].yres < best_x) {
+ best_x = modelist[i].yres;
+ best_y = modelist[i].xres;
+ mode = &modelist[i];
+ }
+ }
- if (par->lcdMode == LCD_MODE_INIT) {
- w100_init_sharp_lcd(LCD_SHARP_VGA);
- w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
- par->lcdMode = LCD_MODE_640;
- lcdtg_hw_init(LCD_SHARP_VGA);
- } else if (var->xres == 320 && var->yres == 240) {
- if (par->lcdMode != LCD_MODE_320) {
- w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_QVGA);
- par->lcdMode = LCD_MODE_320;
- }
- } else if (var->xres == 240 && var->yres == 320) {
- if (par->lcdMode != LCD_MODE_240) {
- w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_QVGA);
- par->lcdMode = LCD_MODE_240;
- }
- } else if (var->xres == 640 && var->yres == 480) {
- if (par->lcdMode != LCD_MODE_640) {
- w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_VGA);
- par->lcdMode = LCD_MODE_640;
- }
- } else if (var->xres == 480 && var->yres == 640) {
- if (par->lcdMode != LCD_MODE_480) {
- w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_VGA);
- par->lcdMode = LCD_MODE_480;
- }
- } else printk(KERN_ERR "W100FB: Resolution error!\n");
+ if (mode && saveval) {
+ *x = best_x;
+ *y = best_y;
+ }
+
+ return mode;
}
@@ -366,31 +311,19 @@
* w100fb_check_var():
* Get the video params out of 'var'. If a value doesn't fit, round it up,
* if it's too big, return -EINVAL.
- *
*/
static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- if (var->xres < var->yres) { /* Portrait mode */
- if ((var->xres > 480) || (var->yres > 640)) {
- return -EINVAL;
- } else if ((var->xres > 240) || (var->yres > 320)) {
- var->xres = 480;
- var->yres = 640;
- } else {
- var->xres = 240;
- var->yres = 320;
- }
- } else { /* Landscape mode */
- if ((var->xres > 640) || (var->yres > 480)) {
- return -EINVAL;
- } else if ((var->xres > 320) || (var->yres > 240)) {
- var->xres = 640;
- var->yres = 480;
- } else {
- var->xres = 320;
- var->yres = 240;
- }
- }
+ struct w100fb_par *par=info->par;
+
+ if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
+ return -EINVAL;
+
+ if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
+ return -EINVAL;
+
+ if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
+ return -EINVAL;
var->xres_virtual = max(var->xres_virtual, var->xres);
var->yres_virtual = max(var->yres_virtual, var->yres);
@@ -409,13 +342,11 @@
var->transp.offset = var->transp.length = 0;
var->nonstd = 0;
-
var->height = -1;
var->width = -1;
var->vmode = FB_VMODE_NONINTERLACED;
-
var->sync = 0;
- var->pixclock = 0x04; /* 171521; */
+ var->pixclock = 0x04; /* 171521; */
return 0;
}
@@ -430,274 +361,286 @@
{
struct w100fb_par *par=info->par;
- par->xres = info->var.xres;
- par->yres = info->var.yres;
+ if (par->xres != info->var.xres || par->yres != info->var.yres) {
+ par->xres = info->var.xres;
+ par->yres = info->var.yres;
+ par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
- info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
- info->fix.ypanstep = 0;
- info->fix.ywrapstep = 0;
+ if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
+ par->extmem_active = 1;
+ info->fix.smem_len = par->mach->mem->size+1;
+ } else {
+ par->extmem_active = 0;
+ info->fix.smem_len = MEM_INT_SIZE+1;
+ }
- if (par->blanking_flag)
- w100fb_clear_buffer();
-
- w100fb_activate_var(info);
-
- if (par->lcdMode == LCD_MODE_480) {
- info->fix.line_length = (480 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x200000;
- } else if (par->lcdMode == LCD_MODE_320) {
- info->fix.line_length = (320 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x60000;
- } else if (par->lcdMode == LCD_MODE_240) {
- info->fix.line_length = (240 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x60000;
- } else if (par->lcdMode == LCD_MODE_INIT || par->lcdMode == LCD_MODE_640) {
- info->fix.line_length = (640 * BITS_PER_PIXEL) / 8;
- info->fix.smem_len = 0x200000;
+ w100fb_activate_var(par);
}
-
return 0;
}
/*
- * Frame buffer operations
+ * Frame buffer operations
*/
static struct fb_ops w100fb_ops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.fb_check_var = w100fb_check_var,
- .fb_set_par = w100fb_set_par,
+ .fb_set_par = w100fb_set_par,
.fb_setcolreg = w100fb_setcolreg,
- .fb_blank = w100fb_blank,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
+ .fb_blank = w100fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
- .fb_cursor = soft_cursor,
+ .fb_cursor = soft_cursor,
};
-
-static void w100fb_clear_screen(u32 mode, long int offset)
-{
- int i, numPix = 0;
-
- if (mode == LCD_SHARP_VGA)
- numPix = 640 * 480;
- else if (mode == LCD_SHARP_QVGA)
- numPix = 320 * 240;
-
- for (i = 0; i < numPix; i++)
- writew(0xffff, remapped_fbuf + offset + (2*i));
-}
-
-
-/* Need to split up the buffers to stay within the limits of kmalloc */
-#define W100_BUF_NUM 6
-static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL };
-
-static void w100fb_save_buffer(void)
-{
- int i, j, bufsize;
-
- bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
- for (i = 0; i < W100_BUF_NUM; i++) {
- if (gSaveImagePtr[i] == NULL)
- gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL);
- if (gSaveImagePtr[i] == NULL) {
- w100fb_clear_buffer();
- printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i);
- break;
- }
- for (j = 0; j < bufsize/4; j++)
- *(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4);
- }
-}
-
-
-static void w100fb_restore_buffer(void)
-{
- int i, j, bufsize;
-
- bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
- for (i = 0; i < W100_BUF_NUM; i++) {
- if (gSaveImagePtr[i] == NULL) {
- printk(KERN_WARNING "can't find pre-off image buffer %d\n", i);
- w100fb_clear_buffer();
- break;
- }
- for (j = 0; j < (bufsize/4); j++)
- writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4));
- kfree(gSaveImagePtr[i]);
- gSaveImagePtr[i] = NULL;
- }
-}
-
-
-static void w100fb_clear_buffer(void)
-{
- int i;
- for (i = 0; i < W100_BUF_NUM; i++) {
- kfree(gSaveImagePtr[i]);
- gSaveImagePtr[i] = NULL;
- }
-}
-
-
#ifdef CONFIG_PM
-static int w100fb_suspend(struct device *dev, pm_message_t state, u32 level)
+static void w100fb_save_vidmem(struct w100fb_par *par)
+{
+ int memsize;
+
+ if (par->extmem_active) {
+ memsize=par->mach->mem->size;
+ par->saved_extmem = vmalloc(memsize);
+ if (par->saved_extmem)
+ memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
+ }
+ memsize=MEM_INT_SIZE;
+ par->saved_intmem = vmalloc(memsize);
+ if (par->saved_intmem && par->extmem_active)
+ memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
+ else if (par->saved_intmem)
+ memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
+}
+
+static void w100fb_restore_vidmem(struct w100fb_par *par)
+{
+ int memsize;
+
+ if (par->extmem_active && par->saved_extmem) {
+ memsize=par->mach->mem->size;
+ memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
+ vfree(par->saved_extmem);
+ }
+ if (par->saved_intmem) {
+ memsize=MEM_INT_SIZE;
+ if (par->extmem_active)
+ memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
+ else
+ memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
+ vfree(par->saved_intmem);
+ }
+}
+
+static int w100fb_suspend(struct device *dev, pm_message_t state, uint32_t level)
{
if (level == SUSPEND_POWER_DOWN) {
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
+ struct w100_tg_info *tg = par->mach->tg;
- w100fb_save_buffer();
- lcdtg_suspend();
+ w100fb_save_vidmem(par);
+ if(tg && tg->suspend)
+ tg->suspend(par);
w100_suspend(W100_SUSPEND_ALL);
- par->blanking_flag = 1;
+ par->blanked = 1;
}
return 0;
}
-static int w100fb_resume(struct device *dev, u32 level)
+static int w100fb_resume(struct device *dev, uint32_t level)
{
if (level == RESUME_POWER_ON) {
struct fb_info *info = dev_get_drvdata(dev);
struct w100fb_par *par=info->par;
+ struct w100_tg_info *tg = par->mach->tg;
- w100_resume();
- w100fb_restore_buffer();
- lcdtg_resume();
- par->blanking_flag = 0;
+ w100_hw_init(par);
+ w100fb_activate_var(par);
+ w100fb_restore_vidmem(par);
+ if(tg && tg->resume)
+ tg->resume(par);
+ par->blanked = 0;
}
return 0;
}
#else
-#define w100fb_suspend NULL
-#define w100fb_resume NULL
+#define w100fb_suspend NULL
+#define w100fb_resume NULL
#endif
int __init w100fb_probe(struct device *dev)
{
+ int err = -EIO;
struct w100fb_mach_info *inf;
- struct fb_info *info;
+ struct fb_info *info = NULL;
struct w100fb_par *par;
struct platform_device *pdev = to_platform_device(dev);
struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ unsigned int chip_id;
if (!mem)
return -EINVAL;
- /* remap the areas we're going to use */
+ /* Remap the chip base address */
remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
if (remapped_base == NULL)
- return -EIO;
+ goto out;
+ /* Map the register space */
remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
- if (remapped_regs == NULL) {
- iounmap(remapped_base);
- return -EIO;
- }
+ if (remapped_regs == NULL)
+ goto out;
- remapped_fbuf = ioremap_nocache(mem->start+MEM_EXT_BASE_VALUE, REMAPPED_FB_LEN);
- if (remapped_fbuf == NULL) {
- iounmap(remapped_base);
- iounmap(remapped_regs);
- return -EIO;
+ /* Identify the chip */
+ printk("Found ");
+ chip_id = readl(remapped_regs + mmCHIP_ID);
+ switch(chip_id) {
+ case CHIP_ID_W100: printk("w100"); break;
+ case CHIP_ID_W3200: printk("w3200"); break;
+ case CHIP_ID_W3220: printk("w3220"); break;
+ default:
+ printk("Unknown imageon chip ID\n");
+ err = -ENODEV;
+ goto out;
}
+ printk(" at 0x%08lx.\n", mem->start+W100_CFG_BASE);
+
+ /* Remap the framebuffer */
+ remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
+ if (remapped_fbuf == NULL)
+ goto out;
info=framebuffer_alloc(sizeof(struct w100fb_par), dev);
if (!info) {
- iounmap(remapped_base);
- iounmap(remapped_regs);
- iounmap(remapped_fbuf);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
- info->device=dev;
par = info->par;
- current_par=info->par;
dev_set_drvdata(dev, info);
inf = dev->platform_data;
- par->phadadj = inf->phadadj;
- par->comadj = inf->comadj;
- par->fastsysclk_mode = 75;
- par->lcdMode = LCD_MODE_INIT;
- par->rotation_flag=0;
- par->blanking_flag=0;
- w100fb_ssp_send = inf->w100fb_ssp_send;
+ par->chip_id = chip_id;
+ par->mach = inf;
+ par->fastpll_mode = 0;
+ par->blanked = 0;
- w100_hw_init();
- w100_pwm_setup();
+ par->pll_table=w100_get_xtal_table(inf->xtal_freq);
+ if (!par->pll_table) {
+ printk(KERN_ERR "No matching Xtal definition found\n");
+ err = -EINVAL;
+ goto out;
+ }
info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL);
if (!info->pseudo_palette) {
- iounmap(remapped_base);
- iounmap(remapped_regs);
- iounmap(remapped_fbuf);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
info->fbops = &w100fb_ops;
info->flags = FBINFO_DEFAULT;
info->node = -1;
- info->screen_base = remapped_fbuf;
+ info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
info->screen_size = REMAPPED_FB_LEN;
- info->var.xres = 640;
+ strcpy(info->fix.id, "w100fb");
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->fix.smem_start = mem->start+W100_FB_BASE;
+ info->fix.mmio_start = mem->start+W100_REG_BASE;
+ info->fix.mmio_len = W100_REG_LEN;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ par->mode = &inf->modelist[0];
+ if(inf->init_mode & INIT_MODE_ROTATED) {
+ info->var.xres = par->mode->yres;
+ info->var.yres = par->mode->xres;
+ }
+ else {
+ info->var.xres = par->mode->xres;
+ info->var.yres = par->mode->yres;
+ }
+
+ if(inf->init_mode &= INIT_MODE_FLIPPED)
+ par->flip = 1;
+ else
+ par->flip = 0;
+
info->var.xres_virtual = info->var.xres;
- info->var.yres = 480;
info->var.yres_virtual = info->var.yres;
- info->var.pixclock = 0x04; /* 171521; */
+ info->var.pixclock = 0x04; /* 171521; */
info->var.sync = 0;
info->var.grayscale = 0;
info->var.xoffset = info->var.yoffset = 0;
info->var.accel_flags = 0;
info->var.activate = FB_ACTIVATE_NOW;
- strcpy(info->fix.id, "w100fb");
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.type_aux = 0;
- info->fix.accel = FB_ACCEL_NONE;
- info->fix.smem_start = mem->start+MEM_EXT_BASE_VALUE;
- info->fix.mmio_start = mem->start+W100_REG_BASE;
- info->fix.mmio_len = W100_REG_LEN;
+ w100_hw_init(par);
- w100fb_check_var(&info->var, info);
+ if (w100fb_check_var(&info->var, info) < 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
w100fb_set_par(info);
if (register_framebuffer(info) < 0) {
- kfree(info->pseudo_palette);
- iounmap(remapped_base);
- iounmap(remapped_regs);
- iounmap(remapped_fbuf);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- device_create_file(dev, &dev_attr_fastsysclk);
+ device_create_file(dev, &dev_attr_fastpllclk);
device_create_file(dev, &dev_attr_reg_read);
device_create_file(dev, &dev_attr_reg_write);
- device_create_file(dev, &dev_attr_rotation);
+ device_create_file(dev, &dev_attr_flip);
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
return 0;
+out:
+ fb_dealloc_cmap(&info->cmap);
+ kfree(info->pseudo_palette);
+ if (remapped_fbuf != NULL)
+ iounmap(remapped_fbuf);
+ if (remapped_regs != NULL)
+ iounmap(remapped_regs);
+ if (remapped_base != NULL)
+ iounmap(remapped_base);
+ if (info)
+ framebuffer_release(info);
+ return err;
}
static int w100fb_remove(struct device *dev)
{
struct fb_info *info = dev_get_drvdata(dev);
+ struct w100fb_par *par=info->par;
- device_remove_file(dev, &dev_attr_fastsysclk);
+ device_remove_file(dev, &dev_attr_fastpllclk);
device_remove_file(dev, &dev_attr_reg_read);
device_remove_file(dev, &dev_attr_reg_write);
- device_remove_file(dev, &dev_attr_rotation);
+ device_remove_file(dev, &dev_attr_flip);
unregister_framebuffer(info);
- w100fb_clear_buffer();
+ vfree(par->saved_intmem);
+ vfree(par->saved_extmem);
kfree(info->pseudo_palette);
+ fb_dealloc_cmap(&info->cmap);
iounmap(remapped_base);
iounmap(remapped_regs);
@@ -721,10 +664,54 @@
udelay(100);
}
+static void w100_update_disable(void)
+{
+ union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+ /* Prevent display updates */
+ disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+ disp_db_buf_wr_cntl.f.update_db_buf = 0;
+ disp_db_buf_wr_cntl.f.en_db_buf = 0;
+ writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+static void w100_update_enable(void)
+{
+ union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+ /* Enable display updates */
+ disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+ disp_db_buf_wr_cntl.f.update_db_buf = 1;
+ disp_db_buf_wr_cntl.f.en_db_buf = 1;
+ writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+unsigned long w100fb_gpio_read(int port)
+{
+ unsigned long value;
+
+ if (port==W100_GPIO_PORT_A)
+ value = readl(remapped_regs + mmGPIO_DATA);
+ else
+ value = readl(remapped_regs + mmGPIO_DATA2);
+
+ return value;
+}
+
+void w100fb_gpio_write(int port, unsigned long value)
+{
+ if (port==W100_GPIO_PORT_A)
+ value = writel(value, remapped_regs + mmGPIO_DATA);
+ else
+ value = writel(value, remapped_regs + mmGPIO_DATA2);
+}
+EXPORT_SYMBOL(w100fb_gpio_read);
+EXPORT_SYMBOL(w100fb_gpio_write);
+
/*
* Initialization of critical w100 hardware
*/
-static void w100_hw_init(void)
+static void w100_hw_init(struct w100fb_par *par)
{
u32 temp32;
union cif_cntl_u cif_cntl;
@@ -735,8 +722,8 @@
union cpu_defaults_u cpu_default;
union cif_write_dbg_u cif_write_dbg;
union wrap_start_dir_u wrap_start_dir;
- union mc_ext_mem_location_u mc_ext_mem_loc;
union cif_io_u cif_io;
+ struct w100_gpio_regs *gpio = par->mach->gpio;
w100_soft_reset();
@@ -791,19 +778,6 @@
cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
- /* This location is relative to internal w100 addresses */
- writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
-
- mc_ext_mem_loc.val = defMC_EXT_MEM_LOCATION;
- mc_ext_mem_loc.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
- mc_ext_mem_loc.f.mc_ext_mem_top = MEM_EXT_TOP_VALUE >> 8;
- writel((u32) (mc_ext_mem_loc.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
-
- if ((current_par->lcdMode == LCD_MODE_240) || (current_par->lcdMode == LCD_MODE_320))
- w100_InitExtMem(LCD_SHARP_QVGA);
- else
- w100_InitExtMem(LCD_SHARP_VGA);
-
wrap_start_dir.val = defWRAP_START_DIR;
wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
@@ -813,339 +787,300 @@
writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
+
+ /* Set the hardware to 565 colour */
+ temp32 = readl(remapped_regs + mmDISP_DEBUG2);
+ temp32 &= 0xff7fffff;
+ temp32 |= 0x00800000;
+ writel(temp32, remapped_regs + mmDISP_DEBUG2);
+
+ /* Initialise the GPIO lines */
+ if (gpio) {
+ writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
+ writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
+ writel(gpio->gpio_dir1, remapped_regs + mmGPIO_CNTL1);
+ writel(gpio->gpio_oe1, remapped_regs + mmGPIO_CNTL2);
+ writel(gpio->gpio_dir2, remapped_regs + mmGPIO_CNTL3);
+ writel(gpio->gpio_oe2, remapped_regs + mmGPIO_CNTL4);
+ }
}
-/*
- * Types
- */
-
-struct pll_parm {
- u16 freq; /* desired Fout for PLL */
- u8 M;
- u8 N_int;
- u8 N_fac;
- u8 tfgoal;
- u8 lock_time;
-};
-
struct power_state {
union clk_pin_cntl_u clk_pin_cntl;
union pll_ref_fb_div_u pll_ref_fb_div;
union pll_cntl_u pll_cntl;
union sclk_cntl_u sclk_cntl;
union pclk_cntl_u pclk_cntl;
- union clk_test_cntl_u clk_test_cntl;
union pwrmgt_cntl_u pwrmgt_cntl;
- u32 freq; /* Fout for PLL calibration */
- u8 tf100; /* for pll calibration */
- u8 tf80; /* for pll calibration */
- u8 tf20; /* for pll calibration */
- u8 M; /* for pll calibration */
- u8 N_int; /* for pll calibration */
- u8 N_fac; /* for pll calibration */
- u8 lock_time; /* for pll calibration */
- u8 tfgoal; /* for pll calibration */
- u8 auto_mode; /* hardware auto switch? */
- u8 pwm_mode; /* 0 fast, 1 normal/slow */
- u16 fast_sclk; /* fast clk freq */
- u16 norm_sclk; /* slow clk freq */
+ int auto_mode; /* system clock auto changing? */
};
-/*
- * Global state variables
- */
-
static struct power_state w100_pwr_state;
-/* This table is specific for 12.5MHz ref crystal. */
-static struct pll_parm gPLLTable[] = {
- /*freq M N_int N_fac tfgoal lock_time */
- { 50, 0, 1, 0, 0xE0, 56}, /* 50.00 MHz */
- { 75, 0, 5, 0, 0xDE, 37}, /* 75.00 MHz */
- {100, 0, 7, 0, 0xE0, 28}, /* 100.00 MHz */
- {125, 0, 9, 0, 0xE0, 22}, /* 125.00 MHz */
- {150, 0, 11, 0, 0xE0, 17}, /* 150.00 MHz */
- { 0, 0, 0, 0, 0, 0} /* Terminator */
+/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
+
+/* 12.5MHz Crystal PLL Table */
+static struct w100_pll_info xtal_12500000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 50, 0, 1, 0, 0xe0, 56}, /* 50.00 MHz */
+ { 75, 0, 5, 0, 0xde, 37}, /* 75.00 MHz */
+ {100, 0, 7, 0, 0xe0, 28}, /* 100.00 MHz */
+ {125, 0, 9, 0, 0xe0, 22}, /* 125.00 MHz */
+ {150, 0, 11, 0, 0xe0, 17}, /* 150.00 MHz */
+ { 0, 0, 0, 0, 0, 0}, /* Terminator */
};
+/* 14.318MHz Crystal PLL Table */
+static struct w100_pll_info xtal_14318000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 40, 4, 13, 0, 0xe0, 80}, /* tfgoal guessed */
+ { 50, 1, 6, 0, 0xe0, 64}, /* 50.05 MHz */
+ { 57, 2, 11, 0, 0xe0, 53}, /* tfgoal guessed */
+ { 75, 0, 4, 3, 0xe0, 43}, /* 75.08 MHz */
+ {100, 0, 6, 0, 0xe0, 32}, /* 100.10 MHz */
+ { 0, 0, 0, 0, 0, 0},
+};
-static u8 w100_pll_get_testcount(u8 testclk_sel)
+/* 16MHz Crystal PLL Table */
+static struct w100_pll_info xtal_16000000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 72, 1, 8, 0, 0xe0, 48}, /* tfgoal guessed */
+ { 95, 1, 10, 7, 0xe0, 38}, /* tfgoal guessed */
+ { 96, 1, 11, 0, 0xe0, 36}, /* tfgoal guessed */
+ { 0, 0, 0, 0, 0, 0},
+};
+
+static struct pll_entries {
+ int xtal_freq;
+ struct w100_pll_info *pll_table;
+} w100_pll_tables[] = {
+ { 12500000, &xtal_12500000[0] },
+ { 14318000, &xtal_14318000[0] },
+ { 16000000, &xtal_16000000[0] },
+ { 0 },
+};
+
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
{
- udelay(5);
+ struct pll_entries *pll_entry = w100_pll_tables;
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
- w100_pwr_state.clk_test_cntl.f.testclk_sel = testclk_sel;
- w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x1; /*reset test count */
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
- w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x1;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-
- udelay(20);
-
- w100_pwr_state.clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-
- return w100_pwr_state.clk_test_cntl.f.test_count;
+ do {
+ if (freq == pll_entry->xtal_freq)
+ return pll_entry->pll_table;
+ pll_entry++;
+ } while (pll_entry->xtal_freq);
+ return 0;
}
-static u8 w100_pll_adjust(void)
+static unsigned int w100_get_testcount(unsigned int testclk_sel)
{
+ union clk_test_cntl_u clk_test_cntl;
+
+ udelay(5);
+
+ /* Select the test clock source and reset */
+ clk_test_cntl.f.start_check_freq = 0x0;
+ clk_test_cntl.f.testclk_sel = testclk_sel;
+ clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+ clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+ /* Run clock test */
+ clk_test_cntl.f.start_check_freq = 0x1;
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+ /* Give the test time to complete */
+ udelay(20);
+
+ /* Return the result */
+ clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
+ clk_test_cntl.f.start_check_freq = 0x0;
+ writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+ return clk_test_cntl.f.test_count;
+}
+
+
+static int w100_pll_adjust(struct w100_pll_info *pll)
+{
+ unsigned int tf80;
+ unsigned int tf20;
+
+ /* Initial Settings */
+ w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */
+ w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */
+ w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */
+ w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */
+ w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */
+ w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */
+ w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
+
+ /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
+ * therefore, commented out the following lines
+ * tf80 meant tf100
+ */
do {
- /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
- * therefore, commented out the following lines
- * tf80 meant tf100
- * set VCO input = 0.8 * VDD
- */
+ /* set VCO input = 0.8 * VDD */
w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- w100_pwr_state.tf80 = w100_pll_get_testcount(0x1); /* PLLCLK */
- if (w100_pwr_state.tf80 >= (w100_pwr_state.tfgoal)) {
+ tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
+ if (tf80 >= (pll->tfgoal)) {
/* set VCO input = 0.2 * VDD */
w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- w100_pwr_state.tf20 = w100_pll_get_testcount(0x1); /* PLLCLK */
- if (w100_pwr_state.tf20 <= (w100_pwr_state.tfgoal))
- return 1; // Success
+ tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
+ if (tf20 <= (pll->tfgoal))
+ return 1; /* Success */
if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
- ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
- (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
+ ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
+ (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
/* slow VCO config */
w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
- writel((u32) (w100_pwr_state.pll_cntl.val),
- remapped_regs + mmPLL_CNTL);
continue;
}
}
if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
- writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- continue;
- }
- if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
+ } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
- writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- continue;
+ } else {
+ return 0; /* Error */
}
- return 0; // error
} while(1);
}
/*
* w100_pll_calibration
- * freq = target frequency of the PLL
- * (note: crystal = 14.3MHz)
*/
-static u8 w100_pll_calibration(u32 freq)
+static int w100_pll_calibration(struct w100_pll_info *pll)
{
- u8 status;
+ int status;
- /* initial setting */
- w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */
- w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */
- w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */
- w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */
- w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */
- w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */
- w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
- writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+ status = w100_pll_adjust(pll);
- /* check for (tf80 >= tfgoal) && (tf20 =< tfgoal) */
- if ((w100_pwr_state.tf80 < w100_pwr_state.tfgoal) || (w100_pwr_state.tf20 > w100_pwr_state.tfgoal)) {
- status=w100_pll_adjust();
- }
/* PLL Reset And Lock */
-
/* set VCO input = 0.5 * VDD */
w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- /* reset time */
- udelay(1);
+ udelay(1); /* reset time */
/* enable charge pump */
- w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */
+ w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- /* set VCO input = Hi-Z */
- /* disable DAC */
+ /* set VCO input = Hi-Z, disable DAC */
w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- /* lock time */
- udelay(400); /* delay 400 us */
+ udelay(400); /* lock time */
/* PLL locked */
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x1; /* PLL clock */
- writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-
- w100_pwr_state.tf100 = w100_pll_get_testcount(0x1); /* PLLCLK */
-
return status;
}
-static u8 w100_pll_set_clk(void)
+static int w100_pll_set_clk(struct w100_pll_info *pll)
{
- u8 status;
+ int status;
- if (w100_pwr_state.auto_mode == 1) /* auto mode */
+ if (w100_pwr_state.auto_mode == 1) /* auto mode */
{
- w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
- w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
}
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* crystal clock */
+ /* Set system clock source to XTAL whilst adjusting the PLL! */
+ w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
- w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = w100_pwr_state.M;
- w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = w100_pwr_state.N_int;
- w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = w100_pwr_state.N_fac;
- w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = w100_pwr_state.lock_time;
+ w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
+ w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
+ w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
+ w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
- status = w100_pll_calibration (w100_pwr_state.freq);
+ status = w100_pll_calibration(pll);
- if (w100_pwr_state.auto_mode == 1) /* auto mode */
+ if (w100_pwr_state.auto_mode == 1) /* auto mode */
{
- w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
- w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
}
return status;
}
-
-/* assume reference crystal clk is 12.5MHz,
- * and that doubling is not enabled.
- *
- * Freq = 12 == 12.5MHz.
- */
-static u16 w100_set_slowsysclk(u16 freq)
+/* freq = target frequency of the PLL */
+static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
{
- if (w100_pwr_state.norm_sclk == freq)
- return freq;
+ struct w100_pll_info *pll = par->pll_table;
- if (w100_pwr_state.auto_mode == 1) /* auto mode */
- return 0;
-
- if (freq == 12) {
- w100_pwr_state.norm_sclk = freq;
- w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* crystal src */
-
- writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
-
- w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x1;
- writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
-
- w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x1;
- w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;
- writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
- w100_pwr_state.pwm_mode = 1; /* normal mode */
- return freq;
- } else
- return 0;
-}
-
-
-static u16 w100_set_fastsysclk(u16 freq)
-{
- u16 pll_freq;
- int i;
-
- while(1) {
- pll_freq = (u16) (freq * (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast + 1));
- i = 0;
- do {
- if (pll_freq == gPLLTable[i].freq) {
- w100_pwr_state.freq = gPLLTable[i].freq * 1000000;
- w100_pwr_state.M = gPLLTable[i].M;
- w100_pwr_state.N_int = gPLLTable[i].N_int;
- w100_pwr_state.N_fac = gPLLTable[i].N_fac;
- w100_pwr_state.tfgoal = gPLLTable[i].tfgoal;
- w100_pwr_state.lock_time = gPLLTable[i].lock_time;
- w100_pwr_state.tf20 = 0xff; /* set highest */
- w100_pwr_state.tf80 = 0x00; /* set lowest */
-
- w100_pll_set_clk();
- w100_pwr_state.pwm_mode = 0; /* fast mode */
- w100_pwr_state.fast_sclk = freq;
- return freq;
- }
- i++;
- } while(gPLLTable[i].freq);
-
- if (w100_pwr_state.auto_mode == 1)
- break;
-
- if (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast == 0)
- break;
-
- w100_pwr_state.sclk_cntl.f.sclk_post_div_fast -= 1;
- writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
- }
+ do {
+ if (freq == pll->freq) {
+ return w100_pll_set_clk(pll);
+ }
+ pll++;
+ } while(pll->freq);
return 0;
}
-
/* Set up an initial state. Some values/fields set
here will be overwritten. */
-static void w100_pwm_setup(void)
+static void w100_pwm_setup(struct w100fb_par *par)
{
w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
- w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = 0x0; /* no freq doubling */
+ w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
- w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0; /* Crystal Clk */
- w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */
+ w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */
w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
- w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
- w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */
- w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */
+ w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */
w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
- w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x0; /* Crystal Clk */
- w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
- w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */
+ w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
+ w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
+ w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */
writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
- w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */
- w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */
+ w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */
+ w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */
w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
@@ -1154,7 +1089,7 @@
w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
- w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */
+ w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */
w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
@@ -1164,221 +1099,276 @@
w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
- w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */
+ w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */
w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
- w100_pwr_state.clk_test_cntl.f.testclk_sel = 0x1; /* PLLCLK (for testing) */
- w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
- w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
- writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
-
w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
- w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */
w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
- w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */
- w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */
+ w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */
w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
- w100_pwr_state.auto_mode = 0; /* manual mode */
- w100_pwr_state.pwm_mode = 1; /* normal mode (0, 1, 2) */
- w100_pwr_state.freq = 50000000; /* 50 MHz */
- w100_pwr_state.M = 3; /* M = 4 */
- w100_pwr_state.N_int = 6; /* N = 7.0 */
- w100_pwr_state.N_fac = 0;
- w100_pwr_state.tfgoal = 0xE0;
- w100_pwr_state.lock_time = 56;
- w100_pwr_state.tf20 = 0xff; /* set highest */
- w100_pwr_state.tf80 = 0x00; /* set lowest */
- w100_pwr_state.tf100 = 0x00; /* set lowest */
- w100_pwr_state.fast_sclk = 50; /* 50.0 MHz */
- w100_pwr_state.norm_sclk = 12; /* 12.5 MHz */
+ w100_pwr_state.auto_mode = 0; /* manual mode */
}
-static void w100_init_sharp_lcd(u32 mode)
+/*
+ * Setup the w100 clocks for the specified mode
+ */
+static void w100_init_clocks(struct w100fb_par *par)
+{
+ struct w100_mode *mode = par->mode;
+
+ if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
+ w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
+
+ w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
+ w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
+ writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+}
+
+static void w100_init_lcd(struct w100fb_par *par)
{
u32 temp32;
- union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+ struct w100_mode *mode = par->mode;
+ struct w100_gen_regs *regs = par->mach->regs;
+ union active_h_disp_u active_h_disp;
+ union active_v_disp_u active_v_disp;
+ union graphic_h_disp_u graphic_h_disp;
+ union graphic_v_disp_u graphic_v_disp;
+ union crtc_total_u crtc_total;
- /* Prevent display updates */
- disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
- disp_db_buf_wr_cntl.f.update_db_buf = 0;
- disp_db_buf_wr_cntl.f.en_db_buf = 0;
- writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+ /* w3200 doesnt like undefined bits being set so zero register values first */
- switch(mode) {
- case LCD_SHARP_QVGA:
- w100_set_slowsysclk(12); /* use crystal -- 12.5MHz */
- /* not use PLL */
+ active_h_disp.val = 0;
+ active_h_disp.f.active_h_start=mode->left_margin;
+ active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
+ writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
- writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
- writel(0x85FF8000, remapped_regs + mmMC_FB_LOCATION);
- writel(0x00000003, remapped_regs + mmLCD_FORMAT);
- writel(0x00CF1C06, remapped_regs + mmGRAPHIC_CTRL);
- writel(0x01410145, remapped_regs + mmCRTC_TOTAL);
- writel(0x01170027, remapped_regs + mmACTIVE_H_DISP);
- writel(0x01410001, remapped_regs + mmACTIVE_V_DISP);
- writel(0x01170027, remapped_regs + mmGRAPHIC_H_DISP);
- writel(0x01410001, remapped_regs + mmGRAPHIC_V_DISP);
- writel(0x81170027, remapped_regs + mmCRTC_SS);
- writel(0xA0140000, remapped_regs + mmCRTC_LS);
- writel(0x00400008, remapped_regs + mmCRTC_REV);
- writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
- writel(0xC0140014, remapped_regs + mmCRTC_GS);
- writel(0x00010141, remapped_regs + mmCRTC_VPOS_GS);
- writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
- writel(0x80100110, remapped_regs + mmCRTC_GOE);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
- writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
- writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
- writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
- writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
- writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
- writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
- writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
- writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
- writel(0x000001e0, remapped_regs + mmGRAPHIC_PITCH);
- writel(0x000000bf, remapped_regs + mmGPIO_DATA);
- writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
- writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
- writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
- break;
- case LCD_SHARP_VGA:
- w100_set_slowsysclk(12); /* use crystal -- 12.5MHz */
- w100_set_fastsysclk(current_par->fastsysclk_mode); /* use PLL -- 75.0MHz */
- w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
- w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x2;
- writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
- writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
- writel(0x9FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
- writel(0x00000003, remapped_regs + mmLCD_FORMAT);
- writel(0x00DE1D66, remapped_regs + mmGRAPHIC_CTRL);
+ active_v_disp.val = 0;
+ active_v_disp.f.active_v_start=mode->upper_margin;
+ active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
+ writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
- writel(0x0283028B, remapped_regs + mmCRTC_TOTAL);
- writel(0x02360056, remapped_regs + mmACTIVE_H_DISP);
- writel(0x02830003, remapped_regs + mmACTIVE_V_DISP);
- writel(0x02360056, remapped_regs + mmGRAPHIC_H_DISP);
- writel(0x02830003, remapped_regs + mmGRAPHIC_V_DISP);
- writel(0x82360056, remapped_regs + mmCRTC_SS);
- writel(0xA0280000, remapped_regs + mmCRTC_LS);
- writel(0x00400008, remapped_regs + mmCRTC_REV);
- writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
- writel(0x80280028, remapped_regs + mmCRTC_GS);
- writel(0x02830002, remapped_regs + mmCRTC_VPOS_GS);
- writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
- writel(0x80100110, remapped_regs + mmCRTC_GOE);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME);
- writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
- writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
- writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
- writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
- writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
- writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
- writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
- writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
- writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
- writel(0x000003C0, remapped_regs + mmGRAPHIC_PITCH);
- writel(0x000000bf, remapped_regs + mmGPIO_DATA);
- writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
- writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
- writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
- break;
- default:
- break;
- }
+ graphic_h_disp.val = 0;
+ graphic_h_disp.f.graphic_h_start=mode->left_margin;
+ graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
+ writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
+
+ graphic_v_disp.val = 0;
+ graphic_v_disp.f.graphic_v_start=mode->upper_margin;
+ graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
+ writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
+
+ crtc_total.val = 0;
+ crtc_total.f.crtc_h_total=mode->left_margin + mode->xres + mode->right_margin;
+ crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
+ writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
+
+ writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
+ writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
+ writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
+ writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
+ writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
+ writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
+ writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
+ writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
+ writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
+
+ writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
+ writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
+ writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
+ writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
+ writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
+ writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
+
+ writel(0x00000000, remapped_regs + mmCRTC_FRAME);
+ writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
+ writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
+ writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
/* Hack for overlay in ext memory */
temp32 = readl(remapped_regs + mmDISP_DEBUG2);
temp32 |= 0xc0000000;
writel(temp32, remapped_regs + mmDISP_DEBUG2);
-
- /* Re-enable display updates */
- disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
- disp_db_buf_wr_cntl.f.update_db_buf = 1;
- disp_db_buf_wr_cntl.f.en_db_buf = 1;
- writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
}
-static void w100_set_vga_rotation_regs(u16 divider, unsigned long ctrl, unsigned long offset, unsigned long pitch)
+static void w100_setup_memory(struct w100fb_par *par)
{
- w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
+ union mc_ext_mem_location_u extmem_location;
+ union mc_fb_location_u intmem_location;
+ struct w100_mem_info *mem = par->mach->mem;
+ struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
+
+ if (!par->extmem_active) {
+ w100_suspend(W100_SUSPEND_EXTMEM);
+
+ /* Map Internal Memory at FB Base */
+ intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
+ intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
+ writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
+
+ /* Unmap External Memory - value is *probably* irrelevant but may have meaning
+ to acceleration libraries */
+ extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
+ extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
+ writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+ } else {
+ /* Map Internal Memory to its default location */
+ intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
+ intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
+ writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
+
+ /* Map External Memory at FB Base */
+ extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
+ extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
+ writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+
+ writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
+ writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
+ writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+ udelay(100);
+ writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+ udelay(100);
+ writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
+ udelay(100);
+ writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
+ writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
+ if (bm_mem) {
+ writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
+ writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
+ writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
+ writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
+ writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
+ writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
+ writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
+ }
+ }
+}
+
+static void w100_set_dispregs(struct w100fb_par *par)
+{
+ unsigned long rot=0, divider, offset=0;
+ union graphic_ctrl_u graphic_ctrl;
+
+ /* See if the mode has been rotated */
+ if (par->xres == par->mode->xres) {
+ if (par->flip) {
+ rot=3; /* 180 degree */
+ offset=(par->xres * par->yres) - 1;
+ } /* else 0 degree */
+ divider = par->mode->pixclk_divider;
+ } else {
+ if (par->flip) {
+ rot=2; /* 270 degree */
+ offset=par->xres - 1;
+ } else {
+ rot=1; /* 90 degree */
+ offset=par->xres * (par->yres - 1);
+ }
+ divider = par->mode->pixclk_divider_rotated;
+ }
+
+ graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
+ switch (par->chip_id) {
+ case CHIP_ID_W100:
+ graphic_ctrl.f_w100.color_depth=6;
+ graphic_ctrl.f_w100.en_crtc=1;
+ graphic_ctrl.f_w100.en_graphic_req=1;
+ graphic_ctrl.f_w100.en_graphic_crtc=1;
+ graphic_ctrl.f_w100.lcd_pclk_on=1;
+ graphic_ctrl.f_w100.lcd_sclk_on=1;
+ graphic_ctrl.f_w100.low_power_on=0;
+ graphic_ctrl.f_w100.req_freq=0;
+ graphic_ctrl.f_w100.portrait_mode=rot;
+
+ /* Zaurus needs this */
+ switch(par->xres) {
+ case 240:
+ case 320:
+ default:
+ graphic_ctrl.f_w100.total_req_graphic=0xa0;
+ break;
+ case 480:
+ case 640:
+ switch(rot) {
+ case 0: /* 0 */
+ case 3: /* 180 */
+ graphic_ctrl.f_w100.low_power_on=1;
+ graphic_ctrl.f_w100.req_freq=5;
+ break;
+ case 1: /* 90 */
+ case 2: /* 270 */
+ graphic_ctrl.f_w100.req_freq=4;
+ break;
+ default:
+ break;
+ }
+ graphic_ctrl.f_w100.total_req_graphic=0xf0;
+ break;
+ }
+ break;
+ case CHIP_ID_W3200:
+ case CHIP_ID_W3220:
+ graphic_ctrl.f_w32xx.color_depth=6;
+ graphic_ctrl.f_w32xx.en_crtc=1;
+ graphic_ctrl.f_w32xx.en_graphic_req=1;
+ graphic_ctrl.f_w32xx.en_graphic_crtc=1;
+ graphic_ctrl.f_w32xx.lcd_pclk_on=1;
+ graphic_ctrl.f_w32xx.lcd_sclk_on=1;
+ graphic_ctrl.f_w32xx.low_power_on=0;
+ graphic_ctrl.f_w32xx.req_freq=0;
+ graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
+ graphic_ctrl.f_w32xx.portrait_mode=rot;
+ break;
+ }
+
+ /* Set the pixel clock source and divider */
+ w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
- writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
- writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
- writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
-
- /* Re-enable display updates */
- writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
+ writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
+ writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
+ writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
}
-static void w100_init_vga_rotation(u16 deg)
+/*
+ * Work out how long the sync pulse lasts
+ * Value is 1/(time in seconds)
+ */
+static void calc_hsync(struct w100fb_par *par)
{
- switch(deg) {
- case 0:
- w100_set_vga_rotation_regs(0x02, 0x00DE1D66, 0x00800000, 0x000003c0);
- break;
- case 90:
- w100_set_vga_rotation_regs(0x06, 0x00DE1D0e, 0x00895b00, 0x00000500);
- break;
- case 180:
- w100_set_vga_rotation_regs(0x02, 0x00DE1D7e, 0x00895ffc, 0x000003c0);
- break;
- case 270:
- w100_set_vga_rotation_regs(0x06, 0x00DE1D16, 0x008004fc, 0x00000500);
- break;
- default:
- /* not-support */
- break;
- }
+ unsigned long hsync;
+ struct w100_mode *mode = par->mode;
+ union crtc_ss_u crtc_ss;
+
+ if (mode->pixclk_src == CLK_SRC_XTAL)
+ hsync=par->mach->xtal_freq;
+ else
+ hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
+
+ hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
+
+ crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
+ if (crtc_ss.val)
+ par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
+ else
+ par->hsync_len = 0;
}
-
-static void w100_set_qvga_rotation_regs(unsigned long ctrl, unsigned long offset, unsigned long pitch)
-{
- writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
- writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
- writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
-
- /* Re-enable display updates */
- writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
-}
-
-
-static void w100_init_qvga_rotation(u16 deg)
-{
- switch(deg) {
- case 0:
- w100_set_qvga_rotation_regs(0x00d41c06, 0x00800000, 0x000001e0);
- break;
- case 90:
- w100_set_qvga_rotation_regs(0x00d41c0E, 0x00825580, 0x00000280);
- break;
- case 180:
- w100_set_qvga_rotation_regs(0x00d41c1e, 0x008257fc, 0x000001e0);
- break;
- case 270:
- w100_set_qvga_rotation_regs(0x00d41c16, 0x0080027c, 0x00000280);
- break;
- default:
- /* not-support */
- break;
- }
-}
-
-
static void w100_suspend(u32 mode)
{
u32 val;
@@ -1387,30 +1377,28 @@
writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
- val &= ~(0x00100000); /* bit20=0 */
- val |= 0xFF000000; /* bit31:24=0xff */
+ val &= ~(0x00100000); /* bit20=0 */
+ val |= 0xFF000000; /* bit31:24=0xff */
writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
val = readl(remapped_regs + mmMEM_EXT_CNTL);
- val &= ~(0x00040000); /* bit18=0 */
- val |= 0x00080000; /* bit19=1 */
+ val &= ~(0x00040000); /* bit18=0 */
+ val |= 0x00080000; /* bit19=1 */
writel(val, remapped_regs + mmMEM_EXT_CNTL);
- udelay(1); /* wait 1us */
+ udelay(1); /* wait 1us */
if (mode == W100_SUSPEND_EXTMEM) {
-
/* CKE: Tri-State */
val = readl(remapped_regs + mmMEM_EXT_CNTL);
- val |= 0x40000000; /* bit30=1 */
+ val |= 0x40000000; /* bit30=1 */
writel(val, remapped_regs + mmMEM_EXT_CNTL);
/* CLK: Stop */
val = readl(remapped_regs + mmMEM_EXT_CNTL);
- val &= ~(0x00000001); /* bit0=0 */
+ val &= ~(0x00000001); /* bit0=0 */
writel(val, remapped_regs + mmMEM_EXT_CNTL);
} else {
-
writel(0x00000000, remapped_regs + mmSCLK_CNTL);
writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
@@ -1418,43 +1406,16 @@
udelay(5);
val = readl(remapped_regs + mmPLL_CNTL);
- val |= 0x00000004; /* bit2=1 */
+ val |= 0x00000004; /* bit2=1 */
writel(val, remapped_regs + mmPLL_CNTL);
writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
}
}
-
-static void w100_resume(void)
-{
- u32 temp32;
-
- w100_hw_init();
- w100_pwm_setup();
-
- temp32 = readl(remapped_regs + mmDISP_DEBUG2);
- temp32 &= 0xff7fffff;
- temp32 |= 0x00800000;
- writel(temp32, remapped_regs + mmDISP_DEBUG2);
-
- if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
- w100_init_sharp_lcd(LCD_SHARP_VGA);
- if (current_par->lcdMode == LCD_MODE_640) {
- w100_init_vga_rotation(current_par->rotation_flag ? 270 : 90);
- }
- } else {
- w100_init_sharp_lcd(LCD_SHARP_QVGA);
- if (current_par->lcdMode == LCD_MODE_320) {
- w100_init_qvga_rotation(current_par->rotation_flag ? 270 : 90);
- }
- }
-}
-
-
static void w100_vsync(void)
{
u32 tmp;
- int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
+ int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
tmp = readl(remapped_regs + mmACTIVE_V_DISP);
@@ -1490,363 +1451,6 @@
writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
}
-
-static void w100_InitExtMem(u32 mode)
-{
- switch(mode) {
- case LCD_SHARP_QVGA:
- /* QVGA doesn't use external memory
- nothing to do, really. */
- break;
- case LCD_SHARP_VGA:
- writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
- writel(0x00040003, remapped_regs + mmMEM_EXT_CNTL);
- writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
- udelay(100);
- writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
- udelay(100);
- writel(0x00650021, remapped_regs + mmMEM_SDRAM_MODE_REG);
- udelay(100);
- writel(0x10002a4a, remapped_regs + mmMEM_EXT_TIMING_CNTL);
- writel(0x7ff87012, remapped_regs + mmMEM_IO_CNTL);
- break;
- default:
- break;
- }
-}
-
-
-#define RESCTL_ADRS 0x00
-#define PHACTRL_ADRS 0x01
-#define DUTYCTRL_ADRS 0x02
-#define POWERREG0_ADRS 0x03
-#define POWERREG1_ADRS 0x04
-#define GPOR3_ADRS 0x05
-#define PICTRL_ADRS 0x06
-#define POLCTRL_ADRS 0x07
-
-#define RESCTL_QVGA 0x01
-#define RESCTL_VGA 0x00
-
-#define POWER1_VW_ON 0x01 /* VW Supply FET ON */
-#define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */
-#define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */
-
-#define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */
-#define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */
-#define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */
-
-#define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */
-#define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */
-#define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */
-#define POWER0_COM_ON 0x08 /* COM Powewr Supply ON */
-#define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */
-
-#define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */
-#define POWER0_COM_OFF 0x00 /* COM Powewr Supply OFF */
-#define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */
-
-#define PICTRL_INIT_STATE 0x01
-#define PICTRL_INIOFF 0x02
-#define PICTRL_POWER_DOWN 0x04
-#define PICTRL_COM_SIGNAL_OFF 0x08
-#define PICTRL_DAC_SIGNAL_OFF 0x10
-
-#define PICTRL_POWER_ACTIVE (0)
-
-#define POLCTRL_SYNC_POL_FALL 0x01
-#define POLCTRL_EN_POL_FALL 0x02
-#define POLCTRL_DATA_POL_FALL 0x04
-#define POLCTRL_SYNC_ACT_H 0x08
-#define POLCTRL_EN_ACT_L 0x10
-
-#define POLCTRL_SYNC_POL_RISE 0x00
-#define POLCTRL_EN_POL_RISE 0x00
-#define POLCTRL_DATA_POL_RISE 0x00
-#define POLCTRL_SYNC_ACT_L 0x00
-#define POLCTRL_EN_ACT_H 0x00
-
-#define PHACTRL_PHASE_MANUAL 0x01
-
-#define PHAD_QVGA_DEFAULT_VAL (9)
-#define COMADJ_DEFAULT (125)
-
-static void lcdtg_ssp_send(u8 adrs, u8 data)
-{
- w100fb_ssp_send(adrs,data);
-}
-
-/*
- * This is only a psuedo I2C interface. We can't use the standard kernel
- * routines as the interface is write only. We just assume the data is acked...
- */
-static void lcdtg_ssp_i2c_send(u8 data)
-{
- lcdtg_ssp_send(POWERREG0_ADRS, data);
- udelay(10);
-}
-
-static void lcdtg_i2c_send_bit(u8 data)
-{
- lcdtg_ssp_i2c_send(data);
- lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
- lcdtg_ssp_i2c_send(data);
-}
-
-static void lcdtg_i2c_send_start(u8 base)
-{
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
- lcdtg_ssp_i2c_send(base);
-}
-
-static void lcdtg_i2c_send_stop(u8 base)
-{
- lcdtg_ssp_i2c_send(base);
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
- lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
-}
-
-static void lcdtg_i2c_send_byte(u8 base, u8 data)
-{
- int i;
- for (i = 0; i < 8; i++) {
- if (data & 0x80)
- lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
- else
- lcdtg_i2c_send_bit(base);
- data <<= 1;
- }
-}
-
-static void lcdtg_i2c_wait_ack(u8 base)
-{
- lcdtg_i2c_send_bit(base);
-}
-
-static void lcdtg_set_common_voltage(u8 base_data, u8 data)
-{
- /* Set Common Voltage to M62332FP via I2C */
- lcdtg_i2c_send_start(base_data);
- lcdtg_i2c_send_byte(base_data, 0x9c);
- lcdtg_i2c_wait_ack(base_data);
- lcdtg_i2c_send_byte(base_data, 0x00);
- lcdtg_i2c_wait_ack(base_data);
- lcdtg_i2c_send_byte(base_data, data);
- lcdtg_i2c_wait_ack(base_data);
- lcdtg_i2c_send_stop(base_data);
-}
-
-static struct lcdtg_register_setting {
- u8 adrs;
- u8 data;
- u32 wait;
-} lcdtg_power_on_table[] = {
-
- /* Initialize Internal Logic & Port */
- { PICTRL_ADRS,
- PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE |
- PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF,
- 0 },
-
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF | POWER0_COM_OFF |
- POWER0_VCC5_OFF,
- 0 },
-
- { POWERREG1_ADRS,
- POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF,
- 0 },
-
- /* VDD(+8V),SVSS(-4V) ON */
- { POWERREG1_ADRS,
- POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON /* VDD ON */,
- 3000 },
-
- /* DAC ON */
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
- POWER0_COM_OFF | POWER0_VCC5_OFF,
- 0 },
-
- /* INIB = H, INI = L */
- { PICTRL_ADRS,
- /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
- PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF,
- 0 },
-
- /* Set Common Voltage */
- { 0xfe, 0, 0 },
-
- /* VCC5 ON */
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
- POWER0_COM_OFF | POWER0_VCC5_ON /* VCC5 ON */,
- 0 },
-
- /* GVSS(-8V) ON */
- { POWERREG1_ADRS,
- POWER1_VW_OFF | POWER1_GVSS_ON /* GVSS ON */ |
- POWER1_VDD_ON /* VDD ON */,
- 2000 },
-
- /* COM SIGNAL ON (PICTL[3] = L) */
- { PICTRL_ADRS,
- PICTRL_INIT_STATE,
- 0 },
-
- /* COM ON */
- { POWERREG0_ADRS,
- POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
- POWER0_COM_ON /* COM ON */ | POWER0_VCC5_ON /* VCC5_ON */,
- 0 },
-
- /* VW ON */
- { POWERREG1_ADRS,
- POWER1_VW_ON /* VW ON */ | POWER1_GVSS_ON /* GVSS ON */ |
- POWER1_VDD_ON /* VDD ON */,
- 0 /* Wait 100ms */ },
-
- /* Signals output enable */
- { PICTRL_ADRS,
- 0 /* Signals output enable */,
- 0 },
-
- { PHACTRL_ADRS,
- PHACTRL_PHASE_MANUAL,
- 0 },
-
- /* Initialize for Input Signals from ATI */
- { POLCTRL_ADRS,
- POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE | POLCTRL_DATA_POL_RISE |
- POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H,
- 1000 /*100000*/ /* Wait 100ms */ },
-
- /* end mark */
- { 0xff, 0, 0 }
-};
-
-static void lcdtg_resume(void)
-{
- if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
- lcdtg_hw_init(LCD_SHARP_VGA);
- } else {
- lcdtg_hw_init(LCD_SHARP_QVGA);
- }
-}
-
-static void lcdtg_suspend(void)
-{
- int i;
-
- for (i = 0; i < (current_par->xres * current_par->yres); i++) {
- writew(0xffff, remapped_fbuf + (2*i));
- }
-
- /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
- mdelay(34);
-
- /* (1)VW OFF */
- lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
-
- /* (2)COM OFF */
- lcdtg_ssp_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
- lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
-
- /* (3)Set Common Voltage Bias 0V */
- lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
-
- /* (4)GVSS OFF */
- lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
-
- /* (5)VCC5 OFF */
- lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
- /* (6)Set PDWN, INIOFF, DACOFF */
- lcdtg_ssp_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
- PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
-
- /* (7)DAC OFF */
- lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
-
- /* (8)VDD OFF */
- lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
-
-}
-
-static void lcdtg_set_phadadj(u32 mode)
-{
- int adj;
-
- if (mode == LCD_SHARP_VGA) {
- /* Setting for VGA */
- adj = current_par->phadadj;
- if (adj < 0) {
- adj = PHACTRL_PHASE_MANUAL;
- } else {
- adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
- }
- } else {
- /* Setting for QVGA */
- adj = (PHAD_QVGA_DEFAULT_VAL << 1) | PHACTRL_PHASE_MANUAL;
- }
- lcdtg_ssp_send(PHACTRL_ADRS, adj);
-}
-
-static void lcdtg_hw_init(u32 mode)
-{
- int i;
- int comadj;
-
- i = 0;
- while(lcdtg_power_on_table[i].adrs != 0xff) {
- if (lcdtg_power_on_table[i].adrs == 0xfe) {
- /* Set Common Voltage */
- comadj = current_par->comadj;
- if (comadj < 0) {
- comadj = COMADJ_DEFAULT;
- }
- lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
- } else if (lcdtg_power_on_table[i].adrs == PHACTRL_ADRS) {
- /* Set Phase Adjuct */
- lcdtg_set_phadadj(mode);
- } else {
- /* Other */
- lcdtg_ssp_send(lcdtg_power_on_table[i].adrs, lcdtg_power_on_table[i].data);
- }
- if (lcdtg_power_on_table[i].wait != 0)
- udelay(lcdtg_power_on_table[i].wait);
- i++;
- }
-
- switch(mode) {
- case LCD_SHARP_QVGA:
- /* Set Lcd Resolution (QVGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
- break;
- case LCD_SHARP_VGA:
- /* Set Lcd Resolution (VGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
- break;
- default:
- break;
- }
-}
-
-static void lcdtg_lcd_change(u32 mode)
-{
- /* Set Phase Adjuct */
- lcdtg_set_phadadj(mode);
-
- if (mode == LCD_SHARP_VGA)
- /* Set Lcd Resolution (VGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
- else if (mode == LCD_SHARP_QVGA)
- /* Set Lcd Resolution (QVGA) */
- lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
-}
-
-
static struct device_driver w100fb_driver = {
.name = "w100fb",
.bus = &platform_bus_type,
@@ -1870,4 +1474,4 @@
module_exit(w100fb_cleanup);
MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/w100fb.h b/drivers/video/w100fb.h
index 41624f9..7a58a1e 100644
--- a/drivers/video/w100fb.h
+++ b/drivers/video/w100fb.h
@@ -5,9 +5,12 @@
*
* Copyright (C) 2002, ATI Corp.
* Copyright (C) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton <spyro@f2s.com>
*
* Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net>
*
+ * w32xx support by Ian Molton
+ *
* 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.
@@ -19,7 +22,7 @@
/* Block CIF Start: */
#define mmCHIP_ID 0x0000
-#define mmREVISION_ID 0x0004
+#define mmREVISION_ID 0x0004
#define mmWRAP_BUF_A 0x0008
#define mmWRAP_BUF_B 0x000C
#define mmWRAP_TOP_DIR 0x0010
@@ -88,7 +91,7 @@
#define mmDISP_DEBUG 0x04D4
#define mmDISP_DB_BUF_CNTL 0x04D8
#define mmDISP_CRC_SIG 0x04DC
-#define mmCRTC_DEFAULT_COUNT 0x04E0
+#define mmCRTC_DEFAULT_COUNT 0x04E0
#define mmLCD_BACKGROUND_COLOR 0x04E4
#define mmCRTC_PS2 0x04E8
#define mmCRTC_PS2_VPOS 0x04EC
@@ -119,17 +122,17 @@
/* Block DISPLAY End: */
/* Block GFX Start: */
-#define mmBRUSH_OFFSET 0x108C
-#define mmBRUSH_Y_X 0x1074
-#define mmDEFAULT_PITCH_OFFSET 0x10A0
-#define mmDEFAULT_SC_BOTTOM_RIGHT 0x10A8
-#define mmDEFAULT2_SC_BOTTOM_RIGHT 0x10AC
-#define mmGLOBAL_ALPHA 0x1210
-#define mmFILTER_COEF 0x1214
-#define mmMVC_CNTL_START 0x11E0
-#define mmE2_ARITHMETIC_CNTL 0x1220
-#define mmENG_CNTL 0x13E8
-#define mmENG_PERF_CNT 0x13F0
+#define mmBRUSH_OFFSET 0x108C
+#define mmBRUSH_Y_X 0x1074
+#define mmDEFAULT_PITCH_OFFSET 0x10A0
+#define mmDEFAULT_SC_BOTTOM_RIGHT 0x10A8
+#define mmDEFAULT2_SC_BOTTOM_RIGHT 0x10AC
+#define mmGLOBAL_ALPHA 0x1210
+#define mmFILTER_COEF 0x1214
+#define mmMVC_CNTL_START 0x11E0
+#define mmE2_ARITHMETIC_CNTL 0x1220
+#define mmENG_CNTL 0x13E8
+#define mmENG_PERF_CNT 0x13F0
/* Block GFX End: */
/* Block IDCT Start: */
@@ -141,22 +144,38 @@
/* Block IDCT End: */
/* Block MC Start: */
-#define mmMEM_CNTL 0x0180
-#define mmMEM_ARB 0x0184
-#define mmMC_FB_LOCATION 0x0188
-#define mmMEM_EXT_CNTL 0x018C
-#define mmMC_EXT_MEM_LOCATION 0x0190
-#define mmMEM_EXT_TIMING_CNTL 0x0194
-#define mmMEM_SDRAM_MODE_REG 0x0198
-#define mmMEM_IO_CNTL 0x019C
-#define mmMC_DEBUG 0x01A0
-#define mmMC_BIST_CTRL 0x01A4
-#define mmMC_BIST_COLLAR_READ 0x01A8
-#define mmTC_MISMATCH 0x01AC
-#define mmMC_PERF_MON_CNTL 0x01B0
-#define mmMC_PERF_COUNTERS 0x01B4
+#define mmMEM_CNTL 0x0180
+#define mmMEM_ARB 0x0184
+#define mmMC_FB_LOCATION 0x0188
+#define mmMEM_EXT_CNTL 0x018C
+#define mmMC_EXT_MEM_LOCATION 0x0190
+#define mmMEM_EXT_TIMING_CNTL 0x0194
+#define mmMEM_SDRAM_MODE_REG 0x0198
+#define mmMEM_IO_CNTL 0x019C
+#define mmMC_DEBUG 0x01A0
+#define mmMC_BIST_CTRL 0x01A4
+#define mmMC_BIST_COLLAR_READ 0x01A8
+#define mmTC_MISMATCH 0x01AC
+#define mmMC_PERF_MON_CNTL 0x01B0
+#define mmMC_PERF_COUNTERS 0x01B4
/* Block MC End: */
+/* Block BM Start: */
+#define mmBM_EXT_MEM_BANDWIDTH 0x0A00
+#define mmBM_OFFSET 0x0A04
+#define mmBM_MEM_EXT_TIMING_CNTL 0x0A08
+#define mmBM_MEM_EXT_CNTL 0x0A0C
+#define mmBM_MEM_MODE_REG 0x0A10
+#define mmBM_MEM_IO_CNTL 0x0A18
+#define mmBM_CONFIG 0x0A1C
+#define mmBM_STATUS 0x0A20
+#define mmBM_DEBUG 0x0A24
+#define mmBM_PERF_MON_CNTL 0x0A28
+#define mmBM_PERF_COUNTERS 0x0A2C
+#define mmBM_PERF2_MON_CNTL 0x0A30
+#define mmBM_PERF2_COUNTERS 0x0A34
+/* Block BM End: */
+
/* Block RBBM Start: */
#define mmWAIT_UNTIL 0x1400
#define mmISYNC_CNTL 0x1404
@@ -176,439 +195,575 @@
/* Block CG End: */
/* default value definitions */
-#define defWRAP_TOP_DIR 0x00000000
-#define defWRAP_START_DIR 0x00000000
-#define defCFGREG_BASE 0x00000000
-#define defCIF_IO 0x000C0902
-#define defINTF_CNTL 0x00000011
-#define defCPU_DEFAULTS 0x00000006
-#define defHW_INT 0x00000000
-#define defMC_EXT_MEM_LOCATION 0x07ff0000
-#define defTC_MISMATCH 0x00000000
+#define defWRAP_TOP_DIR 0x00000000
+#define defWRAP_START_DIR 0x00000000
+#define defCFGREG_BASE 0x00000000
+#define defCIF_IO 0x000C0902
+#define defINTF_CNTL 0x00000011
+#define defCPU_DEFAULTS 0x00000006
+#define defHW_INT 0x00000000
+#define defMC_EXT_MEM_LOCATION 0x07ff0000
+#define defTC_MISMATCH 0x00000000
#define W100_CFG_BASE 0x0
#define W100_CFG_LEN 0x10
#define W100_REG_BASE 0x10000
#define W100_REG_LEN 0x2000
#define MEM_INT_BASE_VALUE 0x100000
-#define MEM_INT_TOP_VALUE_W100 0x15ffff
#define MEM_EXT_BASE_VALUE 0x800000
-#define MEM_EXT_TOP_VALUE 0x9fffff
+#define MEM_INT_SIZE 0x05ffff
+#define MEM_WINDOW_BASE 0x100000
+#define MEM_WINDOW_SIZE 0xf00000
+
#define WRAP_BUF_BASE_VALUE 0x80000
#define WRAP_BUF_TOP_VALUE 0xbffff
+#define CHIP_ID_W100 0x57411002
+#define CHIP_ID_W3200 0x56441002
+#define CHIP_ID_W3220 0x57441002
-/* data structure definitions */
+/* Register structure definitions */
struct wrap_top_dir_t {
- unsigned long top_addr : 23;
- unsigned long : 9;
+ unsigned long top_addr : 23;
+ unsigned long : 9;
} __attribute__((packed));
union wrap_top_dir_u {
- unsigned long val : 32;
- struct wrap_top_dir_t f;
+ unsigned long val : 32;
+ struct wrap_top_dir_t f;
} __attribute__((packed));
struct wrap_start_dir_t {
- unsigned long start_addr : 23;
- unsigned long : 9;
+ unsigned long start_addr : 23;
+ unsigned long : 9;
} __attribute__((packed));
union wrap_start_dir_u {
- unsigned long val : 32;
- struct wrap_start_dir_t f;
+ unsigned long val : 32;
+ struct wrap_start_dir_t f;
} __attribute__((packed));
struct cif_cntl_t {
- unsigned long swap_reg : 2;
- unsigned long swap_fbuf_1 : 2;
- unsigned long swap_fbuf_2 : 2;
- unsigned long swap_fbuf_3 : 2;
- unsigned long pmi_int_disable : 1;
- unsigned long pmi_schmen_disable : 1;
- unsigned long intb_oe : 1;
- unsigned long en_wait_to_compensate_dq_prop_dly : 1;
- unsigned long compensate_wait_rd_size : 2;
- unsigned long wait_asserted_timeout_val : 2;
- unsigned long wait_masked_val : 2;
- unsigned long en_wait_timeout : 1;
- unsigned long en_one_clk_setup_before_wait : 1;
- unsigned long interrupt_active_high : 1;
- unsigned long en_overwrite_straps : 1;
- unsigned long strap_wait_active_hi : 1;
- unsigned long lat_busy_count : 2;
- unsigned long lat_rd_pm4_sclk_busy : 1;
- unsigned long dis_system_bits : 1;
- unsigned long dis_mr : 1;
- unsigned long cif_spare_1 : 4;
+ unsigned long swap_reg : 2;
+ unsigned long swap_fbuf_1 : 2;
+ unsigned long swap_fbuf_2 : 2;
+ unsigned long swap_fbuf_3 : 2;
+ unsigned long pmi_int_disable : 1;
+ unsigned long pmi_schmen_disable : 1;
+ unsigned long intb_oe : 1;
+ unsigned long en_wait_to_compensate_dq_prop_dly : 1;
+ unsigned long compensate_wait_rd_size : 2;
+ unsigned long wait_asserted_timeout_val : 2;
+ unsigned long wait_masked_val : 2;
+ unsigned long en_wait_timeout : 1;
+ unsigned long en_one_clk_setup_before_wait : 1;
+ unsigned long interrupt_active_high : 1;
+ unsigned long en_overwrite_straps : 1;
+ unsigned long strap_wait_active_hi : 1;
+ unsigned long lat_busy_count : 2;
+ unsigned long lat_rd_pm4_sclk_busy : 1;
+ unsigned long dis_system_bits : 1;
+ unsigned long dis_mr : 1;
+ unsigned long cif_spare_1 : 4;
} __attribute__((packed));
union cif_cntl_u {
- unsigned long val : 32;
- struct cif_cntl_t f;
+ unsigned long val : 32;
+ struct cif_cntl_t f;
} __attribute__((packed));
struct cfgreg_base_t {
- unsigned long cfgreg_base : 24;
- unsigned long : 8;
+ unsigned long cfgreg_base : 24;
+ unsigned long : 8;
} __attribute__((packed));
union cfgreg_base_u {
- unsigned long val : 32;
- struct cfgreg_base_t f;
+ unsigned long val : 32;
+ struct cfgreg_base_t f;
} __attribute__((packed));
struct cif_io_t {
- unsigned long dq_srp : 1;
- unsigned long dq_srn : 1;
- unsigned long dq_sp : 4;
- unsigned long dq_sn : 4;
- unsigned long waitb_srp : 1;
- unsigned long waitb_srn : 1;
- unsigned long waitb_sp : 4;
- unsigned long waitb_sn : 4;
- unsigned long intb_srp : 1;
- unsigned long intb_srn : 1;
- unsigned long intb_sp : 4;
- unsigned long intb_sn : 4;
- unsigned long : 2;
+ unsigned long dq_srp : 1;
+ unsigned long dq_srn : 1;
+ unsigned long dq_sp : 4;
+ unsigned long dq_sn : 4;
+ unsigned long waitb_srp : 1;
+ unsigned long waitb_srn : 1;
+ unsigned long waitb_sp : 4;
+ unsigned long waitb_sn : 4;
+ unsigned long intb_srp : 1;
+ unsigned long intb_srn : 1;
+ unsigned long intb_sp : 4;
+ unsigned long intb_sn : 4;
+ unsigned long : 2;
} __attribute__((packed));
union cif_io_u {
- unsigned long val : 32;
- struct cif_io_t f;
+ unsigned long val : 32;
+ struct cif_io_t f;
} __attribute__((packed));
struct cif_read_dbg_t {
- unsigned long unpacker_pre_fetch_trig_gen : 2;
- unsigned long dly_second_rd_fetch_trig : 1;
- unsigned long rst_rd_burst_id : 1;
- unsigned long dis_rd_burst_id : 1;
- unsigned long en_block_rd_when_packer_is_not_emp : 1;
- unsigned long dis_pre_fetch_cntl_sm : 1;
- unsigned long rbbm_chrncy_dis : 1;
- unsigned long rbbm_rd_after_wr_lat : 2;
- unsigned long dis_be_during_rd : 1;
- unsigned long one_clk_invalidate_pulse : 1;
- unsigned long dis_chnl_priority : 1;
- unsigned long rst_read_path_a_pls : 1;
- unsigned long rst_read_path_b_pls : 1;
- unsigned long dis_reg_rd_fetch_trig : 1;
- unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
- unsigned long dis_rd_same_byte_to_trig_fetch : 1;
- unsigned long dis_dir_wrap : 1;
- unsigned long dis_ring_buf_to_force_dec : 1;
- unsigned long dis_addr_comp_in_16bit : 1;
- unsigned long clr_w : 1;
- unsigned long err_rd_tag_is_3 : 1;
- unsigned long err_load_when_ful_a : 1;
- unsigned long err_load_when_ful_b : 1;
- unsigned long : 7;
+ unsigned long unpacker_pre_fetch_trig_gen : 2;
+ unsigned long dly_second_rd_fetch_trig : 1;
+ unsigned long rst_rd_burst_id : 1;
+ unsigned long dis_rd_burst_id : 1;
+ unsigned long en_block_rd_when_packer_is_not_emp : 1;
+ unsigned long dis_pre_fetch_cntl_sm : 1;
+ unsigned long rbbm_chrncy_dis : 1;
+ unsigned long rbbm_rd_after_wr_lat : 2;
+ unsigned long dis_be_during_rd : 1;
+ unsigned long one_clk_invalidate_pulse : 1;
+ unsigned long dis_chnl_priority : 1;
+ unsigned long rst_read_path_a_pls : 1;
+ unsigned long rst_read_path_b_pls : 1;
+ unsigned long dis_reg_rd_fetch_trig : 1;
+ unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
+ unsigned long dis_rd_same_byte_to_trig_fetch : 1;
+ unsigned long dis_dir_wrap : 1;
+ unsigned long dis_ring_buf_to_force_dec : 1;
+ unsigned long dis_addr_comp_in_16bit : 1;
+ unsigned long clr_w : 1;
+ unsigned long err_rd_tag_is_3 : 1;
+ unsigned long err_load_when_ful_a : 1;
+ unsigned long err_load_when_ful_b : 1;
+ unsigned long : 7;
} __attribute__((packed));
union cif_read_dbg_u {
- unsigned long val : 32;
- struct cif_read_dbg_t f;
+ unsigned long val : 32;
+ struct cif_read_dbg_t f;
} __attribute__((packed));
struct cif_write_dbg_t {
- unsigned long packer_timeout_count : 2;
- unsigned long en_upper_load_cond : 1;
- unsigned long en_chnl_change_cond : 1;
- unsigned long dis_addr_comp_cond : 1;
- unsigned long dis_load_same_byte_addr_cond : 1;
- unsigned long dis_timeout_cond : 1;
- unsigned long dis_timeout_during_rbbm : 1;
- unsigned long dis_packer_ful_during_rbbm_timeout : 1;
- unsigned long en_dword_split_to_rbbm : 1;
- unsigned long en_dummy_val : 1;
- unsigned long dummy_val_sel : 1;
- unsigned long mask_pm4_wrptr_dec : 1;
- unsigned long dis_mc_clean_cond : 1;
- unsigned long err_two_reqi_during_ful : 1;
- unsigned long err_reqi_during_idle_clk : 1;
- unsigned long err_global : 1;
- unsigned long en_wr_buf_dbg_load : 1;
- unsigned long en_wr_buf_dbg_path : 1;
- unsigned long sel_wr_buf_byte : 3;
- unsigned long dis_rd_flush_wr : 1;
- unsigned long dis_packer_ful_cond : 1;
- unsigned long dis_invalidate_by_ops_chnl : 1;
- unsigned long en_halt_when_reqi_err : 1;
- unsigned long cif_spare_2 : 5;
- unsigned long : 1;
+ unsigned long packer_timeout_count : 2;
+ unsigned long en_upper_load_cond : 1;
+ unsigned long en_chnl_change_cond : 1;
+ unsigned long dis_addr_comp_cond : 1;
+ unsigned long dis_load_same_byte_addr_cond : 1;
+ unsigned long dis_timeout_cond : 1;
+ unsigned long dis_timeout_during_rbbm : 1;
+ unsigned long dis_packer_ful_during_rbbm_timeout : 1;
+ unsigned long en_dword_split_to_rbbm : 1;
+ unsigned long en_dummy_val : 1;
+ unsigned long dummy_val_sel : 1;
+ unsigned long mask_pm4_wrptr_dec : 1;
+ unsigned long dis_mc_clean_cond : 1;
+ unsigned long err_two_reqi_during_ful : 1;
+ unsigned long err_reqi_during_idle_clk : 1;
+ unsigned long err_global : 1;
+ unsigned long en_wr_buf_dbg_load : 1;
+ unsigned long en_wr_buf_dbg_path : 1;
+ unsigned long sel_wr_buf_byte : 3;
+ unsigned long dis_rd_flush_wr : 1;
+ unsigned long dis_packer_ful_cond : 1;
+ unsigned long dis_invalidate_by_ops_chnl : 1;
+ unsigned long en_halt_when_reqi_err : 1;
+ unsigned long cif_spare_2 : 5;
+ unsigned long : 1;
} __attribute__((packed));
union cif_write_dbg_u {
- unsigned long val : 32;
- struct cif_write_dbg_t f;
+ unsigned long val : 32;
+ struct cif_write_dbg_t f;
} __attribute__((packed));
struct intf_cntl_t {
- unsigned char ad_inc_a : 1;
- unsigned char ring_buf_a : 1;
- unsigned char rd_fetch_trigger_a : 1;
- unsigned char rd_data_rdy_a : 1;
- unsigned char ad_inc_b : 1;
- unsigned char ring_buf_b : 1;
- unsigned char rd_fetch_trigger_b : 1;
- unsigned char rd_data_rdy_b : 1;
+ unsigned char ad_inc_a : 1;
+ unsigned char ring_buf_a : 1;
+ unsigned char rd_fetch_trigger_a : 1;
+ unsigned char rd_data_rdy_a : 1;
+ unsigned char ad_inc_b : 1;
+ unsigned char ring_buf_b : 1;
+ unsigned char rd_fetch_trigger_b : 1;
+ unsigned char rd_data_rdy_b : 1;
} __attribute__((packed));
union intf_cntl_u {
- unsigned char val : 8;
- struct intf_cntl_t f;
+ unsigned char val : 8;
+ struct intf_cntl_t f;
} __attribute__((packed));
struct cpu_defaults_t {
- unsigned char unpack_rd_data : 1;
- unsigned char access_ind_addr_a: 1;
- unsigned char access_ind_addr_b: 1;
- unsigned char access_scratch_reg : 1;
- unsigned char pack_wr_data : 1;
- unsigned char transition_size : 1;
- unsigned char en_read_buf_mode : 1;
- unsigned char rd_fetch_scratch : 1;
+ unsigned char unpack_rd_data : 1;
+ unsigned char access_ind_addr_a : 1;
+ unsigned char access_ind_addr_b : 1;
+ unsigned char access_scratch_reg : 1;
+ unsigned char pack_wr_data : 1;
+ unsigned char transition_size : 1;
+ unsigned char en_read_buf_mode : 1;
+ unsigned char rd_fetch_scratch : 1;
} __attribute__((packed));
union cpu_defaults_u {
- unsigned char val : 8;
- struct cpu_defaults_t f;
+ unsigned char val : 8;
+ struct cpu_defaults_t f;
+} __attribute__((packed));
+
+struct crtc_total_t {
+ unsigned long crtc_h_total : 10;
+ unsigned long : 6;
+ unsigned long crtc_v_total : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union crtc_total_u {
+ unsigned long val : 32;
+ struct crtc_total_t f;
+} __attribute__((packed));
+
+struct crtc_ss_t {
+ unsigned long ss_start : 10;
+ unsigned long : 6;
+ unsigned long ss_end : 10;
+ unsigned long : 2;
+ unsigned long ss_align : 1;
+ unsigned long ss_pol : 1;
+ unsigned long ss_run_mode : 1;
+ unsigned long ss_en : 1;
+} __attribute__((packed));
+
+union crtc_ss_u {
+ unsigned long val : 32;
+ struct crtc_ss_t f;
+} __attribute__((packed));
+
+struct active_h_disp_t {
+ unsigned long active_h_start : 10;
+ unsigned long : 6;
+ unsigned long active_h_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union active_h_disp_u {
+ unsigned long val : 32;
+ struct active_h_disp_t f;
+} __attribute__((packed));
+
+struct active_v_disp_t {
+ unsigned long active_v_start : 10;
+ unsigned long : 6;
+ unsigned long active_v_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union active_v_disp_u {
+ unsigned long val : 32;
+ struct active_v_disp_t f;
+} __attribute__((packed));
+
+struct graphic_h_disp_t {
+ unsigned long graphic_h_start : 10;
+ unsigned long : 6;
+ unsigned long graphic_h_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union graphic_h_disp_u {
+ unsigned long val : 32;
+ struct graphic_h_disp_t f;
+} __attribute__((packed));
+
+struct graphic_v_disp_t {
+ unsigned long graphic_v_start : 10;
+ unsigned long : 6;
+ unsigned long graphic_v_end : 10;
+ unsigned long : 6;
+} __attribute__((packed));
+
+union graphic_v_disp_u{
+ unsigned long val : 32;
+ struct graphic_v_disp_t f;
+} __attribute__((packed));
+
+struct graphic_ctrl_t_w100 {
+ unsigned long color_depth : 3;
+ unsigned long portrait_mode : 2;
+ unsigned long low_power_on : 1;
+ unsigned long req_freq : 4;
+ unsigned long en_crtc : 1;
+ unsigned long en_graphic_req : 1;
+ unsigned long en_graphic_crtc : 1;
+ unsigned long total_req_graphic : 9;
+ unsigned long lcd_pclk_on : 1;
+ unsigned long lcd_sclk_on : 1;
+ unsigned long pclk_running : 1;
+ unsigned long sclk_running : 1;
+ unsigned long : 6;
+} __attribute__((packed));
+
+struct graphic_ctrl_t_w32xx {
+ unsigned long color_depth : 3;
+ unsigned long portrait_mode : 2;
+ unsigned long low_power_on : 1;
+ unsigned long req_freq : 4;
+ unsigned long en_crtc : 1;
+ unsigned long en_graphic_req : 1;
+ unsigned long en_graphic_crtc : 1;
+ unsigned long total_req_graphic : 10;
+ unsigned long lcd_pclk_on : 1;
+ unsigned long lcd_sclk_on : 1;
+ unsigned long pclk_running : 1;
+ unsigned long sclk_running : 1;
+ unsigned long : 5;
+} __attribute__((packed));
+
+union graphic_ctrl_u {
+ unsigned long val : 32;
+ struct graphic_ctrl_t_w100 f_w100;
+ struct graphic_ctrl_t_w32xx f_w32xx;
} __attribute__((packed));
struct video_ctrl_t {
- unsigned long video_mode : 1;
- unsigned long keyer_en : 1;
- unsigned long en_video_req : 1;
- unsigned long en_graphic_req_video : 1;
- unsigned long en_video_crtc : 1;
- unsigned long video_hor_exp : 2;
- unsigned long video_ver_exp : 2;
- unsigned long uv_combine : 1;
- unsigned long total_req_video : 9;
- unsigned long video_ch_sel : 1;
- unsigned long video_portrait : 2;
- unsigned long yuv2rgb_en : 1;
- unsigned long yuv2rgb_option : 1;
- unsigned long video_inv_hor : 1;
- unsigned long video_inv_ver : 1;
- unsigned long gamma_sel : 2;
- unsigned long dis_limit : 1;
- unsigned long en_uv_hblend : 1;
- unsigned long rgb_gamma_sel : 2;
+ unsigned long video_mode : 1;
+ unsigned long keyer_en : 1;
+ unsigned long en_video_req : 1;
+ unsigned long en_graphic_req_video : 1;
+ unsigned long en_video_crtc : 1;
+ unsigned long video_hor_exp : 2;
+ unsigned long video_ver_exp : 2;
+ unsigned long uv_combine : 1;
+ unsigned long total_req_video : 9;
+ unsigned long video_ch_sel : 1;
+ unsigned long video_portrait : 2;
+ unsigned long yuv2rgb_en : 1;
+ unsigned long yuv2rgb_option : 1;
+ unsigned long video_inv_hor : 1;
+ unsigned long video_inv_ver : 1;
+ unsigned long gamma_sel : 2;
+ unsigned long dis_limit : 1;
+ unsigned long en_uv_hblend : 1;
+ unsigned long rgb_gamma_sel : 2;
} __attribute__((packed));
union video_ctrl_u {
- unsigned long val : 32;
- struct video_ctrl_t f;
+ unsigned long val : 32;
+ struct video_ctrl_t f;
} __attribute__((packed));
struct disp_db_buf_cntl_rd_t {
- unsigned long en_db_buf : 1;
- unsigned long update_db_buf_done : 1;
- unsigned long db_buf_cntl : 6;
- unsigned long : 24;
+ unsigned long en_db_buf : 1;
+ unsigned long update_db_buf_done : 1;
+ unsigned long db_buf_cntl : 6;
+ unsigned long : 24;
} __attribute__((packed));
union disp_db_buf_cntl_rd_u {
- unsigned long val : 32;
- struct disp_db_buf_cntl_rd_t f;
+ unsigned long val : 32;
+ struct disp_db_buf_cntl_rd_t f;
} __attribute__((packed));
struct disp_db_buf_cntl_wr_t {
- unsigned long en_db_buf : 1;
- unsigned long update_db_buf : 1;
- unsigned long db_buf_cntl : 6;
- unsigned long : 24;
+ unsigned long en_db_buf : 1;
+ unsigned long update_db_buf : 1;
+ unsigned long db_buf_cntl : 6;
+ unsigned long : 24;
} __attribute__((packed));
union disp_db_buf_cntl_wr_u {
- unsigned long val : 32;
- struct disp_db_buf_cntl_wr_t f;
+ unsigned long val : 32;
+ struct disp_db_buf_cntl_wr_t f;
} __attribute__((packed));
struct gamma_value1_t {
- unsigned long gamma1 : 8;
- unsigned long gamma2 : 8;
- unsigned long gamma3 : 8;
- unsigned long gamma4 : 8;
+ unsigned long gamma1 : 8;
+ unsigned long gamma2 : 8;
+ unsigned long gamma3 : 8;
+ unsigned long gamma4 : 8;
} __attribute__((packed));
union gamma_value1_u {
- unsigned long val : 32;
- struct gamma_value1_t f;
+ unsigned long val : 32;
+ struct gamma_value1_t f;
} __attribute__((packed));
struct gamma_value2_t {
- unsigned long gamma5 : 8;
- unsigned long gamma6 : 8;
- unsigned long gamma7 : 8;
- unsigned long gamma8 : 8;
+ unsigned long gamma5 : 8;
+ unsigned long gamma6 : 8;
+ unsigned long gamma7 : 8;
+ unsigned long gamma8 : 8;
} __attribute__((packed));
union gamma_value2_u {
- unsigned long val : 32;
- struct gamma_value2_t f;
+ unsigned long val : 32;
+ struct gamma_value2_t f;
} __attribute__((packed));
struct gamma_slope_t {
- unsigned long slope1 : 3;
- unsigned long slope2 : 3;
- unsigned long slope3 : 3;
- unsigned long slope4 : 3;
- unsigned long slope5 : 3;
- unsigned long slope6 : 3;
- unsigned long slope7 : 3;
- unsigned long slope8 : 3;
- unsigned long : 8;
+ unsigned long slope1 : 3;
+ unsigned long slope2 : 3;
+ unsigned long slope3 : 3;
+ unsigned long slope4 : 3;
+ unsigned long slope5 : 3;
+ unsigned long slope6 : 3;
+ unsigned long slope7 : 3;
+ unsigned long slope8 : 3;
+ unsigned long : 8;
} __attribute__((packed));
union gamma_slope_u {
- unsigned long val : 32;
- struct gamma_slope_t f;
+ unsigned long val : 32;
+ struct gamma_slope_t f;
} __attribute__((packed));
struct mc_ext_mem_location_t {
- unsigned long mc_ext_mem_start : 16;
- unsigned long mc_ext_mem_top : 16;
+ unsigned long mc_ext_mem_start : 16;
+ unsigned long mc_ext_mem_top : 16;
} __attribute__((packed));
union mc_ext_mem_location_u {
- unsigned long val : 32;
- struct mc_ext_mem_location_t f;
+ unsigned long val : 32;
+ struct mc_ext_mem_location_t f;
+} __attribute__((packed));
+
+struct mc_fb_location_t {
+ unsigned long mc_fb_start : 16;
+ unsigned long mc_fb_top : 16;
+} __attribute__((packed));
+
+union mc_fb_location_u {
+ unsigned long val : 32;
+ struct mc_fb_location_t f;
} __attribute__((packed));
struct clk_pin_cntl_t {
- unsigned long osc_en : 1;
- unsigned long osc_gain : 5;
- unsigned long dont_use_xtalin : 1;
- unsigned long xtalin_pm_en : 1;
- unsigned long xtalin_dbl_en : 1;
- unsigned long : 7;
- unsigned long cg_debug : 16;
+ unsigned long osc_en : 1;
+ unsigned long osc_gain : 5;
+ unsigned long dont_use_xtalin : 1;
+ unsigned long xtalin_pm_en : 1;
+ unsigned long xtalin_dbl_en : 1;
+ unsigned long : 7;
+ unsigned long cg_debug : 16;
} __attribute__((packed));
union clk_pin_cntl_u {
- unsigned long val : 32;
- struct clk_pin_cntl_t f;
+ unsigned long val : 32;
+ struct clk_pin_cntl_t f;
} __attribute__((packed));
struct pll_ref_fb_div_t {
- unsigned long pll_ref_div : 4;
- unsigned long : 4;
- unsigned long pll_fb_div_int : 6;
- unsigned long : 2;
- unsigned long pll_fb_div_frac : 3;
- unsigned long : 1;
- unsigned long pll_reset_time : 4;
- unsigned long pll_lock_time : 8;
+ unsigned long pll_ref_div : 4;
+ unsigned long : 4;
+ unsigned long pll_fb_div_int : 6;
+ unsigned long : 2;
+ unsigned long pll_fb_div_frac : 3;
+ unsigned long : 1;
+ unsigned long pll_reset_time : 4;
+ unsigned long pll_lock_time : 8;
} __attribute__((packed));
union pll_ref_fb_div_u {
- unsigned long val : 32;
- struct pll_ref_fb_div_t f;
+ unsigned long val : 32;
+ struct pll_ref_fb_div_t f;
} __attribute__((packed));
struct pll_cntl_t {
- unsigned long pll_pwdn : 1;
- unsigned long pll_reset : 1;
- unsigned long pll_pm_en : 1;
- unsigned long pll_mode : 1;
- unsigned long pll_refclk_sel : 1;
- unsigned long pll_fbclk_sel : 1;
- unsigned long pll_tcpoff : 1;
- unsigned long pll_pcp : 3;
- unsigned long pll_pvg : 3;
- unsigned long pll_vcofr : 1;
- unsigned long pll_ioffset : 2;
- unsigned long pll_pecc_mode : 2;
- unsigned long pll_pecc_scon : 2;
- unsigned long pll_dactal : 4;
- unsigned long pll_cp_clip : 2;
- unsigned long pll_conf : 3;
- unsigned long pll_mbctrl : 2;
- unsigned long pll_ring_off : 1;
+ unsigned long pll_pwdn : 1;
+ unsigned long pll_reset : 1;
+ unsigned long pll_pm_en : 1;
+ unsigned long pll_mode : 1;
+ unsigned long pll_refclk_sel : 1;
+ unsigned long pll_fbclk_sel : 1;
+ unsigned long pll_tcpoff : 1;
+ unsigned long pll_pcp : 3;
+ unsigned long pll_pvg : 3;
+ unsigned long pll_vcofr : 1;
+ unsigned long pll_ioffset : 2;
+ unsigned long pll_pecc_mode : 2;
+ unsigned long pll_pecc_scon : 2;
+ unsigned long pll_dactal : 4;
+ unsigned long pll_cp_clip : 2;
+ unsigned long pll_conf : 3;
+ unsigned long pll_mbctrl : 2;
+ unsigned long pll_ring_off : 1;
} __attribute__((packed));
union pll_cntl_u {
- unsigned long val : 32;
- struct pll_cntl_t f;
+ unsigned long val : 32;
+ struct pll_cntl_t f;
} __attribute__((packed));
struct sclk_cntl_t {
- unsigned long sclk_src_sel : 2;
- unsigned long : 2;
- unsigned long sclk_post_div_fast : 4;
- unsigned long sclk_clkon_hys : 3;
- unsigned long sclk_post_div_slow : 4;
- unsigned long disp_cg_ok2switch_en : 1;
- unsigned long sclk_force_reg : 1;
- unsigned long sclk_force_disp : 1;
- unsigned long sclk_force_mc : 1;
- unsigned long sclk_force_extmc : 1;
- unsigned long sclk_force_cp : 1;
- unsigned long sclk_force_e2 : 1;
- unsigned long sclk_force_e3 : 1;
- unsigned long sclk_force_idct : 1;
- unsigned long sclk_force_bist : 1;
- unsigned long busy_extend_cp : 1;
- unsigned long busy_extend_e2 : 1;
- unsigned long busy_extend_e3 : 1;
- unsigned long busy_extend_idct : 1;
- unsigned long : 3;
+ unsigned long sclk_src_sel : 2;
+ unsigned long : 2;
+ unsigned long sclk_post_div_fast : 4;
+ unsigned long sclk_clkon_hys : 3;
+ unsigned long sclk_post_div_slow : 4;
+ unsigned long disp_cg_ok2switch_en : 1;
+ unsigned long sclk_force_reg : 1;
+ unsigned long sclk_force_disp : 1;
+ unsigned long sclk_force_mc : 1;
+ unsigned long sclk_force_extmc : 1;
+ unsigned long sclk_force_cp : 1;
+ unsigned long sclk_force_e2 : 1;
+ unsigned long sclk_force_e3 : 1;
+ unsigned long sclk_force_idct : 1;
+ unsigned long sclk_force_bist : 1;
+ unsigned long busy_extend_cp : 1;
+ unsigned long busy_extend_e2 : 1;
+ unsigned long busy_extend_e3 : 1;
+ unsigned long busy_extend_idct : 1;
+ unsigned long : 3;
} __attribute__((packed));
union sclk_cntl_u {
- unsigned long val : 32;
- struct sclk_cntl_t f;
+ unsigned long val : 32;
+ struct sclk_cntl_t f;
} __attribute__((packed));
struct pclk_cntl_t {
- unsigned long pclk_src_sel : 2;
- unsigned long : 2;
- unsigned long pclk_post_div : 4;
- unsigned long : 8;
- unsigned long pclk_force_disp : 1;
- unsigned long : 15;
+ unsigned long pclk_src_sel : 2;
+ unsigned long : 2;
+ unsigned long pclk_post_div : 4;
+ unsigned long : 8;
+ unsigned long pclk_force_disp : 1;
+ unsigned long : 15;
} __attribute__((packed));
union pclk_cntl_u {
- unsigned long val : 32;
- struct pclk_cntl_t f;
+ unsigned long val : 32;
+ struct pclk_cntl_t f;
} __attribute__((packed));
+
+#define TESTCLK_SRC_PLL 0x01
+#define TESTCLK_SRC_SCLK 0x02
+#define TESTCLK_SRC_PCLK 0x03
+/* 4 and 5 seem to by XTAL/M */
+#define TESTCLK_SRC_XTAL 0x06
+
struct clk_test_cntl_t {
- unsigned long testclk_sel : 4;
- unsigned long : 3;
- unsigned long start_check_freq : 1;
- unsigned long tstcount_rst : 1;
- unsigned long : 15;
- unsigned long test_count : 8;
+ unsigned long testclk_sel : 4;
+ unsigned long : 3;
+ unsigned long start_check_freq : 1;
+ unsigned long tstcount_rst : 1;
+ unsigned long : 15;
+ unsigned long test_count : 8;
} __attribute__((packed));
union clk_test_cntl_u {
- unsigned long val : 32;
- struct clk_test_cntl_t f;
+ unsigned long val : 32;
+ struct clk_test_cntl_t f;
} __attribute__((packed));
struct pwrmgt_cntl_t {
- unsigned long pwm_enable : 1;
- unsigned long : 1;
- unsigned long pwm_mode_req : 2;
- unsigned long pwm_wakeup_cond : 2;
- unsigned long pwm_fast_noml_hw_en : 1;
- unsigned long pwm_noml_fast_hw_en : 1;
- unsigned long pwm_fast_noml_cond : 4;
- unsigned long pwm_noml_fast_cond : 4;
- unsigned long pwm_idle_timer : 8;
- unsigned long pwm_busy_timer : 8;
+ unsigned long pwm_enable : 1;
+ unsigned long : 1;
+ unsigned long pwm_mode_req : 2;
+ unsigned long pwm_wakeup_cond : 2;
+ unsigned long pwm_fast_noml_hw_en : 1;
+ unsigned long pwm_noml_fast_hw_en : 1;
+ unsigned long pwm_fast_noml_cond : 4;
+ unsigned long pwm_noml_fast_cond : 4;
+ unsigned long pwm_idle_timer : 8;
+ unsigned long pwm_busy_timer : 8;
} __attribute__((packed));
union pwrmgt_cntl_u {
- unsigned long val : 32;
- struct pwrmgt_cntl_t f;
+ unsigned long val : 32;
+ struct pwrmgt_cntl_t f;
} __attribute__((packed));
#endif
diff --git a/fs/Kconfig b/fs/Kconfig
index e54be70..5e81790 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -382,10 +382,8 @@
usage (also called disk quotas). Currently, it works for the
ext2, ext3, and reiserfs file system. ext3 also supports journalled
quotas for which you don't need to run quotacheck(8) after an unclean
- shutdown. You need additional software in order to use quota support
- (you can download sources from
- <http://www.sf.net/projects/linuxquota/>). For further details, read
- the Quota mini-HOWTO, available from
+ shutdown.
+ For further details, read the Quota mini-HOWTO, available from
<http://www.tldp.org/docs.html#howto>, or the documentation provided
with the quota tools. Probably the quota support is only useful for
multi user systems. If unsure, say N.
@@ -403,8 +401,7 @@
depends on QUOTA
help
This quota format allows using quotas with 32-bit UIDs/GIDs. If you
- need this functionality say Y here. Note that you will need recent
- quota utilities (>= 3.01) for new quota format with this kernel.
+ need this functionality say Y here.
config QUOTACTL
bool
@@ -783,28 +780,6 @@
Designers of embedded systems may wish to say N here to conserve space.
-config DEVPTS_FS_XATTR
- bool "/dev/pts Extended Attributes"
- depends on UNIX98_PTYS
- help
- Extended attributes are name:value pairs associated with inodes by
- the kernel or by users (see the attr(5) manual page, or visit
- <http://acl.bestbits.at/> for details).
-
- If unsure, say N.
-
-config DEVPTS_FS_SECURITY
- bool "/dev/pts Security Labels"
- depends on DEVPTS_FS_XATTR
- help
- Security labels support alternative access control models
- implemented by security modules like SELinux. This option
- enables an extended attribute handler for file security
- labels in the /dev/pts filesystem.
-
- If you are not using a security module that requires using
- extended attributes for file security labels, say N.
-
config TMPFS
bool "Virtual memory file system support (former shm fs)"
help
@@ -817,27 +792,6 @@
See <file:Documentation/filesystems/tmpfs.txt> for details.
-config TMPFS_XATTR
- bool "tmpfs Extended Attributes"
- depends on TMPFS
- help
- Extended attributes are name:value pairs associated with inodes by
- the kernel or by users (see the attr(5) manual page, or visit
- <http://acl.bestbits.at/> for details).
-
- If unsure, say N.
-
-config TMPFS_SECURITY
- bool "tmpfs Security Labels"
- depends on TMPFS_XATTR
- help
- Security labels support alternative access control models
- implemented by security modules like SELinux. This option
- enables an extended attribute handler for file security
- labels in the tmpfs filesystem.
- If you are not using a security module that requires using
- extended attributes for file security labels, say N.
-
config HUGETLBFS
bool "HugeTLB file system support"
depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN
@@ -859,6 +813,18 @@
To compile this as a module, choose M here: the module will be called
ramfs.
+config RELAYFS_FS
+ tristate "Relayfs file system support"
+ ---help---
+ Relayfs is a high-speed data relay filesystem designed to provide
+ an efficient mechanism for tools and facilities to relay large
+ amounts of data from kernel space to user space.
+
+ To compile this code as a module, choose M here: the module will be
+ called relayfs.
+
+ If unsure, say N.
+
endmenu
menu "Miscellaneous filesystems"
diff --git a/fs/Makefile b/fs/Makefile
index cf95eb8..1515830 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -90,6 +90,7 @@
obj-$(CONFIG_AUTOFS4_FS) += autofs4/
obj-$(CONFIG_ADFS_FS) += adfs/
obj-$(CONFIG_UDF_FS) += udf/
+obj-$(CONFIG_RELAYFS_FS) += relayfs/
obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
obj-$(CONFIG_JFS_FS) += jfs/
obj-$(CONFIG_XFS_FS) += xfs/
diff --git a/fs/aio.c b/fs/aio.c
index 06d7d439..4f641ab 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -567,6 +567,10 @@
atomic_inc(&mm->mm_count);
tsk->mm = mm;
tsk->active_mm = mm;
+ /*
+ * Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise
+ * it won't work. Update it accordingly if you change it here
+ */
activate_mm(active_mm, mm);
task_unlock(tsk);
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index c8998dc..7974efa 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -520,7 +520,7 @@
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
down_write(¤t->mm->mmap_sem);
- textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0);
+ textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE, 0);
up_write(¤t->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos)
diff --git a/fs/bio.c b/fs/bio.c
index 1f2d464..a7d4fd3a 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/mempool.h>
#include <linux/workqueue.h>
+#include <scsi/sg.h> /* for struct sg_iovec */
#define BIO_POOL_SIZE 256
@@ -104,18 +105,22 @@
return bvl;
}
-/*
- * default destructor for a bio allocated with bio_alloc_bioset()
- */
-static void bio_destructor(struct bio *bio)
+void bio_free(struct bio *bio, struct bio_set *bio_set)
{
const int pool_idx = BIO_POOL_IDX(bio);
- struct bio_set *bs = bio->bi_set;
BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
- mempool_free(bio->bi_io_vec, bs->bvec_pools[pool_idx]);
- mempool_free(bio, bs->bio_pool);
+ mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
+ mempool_free(bio, bio_set->bio_pool);
+}
+
+/*
+ * default destructor for a bio allocated with bio_alloc_bioset()
+ */
+static void bio_fs_destructor(struct bio *bio)
+{
+ bio_free(bio, fs_bio_set);
}
inline void bio_init(struct bio *bio)
@@ -171,8 +176,6 @@
bio->bi_max_vecs = bvec_slabs[idx].nr_vecs;
}
bio->bi_io_vec = bvl;
- bio->bi_destructor = bio_destructor;
- bio->bi_set = bs;
}
out:
return bio;
@@ -180,7 +183,12 @@
struct bio *bio_alloc(unsigned int __nocast gfp_mask, int nr_iovecs)
{
- return bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+ struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+
+ if (bio)
+ bio->bi_destructor = bio_fs_destructor;
+
+ return bio;
}
void zero_fill_bio(struct bio *bio)
@@ -273,8 +281,10 @@
{
struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set);
- if (b)
+ if (b) {
+ b->bi_destructor = bio_fs_destructor;
__bio_clone(b, bio);
+ }
return b;
}
@@ -546,22 +556,34 @@
return ERR_PTR(ret);
}
-static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev,
- unsigned long uaddr, unsigned int len,
- int write_to_vm)
+static struct bio *__bio_map_user_iov(request_queue_t *q,
+ struct block_device *bdev,
+ struct sg_iovec *iov, int iov_count,
+ int write_to_vm)
{
- unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
- unsigned long start = uaddr >> PAGE_SHIFT;
- const int nr_pages = end - start;
- int ret, offset, i;
+ int i, j;
+ int nr_pages = 0;
struct page **pages;
struct bio *bio;
+ int cur_page = 0;
+ int ret, offset;
- /*
- * transfer and buffer must be aligned to at least hardsector
- * size for now, in the future we can relax this restriction
- */
- if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q)))
+ for (i = 0; i < iov_count; i++) {
+ unsigned long uaddr = (unsigned long)iov[i].iov_base;
+ unsigned long len = iov[i].iov_len;
+ unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = uaddr >> PAGE_SHIFT;
+
+ nr_pages += end - start;
+ /*
+ * transfer and buffer must be aligned to at least hardsector
+ * size for now, in the future we can relax this restriction
+ */
+ if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q)))
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!nr_pages)
return ERR_PTR(-EINVAL);
bio = bio_alloc(GFP_KERNEL, nr_pages);
@@ -573,42 +595,54 @@
if (!pages)
goto out;
- down_read(¤t->mm->mmap_sem);
- ret = get_user_pages(current, current->mm, uaddr, nr_pages,
- write_to_vm, 0, pages, NULL);
- up_read(¤t->mm->mmap_sem);
+ memset(pages, 0, nr_pages * sizeof(struct page *));
- if (ret < nr_pages)
- goto out;
+ for (i = 0; i < iov_count; i++) {
+ unsigned long uaddr = (unsigned long)iov[i].iov_base;
+ unsigned long len = iov[i].iov_len;
+ unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = uaddr >> PAGE_SHIFT;
+ const int local_nr_pages = end - start;
+ const int page_limit = cur_page + local_nr_pages;
+
+ down_read(¤t->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm, uaddr,
+ local_nr_pages,
+ write_to_vm, 0, &pages[cur_page], NULL);
+ up_read(¤t->mm->mmap_sem);
- bio->bi_bdev = bdev;
+ if (ret < local_nr_pages)
+ goto out_unmap;
- offset = uaddr & ~PAGE_MASK;
- for (i = 0; i < nr_pages; i++) {
- unsigned int bytes = PAGE_SIZE - offset;
- if (len <= 0)
- break;
+ offset = uaddr & ~PAGE_MASK;
+ for (j = cur_page; j < page_limit; j++) {
+ unsigned int bytes = PAGE_SIZE - offset;
- if (bytes > len)
- bytes = len;
+ if (len <= 0)
+ break;
+
+ if (bytes > len)
+ bytes = len;
+ /*
+ * sorry...
+ */
+ if (__bio_add_page(q, bio, pages[j], bytes, offset) < bytes)
+ break;
+
+ len -= bytes;
+ offset = 0;
+ }
+
+ cur_page = j;
/*
- * sorry...
+ * release the pages we didn't map into the bio, if any
*/
- if (__bio_add_page(q, bio, pages[i], bytes, offset) < bytes)
- break;
-
- len -= bytes;
- offset = 0;
+ while (j < page_limit)
+ page_cache_release(pages[j++]);
}
- /*
- * release the pages we didn't map into the bio, if any
- */
- while (i < nr_pages)
- page_cache_release(pages[i++]);
-
kfree(pages);
/*
@@ -617,9 +651,17 @@
if (!write_to_vm)
bio->bi_rw |= (1 << BIO_RW);
+ bio->bi_bdev = bdev;
bio->bi_flags |= (1 << BIO_USER_MAPPED);
return bio;
-out:
+
+ out_unmap:
+ for (i = 0; i < nr_pages; i++) {
+ if(!pages[i])
+ break;
+ page_cache_release(pages[i]);
+ }
+ out:
kfree(pages);
bio_put(bio);
return ERR_PTR(ret);
@@ -639,9 +681,33 @@
struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev,
unsigned long uaddr, unsigned int len, int write_to_vm)
{
- struct bio *bio;
+ struct sg_iovec iov;
- bio = __bio_map_user(q, bdev, uaddr, len, write_to_vm);
+ iov.iov_base = (__user void *)uaddr;
+ iov.iov_len = len;
+
+ return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm);
+}
+
+/**
+ * bio_map_user_iov - map user sg_iovec table into bio
+ * @q: the request_queue_t for the bio
+ * @bdev: destination block device
+ * @iov: the iovec.
+ * @iov_count: number of elements in the iovec
+ * @write_to_vm: bool indicating writing to pages or not
+ *
+ * Map the user space address into a bio suitable for io to a block
+ * device. Returns an error pointer in case of error.
+ */
+struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev,
+ struct sg_iovec *iov, int iov_count,
+ int write_to_vm)
+{
+ struct bio *bio;
+ int len = 0, i;
+
+ bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm);
if (IS_ERR(bio))
return bio;
@@ -654,6 +720,9 @@
*/
bio_get(bio);
+ for (i = 0; i < iov_count; i++)
+ len += iov[i].iov_len;
+
if (bio->bi_size == len)
return bio;
@@ -698,6 +767,82 @@
bio_put(bio);
}
+static int bio_map_kern_endio(struct bio *bio, unsigned int bytes_done, int err)
+{
+ if (bio->bi_size)
+ return 1;
+
+ bio_put(bio);
+ return 0;
+}
+
+
+static struct bio *__bio_map_kern(request_queue_t *q, void *data,
+ unsigned int len, unsigned int gfp_mask)
+{
+ unsigned long kaddr = (unsigned long)data;
+ unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = kaddr >> PAGE_SHIFT;
+ const int nr_pages = end - start;
+ int offset, i;
+ struct bio *bio;
+
+ bio = bio_alloc(gfp_mask, nr_pages);
+ if (!bio)
+ return ERR_PTR(-ENOMEM);
+
+ offset = offset_in_page(kaddr);
+ for (i = 0; i < nr_pages; i++) {
+ unsigned int bytes = PAGE_SIZE - offset;
+
+ if (len <= 0)
+ break;
+
+ if (bytes > len)
+ bytes = len;
+
+ if (__bio_add_page(q, bio, virt_to_page(data), bytes,
+ offset) < bytes)
+ break;
+
+ data += bytes;
+ len -= bytes;
+ offset = 0;
+ }
+
+ bio->bi_end_io = bio_map_kern_endio;
+ return bio;
+}
+
+/**
+ * bio_map_kern - map kernel address into bio
+ * @q: the request_queue_t for the bio
+ * @data: pointer to buffer to map
+ * @len: length in bytes
+ * @gfp_mask: allocation flags for bio allocation
+ *
+ * Map the kernel address into a bio suitable for io to a block
+ * device. Returns an error pointer in case of error.
+ */
+struct bio *bio_map_kern(request_queue_t *q, void *data, unsigned int len,
+ unsigned int gfp_mask)
+{
+ struct bio *bio;
+
+ bio = __bio_map_kern(q, data, len, gfp_mask);
+ if (IS_ERR(bio))
+ return bio;
+
+ if (bio->bi_size == len)
+ return bio;
+
+ /*
+ * Don't support partial mappings.
+ */
+ bio_put(bio);
+ return ERR_PTR(-EINVAL);
+}
+
/*
* bio_set_pages_dirty() and bio_check_pages_dirty() are support functions
* for performing direct-IO in BIOs.
@@ -1075,6 +1220,7 @@
EXPORT_SYMBOL(bio_alloc);
EXPORT_SYMBOL(bio_put);
+EXPORT_SYMBOL(bio_free);
EXPORT_SYMBOL(bio_endio);
EXPORT_SYMBOL(bio_init);
EXPORT_SYMBOL(__bio_clone);
@@ -1085,6 +1231,7 @@
EXPORT_SYMBOL(bio_get_nr_vecs);
EXPORT_SYMBOL(bio_map_user);
EXPORT_SYMBOL(bio_unmap_user);
+EXPORT_SYMBOL(bio_map_kern);
EXPORT_SYMBOL(bio_pair_release);
EXPORT_SYMBOL(bio_split);
EXPORT_SYMBOL(bio_split_pool);
diff --git a/fs/buffer.c b/fs/buffer.c
index 6a25d7d..1c62203 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -917,8 +917,7 @@
* contents - it is a noop if I/O is still in
* flight on potentially older contents.
*/
- wait_on_buffer(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(SWRITE, 1, &bh);
brelse(bh);
spin_lock(lock);
}
@@ -2793,21 +2792,22 @@
/**
* ll_rw_block: low-level access to block devices (DEPRECATED)
- * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
+ * @rw: whether to %READ or %WRITE or %SWRITE or maybe %READA (readahead)
* @nr: number of &struct buffer_heads in the array
* @bhs: array of pointers to &struct buffer_head
*
- * ll_rw_block() takes an array of pointers to &struct buffer_heads,
- * and requests an I/O operation on them, either a %READ or a %WRITE.
- * The third %READA option is described in the documentation for
- * generic_make_request() which ll_rw_block() calls.
+ * ll_rw_block() takes an array of pointers to &struct buffer_heads, and
+ * requests an I/O operation on them, either a %READ or a %WRITE. The third
+ * %SWRITE is like %WRITE only we make sure that the *current* data in buffers
+ * are sent to disk. The fourth %READA option is described in the documentation
+ * for generic_make_request() which ll_rw_block() calls.
*
* This function drops any buffer that it cannot get a lock on (with the
- * BH_Lock state bit), any buffer that appears to be clean when doing a
- * write request, and any buffer that appears to be up-to-date when doing
- * read request. Further it marks as clean buffers that are processed for
- * writing (the buffer cache won't assume that they are actually clean until
- * the buffer gets unlocked).
+ * BH_Lock state bit) unless SWRITE is required, any buffer that appears to be
+ * clean when doing a write request, and any buffer that appears to be
+ * up-to-date when doing read request. Further it marks as clean buffers that
+ * are processed for writing (the buffer cache won't assume that they are
+ * actually clean until the buffer gets unlocked).
*
* ll_rw_block sets b_end_io to simple completion handler that marks
* the buffer up-to-date (if approriate), unlocks the buffer and wakes
@@ -2823,11 +2823,13 @@
for (i = 0; i < nr; i++) {
struct buffer_head *bh = bhs[i];
- if (test_set_buffer_locked(bh))
+ if (rw == SWRITE)
+ lock_buffer(bh);
+ else if (test_set_buffer_locked(bh))
continue;
get_bh(bh);
- if (rw == WRITE) {
+ if (rw == WRITE || rw == SWRITE) {
if (test_clear_buffer_dirty(bh)) {
bh->b_end_io = end_buffer_write_sync;
submit_bh(WRITE, bh);
@@ -3046,10 +3048,9 @@
{
struct buffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);
if (ret) {
- preempt_disable();
- __get_cpu_var(bh_accounting).nr++;
+ get_cpu_var(bh_accounting).nr++;
recalc_bh_state();
- preempt_enable();
+ put_cpu_var(bh_accounting);
}
return ret;
}
@@ -3059,10 +3060,9 @@
{
BUG_ON(!list_empty(&bh->b_assoc_buffers));
kmem_cache_free(bh_cachep, bh);
- preempt_disable();
- __get_cpu_var(bh_accounting).nr--;
+ get_cpu_var(bh_accounting).nr--;
recalc_bh_state();
- preempt_enable();
+ put_cpu_var(bh_accounting);
}
EXPORT_SYMBOL(free_buffer_head);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e568cc4..3217ac5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -836,7 +836,7 @@
/* go from value to value + temp_len condensing
double commas to singles. Note that this ends up
allocating a few bytes too many, which is ok */
- vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+ vol->password = kzalloc(temp_len, GFP_KERNEL);
if(vol->password == NULL) {
printk("CIFS: no memory for pass\n");
return 1;
@@ -851,7 +851,7 @@
}
vol->password[j] = 0;
} else {
- vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
+ vol->password = kzalloc(temp_len+1, GFP_KERNEL);
if(vol->password == NULL) {
printk("CIFS: no memory for pass\n");
return 1;
@@ -1317,7 +1317,7 @@
sessinit is sent but no second negprot */
struct rfc1002_session_packet * ses_init_buf;
struct smb_hdr * smb_buf;
- ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+ ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
if(ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32;
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
@@ -1964,7 +1964,7 @@
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
- ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+ ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
if(ses->serverOS == NULL)
goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverOS,
@@ -1976,7 +1976,7 @@
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1);
- ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+ ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
if(ses->serverNOS == NULL)
goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverNOS,
@@ -1994,7 +1994,7 @@
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
ses->serverDomain =
- kcalloc(1, 2*(len+1),GFP_KERNEL);
+ kzalloc(2*(len+1),GFP_KERNEL);
if(ses->serverDomain == NULL)
goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverDomain,
@@ -2005,22 +2005,22 @@
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- kcalloc(1, 2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
/* if these kcallocs fail not much we
can do, but better to not fail the
sesssetup itself */
ses->serverDomain =
- kcalloc(1, 2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
ses->serverNOS =
- kcalloc(1, 2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+ ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
if(ses->serverOS == NULL)
goto sesssetup_nomem;
strncpy(ses->serverOS,bcc_ptr, len);
@@ -2030,7 +2030,7 @@
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+ ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
if(ses->serverNOS == NULL)
goto sesssetup_nomem;
strncpy(ses->serverNOS, bcc_ptr, len);
@@ -2039,7 +2039,7 @@
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+ ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
if(ses->serverDomain == NULL)
goto sesssetup_nomem;
strncpy(ses->serverDomain, bcc_ptr, len);
@@ -2240,7 +2240,7 @@
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
@@ -2254,7 +2254,7 @@
remaining_words
- 1);
ses->serverNOS =
- kcalloc(1, 2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->serverNOS,
(wchar_t *)bcc_ptr,
@@ -2267,7 +2267,7 @@
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
- ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
+ ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
cifs_strfromUCS_le(ses->serverDomain,
(wchar_t *)bcc_ptr,
len,
@@ -2278,10 +2278,10 @@
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- kcalloc(1, 2,GFP_KERNEL);
+ kzalloc(2,GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
- ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
+ ses->serverDomain = kzalloc(2, GFP_KERNEL);
+ ses->serverNOS = kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
@@ -2289,7 +2289,7 @@
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
+ ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len;
@@ -2297,14 +2297,14 @@
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+ ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
+ ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
@@ -2554,7 +2554,7 @@
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
@@ -2569,7 +2569,7 @@
remaining_words
- 1);
ses->serverNOS =
- kcalloc(1, 2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
@@ -2586,7 +2586,7 @@
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
ses->serverDomain =
- kcalloc(1, 2 *
+ kzalloc(2 *
(len +
1),
GFP_KERNEL);
@@ -2612,13 +2612,13 @@
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- kcalloc(1, 2,
+ kzalloc(2,
GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
ses->serverDomain =
- kcalloc(1, 2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
ses->serverNOS =
- kcalloc(1, 2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
@@ -2626,7 +2626,7 @@
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
ses->serverOS =
- kcalloc(1, len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverOS,
bcc_ptr, len);
@@ -2637,7 +2637,7 @@
len = strnlen(bcc_ptr, 1024);
ses->serverNOS =
- kcalloc(1, len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
@@ -2646,7 +2646,7 @@
len = strnlen(bcc_ptr, 1024);
ses->serverDomain =
- kcalloc(1, len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
@@ -2948,7 +2948,7 @@
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
@@ -2963,7 +2963,7 @@
remaining_words
- 1);
ses->serverNOS =
- kcalloc(1, 2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
@@ -2979,7 +2979,7 @@
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string not always null terminated (e.g. for Windows XP & 2000) */
ses->serverDomain =
- kcalloc(1, 2 *
+ kzalloc(2 *
(len +
1),
GFP_KERNEL);
@@ -3004,17 +3004,17 @@
= 0;
} /* else no more room so create dummy domain string */
else
- ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
+ ses->serverDomain = kzalloc(2,GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
- ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
+ ses->serverDomain = kzalloc(2, GFP_KERNEL);
+ ses->serverNOS = kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
if (((long) bcc_ptr + len) -
(long) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+ ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len;
@@ -3022,14 +3022,14 @@
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
+ ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
+ ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
@@ -3141,7 +3141,7 @@
if(tcon->nativeFileSystem)
kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- kcalloc(1, length + 2, GFP_KERNEL);
+ kzalloc(length + 2, GFP_KERNEL);
cifs_strfromUCS_le(tcon->nativeFileSystem,
(wchar_t *) bcc_ptr,
length, nls_codepage);
@@ -3159,7 +3159,7 @@
if(tcon->nativeFileSystem)
kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- kcalloc(1, length + 1, GFP_KERNEL);
+ kzalloc(length + 1, GFP_KERNEL);
strncpy(tcon->nativeFileSystem, bcc_ptr,
length);
}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3f3538d..d335269 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -145,24 +145,23 @@
return -ENOMEM;
}
- if(nd) {
- if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
- desiredAccess = GENERIC_READ;
- else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) {
- desiredAccess = GENERIC_WRITE;
- write_only = TRUE;
- } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
- /* GENERIC_ALL is too much permission to request */
- /* can cause unnecessary access denied on create */
- /* desiredAccess = GENERIC_ALL; */
- desiredAccess = GENERIC_READ | GENERIC_WRITE;
+ if(nd && (nd->flags & LOOKUP_OPEN)) {
+ int oflags = nd->intent.open.flags;
+
+ desiredAccess = 0;
+ if (oflags & FMODE_READ)
+ desiredAccess |= GENERIC_READ;
+ if (oflags & FMODE_WRITE) {
+ desiredAccess |= GENERIC_WRITE;
+ if (!(oflags & FMODE_READ))
+ write_only = TRUE;
}
- if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
disposition = FILE_CREATE;
- else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+ else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
disposition = FILE_OVERWRITE_IF;
- else if((nd->intent.open.flags & O_CREAT) == O_CREAT)
+ else if((oflags & O_CREAT) == O_CREAT)
disposition = FILE_OPEN_IF;
else {
cFYI(1,("Create flag not set in create function"));
diff --git a/fs/compat.c b/fs/compat.c
index 6b06b6b..8c66570 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -310,96 +310,6 @@
__initcall(init_sys32_ioctl);
-int register_ioctl32_conversion(unsigned int cmd,
- ioctl_trans_handler_t handler)
-{
- struct ioctl_trans *t;
- struct ioctl_trans *new_t;
- unsigned long hash = ioctl32_hash(cmd);
-
- new_t = kmalloc(sizeof(*new_t), GFP_KERNEL);
- if (!new_t)
- return -ENOMEM;
-
- down_write(&ioctl32_sem);
- for (t = ioctl32_hash_table[hash]; t; t = t->next) {
- if (t->cmd == cmd) {
- printk(KERN_ERR "Trying to register duplicated ioctl32 "
- "handler %x\n", cmd);
- up_write(&ioctl32_sem);
- kfree(new_t);
- return -EINVAL;
- }
- }
- new_t->next = NULL;
- new_t->cmd = cmd;
- new_t->handler = handler;
- ioctl32_insert_translation(new_t);
-
- up_write(&ioctl32_sem);
- return 0;
-}
-EXPORT_SYMBOL(register_ioctl32_conversion);
-
-static inline int builtin_ioctl(struct ioctl_trans *t)
-{
- return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
-}
-
-/* Problem:
- This function cannot unregister duplicate ioctls, because they are not
- unique.
- When they happen we need to extend the prototype to pass the handler too. */
-
-int unregister_ioctl32_conversion(unsigned int cmd)
-{
- unsigned long hash = ioctl32_hash(cmd);
- struct ioctl_trans *t, *t1;
-
- down_write(&ioctl32_sem);
-
- t = ioctl32_hash_table[hash];
- if (!t) {
- up_write(&ioctl32_sem);
- return -EINVAL;
- }
-
- if (t->cmd == cmd) {
- if (builtin_ioctl(t)) {
- printk("%p tried to unregister builtin ioctl %x\n",
- __builtin_return_address(0), cmd);
- } else {
- ioctl32_hash_table[hash] = t->next;
- up_write(&ioctl32_sem);
- kfree(t);
- return 0;
- }
- }
- while (t->next) {
- t1 = t->next;
- if (t1->cmd == cmd) {
- if (builtin_ioctl(t1)) {
- printk("%p tried to unregister builtin "
- "ioctl %x\n",
- __builtin_return_address(0), cmd);
- goto out;
- } else {
- t->next = t1->next;
- up_write(&ioctl32_sem);
- kfree(t1);
- return 0;
- }
- }
- t = t1;
- }
- printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n",
- cmd);
-out:
- up_write(&ioctl32_sem);
- return -EINVAL;
-}
-EXPORT_SYMBOL(unregister_ioctl32_conversion);
-
static void compat_ioctl_error(struct file *filp, unsigned int fd,
unsigned int cmd, unsigned long arg)
{
@@ -720,14 +630,14 @@
struct compat_ncp_mount_data {
compat_int_t version;
compat_uint_t ncp_fd;
- compat_uid_t mounted_uid;
+ __compat_uid_t mounted_uid;
compat_pid_t wdog_pid;
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
compat_uint_t time_out;
compat_uint_t retry_count;
compat_uint_t flags;
- compat_uid_t uid;
- compat_gid_t gid;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
@@ -784,9 +694,9 @@
struct compat_smb_mount_data {
compat_int_t version;
- compat_uid_t mounted_uid;
- compat_uid_t uid;
- compat_gid_t gid;
+ __compat_uid_t mounted_uid;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
@@ -1365,6 +1275,16 @@
}
/*
+ * Exactly like fs/open.c:sys_open(), except that it doesn't set the
+ * O_LARGEFILE flag.
+ */
+asmlinkage long
+compat_sys_open(const char __user *filename, int flags, int mode)
+{
+ return do_sys_open(filename, flags, mode);
+}
+
+/*
* compat_count() counts the number of arguments/envelopes. It is basically
* a copy of count() from fs/exec.c, except that it works with 32 bit argv
* and envp pointers.
@@ -1808,8 +1728,8 @@
compat_dev_t ex32_dev;
compat_ino_t ex32_ino;
compat_int_t ex32_flags;
- compat_uid_t ex32_anon_uid;
- compat_gid_t ex32_anon_gid;
+ __compat_uid_t ex32_anon_uid;
+ __compat_gid_t ex32_anon_gid;
};
struct compat_nfsctl_fdparm {
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 6c285efa..7fe85415 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -39,12 +39,47 @@
#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1)
#define OFFSET(x) ((x)->i_ino)
-static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
+
+static int cramfs_iget5_test(struct inode *inode, void *opaque)
{
- struct inode * inode = new_inode(sb);
+ struct cramfs_inode *cramfs_inode = opaque;
+
+ if (inode->i_ino != CRAMINO(cramfs_inode))
+ return 0; /* does not match */
+
+ if (inode->i_ino != 1)
+ return 1;
+
+ /* all empty directories, char, block, pipe, and sock, share inode #1 */
+
+ if ((inode->i_mode != cramfs_inode->mode) ||
+ (inode->i_gid != cramfs_inode->gid) ||
+ (inode->i_uid != cramfs_inode->uid))
+ return 0; /* does not match */
+
+ if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) &&
+ (inode->i_rdev != old_decode_dev(cramfs_inode->size)))
+ return 0; /* does not match */
+
+ return 1; /* matches */
+}
+
+static int cramfs_iget5_set(struct inode *inode, void *opaque)
+{
+ struct cramfs_inode *cramfs_inode = opaque;
+ inode->i_ino = CRAMINO(cramfs_inode);
+ return 0;
+}
+
+static struct inode *get_cramfs_inode(struct super_block *sb,
+ struct cramfs_inode * cramfs_inode)
+{
+ struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
+ cramfs_iget5_test, cramfs_iget5_set,
+ cramfs_inode);
static struct timespec zerotime;
- if (inode) {
+ if (inode && (inode->i_state & I_NEW)) {
inode->i_mode = cramfs_inode->mode;
inode->i_uid = cramfs_inode->uid;
inode->i_size = cramfs_inode->size;
@@ -58,7 +93,6 @@
but it's the best we can do without reading the directory
contents. 1 yields the right result in GNU find, even
without -noleaf option. */
- insert_inode_hash(inode);
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &cramfs_aops;
@@ -74,6 +108,7 @@
init_special_inode(inode, inode->i_mode,
old_decode_dev(cramfs_inode->size));
}
+ unlock_new_inode(inode);
}
return inode;
}
diff --git a/fs/devpts/Makefile b/fs/devpts/Makefile
index 5800df2..236696e 100644
--- a/fs/devpts/Makefile
+++ b/fs/devpts/Makefile
@@ -5,4 +5,3 @@
obj-$(CONFIG_UNIX98_PTYS) += devpts.o
devpts-$(CONFIG_UNIX98_PTYS) := inode.o
-devpts-$(CONFIG_DEVPTS_FS_SECURITY) += xattr_security.o
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 1571c8d..f2be44d 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -18,28 +18,9 @@
#include <linux/mount.h>
#include <linux/tty.h>
#include <linux/devpts_fs.h>
-#include <linux/xattr.h>
#define DEVPTS_SUPER_MAGIC 0x1cd1
-extern struct xattr_handler devpts_xattr_security_handler;
-
-static struct xattr_handler *devpts_xattr_handlers[] = {
-#ifdef CONFIG_DEVPTS_FS_SECURITY
- &devpts_xattr_security_handler,
-#endif
- NULL
-};
-
-static struct inode_operations devpts_file_inode_operations = {
-#ifdef CONFIG_DEVPTS_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .listxattr = generic_listxattr,
- .removexattr = generic_removexattr,
-#endif
-};
-
static struct vfsmount *devpts_mnt;
static struct dentry *devpts_root;
@@ -102,7 +83,6 @@
s->s_blocksize_bits = 10;
s->s_magic = DEVPTS_SUPER_MAGIC;
s->s_op = &devpts_sops;
- s->s_xattr = devpts_xattr_handlers;
s->s_time_gran = 1;
inode = new_inode(s);
@@ -175,7 +155,6 @@
inode->i_gid = config.setgid ? config.gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
- inode->i_op = &devpts_file_inode_operations;
inode->u.generic_ip = tty;
dentry = get_node(number);
diff --git a/fs/devpts/xattr_security.c b/fs/devpts/xattr_security.c
deleted file mode 100644
index 864cb5c..0000000
--- a/fs/devpts/xattr_security.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Security xattr support for devpts.
- *
- * Author: Stephen Smalley <sds@epoch.ncsc.mil>
- * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/security.h>
-#include <linux/xattr.h>
-
-static size_t
-devpts_xattr_security_list(struct inode *inode, char *list, size_t list_len,
- const char *name, size_t name_len)
-{
- return security_inode_listsecurity(inode, list, list_len);
-}
-
-static int
-devpts_xattr_security_get(struct inode *inode, const char *name,
- void *buffer, size_t size)
-{
- if (strcmp(name, "") == 0)
- return -EINVAL;
- return security_inode_getsecurity(inode, name, buffer, size);
-}
-
-static int
-devpts_xattr_security_set(struct inode *inode, const char *name,
- const void *value, size_t size, int flags)
-{
- if (strcmp(name, "") == 0)
- return -EINVAL;
- return security_inode_setsecurity(inode, name, value, size, flags);
-}
-
-struct xattr_handler devpts_xattr_security_handler = {
- .prefix = XATTR_SECURITY_PREFIX,
- .list = devpts_xattr_security_list,
- .get = devpts_xattr_security_get,
- .set = devpts_xattr_security_set,
-};
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index dcfe331..3c0c7c6 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -19,6 +19,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/blkdev.h>
@@ -27,6 +28,8 @@
#include <linux/buffer_head.h>
#include <linux/smp_lock.h>
#include <linux/vfs.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
#include <asm/uaccess.h>
#include "ext2.h"
#include "xattr.h"
@@ -201,6 +204,26 @@
#endif
}
+static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(vfs->mnt_sb);
+
+ if (sbi->s_mount_opt & EXT2_MOUNT_GRPID)
+ seq_puts(seq, ",grpid");
+ else
+ seq_puts(seq, ",nogrpid");
+
+#if defined(CONFIG_QUOTA)
+ if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA)
+ seq_puts(seq, ",usrquota");
+
+ if (sbi->s_mount_opt & EXT2_MOUNT_GRPQUOTA)
+ seq_puts(seq, ",grpquota");
+#endif
+
+ return 0;
+}
+
#ifdef CONFIG_QUOTA
static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off);
static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);
@@ -218,6 +241,7 @@
.statfs = ext2_statfs,
.remount_fs = ext2_remount,
.clear_inode = ext2_clear_inode,
+ .show_options = ext2_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext2_quota_read,
.quota_write = ext2_quota_write,
@@ -256,10 +280,11 @@
enum {
Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
- Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
- Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
- Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
- Opt_ignore, Opt_err,
+ Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
+ Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug,
+ Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
+ Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
+ Opt_usrquota, Opt_grpquota
};
static match_table_t tokens = {
@@ -288,10 +313,10 @@
{Opt_acl, "acl"},
{Opt_noacl, "noacl"},
{Opt_xip, "xip"},
- {Opt_ignore, "grpquota"},
+ {Opt_grpquota, "grpquota"},
{Opt_ignore, "noquota"},
- {Opt_ignore, "quota"},
- {Opt_ignore, "usrquota"},
+ {Opt_quota, "quota"},
+ {Opt_usrquota, "usrquota"},
{Opt_err, NULL}
};
@@ -406,6 +431,26 @@
printk("EXT2 xip option not supported\n");
#endif
break;
+
+#if defined(CONFIG_QUOTA)
+ case Opt_quota:
+ case Opt_usrquota:
+ set_opt(sbi->s_mount_opt, USRQUOTA);
+ break;
+
+ case Opt_grpquota:
+ set_opt(sbi->s_mount_opt, GRPQUOTA);
+ break;
+#else
+ case Opt_quota:
+ case Opt_usrquota:
+ case Opt_grpquota:
+ printk(KERN_ERR
+ "EXT2-fs: quota operations not supported.\n");
+
+ break;
+#endif
+
case Opt_ignore:
break;
default:
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 3c3c6e3..a93c360 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -35,6 +35,7 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include "xattr.h"
#include "acl.h"
@@ -509,8 +510,41 @@
kfree(rsv);
}
-#ifdef CONFIG_QUOTA
+static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct ext3_sb_info *sbi = EXT3_SB(vfs->mnt_sb);
+ if (sbi->s_mount_opt & EXT3_MOUNT_JOURNAL_DATA)
+ seq_puts(seq, ",data=journal");
+
+ if (sbi->s_mount_opt & EXT3_MOUNT_ORDERED_DATA)
+ seq_puts(seq, ",data=ordered");
+
+ if (sbi->s_mount_opt & EXT3_MOUNT_WRITEBACK_DATA)
+ seq_puts(seq, ",data=writeback");
+
+#if defined(CONFIG_QUOTA)
+ if (sbi->s_jquota_fmt)
+ seq_printf(seq, ",jqfmt=%s",
+ (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
+
+ if (sbi->s_qf_names[USRQUOTA])
+ seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+ if (sbi->s_qf_names[GRPQUOTA])
+ seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+ if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA)
+ seq_puts(seq, ",usrquota");
+
+ if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)
+ seq_puts(seq, ",grpquota");
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_QUOTA
#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
@@ -569,6 +603,7 @@
.statfs = ext3_statfs,
.remount_fs = ext3_remount,
.clear_inode = ext3_clear_inode,
+ .show_options = ext3_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext3_quota_read,
.quota_write = ext3_quota_write,
@@ -590,7 +625,8 @@
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
- Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
+ Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
+ Opt_grpquota
};
static match_table_t tokens = {
@@ -634,10 +670,10 @@
{Opt_grpjquota, "grpjquota=%s"},
{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
- {Opt_quota, "grpquota"},
+ {Opt_grpquota, "grpquota"},
{Opt_noquota, "noquota"},
{Opt_quota, "quota"},
- {Opt_quota, "usrquota"},
+ {Opt_usrquota, "usrquota"},
{Opt_barrier, "barrier=%u"},
{Opt_err, NULL},
{Opt_resize, "resize"},
@@ -903,7 +939,13 @@
sbi->s_jquota_fmt = QFMT_VFS_V0;
break;
case Opt_quota:
+ case Opt_usrquota:
set_opt(sbi->s_mount_opt, QUOTA);
+ set_opt(sbi->s_mount_opt, USRQUOTA);
+ break;
+ case Opt_grpquota:
+ set_opt(sbi->s_mount_opt, QUOTA);
+ set_opt(sbi->s_mount_opt, GRPQUOTA);
break;
case Opt_noquota:
if (sb_any_quota_enabled(sb)) {
@@ -912,8 +954,13 @@
return 0;
}
clear_opt(sbi->s_mount_opt, QUOTA);
+ clear_opt(sbi->s_mount_opt, USRQUOTA);
+ clear_opt(sbi->s_mount_opt, GRPQUOTA);
break;
#else
+ case Opt_quota:
+ case Opt_usrquota:
+ case Opt_grpquota:
case Opt_usrjquota:
case Opt_grpjquota:
case Opt_offusrjquota:
@@ -924,7 +971,6 @@
"EXT3-fs: journalled quota options not "
"supported.\n");
break;
- case Opt_quota:
case Opt_noquota:
break;
#endif
@@ -962,14 +1008,38 @@
}
}
#ifdef CONFIG_QUOTA
- if (!sbi->s_jquota_fmt && (sbi->s_qf_names[USRQUOTA] ||
- sbi->s_qf_names[GRPQUOTA])) {
- printk(KERN_ERR
- "EXT3-fs: journalled quota format not specified.\n");
- return 0;
+ if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+ if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) &&
+ sbi->s_qf_names[USRQUOTA])
+ clear_opt(sbi->s_mount_opt, USRQUOTA);
+
+ if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) &&
+ sbi->s_qf_names[GRPQUOTA])
+ clear_opt(sbi->s_mount_opt, GRPQUOTA);
+
+ if ((sbi->s_qf_names[USRQUOTA] &&
+ (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) ||
+ (sbi->s_qf_names[GRPQUOTA] &&
+ (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) {
+ printk(KERN_ERR "EXT3-fs: old and new quota "
+ "format mixing.\n");
+ return 0;
+ }
+
+ if (!sbi->s_jquota_fmt) {
+ printk(KERN_ERR "EXT3-fs: journalled quota format "
+ "not specified.\n");
+ return 0;
+ }
+ } else {
+ if (sbi->s_jquota_fmt) {
+ printk(KERN_ERR "EXT3-fs: journalled quota format "
+ "specified with no journalling "
+ "enabled.\n");
+ return 0;
+ }
}
#endif
-
return 1;
}
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index e5ae1b7..895049b 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -30,6 +30,29 @@
| (de - (struct msdos_dir_entry *)bh->b_data);
}
+static inline void fat_dir_readahead(struct inode *dir, sector_t iblock,
+ sector_t phys)
+{
+ struct super_block *sb = dir->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct buffer_head *bh;
+ int sec;
+
+ /* This is not a first sector of cluster, or sec_per_clus == 1 */
+ if ((iblock & (sbi->sec_per_clus - 1)) || sbi->sec_per_clus == 1)
+ return;
+ /* root dir of FAT12/FAT16 */
+ if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO))
+ return;
+
+ bh = sb_getblk(sb, phys);
+ if (bh && !buffer_uptodate(bh)) {
+ for (sec = 0; sec < sbi->sec_per_clus; sec++)
+ sb_breadahead(sb, phys + sec);
+ }
+ brelse(bh);
+}
+
/* Returns the inode number of the directory entry at offset pos. If bh is
non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
returned in bh.
@@ -58,6 +81,8 @@
if (err || !phys)
return -1; /* beyond EOF or error */
+ fat_dir_readahead(dir, iblock, phys);
+
*bh = sb_bread(sb, phys);
if (*bh == NULL) {
printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
@@ -635,8 +660,7 @@
EODir:
filp->f_pos = cpos;
FillFailed:
- if (bh)
- brelse(bh);
+ brelse(bh);
if (unicode)
free_page((unsigned long)unicode);
out:
diff --git a/fs/file_table.c b/fs/file_table.c
index 1d3de78..43e9e17 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -89,7 +89,6 @@
rwlock_init(&f->f_owner.lock);
/* f->f_version: 0 */
INIT_LIST_HEAD(&f->f_list);
- f->f_maxcount = INT_MAX;
return f;
over:
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 27f66d3..6aa6fbe 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -155,7 +155,7 @@
sbp->s_flags |= MS_RDONLY;
- infp = kcalloc(1, sizeof(*infp), GFP_KERNEL);
+ infp = kzalloc(sizeof(*infp), GFP_KERNEL);
if (!infp) {
printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
return -ENOMEM;
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
index a096c5a..3d5cdc6 100644
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -13,8 +13,6 @@
#include "btree.h"
-#define REF_PAGES 0
-
void hfs_bnode_read(struct hfs_bnode *node, void *buf,
int off, int len)
{
@@ -289,9 +287,7 @@
page_cache_release(page);
goto fail;
}
-#if !REF_PAGES
page_cache_release(page);
-#endif
node->page[i] = page;
}
@@ -449,13 +445,6 @@
{
if (node) {
atomic_inc(&node->refcnt);
-#if REF_PAGES
- {
- int i;
- for (i = 0; i < node->tree->pages_per_bnode; i++)
- get_page(node->page[i]);
- }
-#endif
dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
node->tree->cnid, node->this, atomic_read(&node->refcnt));
}
@@ -472,20 +461,12 @@
node->tree->cnid, node->this, atomic_read(&node->refcnt));
if (!atomic_read(&node->refcnt))
BUG();
- if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) {
-#if REF_PAGES
- for (i = 0; i < tree->pages_per_bnode; i++)
- put_page(node->page[i]);
-#endif
+ if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
return;
- }
for (i = 0; i < tree->pages_per_bnode; i++) {
if (!node->page[i])
continue;
mark_page_accessed(node->page[i]);
-#if REF_PAGES
- put_page(node->page[i]);
-#endif
}
if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 65dedef..2fcd679 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -20,12 +20,12 @@
*
* Given the ID of the parent and the name build a search key.
*/
-void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name)
+void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, struct qstr *name)
{
key->cat.reserved = 0;
key->cat.ParID = cpu_to_be32(parent);
if (name) {
- hfs_triv2mac(&key->cat.CName, name);
+ hfs_asc2mac(sb, &key->cat.CName, name);
key->key_len = 6 + key->cat.CName.len;
} else {
memset(&key->cat.CName, 0, sizeof(struct hfs_name));
@@ -62,13 +62,14 @@
}
}
-static int hfs_cat_build_thread(hfs_cat_rec *rec, int type,
+static int hfs_cat_build_thread(struct super_block *sb,
+ hfs_cat_rec *rec, int type,
u32 parentid, struct qstr *name)
{
rec->type = type;
memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
rec->thread.ParID = cpu_to_be32(parentid);
- hfs_triv2mac(&rec->thread.CName, name);
+ hfs_asc2mac(sb, &rec->thread.CName, name);
return sizeof(struct hfs_cat_thread);
}
@@ -93,8 +94,8 @@
sb = dir->i_sb;
hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
- hfs_cat_build_key(fd.search_key, cnid, NULL);
- entry_size = hfs_cat_build_thread(&entry, S_ISDIR(inode->i_mode) ?
+ hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
+ entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
HFS_CDR_THD : HFS_CDR_FTH,
dir->i_ino, str);
err = hfs_brec_find(&fd);
@@ -107,7 +108,7 @@
if (err)
goto err2;
- hfs_cat_build_key(fd.search_key, dir->i_ino, str);
+ hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
entry_size = hfs_cat_build_record(&entry, cnid, inode);
err = hfs_brec_find(&fd);
if (err != -ENOENT) {
@@ -127,7 +128,7 @@
return 0;
err1:
- hfs_cat_build_key(fd.search_key, cnid, NULL);
+ hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
if (!hfs_brec_find(&fd))
hfs_brec_remove(&fd);
err2:
@@ -176,7 +177,7 @@
hfs_cat_rec rec;
int res, len, type;
- hfs_cat_build_key(fd->search_key, cnid, NULL);
+ hfs_cat_build_key(sb, fd->search_key, cnid, NULL);
res = hfs_brec_read(fd, &rec, sizeof(rec));
if (res)
return res;
@@ -211,7 +212,7 @@
sb = dir->i_sb;
hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
- hfs_cat_build_key(fd.search_key, dir->i_ino, str);
+ hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
res = hfs_brec_find(&fd);
if (res)
goto out;
@@ -239,7 +240,7 @@
if (res)
goto out;
- hfs_cat_build_key(fd.search_key, cnid, NULL);
+ hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
res = hfs_brec_find(&fd);
if (!res) {
res = hfs_brec_remove(&fd);
@@ -280,7 +281,7 @@
dst_fd = src_fd;
/* find the old dir entry and read the data */
- hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+ hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
@@ -289,7 +290,7 @@
src_fd.entrylength);
/* create new dir entry with the data from the old entry */
- hfs_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
+ hfs_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
err = hfs_brec_find(&dst_fd);
if (err != -ENOENT) {
if (!err)
@@ -305,7 +306,7 @@
mark_inode_dirty(dst_dir);
/* finally remove the old entry */
- hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+ hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
@@ -321,7 +322,7 @@
goto out;
/* remove old thread entry */
- hfs_cat_build_key(src_fd.search_key, cnid, NULL);
+ hfs_cat_build_key(sb, src_fd.search_key, cnid, NULL);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
@@ -330,8 +331,8 @@
goto out;
/* create new thread entry */
- hfs_cat_build_key(dst_fd.search_key, cnid, NULL);
- entry_size = hfs_cat_build_thread(&entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
+ hfs_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
+ entry_size = hfs_cat_build_thread(sb, &entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
dst_dir->i_ino, dst_name);
err = hfs_brec_find(&dst_fd);
if (err != -ENOENT) {
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index c559982..e1f24be 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -28,7 +28,7 @@
dentry->d_op = &hfs_dentry_operations;
hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
- hfs_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
+ hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
res = hfs_brec_read(&fd, &rec, sizeof(rec));
if (res) {
hfs_find_exit(&fd);
@@ -56,7 +56,7 @@
struct inode *inode = filp->f_dentry->d_inode;
struct super_block *sb = inode->i_sb;
int len, err;
- char strbuf[HFS_NAMELEN + 1];
+ char strbuf[HFS_MAX_NAMELEN];
union hfs_cat_rec entry;
struct hfs_find_data fd;
struct hfs_readdir_data *rd;
@@ -66,7 +66,7 @@
return 0;
hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
- hfs_cat_build_key(fd.search_key, inode->i_ino, NULL);
+ hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
err = hfs_brec_find(&fd);
if (err)
goto out;
@@ -111,7 +111,7 @@
}
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
type = entry.type;
- len = hfs_mac2triv(strbuf, &fd.key->cat.CName);
+ len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
if (type == HFS_CDR_DIR) {
if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
printk("HFS: small dir entry\n");
@@ -307,7 +307,8 @@
old_dir, &old_dentry->d_name,
new_dir, &new_dentry->d_name);
if (!res)
- hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
+ hfs_cat_build_key(old_dir->i_sb,
+ (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
new_dir->i_ino, &new_dentry->d_name);
return res;
}
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h
index df6b33a..88099ab 100644
--- a/fs/hfs/hfs.h
+++ b/fs/hfs/hfs.h
@@ -25,6 +25,7 @@
#define HFS_SECTOR_SIZE 512 /* size of an HFS sector */
#define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */
#define HFS_NAMELEN 31 /* maximum length of an HFS filename */
+#define HFS_MAX_NAMELEN 128
#define HFS_MAX_VALENCE 32767U
/* Meanings of the drAtrb field of the MDB,
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 0dc8ef8..aae019a 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -141,6 +141,8 @@
int session, part;
+ struct nls_table *nls_io, *nls_disk;
+
struct semaphore bitmap_lock;
unsigned long flags;
@@ -168,7 +170,7 @@
extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
extern int hfs_cat_move(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *);
-extern void hfs_cat_build_key(btree_key *, u32, struct qstr *);
+extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);
/* dir.c */
extern struct file_operations hfs_dir_operations;
@@ -222,8 +224,8 @@
extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
/* trans.c */
-extern void hfs_triv2mac(struct hfs_name *, struct qstr *);
-extern int hfs_mac2triv(char *, const struct hfs_name *);
+extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
+extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
extern struct timezone sys_tz;
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 7519123..f1570b9 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -160,7 +160,7 @@
init_MUTEX(&HFS_I(inode)->extents_lock);
INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
- hfs_cat_build_key((btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
+ hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
inode->i_ino = HFS_SB(sb)->next_id++;
inode->i_mode = mode;
inode->i_uid = current->fsuid;
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index 217e32f..0a473f7 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -10,6 +10,7 @@
#include <linux/cdrom.h>
#include <linux/genhd.h>
+#include <linux/nls.h>
#include "hfs_fs.h"
#include "btree.h"
@@ -343,6 +344,11 @@
brelse(HFS_SB(sb)->mdb_bh);
brelse(HFS_SB(sb)->alt_mdb_bh);
+ if (HFS_SB(sb)->nls_io)
+ unload_nls(HFS_SB(sb)->nls_io);
+ if (HFS_SB(sb)->nls_disk)
+ unload_nls(HFS_SB(sb)->nls_disk);
+
kfree(HFS_SB(sb));
sb->s_fs_info = NULL;
}
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index ab783f6..c5074ae 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -15,8 +15,11 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/blkdev.h>
+#include <linux/mount.h>
#include <linux/init.h>
+#include <linux/nls.h>
#include <linux/parser.h>
+#include <linux/seq_file.h>
#include <linux/vfs.h>
#include "hfs_fs.h"
@@ -111,6 +114,32 @@
return 0;
}
+static int hfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+ struct hfs_sb_info *sbi = HFS_SB(mnt->mnt_sb);
+
+ if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f))
+ seq_printf(seq, ",creator=%.4s", (char *)&sbi->s_creator);
+ if (sbi->s_type != cpu_to_be32(0x3f3f3f3f))
+ seq_printf(seq, ",type=%.4s", (char *)&sbi->s_type);
+ seq_printf(seq, ",uid=%u,gid=%u", sbi->s_uid, sbi->s_gid);
+ if (sbi->s_file_umask != 0133)
+ seq_printf(seq, ",file_umask=%o", sbi->s_file_umask);
+ if (sbi->s_dir_umask != 0022)
+ seq_printf(seq, ",dir_umask=%o", sbi->s_dir_umask);
+ if (sbi->part >= 0)
+ seq_printf(seq, ",part=%u", sbi->part);
+ if (sbi->session >= 0)
+ seq_printf(seq, ",session=%u", sbi->session);
+ if (sbi->nls_disk)
+ seq_printf(seq, ",codepage=%s", sbi->nls_disk->charset);
+ if (sbi->nls_io)
+ seq_printf(seq, ",iocharset=%s", sbi->nls_io->charset);
+ if (sbi->s_quiet)
+ seq_printf(seq, ",quiet");
+ return 0;
+}
+
static struct inode *hfs_alloc_inode(struct super_block *sb)
{
struct hfs_inode_info *i;
@@ -133,11 +162,13 @@
.write_super = hfs_write_super,
.statfs = hfs_statfs,
.remount_fs = hfs_remount,
+ .show_options = hfs_show_options,
};
enum {
opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask,
opt_part, opt_session, opt_type, opt_creator, opt_quiet,
+ opt_codepage, opt_iocharset,
opt_err
};
@@ -152,6 +183,8 @@
{ opt_type, "type=%s" },
{ opt_creator, "creator=%s" },
{ opt_quiet, "quiet" },
+ { opt_codepage, "codepage=%s" },
+ { opt_iocharset, "iocharset=%s" },
{ opt_err, NULL }
};
@@ -257,11 +290,46 @@
case opt_quiet:
hsb->s_quiet = 1;
break;
+ case opt_codepage:
+ if (hsb->nls_disk) {
+ printk("HFS+-fs: unable to change codepage\n");
+ return 0;
+ }
+ p = match_strdup(&args[0]);
+ hsb->nls_disk = load_nls(p);
+ if (!hsb->nls_disk) {
+ printk("HFS+-fs: unable to load codepage \"%s\"\n", p);
+ kfree(p);
+ return 0;
+ }
+ kfree(p);
+ break;
+ case opt_iocharset:
+ if (hsb->nls_io) {
+ printk("HFS: unable to change iocharset\n");
+ return 0;
+ }
+ p = match_strdup(&args[0]);
+ hsb->nls_io = load_nls(p);
+ if (!hsb->nls_io) {
+ printk("HFS: unable to load iocharset \"%s\"\n", p);
+ kfree(p);
+ return 0;
+ }
+ kfree(p);
+ break;
default:
return 0;
}
}
+ if (hsb->nls_disk && !hsb->nls_io) {
+ hsb->nls_io = load_nls_default();
+ if (!hsb->nls_io) {
+ printk("HFS: unable to load default iocharset\n");
+ return 0;
+ }
+ }
hsb->s_dir_umask &= 0777;
hsb->s_file_umask &= 0577;
diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c
index fb9720a..e673a88 100644
--- a/fs/hfs/trans.c
+++ b/fs/hfs/trans.c
@@ -9,12 +9,15 @@
* with ':' vs. '/' as the path-element separator.
*/
+#include <linux/types.h>
+#include <linux/nls.h>
+
#include "hfs_fs.h"
/*================ Global functions ================*/
/*
- * hfs_mac2triv()
+ * hfs_mac2asc()
*
* Given a 'Pascal String' (a string preceded by a length byte) in
* the Macintosh character set produce the corresponding filename using
@@ -27,23 +30,58 @@
* by ':' which never appears in HFS filenames. All other characters
* are passed unchanged from input to output.
*/
-int hfs_mac2triv(char *out, const struct hfs_name *in)
+int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
{
- const char *p;
- char c;
- int i, len;
+ struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
+ struct nls_table *nls_io = HFS_SB(sb)->nls_io;
+ const char *src;
+ char *dst;
+ int srclen, dstlen, size;
- len = in->len;
- p = in->name;
- for (i = 0; i < len; i++) {
- c = *p++;
- *out++ = c == '/' ? ':' : c;
+ src = in->name;
+ srclen = in->len;
+ dst = out;
+ dstlen = HFS_MAX_NAMELEN;
+ if (nls_io) {
+ wchar_t ch;
+
+ while (srclen > 0) {
+ if (nls_disk) {
+ size = nls_disk->char2uni(src, srclen, &ch);
+ if (size <= 0) {
+ ch = '?';
+ size = 1;
+ }
+ src += size;
+ srclen -= size;
+ } else {
+ ch = *src++;
+ srclen--;
+ }
+ if (ch == '/')
+ ch = ':';
+ size = nls_io->uni2char(ch, dst, dstlen);
+ if (size < 0) {
+ if (size == -ENAMETOOLONG)
+ goto out;
+ *dst = '?';
+ size = 1;
+ }
+ dst += size;
+ dstlen -= size;
+ }
+ } else {
+ char ch;
+
+ while (--srclen >= 0)
+ *dst++ = (ch = *src++) == '/' ? ':' : ch;
}
- return i;
+out:
+ return dst - out;
}
/*
- * hfs_triv2mac()
+ * hfs_asc2mac()
*
* Given an ASCII string (not null-terminated) and its length,
* generate the corresponding filename in the Macintosh character set
@@ -54,19 +92,57 @@
* This routine is a inverse to hfs_mac2triv().
* A ':' is replaced by a '/'.
*/
-void hfs_triv2mac(struct hfs_name *out, struct qstr *in)
+void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, struct qstr *in)
{
+ struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
+ struct nls_table *nls_io = HFS_SB(sb)->nls_io;
const char *src;
- char *dst, c;
- int i, len;
+ char *dst;
+ int srclen, dstlen, size;
- out->len = len = min((unsigned int)HFS_NAMELEN, in->len);
src = in->name;
+ srclen = in->len;
dst = out->name;
- for (i = 0; i < len; i++) {
- c = *src++;
- *dst++ = c == ':' ? '/' : c;
+ dstlen = HFS_NAMELEN;
+ if (nls_io) {
+ wchar_t ch;
+
+ while (srclen > 0) {
+ size = nls_io->char2uni(src, srclen, &ch);
+ if (size < 0) {
+ ch = '?';
+ size = 1;
+ }
+ src += size;
+ srclen -= size;
+ if (ch == ':')
+ ch = '/';
+ if (nls_disk) {
+ size = nls_disk->uni2char(ch, dst, dstlen);
+ if (size < 0) {
+ if (size == -ENAMETOOLONG)
+ goto out;
+ *dst = '?';
+ size = 1;
+ }
+ dst += size;
+ dstlen -= size;
+ } else {
+ *dst++ = ch > 0xff ? '?' : ch;
+ dstlen--;
+ }
+ }
+ } else {
+ char ch;
+
+ if (dstlen > srclen)
+ dstlen = srclen;
+ while (--dstlen >= 0)
+ *dst++ = (ch = *src++) == ':' ? '/' : ch;
}
- for (; i < HFS_NAMELEN; i++)
+out:
+ out->len = dst - (char *)out->name;
+ dstlen = HFS_NAMELEN - out->len;
+ while (--dstlen >= 0)
*dst++ = 0;
}
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index 8868d3b..b85abc6 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -18,8 +18,6 @@
#include "hfsplus_fs.h"
#include "hfsplus_raw.h"
-#define REF_PAGES 0
-
/* Copy a specified range of bytes from the raw data of a node */
void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
{
@@ -450,9 +448,7 @@
page_cache_release(page);
goto fail;
}
-#if !REF_PAGES
page_cache_release(page);
-#endif
node->page[i] = page;
}
@@ -612,13 +608,6 @@
{
if (node) {
atomic_inc(&node->refcnt);
-#if REF_PAGES
- {
- int i;
- for (i = 0; i < node->tree->pages_per_bnode; i++)
- get_page(node->page[i]);
- }
-#endif
dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
node->tree->cnid, node->this, atomic_read(&node->refcnt));
}
@@ -635,20 +624,12 @@
node->tree->cnid, node->this, atomic_read(&node->refcnt));
if (!atomic_read(&node->refcnt))
BUG();
- if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) {
-#if REF_PAGES
- for (i = 0; i < tree->pages_per_bnode; i++)
- put_page(node->page[i]);
-#endif
+ if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
return;
- }
for (i = 0; i < tree->pages_per_bnode; i++) {
if (!node->page[i])
continue;
mark_page_accessed(node->page[i]);
-#if REF_PAGES
- put_page(node->page[i]);
-#endif
}
if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 533094a..2bc0cdd 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -343,8 +343,9 @@
ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
/* options.c */
-int parse_options(char *, struct hfsplus_sb_info *);
-void fill_defaults(struct hfsplus_sb_info *);
+int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
+void hfsplus_fill_defaults(struct hfsplus_sb_info *);
+int hfsplus_show_options(struct seq_file *, struct vfsmount *);
/* tables.c */
extern u16 hfsplus_case_fold_table[];
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 1cca010..cca0818 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -13,6 +13,8 @@
#include <linux/sched.h>
#include <linux/parser.h>
#include <linux/nls.h>
+#include <linux/mount.h>
+#include <linux/seq_file.h>
#include "hfsplus_fs.h"
enum {
@@ -38,7 +40,7 @@
};
/* Initialize an options object to reasonable defaults */
-void fill_defaults(struct hfsplus_sb_info *opts)
+void hfsplus_fill_defaults(struct hfsplus_sb_info *opts)
{
if (!opts)
return;
@@ -63,7 +65,7 @@
/* Parse options from mount. Returns 0 on failure */
/* input is the options passed to mount() as a string */
-int parse_options(char *input, struct hfsplus_sb_info *sbi)
+int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
{
char *p;
substring_t args[MAX_OPT_ARGS];
@@ -160,3 +162,23 @@
return 1;
}
+
+int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+ struct hfsplus_sb_info *sbi = &HFSPLUS_SB(mnt->mnt_sb);
+
+ if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
+ seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
+ if (sbi->type != HFSPLUS_DEF_CR_TYPE)
+ seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
+ seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid);
+ if (sbi->part >= 0)
+ seq_printf(seq, ",part=%u", sbi->part);
+ if (sbi->session >= 0)
+ seq_printf(seq, ",session=%u", sbi->session);
+ if (sbi->nls)
+ seq_printf(seq, ",nls=%s", sbi->nls->charset);
+ if (sbi->flags & HFSPLUS_SB_NODECOMPOSE)
+ seq_printf(seq, ",nodecompose");
+ return 0;
+}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index d55ad67..fd0f0f0 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -217,8 +217,7 @@
vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
- ll_rw_block(WRITE, 1, &HFSPLUS_SB(sb).s_vhbh);
- wait_on_buffer(HFSPLUS_SB(sb).s_vhbh);
+ sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
}
hfs_btree_close(HFSPLUS_SB(sb).cat_tree);
@@ -277,6 +276,7 @@
.write_super = hfsplus_write_super,
.statfs = hfsplus_statfs,
.remount_fs = hfsplus_remount,
+ .show_options = hfsplus_show_options,
};
static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
@@ -297,8 +297,8 @@
memset(sbi, 0, sizeof(HFSPLUS_SB(sb)));
sb->s_fs_info = sbi;
INIT_HLIST_HEAD(&sbi->rsrc_inodes);
- fill_defaults(sbi);
- if (!parse_options(data, sbi)) {
+ hfsplus_fill_defaults(sbi);
+ if (!hfsplus_parse_options(data, sbi)) {
if (!silent)
printk("HFS+-fs: unable to parse mount options\n");
err = -EINVAL;
@@ -415,8 +415,7 @@
vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
- ll_rw_block(WRITE, 1, &HFSPLUS_SB(sb).s_vhbh);
- wait_on_buffer(HFSPLUS_SB(sb).s_vhbh);
+ sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
if (!HFSPLUS_SB(sb).hidden_dir) {
printk("HFS+: create hidden dir...\n");
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 67bca0d..cca3fb6 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -49,7 +49,6 @@
struct timespec ia_atime;
struct timespec ia_mtime;
struct timespec ia_ctime;
- unsigned int ia_attr_flags;
};
extern int stat_file(const char *path, unsigned long long *inode_out,
diff --git a/fs/inode.c b/fs/inode.c
index e57f172..71df1b1 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1195,9 +1195,6 @@
if (!timespec_equal(&inode->i_atime, &now)) {
inode->i_atime = now;
mark_inode_dirty_sync(inode);
- } else {
- if (!timespec_equal(&inode->i_atime, &now))
- inode->i_atime = now;
}
}
diff --git a/fs/inotify.c b/fs/inotify.c
index 2e4e2a5..a37e9fb 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -37,6 +37,7 @@
#include <asm/ioctls.h>
static atomic_t inotify_cookie;
+static atomic_t inotify_watches;
static kmem_cache_t *watch_cachep;
static kmem_cache_t *event_cachep;
@@ -422,6 +423,7 @@
get_inotify_watch(watch);
atomic_inc(&dev->user->inotify_watches);
+ atomic_inc(&inotify_watches);
return watch;
}
@@ -454,6 +456,7 @@
list_del(&watch->d_list);
atomic_dec(&dev->user->inotify_watches);
+ atomic_dec(&inotify_watches);
idr_remove(&dev->idr, watch->wd);
put_inotify_watch(watch);
}
@@ -532,6 +535,9 @@
struct dentry *parent;
struct inode *inode;
+ if (!atomic_read (&inotify_watches))
+ return;
+
spin_lock(&dentry->d_lock);
parent = dentry->d_parent;
inode = parent->d_inode;
@@ -925,6 +931,7 @@
struct nameidata nd;
struct file *filp;
int ret, fput_needed;
+ int mask_add = 0;
filp = fget_light(fd, &fput_needed);
if (unlikely(!filp))
@@ -947,6 +954,9 @@
down(&inode->inotify_sem);
down(&dev->sem);
+ if (mask & IN_MASK_ADD)
+ mask_add = 1;
+
/* don't let user-space set invalid bits: we don't want flags set */
mask &= IN_ALL_EVENTS;
if (unlikely(!mask)) {
@@ -960,7 +970,10 @@
*/
old = inode_find_dev(inode, dev);
if (unlikely(old)) {
- old->mask = mask;
+ if (mask_add)
+ old->mask |= mask;
+ else
+ old->mask = mask;
ret = old->wd;
goto out;
}
@@ -1043,6 +1056,7 @@
inotify_max_user_watches = 8192;
atomic_set(&inotify_cookie, 0);
+ atomic_set(&inotify_watches, 0);
watch_cachep = kmem_cache_create("inotify_watch_cache",
sizeof(struct inotify_watch),
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 5a97e34..014a51f 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -204,7 +204,7 @@
int i;
spin_unlock(&journal->j_list_lock);
- ll_rw_block(WRITE, *batch_count, bhs);
+ ll_rw_block(SWRITE, *batch_count, bhs);
spin_lock(&journal->j_list_lock);
for (i = 0; i < *batch_count; i++) {
struct buffer_head *bh = bhs[i];
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index dac720c..2a3e310 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -358,7 +358,7 @@
jbd_debug(2, "submit %d writes\n",
bufs);
spin_unlock(&journal->j_list_lock);
- ll_rw_block(WRITE, bufs, wbuf);
+ ll_rw_block(SWRITE, bufs, wbuf);
journal_brelse_array(wbuf, bufs);
bufs = 0;
goto write_out_data;
@@ -381,7 +381,7 @@
if (bufs) {
spin_unlock(&journal->j_list_lock);
- ll_rw_block(WRITE, bufs, wbuf);
+ ll_rw_block(SWRITE, bufs, wbuf);
journal_brelse_array(wbuf, bufs);
spin_lock(&journal->j_list_lock);
}
@@ -720,11 +720,17 @@
J_ASSERT(commit_transaction->t_log_list == NULL);
restart_loop:
+ /*
+ * As there are other places (journal_unmap_buffer()) adding buffers
+ * to this list we have to be careful and hold the j_list_lock.
+ */
+ spin_lock(&journal->j_list_lock);
while (commit_transaction->t_forget) {
transaction_t *cp_transaction;
struct buffer_head *bh;
jh = commit_transaction->t_forget;
+ spin_unlock(&journal->j_list_lock);
bh = jh2bh(jh);
jbd_lock_bh_state(bh);
J_ASSERT_JH(jh, jh->b_transaction == commit_transaction ||
@@ -792,9 +798,25 @@
journal_remove_journal_head(bh); /* needs a brelse */
release_buffer_page(bh);
}
+ cond_resched_lock(&journal->j_list_lock);
+ }
+ spin_unlock(&journal->j_list_lock);
+ /*
+ * This is a bit sleazy. We borrow j_list_lock to protect
+ * journal->j_committing_transaction in __journal_remove_checkpoint.
+ * Really, __journal_remove_checkpoint should be using j_state_lock but
+ * it's a bit hassle to hold that across __journal_remove_checkpoint
+ */
+ spin_lock(&journal->j_state_lock);
+ spin_lock(&journal->j_list_lock);
+ /*
+ * Now recheck if some buffers did not get attached to the transaction
+ * while the lock was dropped...
+ */
+ if (commit_transaction->t_forget) {
spin_unlock(&journal->j_list_lock);
- if (cond_resched())
- goto restart_loop;
+ spin_unlock(&journal->j_state_lock);
+ goto restart_loop;
}
/* Done with this transaction! */
@@ -803,14 +825,6 @@
J_ASSERT(commit_transaction->t_state == T_COMMIT);
- /*
- * This is a bit sleazy. We borrow j_list_lock to protect
- * journal->j_committing_transaction in __journal_remove_checkpoint.
- * Really, __jornal_remove_checkpoint should be using j_state_lock but
- * it's a bit hassle to hold that across __journal_remove_checkpoint
- */
- spin_lock(&journal->j_state_lock);
- spin_lock(&journal->j_list_lock);
commit_transaction->t_state = T_FINISHED;
J_ASSERT(commit_transaction == journal->j_committing_transaction);
journal->j_commit_sequence = commit_transaction->t_tid;
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 5e7b439..7ae2c4f 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -65,7 +65,6 @@
EXPORT_SYMBOL(journal_create);
EXPORT_SYMBOL(journal_load);
EXPORT_SYMBOL(journal_destroy);
-EXPORT_SYMBOL(journal_recover);
EXPORT_SYMBOL(journal_update_superblock);
EXPORT_SYMBOL(journal_abort);
EXPORT_SYMBOL(journal_errno);
@@ -81,6 +80,7 @@
EXPORT_SYMBOL(journal_force_commit);
static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+static void __journal_abort_soft (journal_t *journal, int errno);
/*
* Helper function used to manage commit timeouts
@@ -93,16 +93,6 @@
wake_up_process(p);
}
-/* Static check for data structure consistency. There's no code
- * invoked --- we'll just get a linker failure if things aren't right.
- */
-void __journal_internal_check(void)
-{
- extern void journal_bad_superblock_size(void);
- if (sizeof(struct journal_superblock_s) != 1024)
- journal_bad_superblock_size();
-}
-
/*
* kjournald: The main thread function used to manage a logging device
* journal.
@@ -119,16 +109,12 @@
* known as checkpointing, and this thread is responsible for that job.
*/
-journal_t *current_journal; // AKPM: debug
-
-int kjournald(void *arg)
+static int kjournald(void *arg)
{
journal_t *journal = (journal_t *) arg;
transaction_t *transaction;
struct timer_list timer;
- current_journal = journal;
-
daemonize("kjournald");
/* Set up an interval timer which can be used to trigger a
@@ -193,6 +179,8 @@
if (transaction && time_after_eq(jiffies,
transaction->t_expires))
should_sleep = 0;
+ if (journal->j_flags & JFS_UNMOUNT)
+ should_sleep = 0;
if (should_sleep) {
spin_unlock(&journal->j_state_lock);
schedule();
@@ -969,7 +957,7 @@
if (wait)
sync_dirty_buffer(bh);
else
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(SWRITE, 1, &bh);
out:
/* If we have just flushed the log (by marking s_start==0), then
@@ -1439,7 +1427,7 @@
* device this journal is present.
*/
-const char *journal_dev_name(journal_t *journal, char *buffer)
+static const char *journal_dev_name(journal_t *journal, char *buffer)
{
struct block_device *bdev;
@@ -1485,7 +1473,7 @@
/* Soft abort: record the abort error status in the journal superblock,
* but don't do any other IO. */
-void __journal_abort_soft (journal_t *journal, int errno)
+static void __journal_abort_soft (journal_t *journal, int errno)
{
if (journal->j_flags & JFS_ABORT)
return;
@@ -1880,7 +1868,7 @@
static struct proc_dir_entry *proc_jbd_debug;
-int read_jbd_debug(char *page, char **start, off_t off,
+static int read_jbd_debug(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int ret;
@@ -1890,7 +1878,7 @@
return ret;
}
-int write_jbd_debug(struct file *file, const char __user *buffer,
+static int write_jbd_debug(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char buf[32];
@@ -1979,6 +1967,14 @@
{
int ret;
+/* Static check for data structure consistency. There's no code
+ * invoked --- we'll just get a linker failure if things aren't right.
+ */
+ extern void journal_bad_superblock_size(void);
+ if (sizeof(struct journal_superblock_s) != 1024)
+ journal_bad_superblock_size();
+
+
ret = journal_init_caches();
if (ret != 0)
journal_destroy_caches();
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index d327a59..a561441 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -116,7 +116,8 @@
(block << (hash_shift - 12))) & (table->hash_size - 1);
}
-int insert_revoke_hash(journal_t *journal, unsigned long blocknr, tid_t seq)
+static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
+ tid_t seq)
{
struct list_head *hash_list;
struct jbd_revoke_record_s *record;
@@ -613,7 +614,7 @@
set_buffer_jwrite(bh);
BUFFER_TRACE(bh, "write");
set_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(SWRITE, 1, &bh);
}
#endif
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 77b7662..c6ec66f 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -490,23 +490,21 @@
*/
static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
{
- struct buffer_head *bh = jh2bh(jh);
int jlist;
- if (buffer_dirty(bh)) {
- /* If this buffer is one which might reasonably be dirty
- * --- ie. data, or not part of this journal --- then
- * we're OK to leave it alone, but otherwise we need to
- * move the dirty bit to the journal's own internal
- * JBDDirty bit. */
- jlist = jh->b_jlist;
+ /* If this buffer is one which might reasonably be dirty
+ * --- ie. data, or not part of this journal --- then
+ * we're OK to leave it alone, but otherwise we need to
+ * move the dirty bit to the journal's own internal
+ * JBDDirty bit. */
+ jlist = jh->b_jlist;
- if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
- jlist == BJ_Shadow || jlist == BJ_Forget) {
- if (test_clear_buffer_dirty(jh2bh(jh))) {
- set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
- }
- }
+ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
+ jlist == BJ_Shadow || jlist == BJ_Forget) {
+ struct buffer_head *bh = jh2bh(jh);
+
+ if (test_clear_buffer_dirty(bh))
+ set_buffer_jbddirty(bh);
}
}
@@ -574,9 +572,14 @@
if (jh->b_next_transaction)
J_ASSERT_JH(jh, jh->b_next_transaction ==
transaction);
- JBUFFER_TRACE(jh, "Unexpected dirty buffer");
- jbd_unexpected_dirty_buffer(jh);
- }
+ }
+ /*
+ * In any case we need to clean the dirty flag and we must
+ * do it under the buffer lock to be sure we don't race
+ * with running write-out.
+ */
+ JBUFFER_TRACE(jh, "Unexpected dirty buffer");
+ jbd_unexpected_dirty_buffer(jh);
}
unlock_buffer(bh);
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index bfbeb4c..777b900 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -1629,9 +1629,6 @@
}
-extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
-extern loff_t generic_file_llseek(struct file *, loff_t, int) __attribute__((weak));
-
static struct file_operations jffs_file_operations =
{
.open = generic_file_open,
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index bd9ed9b..8279bf0 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -21,9 +21,6 @@
#include <linux/jffs2.h>
#include "nodelist.h"
-extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
-extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
-
static int jffs2_commit_write (struct file *filp, struct page *pg,
unsigned start, unsigned end);
static int jffs2_prepare_write (struct file *filp, struct page *pg,
diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
index 86ccac8..72a5588 100644
--- a/fs/jfs/jfs_filsys.h
+++ b/fs/jfs/jfs_filsys.h
@@ -37,6 +37,9 @@
#define JFS_ERR_CONTINUE 0x00000004 /* continue */
#define JFS_ERR_PANIC 0x00000008 /* panic */
+#define JFS_USRQUOTA 0x00000010
+#define JFS_GRPQUOTA 0x00000020
+
/* platform option (conditional compilation) */
#define JFS_AIX 0x80000000 /* AIX support */
/* POSIX name/directory support */
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 9ff8972..71bc34b 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -23,9 +23,11 @@
#include <linux/parser.h>
#include <linux/completion.h>
#include <linux/vfs.h>
+#include <linux/mount.h>
#include <linux/moduleparam.h>
#include <linux/posix_acl.h>
#include <asm/uaccess.h>
+#include <linux/seq_file.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
@@ -192,7 +194,8 @@
enum {
Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
- Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err,
+ Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
+ Opt_usrquota, Opt_grpquota
};
static match_table_t tokens = {
@@ -204,8 +207,8 @@
{Opt_errors, "errors=%s"},
{Opt_ignore, "noquota"},
{Opt_ignore, "quota"},
- {Opt_ignore, "usrquota"},
- {Opt_ignore, "grpquota"},
+ {Opt_usrquota, "usrquota"},
+ {Opt_grpquota, "grpquota"},
{Opt_err, NULL}
};
@@ -293,6 +296,24 @@
}
break;
}
+
+#if defined(CONFIG_QUOTA)
+ case Opt_quota:
+ case Opt_usrquota:
+ *flag |= JFS_USRQUOTA;
+ break;
+ case Opt_grpquota:
+ *flag |= JFS_GRPQUOTA;
+ break;
+#else
+ case Opt_usrquota:
+ case Opt_grpquota:
+ case Opt_quota:
+ printk(KERN_ERR
+ "JFS: quota operations not supported\n");
+ break;
+#endif
+
default:
printk("jfs: Unrecognized mount option \"%s\" "
" or missing value\n", p);
@@ -539,6 +560,26 @@
return 0;
}
+static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb);
+
+ if (sbi->flag & JFS_NOINTEGRITY)
+ seq_puts(seq, ",nointegrity");
+ else
+ seq_puts(seq, ",integrity");
+
+#if defined(CONFIG_QUOTA)
+ if (sbi->flag & JFS_USRQUOTA)
+ seq_puts(seq, ",usrquota");
+
+ if (sbi->flag & JFS_GRPQUOTA)
+ seq_puts(seq, ",grpquota");
+#endif
+
+ return 0;
+}
+
static struct super_operations jfs_super_operations = {
.alloc_inode = jfs_alloc_inode,
.destroy_inode = jfs_destroy_inode,
@@ -552,6 +593,7 @@
.unlockfs = jfs_unlockfs,
.statfs = jfs_statfs,
.remount_fs = jfs_remount,
+ .show_options = jfs_show_options
};
static struct export_operations jfs_export_operations = {
diff --git a/fs/namei.c b/fs/namei.c
index 6ec1f0f..145e852 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -525,6 +525,22 @@
return error;
}
+static inline void dput_path(struct path *path, struct nameidata *nd)
+{
+ dput(path->dentry);
+ if (path->mnt != nd->mnt)
+ mntput(path->mnt);
+}
+
+static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+{
+ dput(nd->dentry);
+ if (nd->mnt != path->mnt)
+ mntput(nd->mnt);
+ nd->mnt = path->mnt;
+ nd->dentry = path->dentry;
+}
+
/*
* This limits recursive symlink follows to 8, while
* limiting consecutive symlinks to 40.
@@ -552,9 +568,7 @@
nd->depth--;
return err;
loop:
- dput(path->dentry);
- if (path->mnt != nd->mnt)
- mntput(path->mnt);
+ dput_path(path, nd);
path_release(nd);
return err;
}
@@ -813,13 +827,8 @@
err = -ENOTDIR;
if (!inode->i_op)
break;
- } else {
- dput(nd->dentry);
- if (nd->mnt != next.mnt)
- mntput(nd->mnt);
- nd->mnt = next.mnt;
- nd->dentry = next.dentry;
- }
+ } else
+ path_to_nameidata(&next, nd);
err = -ENOTDIR;
if (!inode->i_op->lookup)
break;
@@ -859,13 +868,8 @@
if (err)
goto return_err;
inode = nd->dentry->d_inode;
- } else {
- dput(nd->dentry);
- if (nd->mnt != next.mnt)
- mntput(nd->mnt);
- nd->mnt = next.mnt;
- nd->dentry = next.dentry;
- }
+ } else
+ path_to_nameidata(&next, nd);
err = -ENOENT;
if (!inode)
break;
@@ -901,9 +905,7 @@
return_base:
return 0;
out_dput:
- dput(next.dentry);
- if (nd->mnt != next.mnt)
- mntput(next.mnt);
+ dput_path(&next, nd);
break;
}
path_release(nd);
@@ -1507,11 +1509,7 @@
if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
goto do_link;
- dput(nd->dentry);
- nd->dentry = path.dentry;
- if (nd->mnt != path.mnt)
- mntput(nd->mnt);
- nd->mnt = path.mnt;
+ path_to_nameidata(&path, nd);
error = -EISDIR;
if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
goto exit;
@@ -1522,9 +1520,7 @@
return 0;
exit_dput:
- dput(path.dentry);
- if (nd->mnt != path.mnt)
- mntput(path.mnt);
+ dput_path(&path, nd);
exit:
path_release(nd);
return error;
diff --git a/fs/namespace.c b/fs/namespace.c
index 79bd8a4..3415626 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -40,7 +40,7 @@
__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
static struct list_head *mount_hashtable;
-static int hash_mask, hash_bits;
+static int hash_mask __read_mostly, hash_bits __read_mostly;
static kmem_cache_t *mnt_cache;
static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
@@ -1334,8 +1334,12 @@
error = -EINVAL;
if (user_nd.mnt->mnt_root != user_nd.dentry)
goto out2; /* not a mountpoint */
+ if (user_nd.mnt->mnt_parent == user_nd.mnt)
+ goto out2; /* not attached */
if (new_nd.mnt->mnt_root != new_nd.dentry)
goto out2; /* not a mountpoint */
+ if (new_nd.mnt->mnt_parent == new_nd.mnt)
+ goto out2; /* not attached */
tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
spin_lock(&vfsmount_lock);
if (tmp != new_nd.mnt) {
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 9a11aa3..057aff7 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -26,6 +26,7 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/hash.h>
+#include <linux/module.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -221,6 +222,7 @@
}
struct cache_detail svc_expkey_cache = {
+ .owner = THIS_MODULE,
.hash_size = EXPKEY_HASHMAX,
.hash_table = expkey_table,
.name = "nfsd.fh",
@@ -456,6 +458,7 @@
return 0;
}
struct cache_detail svc_export_cache = {
+ .owner = THIS_MODULE,
.hash_size = EXPORT_HASHMAX,
.hash_table = export_table,
.name = "nfsd.export",
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 5605a26..1336965 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -187,6 +187,7 @@
static struct ent *idtoname_lookup(struct ent *, int);
static struct cache_detail idtoname_cache = {
+ .owner = THIS_MODULE,
.hash_size = ENT_HASHMAX,
.hash_table = idtoname_table,
.name = "nfs4.idtoname",
@@ -320,6 +321,7 @@
static int nametoid_parse(struct cache_detail *, char *, int);
static struct cache_detail nametoid_cache = {
+ .owner = THIS_MODULE,
.hash_size = ENT_HASHMAX,
.hash_table = nametoid_table,
.name = "nfs4.nametoid",
@@ -404,8 +406,10 @@
void
nfsd_idmap_shutdown(void)
{
- cache_unregister(&idtoname_cache);
- cache_unregister(&nametoid_cache);
+ if (cache_unregister(&idtoname_cache))
+ printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n");
+ if (cache_unregister(&nametoid_cache))
+ printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
}
/*
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 57ed50f..954cf89 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -93,7 +93,7 @@
dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
clname->len, clname->data);
- tfm = crypto_alloc_tfm("md5", 0);
+ tfm = crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
if (tfm == NULL)
goto out;
cksum.len = crypto_tfm_alg_digestsize(tfm);
@@ -114,8 +114,7 @@
kfree(cksum.data);
status = nfs_ok;
out:
- if (tfm)
- crypto_free_tfm(tfm);
+ crypto_free_tfm(tfm);
return status;
}
diff --git a/fs/open.c b/fs/open.c
index 32bf05e..4ee2dcc 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -933,16 +933,11 @@
EXPORT_SYMBOL(fd_install);
-asmlinkage long sys_open(const char __user * filename, int flags, int mode)
+long do_sys_open(const char __user *filename, int flags, int mode)
{
- char * tmp;
- int fd;
+ char *tmp = getname(filename);
+ int fd = PTR_ERR(tmp);
- if (force_o_largefile())
- flags |= O_LARGEFILE;
-
- tmp = getname(filename);
- fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd();
if (fd >= 0) {
@@ -959,6 +954,14 @@
}
return fd;
}
+
+asmlinkage long sys_open(const char __user *filename, int flags, int mode)
+{
+ if (force_o_largefile())
+ flags |= O_LARGEFILE;
+
+ return do_sys_open(filename, flags, mode);
+}
EXPORT_SYMBOL_GPL(sys_open);
#ifndef __alpha__
diff --git a/fs/pipe.c b/fs/pipe.c
index 25aa09f..2c7a23d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -415,6 +415,10 @@
if (filp->f_mode & FMODE_WRITE) {
mask |= (nrbufs < PIPE_BUFFERS) ? POLLOUT | POLLWRNORM : 0;
+ /*
+ * Most Unices do not set POLLERR for FIFOs but on Linux they
+ * behave exactly like pipes for poll().
+ */
if (!PIPE_READERS(*inode))
mask |= POLLERR;
}
@@ -422,9 +426,6 @@
return mask;
}
-/* FIXME: most Unices do not set POLLERR for fifos */
-#define fifo_poll pipe_poll
-
static int
pipe_release(struct inode *inode, int decr, int decw)
{
@@ -568,7 +569,7 @@
.read = pipe_read,
.readv = pipe_readv,
.write = bad_pipe_w,
- .poll = fifo_poll,
+ .poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_read_open,
.release = pipe_read_release,
@@ -580,7 +581,7 @@
.read = bad_pipe_r,
.write = pipe_write,
.writev = pipe_writev,
- .poll = fifo_poll,
+ .poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_write_open,
.release = pipe_write_release,
@@ -593,7 +594,7 @@
.readv = pipe_readv,
.write = pipe_write,
.writev = pipe_writev,
- .poll = fifo_poll,
+ .poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_rdwr_open,
.release = pipe_rdwr_release,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 491f2d9..84751f3 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -11,6 +11,40 @@
* go into icache. We cache the reference to task_struct upon lookup too.
* Eventually it should become a filesystem in its own. We don't use the
* rest of procfs anymore.
+ *
+ *
+ * Changelog:
+ * 17-Jan-2005
+ * Allan Bezerra
+ * Bruna Moreira <bruna.moreira@indt.org.br>
+ * Edjard Mota <edjard.mota@indt.org.br>
+ * Ilias Biris <ilias.biris@indt.org.br>
+ * Mauricio Lin <mauricio.lin@indt.org.br>
+ *
+ * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
+ *
+ * A new process specific entry (smaps) included in /proc. It shows the
+ * size of rss for each memory area. The maps entry lacks information
+ * about physical memory size (rss) for each mapped file, i.e.,
+ * rss information for executables and library files.
+ * This additional information is useful for any tools that need to know
+ * about physical memory consumption for a process specific library.
+ *
+ * Changelog:
+ * 21-Feb-2005
+ * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
+ * Pud inclusion in the page table walking.
+ *
+ * ChangeLog:
+ * 10-Mar-2005
+ * 10LE Instituto Nokia de Tecnologia - INdT:
+ * A better way to walks through the page table as suggested by Hugh Dickins.
+ *
+ * Simo Piiroinen <simo.piiroinen@nokia.com>:
+ * Smaps information related to shared, private, clean and dirty pages.
+ *
+ * Paul Mundt <paul.mundt@nokia.com>:
+ * Overall revision about smaps.
*/
#include <asm/uaccess.h>
@@ -65,8 +99,10 @@
PROC_TGID_STAT,
PROC_TGID_STATM,
PROC_TGID_MAPS,
+ PROC_TGID_NUMA_MAPS,
PROC_TGID_MOUNTS,
PROC_TGID_WCHAN,
+ PROC_TGID_SMAPS,
#ifdef CONFIG_SCHEDSTATS
PROC_TGID_SCHEDSTAT,
#endif
@@ -83,7 +119,6 @@
#ifdef CONFIG_AUDITSYSCALL
PROC_TGID_LOGINUID,
#endif
- PROC_TGID_FD_DIR,
PROC_TGID_OOM_SCORE,
PROC_TGID_OOM_ADJUST,
PROC_TID_INO,
@@ -102,8 +137,10 @@
PROC_TID_STAT,
PROC_TID_STATM,
PROC_TID_MAPS,
+ PROC_TID_NUMA_MAPS,
PROC_TID_MOUNTS,
PROC_TID_WCHAN,
+ PROC_TID_SMAPS,
#ifdef CONFIG_SCHEDSTATS
PROC_TID_SCHEDSTAT,
#endif
@@ -120,9 +157,11 @@
#ifdef CONFIG_AUDITSYSCALL
PROC_TID_LOGINUID,
#endif
- PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
PROC_TID_OOM_SCORE,
PROC_TID_OOM_ADJUST,
+
+ /* Add new entries before this */
+ PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
};
struct pid_entry {
@@ -144,6 +183,9 @@
E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO),
E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO),
E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO),
+#ifdef CONFIG_NUMA
+ E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+#endif
E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
#ifdef CONFIG_SECCOMP
E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -152,6 +194,7 @@
E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO),
E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO),
E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
+ E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO),
#ifdef CONFIG_SECURITY
E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
#endif
@@ -180,6 +223,9 @@
E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO),
E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO),
E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO),
+#ifdef CONFIG_NUMA
+ E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+#endif
E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
#ifdef CONFIG_SECCOMP
E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -188,6 +234,7 @@
E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO),
E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO),
E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
+ E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO),
#ifdef CONFIG_SECURITY
E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
#endif
@@ -251,15 +298,21 @@
return -ENOENT;
}
-static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static struct fs_struct *get_fs_struct(struct task_struct *task)
{
struct fs_struct *fs;
- int result = -ENOENT;
- task_lock(proc_task(inode));
- fs = proc_task(inode)->fs;
+ task_lock(task);
+ fs = task->fs;
if(fs)
atomic_inc(&fs->count);
- task_unlock(proc_task(inode));
+ task_unlock(task);
+ return fs;
+}
+
+static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+ struct fs_struct *fs = get_fs_struct(proc_task(inode));
+ int result = -ENOENT;
if (fs) {
read_lock(&fs->lock);
*mnt = mntget(fs->pwdmnt);
@@ -273,13 +326,8 @@
static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
{
- struct fs_struct *fs;
+ struct fs_struct *fs = get_fs_struct(proc_task(inode));
int result = -ENOENT;
- task_lock(proc_task(inode));
- fs = proc_task(inode)->fs;
- if(fs)
- atomic_inc(&fs->count);
- task_unlock(proc_task(inode));
if (fs) {
read_lock(&fs->lock);
*mnt = mntget(fs->rootmnt);
@@ -298,33 +346,6 @@
(task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
security_ptrace(current,task) == 0))
-static int may_ptrace_attach(struct task_struct *task)
-{
- int retval = 0;
-
- task_lock(task);
-
- if (!task->mm)
- goto out;
- if (((current->uid != task->euid) ||
- (current->uid != task->suid) ||
- (current->uid != task->uid) ||
- (current->gid != task->egid) ||
- (current->gid != task->sgid) ||
- (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
- goto out;
- rmb();
- if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE))
- goto out;
- if (security_ptrace(current, task))
- goto out;
-
- retval = 1;
-out:
- task_unlock(task);
- return retval;
-}
-
static int proc_pid_environ(struct task_struct *task, char * buffer)
{
int res = 0;
@@ -334,7 +355,7 @@
if (len > PAGE_SIZE)
len = PAGE_SIZE;
res = access_process_vm(task, mm->env_start, buffer, len, 0);
- if (!may_ptrace_attach(task))
+ if (!ptrace_may_attach(task))
res = -ESRCH;
mmput(mm);
}
@@ -515,6 +536,46 @@
.release = seq_release,
};
+#ifdef CONFIG_NUMA
+extern struct seq_operations proc_pid_numa_maps_op;
+static int numa_maps_open(struct inode *inode, struct file *file)
+{
+ struct task_struct *task = proc_task(inode);
+ int ret = seq_open(file, &proc_pid_numa_maps_op);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = task;
+ }
+ return ret;
+}
+
+static struct file_operations proc_numa_maps_operations = {
+ .open = numa_maps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif
+
+extern struct seq_operations proc_pid_smaps_op;
+static int smaps_open(struct inode *inode, struct file *file)
+{
+ struct task_struct *task = proc_task(inode);
+ int ret = seq_open(file, &proc_pid_smaps_op);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = task;
+ }
+ return ret;
+}
+
+static struct file_operations proc_smaps_operations = {
+ .open = smaps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
extern struct seq_operations mounts_op;
static int mounts_open(struct inode *inode, struct file *file)
{
@@ -597,7 +658,7 @@
int ret = -ESRCH;
struct mm_struct *mm;
- if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
+ if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
goto out;
ret = -ENOMEM;
@@ -623,7 +684,7 @@
this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
retval = access_process_vm(task, src, page, this_len, 0);
- if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) {
+ if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
if (!ret)
ret = -EIO;
break;
@@ -661,7 +722,7 @@
struct task_struct *task = proc_task(file->f_dentry->d_inode);
unsigned long dst = *ppos;
- if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
+ if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
return -ESRCH;
page = (char *)__get_free_page(GFP_USER);
@@ -1524,6 +1585,12 @@
case PROC_TGID_MAPS:
inode->i_fop = &proc_maps_operations;
break;
+#ifdef CONFIG_NUMA
+ case PROC_TID_NUMA_MAPS:
+ case PROC_TGID_NUMA_MAPS:
+ inode->i_fop = &proc_numa_maps_operations;
+ break;
+#endif
case PROC_TID_MEM:
case PROC_TGID_MEM:
inode->i_op = &proc_mem_inode_operations;
@@ -1539,6 +1606,10 @@
case PROC_TGID_MOUNTS:
inode->i_fop = &proc_mounts_operations;
break;
+ case PROC_TID_SMAPS:
+ case PROC_TGID_SMAPS:
+ inode->i_fop = &proc_smaps_operations;
+ break;
#ifdef CONFIG_SECURITY
case PROC_TID_ATTR:
inode->i_nlink = 2;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index abe8920..8a8c344 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -249,6 +249,18 @@
return error;
}
+static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry *de = PROC_I(inode)->pde;
+ if (de && de->nlink)
+ inode->i_nlink = de->nlink;
+
+ generic_fillattr(inode, stat);
+ return 0;
+}
+
static struct inode_operations proc_file_inode_operations = {
.setattr = proc_notify_change,
};
@@ -475,6 +487,7 @@
*/
static struct inode_operations proc_dir_inode_operations = {
.lookup = proc_lookup,
+ .getattr = proc_getattr,
.setattr = proc_notify_change,
};
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 28b4a02..c7ef3e4 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -2,8 +2,13 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/seq_file.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/mempolicy.h>
+
#include <asm/elf.h>
#include <asm/uaccess.h>
+#include <asm/tlbflush.h>
#include "internal.h"
char *task_mem(struct mm_struct *mm, char *buffer)
@@ -87,49 +92,58 @@
seq_printf(m, "%*c", len, ' ');
}
-static int show_map(struct seq_file *m, void *v)
+struct mem_size_stats
+{
+ unsigned long resident;
+ unsigned long shared_clean;
+ unsigned long shared_dirty;
+ unsigned long private_clean;
+ unsigned long private_dirty;
+};
+
+static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
{
struct task_struct *task = m->private;
- struct vm_area_struct *map = v;
- struct mm_struct *mm = map->vm_mm;
- struct file *file = map->vm_file;
- int flags = map->vm_flags;
+ struct vm_area_struct *vma = v;
+ struct mm_struct *mm = vma->vm_mm;
+ struct file *file = vma->vm_file;
+ int flags = vma->vm_flags;
unsigned long ino = 0;
dev_t dev = 0;
int len;
if (file) {
- struct inode *inode = map->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
- map->vm_start,
- map->vm_end,
+ vma->vm_start,
+ vma->vm_end,
flags & VM_READ ? 'r' : '-',
flags & VM_WRITE ? 'w' : '-',
flags & VM_EXEC ? 'x' : '-',
flags & VM_MAYSHARE ? 's' : 'p',
- map->vm_pgoff << PAGE_SHIFT,
+ vma->vm_pgoff << PAGE_SHIFT,
MAJOR(dev), MINOR(dev), ino, &len);
/*
* Print the dentry name for named mappings, and a
* special [heap] marker for the heap:
*/
- if (map->vm_file) {
+ if (file) {
pad_len_spaces(m, len);
- seq_path(m, file->f_vfsmnt, file->f_dentry, "");
+ seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
} else {
if (mm) {
- if (map->vm_start <= mm->start_brk &&
- map->vm_end >= mm->brk) {
+ if (vma->vm_start <= mm->start_brk &&
+ vma->vm_end >= mm->brk) {
pad_len_spaces(m, len);
seq_puts(m, "[heap]");
} else {
- if (map->vm_start <= mm->start_stack &&
- map->vm_end >= mm->start_stack) {
+ if (vma->vm_start <= mm->start_stack &&
+ vma->vm_end >= mm->start_stack) {
pad_len_spaces(m, len);
seq_puts(m, "[stack]");
@@ -141,24 +155,146 @@
}
}
seq_putc(m, '\n');
- if (m->count < m->size) /* map is copied successfully */
- m->version = (map != get_gate_vma(task))? map->vm_start: 0;
+
+ if (mss)
+ seq_printf(m,
+ "Size: %8lu kB\n"
+ "Rss: %8lu kB\n"
+ "Shared_Clean: %8lu kB\n"
+ "Shared_Dirty: %8lu kB\n"
+ "Private_Clean: %8lu kB\n"
+ "Private_Dirty: %8lu kB\n",
+ (vma->vm_end - vma->vm_start) >> 10,
+ mss->resident >> 10,
+ mss->shared_clean >> 10,
+ mss->shared_dirty >> 10,
+ mss->private_clean >> 10,
+ mss->private_dirty >> 10);
+
+ if (m->count < m->size) /* vma is copied successfully */
+ m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
return 0;
}
+static int show_map(struct seq_file *m, void *v)
+{
+ return show_map_internal(m, v, 0);
+}
+
+static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ struct mem_size_stats *mss)
+{
+ pte_t *pte, ptent;
+ unsigned long pfn;
+ struct page *page;
+
+ pte = pte_offset_map(pmd, addr);
+ do {
+ ptent = *pte;
+ if (pte_none(ptent) || !pte_present(ptent))
+ continue;
+
+ mss->resident += PAGE_SIZE;
+ pfn = pte_pfn(ptent);
+ if (!pfn_valid(pfn))
+ continue;
+
+ page = pfn_to_page(pfn);
+ if (page_count(page) >= 2) {
+ if (pte_dirty(ptent))
+ mss->shared_dirty += PAGE_SIZE;
+ else
+ mss->shared_clean += PAGE_SIZE;
+ } else {
+ if (pte_dirty(ptent))
+ mss->private_dirty += PAGE_SIZE;
+ else
+ mss->private_clean += PAGE_SIZE;
+ }
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ pte_unmap(pte - 1);
+ cond_resched_lock(&vma->vm_mm->page_table_lock);
+}
+
+static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+ unsigned long addr, unsigned long end,
+ struct mem_size_stats *mss)
+{
+ pmd_t *pmd;
+ unsigned long next;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if (pmd_none_or_clear_bad(pmd))
+ continue;
+ smaps_pte_range(vma, pmd, addr, next, mss);
+ } while (pmd++, addr = next, addr != end);
+}
+
+static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+ unsigned long addr, unsigned long end,
+ struct mem_size_stats *mss)
+{
+ pud_t *pud;
+ unsigned long next;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+ smaps_pmd_range(vma, pud, addr, next, mss);
+ } while (pud++, addr = next, addr != end);
+}
+
+static inline void smaps_pgd_range(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long end,
+ struct mem_size_stats *mss)
+{
+ pgd_t *pgd;
+ unsigned long next;
+
+ pgd = pgd_offset(vma->vm_mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ smaps_pud_range(vma, pgd, addr, next, mss);
+ } while (pgd++, addr = next, addr != end);
+}
+
+static int show_smap(struct seq_file *m, void *v)
+{
+ struct vm_area_struct *vma = v;
+ struct mm_struct *mm = vma->vm_mm;
+ struct mem_size_stats mss;
+
+ memset(&mss, 0, sizeof mss);
+
+ if (mm) {
+ spin_lock(&mm->page_table_lock);
+ smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss);
+ spin_unlock(&mm->page_table_lock);
+ }
+
+ return show_map_internal(m, v, &mss);
+}
+
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct task_struct *task = m->private;
unsigned long last_addr = m->version;
struct mm_struct *mm;
- struct vm_area_struct *map, *tail_map;
+ struct vm_area_struct *vma, *tail_vma;
loff_t l = *pos;
/*
* We remember last_addr rather than next_addr to hit with
* mmap_cache most of the time. We have zero last_addr at
- * the begining and also after lseek. We will have -1 last_addr
- * after the end of the maps.
+ * the beginning and also after lseek. We will have -1 last_addr
+ * after the end of the vmas.
*/
if (last_addr == -1UL)
@@ -168,47 +304,47 @@
if (!mm)
return NULL;
- tail_map = get_gate_vma(task);
+ tail_vma = get_gate_vma(task);
down_read(&mm->mmap_sem);
/* Start with last addr hint */
- if (last_addr && (map = find_vma(mm, last_addr))) {
- map = map->vm_next;
+ if (last_addr && (vma = find_vma(mm, last_addr))) {
+ vma = vma->vm_next;
goto out;
}
/*
- * Check the map index is within the range and do
+ * Check the vma index is within the range and do
* sequential scan until m_index.
*/
- map = NULL;
+ vma = NULL;
if ((unsigned long)l < mm->map_count) {
- map = mm->mmap;
- while (l-- && map)
- map = map->vm_next;
+ vma = mm->mmap;
+ while (l-- && vma)
+ vma = vma->vm_next;
goto out;
}
if (l != mm->map_count)
- tail_map = NULL; /* After gate map */
+ tail_vma = NULL; /* After gate vma */
out:
- if (map)
- return map;
+ if (vma)
+ return vma;
- /* End of maps has reached */
- m->version = (tail_map != NULL)? 0: -1UL;
+ /* End of vmas has been reached */
+ m->version = (tail_vma != NULL)? 0: -1UL;
up_read(&mm->mmap_sem);
mmput(mm);
- return tail_map;
+ return tail_vma;
}
static void m_stop(struct seq_file *m, void *v)
{
struct task_struct *task = m->private;
- struct vm_area_struct *map = v;
- if (map && map != get_gate_vma(task)) {
- struct mm_struct *mm = map->vm_mm;
+ struct vm_area_struct *vma = v;
+ if (vma && vma != get_gate_vma(task)) {
+ struct mm_struct *mm = vma->vm_mm;
up_read(&mm->mmap_sem);
mmput(mm);
}
@@ -217,14 +353,14 @@
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct task_struct *task = m->private;
- struct vm_area_struct *map = v;
- struct vm_area_struct *tail_map = get_gate_vma(task);
+ struct vm_area_struct *vma = v;
+ struct vm_area_struct *tail_vma = get_gate_vma(task);
(*pos)++;
- if (map && (map != tail_map) && map->vm_next)
- return map->vm_next;
+ if (vma && (vma != tail_vma) && vma->vm_next)
+ return vma->vm_next;
m_stop(m, v);
- return (map != tail_map)? tail_map: NULL;
+ return (vma != tail_vma)? tail_vma: NULL;
}
struct seq_operations proc_pid_maps_op = {
@@ -233,3 +369,140 @@
.stop = m_stop,
.show = show_map
};
+
+struct seq_operations proc_pid_smaps_op = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+ .show = show_smap
+};
+
+#ifdef CONFIG_NUMA
+
+struct numa_maps {
+ unsigned long pages;
+ unsigned long anon;
+ unsigned long mapped;
+ unsigned long mapcount_max;
+ unsigned long node[MAX_NUMNODES];
+};
+
+/*
+ * Calculate numa node maps for a vma
+ */
+static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma)
+{
+ struct page *page;
+ unsigned long vaddr;
+ struct mm_struct *mm = vma->vm_mm;
+ int i;
+ struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL);
+
+ if (!md)
+ return NULL;
+ md->pages = 0;
+ md->anon = 0;
+ md->mapped = 0;
+ md->mapcount_max = 0;
+ for_each_node(i)
+ md->node[i] =0;
+
+ spin_lock(&mm->page_table_lock);
+ for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) {
+ page = follow_page(mm, vaddr, 0);
+ if (page) {
+ int count = page_mapcount(page);
+
+ if (count)
+ md->mapped++;
+ if (count > md->mapcount_max)
+ md->mapcount_max = count;
+ md->pages++;
+ if (PageAnon(page))
+ md->anon++;
+ md->node[page_to_nid(page)]++;
+ }
+ }
+ spin_unlock(&mm->page_table_lock);
+ return md;
+}
+
+static int show_numa_map(struct seq_file *m, void *v)
+{
+ struct task_struct *task = m->private;
+ struct vm_area_struct *vma = v;
+ struct mempolicy *pol;
+ struct numa_maps *md;
+ struct zone **z;
+ int n;
+ int first;
+
+ if (!vma->vm_mm)
+ return 0;
+
+ md = get_numa_maps(vma);
+ if (!md)
+ return 0;
+
+ seq_printf(m, "%08lx", vma->vm_start);
+ pol = get_vma_policy(task, vma, vma->vm_start);
+ /* Print policy */
+ switch (pol->policy) {
+ case MPOL_PREFERRED:
+ seq_printf(m, " prefer=%d", pol->v.preferred_node);
+ break;
+ case MPOL_BIND:
+ seq_printf(m, " bind={");
+ first = 1;
+ for (z = pol->v.zonelist->zones; *z; z++) {
+
+ if (!first)
+ seq_putc(m, ',');
+ else
+ first = 0;
+ seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id,
+ (*z)->name);
+ }
+ seq_putc(m, '}');
+ break;
+ case MPOL_INTERLEAVE:
+ seq_printf(m, " interleave={");
+ first = 1;
+ for_each_node(n) {
+ if (test_bit(n, pol->v.nodes)) {
+ if (!first)
+ seq_putc(m,',');
+ else
+ first = 0;
+ seq_printf(m, "%d",n);
+ }
+ }
+ seq_putc(m, '}');
+ break;
+ default:
+ seq_printf(m," default");
+ break;
+ }
+ seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu",
+ md->mapcount_max, md->pages, md->mapped);
+ if (md->anon)
+ seq_printf(m," Anon=%lu",md->anon);
+
+ for_each_online_node(n) {
+ if (md->node[n])
+ seq_printf(m, " N%d=%lu", n, md->node[n]);
+ }
+ seq_putc(m, '\n');
+ kfree(md);
+ if (m->count < m->size) /* vma is copied successfully */
+ m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
+ return 0;
+}
+
+struct seq_operations proc_pid_numa_maps_op = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+ .show = show_numa_map
+};
+#endif
diff --git a/fs/read_write.c b/fs/read_write.c
index 563abd0..b60324a 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -188,7 +188,7 @@
struct inode *inode;
loff_t pos;
- if (unlikely(count > file->f_maxcount))
+ if (unlikely(count > INT_MAX))
goto Einval;
pos = *ppos;
if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index ca7989b..a8e29e9 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1034,7 +1034,7 @@
SB_ONDISK_JOURNAL_SIZE(s);
tbh = journal_find_get_block(s, bn);
if (buffer_dirty(tbh)) /* redundant, ll_rw_block() checks */
- ll_rw_block(WRITE, 1, &tbh);
+ ll_rw_block(SWRITE, 1, &tbh);
put_bh(tbh);
}
atomic_dec(&journal->j_async_throttle);
@@ -2172,7 +2172,7 @@
/* flush out the real blocks */
for (i = 0; i < get_desc_trans_len(desc); i++) {
set_buffer_dirty(real_blocks[i]);
- ll_rw_block(WRITE, 1, real_blocks + i);
+ ll_rw_block(SWRITE, 1, real_blocks + i);
}
for (i = 0; i < get_desc_trans_len(desc); i++) {
wait_on_buffer(real_blocks[i]);
diff --git a/fs/relayfs/Makefile b/fs/relayfs/Makefile
new file mode 100644
index 0000000..e76e182
--- /dev/null
+++ b/fs/relayfs/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_RELAYFS_FS) += relayfs.o
+
+relayfs-y := relay.o inode.o buffers.o
+
diff --git a/fs/relayfs/buffers.c b/fs/relayfs/buffers.c
new file mode 100644
index 0000000..2aa8e27
--- /dev/null
+++ b/fs/relayfs/buffers.c
@@ -0,0 +1,189 @@
+/*
+ * RelayFS buffer management code.
+ *
+ * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/relayfs_fs.h>
+#include "relay.h"
+#include "buffers.h"
+
+/*
+ * close() vm_op implementation for relayfs file mapping.
+ */
+static void relay_file_mmap_close(struct vm_area_struct *vma)
+{
+ struct rchan_buf *buf = vma->vm_private_data;
+ buf->chan->cb->buf_unmapped(buf, vma->vm_file);
+}
+
+/*
+ * nopage() vm_op implementation for relayfs file mapping.
+ */
+static struct page *relay_buf_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type)
+{
+ struct page *page;
+ struct rchan_buf *buf = vma->vm_private_data;
+ unsigned long offset = address - vma->vm_start;
+
+ if (address > vma->vm_end)
+ return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!buf)
+ return NOPAGE_OOM;
+
+ page = vmalloc_to_page(buf->start + offset);
+ if (!page)
+ return NOPAGE_OOM;
+ get_page(page);
+
+ if (type)
+ *type = VM_FAULT_MINOR;
+
+ return page;
+}
+
+/*
+ * vm_ops for relay file mappings.
+ */
+static struct vm_operations_struct relay_file_mmap_ops = {
+ .nopage = relay_buf_nopage,
+ .close = relay_file_mmap_close,
+};
+
+/**
+ * relay_mmap_buf: - mmap channel buffer to process address space
+ * @buf: relay channel buffer
+ * @vma: vm_area_struct describing memory to be mapped
+ *
+ * Returns 0 if ok, negative on error
+ *
+ * Caller should already have grabbed mmap_sem.
+ */
+int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
+{
+ unsigned long length = vma->vm_end - vma->vm_start;
+ struct file *filp = vma->vm_file;
+
+ if (!buf)
+ return -EBADF;
+
+ if (length != (unsigned long)buf->chan->alloc_size)
+ return -EINVAL;
+
+ vma->vm_ops = &relay_file_mmap_ops;
+ vma->vm_private_data = buf;
+ buf->chan->cb->buf_mapped(buf, filp);
+
+ return 0;
+}
+
+/**
+ * relay_alloc_buf - allocate a channel buffer
+ * @buf: the buffer struct
+ * @size: total size of the buffer
+ *
+ * Returns a pointer to the resulting buffer, NULL if unsuccessful
+ */
+static void *relay_alloc_buf(struct rchan_buf *buf, unsigned long size)
+{
+ void *mem;
+ unsigned int i, j, n_pages;
+
+ size = PAGE_ALIGN(size);
+ n_pages = size >> PAGE_SHIFT;
+
+ buf->page_array = kcalloc(n_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!buf->page_array)
+ return NULL;
+
+ for (i = 0; i < n_pages; i++) {
+ buf->page_array[i] = alloc_page(GFP_KERNEL);
+ if (unlikely(!buf->page_array[i]))
+ goto depopulate;
+ }
+ mem = vmap(buf->page_array, n_pages, GFP_KERNEL, PAGE_KERNEL);
+ if (!mem)
+ goto depopulate;
+
+ memset(mem, 0, size);
+ buf->page_count = n_pages;
+ return mem;
+
+depopulate:
+ for (j = 0; j < i; j++)
+ __free_page(buf->page_array[j]);
+ kfree(buf->page_array);
+ return NULL;
+}
+
+/**
+ * relay_create_buf - allocate and initialize a channel buffer
+ * @alloc_size: size of the buffer to allocate
+ * @n_subbufs: number of sub-buffers in the channel
+ *
+ * Returns channel buffer if successful, NULL otherwise
+ */
+struct rchan_buf *relay_create_buf(struct rchan *chan)
+{
+ struct rchan_buf *buf = kcalloc(1, sizeof(struct rchan_buf), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->padding = kmalloc(chan->n_subbufs * sizeof(size_t *), GFP_KERNEL);
+ if (!buf->padding)
+ goto free_buf;
+
+ buf->start = relay_alloc_buf(buf, chan->alloc_size);
+ if (!buf->start)
+ goto free_buf;
+
+ buf->chan = chan;
+ kref_get(&buf->chan->kref);
+ return buf;
+
+free_buf:
+ kfree(buf->padding);
+ kfree(buf);
+ return NULL;
+}
+
+/**
+ * relay_destroy_buf - destroy an rchan_buf struct and associated buffer
+ * @buf: the buffer struct
+ */
+void relay_destroy_buf(struct rchan_buf *buf)
+{
+ struct rchan *chan = buf->chan;
+ unsigned int i;
+
+ if (likely(buf->start)) {
+ vunmap(buf->start);
+ for (i = 0; i < buf->page_count; i++)
+ __free_page(buf->page_array[i]);
+ kfree(buf->page_array);
+ }
+ kfree(buf->padding);
+ kfree(buf);
+ kref_put(&chan->kref, relay_destroy_channel);
+}
+
+/**
+ * relay_remove_buf - remove a channel buffer
+ *
+ * Removes the file from the relayfs fileystem, which also frees the
+ * rchan_buf_struct and the channel buffer. Should only be called from
+ * kref_put().
+ */
+void relay_remove_buf(struct kref *kref)
+{
+ struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref);
+ relayfs_remove(buf->dentry);
+}
diff --git a/fs/relayfs/buffers.h b/fs/relayfs/buffers.h
new file mode 100644
index 0000000..37a1249
--- /dev/null
+++ b/fs/relayfs/buffers.h
@@ -0,0 +1,12 @@
+#ifndef _BUFFERS_H
+#define _BUFFERS_H
+
+/* This inspired by rtai/shmem */
+#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE
+
+extern int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma);
+extern struct rchan_buf *relay_create_buf(struct rchan *chan);
+extern void relay_destroy_buf(struct rchan_buf *buf);
+extern void relay_remove_buf(struct kref *kref);
+
+#endif/* _BUFFERS_H */
diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c
new file mode 100644
index 0000000..0f7f88d
--- /dev/null
+++ b/fs/relayfs/inode.c
@@ -0,0 +1,609 @@
+/*
+ * VFS-related code for RelayFS, a high-speed data relay filesystem.
+ *
+ * Copyright (C) 2003-2005 - Tom Zanussi <zanussi@us.ibm.com>, IBM Corp
+ * Copyright (C) 2003-2005 - Karim Yaghmour <karim@opersys.com>
+ *
+ * Based on ramfs, Copyright (C) 2002 - Linus Torvalds
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/backing-dev.h>
+#include <linux/namei.h>
+#include <linux/poll.h>
+#include <linux/relayfs_fs.h>
+#include "relay.h"
+#include "buffers.h"
+
+#define RELAYFS_MAGIC 0xF0B4A981
+
+static struct vfsmount * relayfs_mount;
+static int relayfs_mount_count;
+static kmem_cache_t * relayfs_inode_cachep;
+
+static struct backing_dev_info relayfs_backing_dev_info = {
+ .ra_pages = 0, /* No readahead */
+ .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+};
+
+static struct inode *relayfs_get_inode(struct super_block *sb, int mode,
+ struct rchan *chan)
+{
+ struct rchan_buf *buf = NULL;
+ struct inode *inode;
+
+ if (S_ISREG(mode)) {
+ BUG_ON(!chan);
+ buf = relay_create_buf(chan);
+ if (!buf)
+ return NULL;
+ }
+
+ inode = new_inode(sb);
+ if (!inode) {
+ relay_destroy_buf(buf);
+ return NULL;
+ }
+
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_mapping->backing_dev_info = &relayfs_backing_dev_info;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ inode->i_fop = &relayfs_file_operations;
+ RELAYFS_I(inode)->buf = buf;
+ break;
+ case S_IFDIR:
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ inode->i_nlink++;
+ break;
+ default:
+ break;
+ }
+
+ return inode;
+}
+
+/**
+ * relayfs_create_entry - create a relayfs directory or file
+ * @name: the name of the file to create
+ * @parent: parent directory
+ * @mode: mode
+ * @chan: relay channel associated with the file
+ *
+ * Returns the new dentry, NULL on failure
+ *
+ * Creates a file or directory with the specifed permissions.
+ */
+static struct dentry *relayfs_create_entry(const char *name,
+ struct dentry *parent,
+ int mode,
+ struct rchan *chan)
+{
+ struct dentry *d;
+ struct inode *inode;
+ int error = 0;
+
+ BUG_ON(!name || !(S_ISREG(mode) || S_ISDIR(mode)));
+
+ error = simple_pin_fs("relayfs", &relayfs_mount, &relayfs_mount_count);
+ if (error) {
+ printk(KERN_ERR "Couldn't mount relayfs: errcode %d\n", error);
+ return NULL;
+ }
+
+ if (!parent && relayfs_mount && relayfs_mount->mnt_sb)
+ parent = relayfs_mount->mnt_sb->s_root;
+
+ if (!parent) {
+ simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+ return NULL;
+ }
+
+ parent = dget(parent);
+ down(&parent->d_inode->i_sem);
+ d = lookup_one_len(name, parent, strlen(name));
+ if (IS_ERR(d)) {
+ d = NULL;
+ goto release_mount;
+ }
+
+ if (d->d_inode) {
+ d = NULL;
+ goto release_mount;
+ }
+
+ inode = relayfs_get_inode(parent->d_inode->i_sb, mode, chan);
+ if (!inode) {
+ d = NULL;
+ goto release_mount;
+ }
+
+ d_instantiate(d, inode);
+ dget(d); /* Extra count - pin the dentry in core */
+
+ if (S_ISDIR(mode))
+ parent->d_inode->i_nlink++;
+
+ goto exit;
+
+release_mount:
+ simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+
+exit:
+ up(&parent->d_inode->i_sem);
+ dput(parent);
+ return d;
+}
+
+/**
+ * relayfs_create_file - create a file in the relay filesystem
+ * @name: the name of the file to create
+ * @parent: parent directory
+ * @mode: mode, if not specied the default perms are used
+ * @chan: channel associated with the file
+ *
+ * Returns file dentry if successful, NULL otherwise.
+ *
+ * The file will be created user r on behalf of current user.
+ */
+struct dentry *relayfs_create_file(const char *name, struct dentry *parent,
+ int mode, struct rchan *chan)
+{
+ if (!mode)
+ mode = S_IRUSR;
+ mode = (mode & S_IALLUGO) | S_IFREG;
+
+ return relayfs_create_entry(name, parent, mode, chan);
+}
+
+/**
+ * relayfs_create_dir - create a directory in the relay filesystem
+ * @name: the name of the directory to create
+ * @parent: parent directory, NULL if parent should be fs root
+ *
+ * Returns directory dentry if successful, NULL otherwise.
+ *
+ * The directory will be created world rwx on behalf of current user.
+ */
+struct dentry *relayfs_create_dir(const char *name, struct dentry *parent)
+{
+ int mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+ return relayfs_create_entry(name, parent, mode, NULL);
+}
+
+/**
+ * relayfs_remove - remove a file or directory in the relay filesystem
+ * @dentry: file or directory dentry
+ *
+ * Returns 0 if successful, negative otherwise.
+ */
+int relayfs_remove(struct dentry *dentry)
+{
+ struct dentry *parent;
+ int error = 0;
+
+ if (!dentry)
+ return -EINVAL;
+ parent = dentry->d_parent;
+ if (!parent)
+ return -EINVAL;
+
+ parent = dget(parent);
+ down(&parent->d_inode->i_sem);
+ if (dentry->d_inode) {
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ error = simple_rmdir(parent->d_inode, dentry);
+ else
+ error = simple_unlink(parent->d_inode, dentry);
+ if (!error)
+ d_delete(dentry);
+ }
+ if (!error)
+ dput(dentry);
+ up(&parent->d_inode->i_sem);
+ dput(parent);
+
+ if (!error)
+ simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+
+ return error;
+}
+
+/**
+ * relayfs_remove_dir - remove a directory in the relay filesystem
+ * @dentry: directory dentry
+ *
+ * Returns 0 if successful, negative otherwise.
+ */
+int relayfs_remove_dir(struct dentry *dentry)
+{
+ return relayfs_remove(dentry);
+}
+
+/**
+ * relayfs_open - open file op for relayfs files
+ * @inode: the inode
+ * @filp: the file
+ *
+ * Increments the channel buffer refcount.
+ */
+static int relayfs_open(struct inode *inode, struct file *filp)
+{
+ struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+ kref_get(&buf->kref);
+
+ return 0;
+}
+
+/**
+ * relayfs_mmap - mmap file op for relayfs files
+ * @filp: the file
+ * @vma: the vma describing what to map
+ *
+ * Calls upon relay_mmap_buf to map the file into user space.
+ */
+static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ return relay_mmap_buf(RELAYFS_I(inode)->buf, vma);
+}
+
+/**
+ * relayfs_poll - poll file op for relayfs files
+ * @filp: the file
+ * @wait: poll table
+ *
+ * Poll implemention.
+ */
+static unsigned int relayfs_poll(struct file *filp, poll_table *wait)
+{
+ unsigned int mask = 0;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+
+ if (buf->finalized)
+ return POLLERR;
+
+ if (filp->f_mode & FMODE_READ) {
+ poll_wait(filp, &buf->read_wait, wait);
+ if (!relay_buf_empty(buf))
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ return mask;
+}
+
+/**
+ * relayfs_release - release file op for relayfs files
+ * @inode: the inode
+ * @filp: the file
+ *
+ * Decrements the channel refcount, as the filesystem is
+ * no longer using it.
+ */
+static int relayfs_release(struct inode *inode, struct file *filp)
+{
+ struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+ kref_put(&buf->kref, relay_remove_buf);
+
+ return 0;
+}
+
+/**
+ * relayfs_read_consume - update the consumed count for the buffer
+ */
+static void relayfs_read_consume(struct rchan_buf *buf,
+ size_t read_pos,
+ size_t bytes_consumed)
+{
+ size_t subbuf_size = buf->chan->subbuf_size;
+ size_t n_subbufs = buf->chan->n_subbufs;
+ size_t read_subbuf;
+
+ if (buf->bytes_consumed + bytes_consumed > subbuf_size) {
+ relay_subbufs_consumed(buf->chan, buf->cpu, 1);
+ buf->bytes_consumed = 0;
+ }
+
+ buf->bytes_consumed += bytes_consumed;
+ read_subbuf = read_pos / buf->chan->subbuf_size;
+ if (buf->bytes_consumed + buf->padding[read_subbuf] == subbuf_size) {
+ if ((read_subbuf == buf->subbufs_produced % n_subbufs) &&
+ (buf->offset == subbuf_size))
+ return;
+ relay_subbufs_consumed(buf->chan, buf->cpu, 1);
+ buf->bytes_consumed = 0;
+ }
+}
+
+/**
+ * relayfs_read_avail - boolean, are there unconsumed bytes available?
+ */
+static int relayfs_read_avail(struct rchan_buf *buf, size_t read_pos)
+{
+ size_t bytes_produced, bytes_consumed, write_offset;
+ size_t subbuf_size = buf->chan->subbuf_size;
+ size_t n_subbufs = buf->chan->n_subbufs;
+ size_t produced = buf->subbufs_produced % n_subbufs;
+ size_t consumed = buf->subbufs_consumed % n_subbufs;
+
+ write_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset;
+
+ if (consumed > produced) {
+ if ((produced > n_subbufs) &&
+ (produced + n_subbufs - consumed <= n_subbufs))
+ produced += n_subbufs;
+ } else if (consumed == produced) {
+ if (buf->offset > subbuf_size) {
+ produced += n_subbufs;
+ if (buf->subbufs_produced == buf->subbufs_consumed)
+ consumed += n_subbufs;
+ }
+ }
+
+ if (buf->offset > subbuf_size)
+ bytes_produced = (produced - 1) * subbuf_size + write_offset;
+ else
+ bytes_produced = produced * subbuf_size + write_offset;
+ bytes_consumed = consumed * subbuf_size + buf->bytes_consumed;
+
+ if (bytes_produced == bytes_consumed)
+ return 0;
+
+ relayfs_read_consume(buf, read_pos, 0);
+
+ return 1;
+}
+
+/**
+ * relayfs_read_subbuf_avail - return bytes available in sub-buffer
+ */
+static size_t relayfs_read_subbuf_avail(size_t read_pos,
+ struct rchan_buf *buf)
+{
+ size_t padding, avail = 0;
+ size_t read_subbuf, read_offset, write_subbuf, write_offset;
+ size_t subbuf_size = buf->chan->subbuf_size;
+
+ write_subbuf = (buf->data - buf->start) / subbuf_size;
+ write_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset;
+ read_subbuf = read_pos / subbuf_size;
+ read_offset = read_pos % subbuf_size;
+ padding = buf->padding[read_subbuf];
+
+ if (read_subbuf == write_subbuf) {
+ if (read_offset + padding < write_offset)
+ avail = write_offset - (read_offset + padding);
+ } else
+ avail = (subbuf_size - padding) - read_offset;
+
+ return avail;
+}
+
+/**
+ * relayfs_read_start_pos - find the first available byte to read
+ *
+ * If the read_pos is in the middle of padding, return the
+ * position of the first actually available byte, otherwise
+ * return the original value.
+ */
+static size_t relayfs_read_start_pos(size_t read_pos,
+ struct rchan_buf *buf)
+{
+ size_t read_subbuf, padding, padding_start, padding_end;
+ size_t subbuf_size = buf->chan->subbuf_size;
+ size_t n_subbufs = buf->chan->n_subbufs;
+
+ read_subbuf = read_pos / subbuf_size;
+ padding = buf->padding[read_subbuf];
+ padding_start = (read_subbuf + 1) * subbuf_size - padding;
+ padding_end = (read_subbuf + 1) * subbuf_size;
+ if (read_pos >= padding_start && read_pos < padding_end) {
+ read_subbuf = (read_subbuf + 1) % n_subbufs;
+ read_pos = read_subbuf * subbuf_size;
+ }
+
+ return read_pos;
+}
+
+/**
+ * relayfs_read_end_pos - return the new read position
+ */
+static size_t relayfs_read_end_pos(struct rchan_buf *buf,
+ size_t read_pos,
+ size_t count)
+{
+ size_t read_subbuf, padding, end_pos;
+ size_t subbuf_size = buf->chan->subbuf_size;
+ size_t n_subbufs = buf->chan->n_subbufs;
+
+ read_subbuf = read_pos / subbuf_size;
+ padding = buf->padding[read_subbuf];
+ if (read_pos % subbuf_size + count + padding == subbuf_size)
+ end_pos = (read_subbuf + 1) * subbuf_size;
+ else
+ end_pos = read_pos + count;
+ if (end_pos >= subbuf_size * n_subbufs)
+ end_pos = 0;
+
+ return end_pos;
+}
+
+/**
+ * relayfs_read - read file op for relayfs files
+ * @filp: the file
+ * @buffer: the userspace buffer
+ * @count: number of bytes to read
+ * @ppos: position to read from
+ *
+ * Reads count bytes or the number of bytes available in the
+ * current sub-buffer being read, whichever is smaller.
+ */
+static ssize_t relayfs_read(struct file *filp,
+ char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+ size_t read_start, avail;
+ ssize_t ret = 0;
+ void *from;
+
+ down(&inode->i_sem);
+ if(!relayfs_read_avail(buf, *ppos))
+ goto out;
+
+ read_start = relayfs_read_start_pos(*ppos, buf);
+ avail = relayfs_read_subbuf_avail(read_start, buf);
+ if (!avail)
+ goto out;
+
+ from = buf->start + read_start;
+ ret = count = min(count, avail);
+ if (copy_to_user(buffer, from, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ relayfs_read_consume(buf, read_start, count);
+ *ppos = relayfs_read_end_pos(buf, read_start, count);
+out:
+ up(&inode->i_sem);
+ return ret;
+}
+
+/**
+ * relayfs alloc_inode() implementation
+ */
+static struct inode *relayfs_alloc_inode(struct super_block *sb)
+{
+ struct relayfs_inode_info *p = kmem_cache_alloc(relayfs_inode_cachep, SLAB_KERNEL);
+ if (!p)
+ return NULL;
+ p->buf = NULL;
+
+ return &p->vfs_inode;
+}
+
+/**
+ * relayfs destroy_inode() implementation
+ */
+static void relayfs_destroy_inode(struct inode *inode)
+{
+ if (RELAYFS_I(inode)->buf)
+ relay_destroy_buf(RELAYFS_I(inode)->buf);
+
+ kmem_cache_free(relayfs_inode_cachep, RELAYFS_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct relayfs_inode_info *i = p;
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&i->vfs_inode);
+}
+
+struct file_operations relayfs_file_operations = {
+ .open = relayfs_open,
+ .poll = relayfs_poll,
+ .mmap = relayfs_mmap,
+ .read = relayfs_read,
+ .llseek = no_llseek,
+ .release = relayfs_release,
+};
+
+static struct super_operations relayfs_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+ .alloc_inode = relayfs_alloc_inode,
+ .destroy_inode = relayfs_destroy_inode,
+};
+
+static int relayfs_fill_super(struct super_block * sb, void * data, int silent)
+{
+ struct inode *inode;
+ struct dentry *root;
+ int mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = RELAYFS_MAGIC;
+ sb->s_op = &relayfs_ops;
+ inode = relayfs_get_inode(sb, mode, NULL);
+
+ if (!inode)
+ return -ENOMEM;
+
+ root = d_alloc_root(inode);
+ if (!root) {
+ iput(inode);
+ return -ENOMEM;
+ }
+ sb->s_root = root;
+
+ return 0;
+}
+
+static struct super_block * relayfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data)
+{
+ return get_sb_single(fs_type, flags, data, relayfs_fill_super);
+}
+
+static struct file_system_type relayfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "relayfs",
+ .get_sb = relayfs_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+static int __init init_relayfs_fs(void)
+{
+ int err;
+
+ relayfs_inode_cachep = kmem_cache_create("relayfs_inode_cache",
+ sizeof(struct relayfs_inode_info), 0,
+ 0, init_once, NULL);
+ if (!relayfs_inode_cachep)
+ return -ENOMEM;
+
+ err = register_filesystem(&relayfs_fs_type);
+ if (err)
+ kmem_cache_destroy(relayfs_inode_cachep);
+
+ return err;
+}
+
+static void __exit exit_relayfs_fs(void)
+{
+ unregister_filesystem(&relayfs_fs_type);
+ kmem_cache_destroy(relayfs_inode_cachep);
+}
+
+module_init(init_relayfs_fs)
+module_exit(exit_relayfs_fs)
+
+EXPORT_SYMBOL_GPL(relayfs_file_operations);
+EXPORT_SYMBOL_GPL(relayfs_create_dir);
+EXPORT_SYMBOL_GPL(relayfs_remove_dir);
+
+MODULE_AUTHOR("Tom Zanussi <zanussi@us.ibm.com> and Karim Yaghmour <karim@opersys.com>");
+MODULE_DESCRIPTION("Relay Filesystem");
+MODULE_LICENSE("GPL");
+
diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c
new file mode 100644
index 0000000..16446a1
--- /dev/null
+++ b/fs/relayfs/relay.c
@@ -0,0 +1,431 @@
+/*
+ * Public API and common code for RelayFS.
+ *
+ * See Documentation/filesystems/relayfs.txt for an overview of relayfs.
+ *
+ * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/relayfs_fs.h>
+#include "relay.h"
+#include "buffers.h"
+
+/**
+ * relay_buf_empty - boolean, is the channel buffer empty?
+ * @buf: channel buffer
+ *
+ * Returns 1 if the buffer is empty, 0 otherwise.
+ */
+int relay_buf_empty(struct rchan_buf *buf)
+{
+ return (buf->subbufs_produced - buf->subbufs_consumed) ? 0 : 1;
+}
+
+/**
+ * relay_buf_full - boolean, is the channel buffer full?
+ * @buf: channel buffer
+ *
+ * Returns 1 if the buffer is full, 0 otherwise.
+ */
+int relay_buf_full(struct rchan_buf *buf)
+{
+ size_t ready = buf->subbufs_produced - buf->subbufs_consumed;
+ return (ready >= buf->chan->n_subbufs) ? 1 : 0;
+}
+
+/*
+ * High-level relayfs kernel API and associated functions.
+ */
+
+/*
+ * rchan_callback implementations defining default channel behavior. Used
+ * in place of corresponding NULL values in client callback struct.
+ */
+
+/*
+ * subbuf_start() default callback. Does nothing.
+ */
+static int subbuf_start_default_callback (struct rchan_buf *buf,
+ void *subbuf,
+ void *prev_subbuf,
+ size_t prev_padding)
+{
+ if (relay_buf_full(buf))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * buf_mapped() default callback. Does nothing.
+ */
+static void buf_mapped_default_callback(struct rchan_buf *buf,
+ struct file *filp)
+{
+}
+
+/*
+ * buf_unmapped() default callback. Does nothing.
+ */
+static void buf_unmapped_default_callback(struct rchan_buf *buf,
+ struct file *filp)
+{
+}
+
+/* relay channel default callbacks */
+static struct rchan_callbacks default_channel_callbacks = {
+ .subbuf_start = subbuf_start_default_callback,
+ .buf_mapped = buf_mapped_default_callback,
+ .buf_unmapped = buf_unmapped_default_callback,
+};
+
+/**
+ * wakeup_readers - wake up readers waiting on a channel
+ * @private: the channel buffer
+ *
+ * This is the work function used to defer reader waking. The
+ * reason waking is deferred is that calling directly from write
+ * causes problems if you're writing from say the scheduler.
+ */
+static void wakeup_readers(void *private)
+{
+ struct rchan_buf *buf = private;
+ wake_up_interruptible(&buf->read_wait);
+}
+
+/**
+ * __relay_reset - reset a channel buffer
+ * @buf: the channel buffer
+ * @init: 1 if this is a first-time initialization
+ *
+ * See relay_reset for description of effect.
+ */
+static inline void __relay_reset(struct rchan_buf *buf, unsigned int init)
+{
+ size_t i;
+
+ if (init) {
+ init_waitqueue_head(&buf->read_wait);
+ kref_init(&buf->kref);
+ INIT_WORK(&buf->wake_readers, NULL, NULL);
+ } else {
+ cancel_delayed_work(&buf->wake_readers);
+ flush_scheduled_work();
+ }
+
+ buf->subbufs_produced = 0;
+ buf->subbufs_consumed = 0;
+ buf->bytes_consumed = 0;
+ buf->finalized = 0;
+ buf->data = buf->start;
+ buf->offset = 0;
+
+ for (i = 0; i < buf->chan->n_subbufs; i++)
+ buf->padding[i] = 0;
+
+ buf->chan->cb->subbuf_start(buf, buf->data, NULL, 0);
+}
+
+/**
+ * relay_reset - reset the channel
+ * @chan: the channel
+ *
+ * This has the effect of erasing all data from all channel buffers
+ * and restarting the channel in its initial state. The buffers
+ * are not freed, so any mappings are still in effect.
+ *
+ * NOTE: Care should be taken that the channel isn't actually
+ * being used by anything when this call is made.
+ */
+void relay_reset(struct rchan *chan)
+{
+ unsigned int i;
+
+ if (!chan)
+ return;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!chan->buf[i])
+ continue;
+ __relay_reset(chan->buf[i], 0);
+ }
+}
+
+/**
+ * relay_open_buf - create a new channel buffer in relayfs
+ *
+ * Internal - used by relay_open().
+ */
+static struct rchan_buf *relay_open_buf(struct rchan *chan,
+ const char *filename,
+ struct dentry *parent)
+{
+ struct rchan_buf *buf;
+ struct dentry *dentry;
+
+ /* Create file in fs */
+ dentry = relayfs_create_file(filename, parent, S_IRUSR, chan);
+ if (!dentry)
+ return NULL;
+
+ buf = RELAYFS_I(dentry->d_inode)->buf;
+ buf->dentry = dentry;
+ __relay_reset(buf, 1);
+
+ return buf;
+}
+
+/**
+ * relay_close_buf - close a channel buffer
+ * @buf: channel buffer
+ *
+ * Marks the buffer finalized and restores the default callbacks.
+ * The channel buffer and channel buffer data structure are then freed
+ * automatically when the last reference is given up.
+ */
+static inline void relay_close_buf(struct rchan_buf *buf)
+{
+ buf->finalized = 1;
+ buf->chan->cb = &default_channel_callbacks;
+ cancel_delayed_work(&buf->wake_readers);
+ flush_scheduled_work();
+ kref_put(&buf->kref, relay_remove_buf);
+}
+
+static inline void setup_callbacks(struct rchan *chan,
+ struct rchan_callbacks *cb)
+{
+ if (!cb) {
+ chan->cb = &default_channel_callbacks;
+ return;
+ }
+
+ if (!cb->subbuf_start)
+ cb->subbuf_start = subbuf_start_default_callback;
+ if (!cb->buf_mapped)
+ cb->buf_mapped = buf_mapped_default_callback;
+ if (!cb->buf_unmapped)
+ cb->buf_unmapped = buf_unmapped_default_callback;
+ chan->cb = cb;
+}
+
+/**
+ * relay_open - create a new relayfs channel
+ * @base_filename: base name of files to create
+ * @parent: dentry of parent directory, NULL for root directory
+ * @subbuf_size: size of sub-buffers
+ * @n_subbufs: number of sub-buffers
+ * @cb: client callback functions
+ *
+ * Returns channel pointer if successful, NULL otherwise.
+ *
+ * Creates a channel buffer for each cpu using the sizes and
+ * attributes specified. The created channel buffer files
+ * will be named base_filename0...base_filenameN-1. File
+ * permissions will be S_IRUSR.
+ */
+struct rchan *relay_open(const char *base_filename,
+ struct dentry *parent,
+ size_t subbuf_size,
+ size_t n_subbufs,
+ struct rchan_callbacks *cb)
+{
+ unsigned int i;
+ struct rchan *chan;
+ char *tmpname;
+
+ if (!base_filename)
+ return NULL;
+
+ if (!(subbuf_size && n_subbufs))
+ return NULL;
+
+ chan = kcalloc(1, sizeof(struct rchan), GFP_KERNEL);
+ if (!chan)
+ return NULL;
+
+ chan->version = RELAYFS_CHANNEL_VERSION;
+ chan->n_subbufs = n_subbufs;
+ chan->subbuf_size = subbuf_size;
+ chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs);
+ setup_callbacks(chan, cb);
+ kref_init(&chan->kref);
+
+ tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL);
+ if (!tmpname)
+ goto free_chan;
+
+ for_each_online_cpu(i) {
+ sprintf(tmpname, "%s%d", base_filename, i);
+ chan->buf[i] = relay_open_buf(chan, tmpname, parent);
+ chan->buf[i]->cpu = i;
+ if (!chan->buf[i])
+ goto free_bufs;
+ }
+
+ kfree(tmpname);
+ return chan;
+
+free_bufs:
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!chan->buf[i])
+ break;
+ relay_close_buf(chan->buf[i]);
+ }
+ kfree(tmpname);
+
+free_chan:
+ kref_put(&chan->kref, relay_destroy_channel);
+ return NULL;
+}
+
+/**
+ * relay_switch_subbuf - switch to a new sub-buffer
+ * @buf: channel buffer
+ * @length: size of current event
+ *
+ * Returns either the length passed in or 0 if full.
+
+ * Performs sub-buffer-switch tasks such as invoking callbacks,
+ * updating padding counts, waking up readers, etc.
+ */
+size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
+{
+ void *old, *new;
+ size_t old_subbuf, new_subbuf;
+
+ if (unlikely(length > buf->chan->subbuf_size))
+ goto toobig;
+
+ if (buf->offset != buf->chan->subbuf_size + 1) {
+ buf->prev_padding = buf->chan->subbuf_size - buf->offset;
+ old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
+ buf->padding[old_subbuf] = buf->prev_padding;
+ buf->subbufs_produced++;
+ if (waitqueue_active(&buf->read_wait)) {
+ PREPARE_WORK(&buf->wake_readers, wakeup_readers, buf);
+ schedule_delayed_work(&buf->wake_readers, 1);
+ }
+ }
+
+ old = buf->data;
+ new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
+ new = buf->start + new_subbuf * buf->chan->subbuf_size;
+ buf->offset = 0;
+ if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) {
+ buf->offset = buf->chan->subbuf_size + 1;
+ return 0;
+ }
+ buf->data = new;
+ buf->padding[new_subbuf] = 0;
+
+ if (unlikely(length + buf->offset > buf->chan->subbuf_size))
+ goto toobig;
+
+ return length;
+
+toobig:
+ printk(KERN_WARNING "relayfs: event too large (%Zd)\n", length);
+ WARN_ON(1);
+ return 0;
+}
+
+/**
+ * relay_subbufs_consumed - update the buffer's sub-buffers-consumed count
+ * @chan: the channel
+ * @cpu: the cpu associated with the channel buffer to update
+ * @subbufs_consumed: number of sub-buffers to add to current buf's count
+ *
+ * Adds to the channel buffer's consumed sub-buffer count.
+ * subbufs_consumed should be the number of sub-buffers newly consumed,
+ * not the total consumed.
+ *
+ * NOTE: kernel clients don't need to call this function if the channel
+ * mode is 'overwrite'.
+ */
+void relay_subbufs_consumed(struct rchan *chan,
+ unsigned int cpu,
+ size_t subbufs_consumed)
+{
+ struct rchan_buf *buf;
+
+ if (!chan)
+ return;
+
+ if (cpu >= NR_CPUS || !chan->buf[cpu])
+ return;
+
+ buf = chan->buf[cpu];
+ buf->subbufs_consumed += subbufs_consumed;
+ if (buf->subbufs_consumed > buf->subbufs_produced)
+ buf->subbufs_consumed = buf->subbufs_produced;
+}
+
+/**
+ * relay_destroy_channel - free the channel struct
+ *
+ * Should only be called from kref_put().
+ */
+void relay_destroy_channel(struct kref *kref)
+{
+ struct rchan *chan = container_of(kref, struct rchan, kref);
+ kfree(chan);
+}
+
+/**
+ * relay_close - close the channel
+ * @chan: the channel
+ *
+ * Closes all channel buffers and frees the channel.
+ */
+void relay_close(struct rchan *chan)
+{
+ unsigned int i;
+
+ if (!chan)
+ return;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!chan->buf[i])
+ continue;
+ relay_close_buf(chan->buf[i]);
+ }
+
+ kref_put(&chan->kref, relay_destroy_channel);
+}
+
+/**
+ * relay_flush - close the channel
+ * @chan: the channel
+ *
+ * Flushes all channel buffers i.e. forces buffer switch.
+ */
+void relay_flush(struct rchan *chan)
+{
+ unsigned int i;
+
+ if (!chan)
+ return;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!chan->buf[i])
+ continue;
+ relay_switch_subbuf(chan->buf[i], 0);
+ }
+}
+
+EXPORT_SYMBOL_GPL(relay_open);
+EXPORT_SYMBOL_GPL(relay_close);
+EXPORT_SYMBOL_GPL(relay_flush);
+EXPORT_SYMBOL_GPL(relay_reset);
+EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
+EXPORT_SYMBOL_GPL(relay_switch_subbuf);
+EXPORT_SYMBOL_GPL(relay_buf_full);
diff --git a/fs/relayfs/relay.h b/fs/relayfs/relay.h
new file mode 100644
index 0000000..703503f
--- /dev/null
+++ b/fs/relayfs/relay.h
@@ -0,0 +1,12 @@
+#ifndef _RELAY_H
+#define _RELAY_H
+
+struct dentry *relayfs_create_file(const char *name,
+ struct dentry *parent,
+ int mode,
+ struct rchan *chan);
+extern int relayfs_remove(struct dentry *dentry);
+extern int relay_buf_empty(struct rchan_buf *buf);
+extern void relay_destroy_channel(struct kref *kref);
+
+#endif /* _RELAY_H */
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 997640c..faf1512 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -114,8 +114,7 @@
ubh_mark_buffer_dirty (USPI_UBH);
ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_wait_on_buffer (UCPI_UBH);
- ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
}
sb->s_dirt = 1;
@@ -200,8 +199,7 @@
ubh_mark_buffer_dirty (USPI_UBH);
ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_wait_on_buffer (UCPI_UBH);
- ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
}
@@ -459,8 +457,7 @@
ubh_mark_buffer_dirty (USPI_UBH);
ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_wait_on_buffer (UCPI_UBH);
- ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
}
sb->s_dirt = 1;
@@ -585,8 +582,7 @@
ubh_mark_buffer_dirty (USPI_UBH);
ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_wait_on_buffer (UCPI_UBH);
- ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+ ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
}
sb->s_dirt = 1;
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 61a6b15..0938945 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -124,8 +124,7 @@
ubh_mark_buffer_dirty (USPI_UBH);
ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_wait_on_buffer (UCPI_UBH);
- ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+ ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
ubh_wait_on_buffer (UCPI_UBH);
}
@@ -249,8 +248,7 @@
ubh_mark_buffer_dirty (USPI_UBH);
ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
- ubh_wait_on_buffer (UCPI_UBH);
- ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+ ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
ubh_wait_on_buffer (UCPI_UBH);
}
sb->s_dirt = 1;
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index e312bf8..61d2e35 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -285,8 +285,7 @@
}
}
if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
- ubh_wait_on_buffer (ind_ubh);
- ubh_ll_rw_block (WRITE, 1, &ind_ubh);
+ ubh_ll_rw_block (SWRITE, 1, &ind_ubh);
ubh_wait_on_buffer (ind_ubh);
}
ubh_brelse (ind_ubh);
@@ -353,8 +352,7 @@
}
}
if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
- ubh_wait_on_buffer (dind_bh);
- ubh_ll_rw_block (WRITE, 1, &dind_bh);
+ ubh_ll_rw_block (SWRITE, 1, &dind_bh);
ubh_wait_on_buffer (dind_bh);
}
ubh_brelse (dind_bh);
@@ -418,8 +416,7 @@
}
}
if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
- ubh_wait_on_buffer (tind_bh);
- ubh_ll_rw_block (WRITE, 1, &tind_bh);
+ ubh_ll_rw_block (SWRITE, 1, &tind_bh);
ubh_wait_on_buffer (tind_bh);
}
ubh_brelse (tind_bh);
diff --git a/fs/umsdos/notes b/fs/umsdos/notes
deleted file mode 100644
index 3c47d1f..0000000
--- a/fs/umsdos/notes
+++ /dev/null
@@ -1,17 +0,0 @@
-This file contain idea and things I don't want to forget
-
-Possible bug in fs/read_write.c
-Function sys_readdir()
-
- There is a call the verify_area that does not take in account
- the count parameter. I guess it should read
-
- error = verify_area(VERIFY_WRITE, dirent, count*sizeof (*dirent));
-
- instead of
-
- error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent));
-
- Of course, now , count is always 1
-
-
diff --git a/fs/xattr.c b/fs/xattr.c
index 6acd5c6..3f9c64b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -51,20 +51,29 @@
}
}
+ down(&d->d_inode->i_sem);
+ error = security_inode_setxattr(d, kname, kvalue, size, flags);
+ if (error)
+ goto out;
error = -EOPNOTSUPP;
if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
- down(&d->d_inode->i_sem);
- error = security_inode_setxattr(d, kname, kvalue, size, flags);
- if (error)
- goto out;
- error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
+ error = d->d_inode->i_op->setxattr(d, kname, kvalue,
+ size, flags);
if (!error) {
fsnotify_xattr(d);
- security_inode_post_setxattr(d, kname, kvalue, size, flags);
+ security_inode_post_setxattr(d, kname, kvalue,
+ size, flags);
}
-out:
- up(&d->d_inode->i_sem);
+ } else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
+ sizeof XATTR_SECURITY_PREFIX - 1)) {
+ const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
+ error = security_inode_setsecurity(d->d_inode, suffix, kvalue,
+ size, flags);
+ if (!error)
+ fsnotify_xattr(d);
}
+out:
+ up(&d->d_inode->i_sem);
if (kvalue)
kfree(kvalue);
return error;
@@ -139,20 +148,25 @@
return -ENOMEM;
}
+ error = security_inode_getxattr(d, kname);
+ if (error)
+ goto out;
error = -EOPNOTSUPP;
- if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
- error = security_inode_getxattr(d, kname);
- if (error)
- goto out;
+ if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
- if (error > 0) {
- if (size && copy_to_user(value, kvalue, error))
- error = -EFAULT;
- } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
- /* The file system tried to returned a value bigger
- than XATTR_SIZE_MAX bytes. Not possible. */
- error = -E2BIG;
- }
+ else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
+ sizeof XATTR_SECURITY_PREFIX - 1)) {
+ const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
+ error = security_inode_getsecurity(d->d_inode, suffix, kvalue,
+ size);
+ }
+ if (error > 0) {
+ if (size && copy_to_user(value, kvalue, error))
+ error = -EFAULT;
+ } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
+ /* The file system tried to returned a value bigger
+ than XATTR_SIZE_MAX bytes. Not possible. */
+ error = -E2BIG;
}
out:
if (kvalue)
@@ -221,20 +235,24 @@
return -ENOMEM;
}
+ error = security_inode_listxattr(d);
+ if (error)
+ goto out;
error = -EOPNOTSUPP;
if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
- error = security_inode_listxattr(d);
- if (error)
- goto out;
error = d->d_inode->i_op->listxattr(d, klist, size);
- if (error > 0) {
- if (size && copy_to_user(list, klist, error))
- error = -EFAULT;
- } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
- /* The file system tried to returned a list bigger
- than XATTR_LIST_MAX bytes. Not possible. */
- error = -E2BIG;
- }
+ } else {
+ error = security_inode_listsecurity(d->d_inode, klist, size);
+ if (size && error >= size)
+ error = -ERANGE;
+ }
+ if (error > 0) {
+ if (size && copy_to_user(list, klist, error))
+ error = -EFAULT;
+ } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
+ /* The file system tried to returned a list bigger
+ than XATTR_LIST_MAX bytes. Not possible. */
+ error = -E2BIG;
}
out:
if (klist)
@@ -307,6 +325,8 @@
down(&d->d_inode->i_sem);
error = d->d_inode->i_op->removexattr(d, kname);
up(&d->d_inode->i_sem);
+ if (!error)
+ fsnotify_xattr(d);
}
out:
return error;
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index d3ff783..49e3e7e 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -1,150 +1 @@
-#
-# Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of version 2 of the GNU General Public License as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it would be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#
-# Further, this software is distributed without any warranty that it is
-# free of the rightful claim of any third person regarding infringement
-# or the like. Any license provided herein, whether implied or
-# otherwise, applies only to this software file. Patent licenses, if
-# any, provided herein do not apply to combinations of this program with
-# other software, or any other product whatsoever.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write the Free Software Foundation, Inc., 59
-# Temple Place - Suite 330, Boston MA 02111-1307, USA.
-#
-# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
-# Mountain View, CA 94043, or:
-#
-# http://www.sgi.com
-#
-# For further information regarding this notice, see:
-#
-# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
-#
-
-EXTRA_CFLAGS += -Ifs/xfs -Ifs/xfs/linux-2.6 -funsigned-char
-
-ifeq ($(CONFIG_XFS_DEBUG),y)
- EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG
- EXTRA_CFLAGS += -DPAGEBUF_LOCK_TRACKING
-endif
-ifeq ($(CONFIG_XFS_TRACE),y)
- EXTRA_CFLAGS += -DXFS_ALLOC_TRACE
- EXTRA_CFLAGS += -DXFS_ATTR_TRACE
- EXTRA_CFLAGS += -DXFS_BLI_TRACE
- EXTRA_CFLAGS += -DXFS_BMAP_TRACE
- EXTRA_CFLAGS += -DXFS_BMBT_TRACE
- EXTRA_CFLAGS += -DXFS_DIR_TRACE
- EXTRA_CFLAGS += -DXFS_DIR2_TRACE
- EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
- EXTRA_CFLAGS += -DXFS_ILOCK_TRACE
- EXTRA_CFLAGS += -DXFS_LOG_TRACE
- EXTRA_CFLAGS += -DXFS_RW_TRACE
- EXTRA_CFLAGS += -DPAGEBUF_TRACE
- EXTRA_CFLAGS += -DXFS_VNODE_TRACE
-endif
-
-obj-$(CONFIG_XFS_FS) += xfs.o
-
-xfs-$(CONFIG_XFS_QUOTA) += $(addprefix quota/, \
- xfs_dquot.o \
- xfs_dquot_item.o \
- xfs_trans_dquot.o \
- xfs_qm_syscalls.o \
- xfs_qm_bhv.o \
- xfs_qm.o)
-ifeq ($(CONFIG_XFS_QUOTA),y)
-xfs-$(CONFIG_PROC_FS) += quota/xfs_qm_stats.o
-endif
-
-xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
-xfs-$(CONFIG_PROC_FS) += linux-2.6/xfs_stats.o
-xfs-$(CONFIG_SYSCTL) += linux-2.6/xfs_sysctl.o
-xfs-$(CONFIG_COMPAT) += linux-2.6/xfs_ioctl32.o
-xfs-$(CONFIG_XFS_EXPORT) += linux-2.6/xfs_export.o
-
-
-xfs-y += xfs_alloc.o \
- xfs_alloc_btree.o \
- xfs_attr.o \
- xfs_attr_leaf.o \
- xfs_behavior.o \
- xfs_bit.o \
- xfs_bmap.o \
- xfs_bmap_btree.o \
- xfs_btree.o \
- xfs_buf_item.o \
- xfs_da_btree.o \
- xfs_dir.o \
- xfs_dir2.o \
- xfs_dir2_block.o \
- xfs_dir2_data.o \
- xfs_dir2_leaf.o \
- xfs_dir2_node.o \
- xfs_dir2_sf.o \
- xfs_dir_leaf.o \
- xfs_error.o \
- xfs_extfree_item.o \
- xfs_fsops.o \
- xfs_ialloc.o \
- xfs_ialloc_btree.o \
- xfs_iget.o \
- xfs_inode.o \
- xfs_inode_item.o \
- xfs_iocore.o \
- xfs_iomap.o \
- xfs_itable.o \
- xfs_dfrag.o \
- xfs_log.o \
- xfs_log_recover.o \
- xfs_macros.o \
- xfs_mount.o \
- xfs_rename.o \
- xfs_trans.o \
- xfs_trans_ail.o \
- xfs_trans_buf.o \
- xfs_trans_extfree.o \
- xfs_trans_inode.o \
- xfs_trans_item.o \
- xfs_utils.o \
- xfs_vfsops.o \
- xfs_vnodeops.o \
- xfs_rw.o \
- xfs_dmops.o \
- xfs_qmops.o
-
-xfs-$(CONFIG_XFS_TRACE) += xfs_dir2_trace.o
-
-# Objects in linux-2.6/
-xfs-y += $(addprefix linux-2.6/, \
- kmem.o \
- xfs_aops.o \
- xfs_buf.o \
- xfs_file.o \
- xfs_fs_subr.o \
- xfs_globals.o \
- xfs_ioctl.o \
- xfs_iops.o \
- xfs_lrw.o \
- xfs_super.o \
- xfs_vfs.o \
- xfs_vnode.o)
-
-# Objects in support/
-xfs-y += $(addprefix support/, \
- debug.o \
- move.o \
- qsort.o \
- uuid.o)
-
-xfs-$(CONFIG_XFS_TRACE) += support/ktrace.o
-
+include $(TOPDIR)/fs/xfs/Makefile-linux-$(VERSION).$(PATCHLEVEL)
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6
new file mode 100644
index 0000000..fbfcbe5
--- /dev/null
+++ b/fs/xfs/Makefile-linux-2.6
@@ -0,0 +1,141 @@
+#
+# Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+EXTRA_CFLAGS += -Ifs/xfs -Ifs/xfs/linux-2.6 -funsigned-char
+
+XFS_LINUX := linux-2.6
+
+ifeq ($(CONFIG_XFS_DEBUG),y)
+ EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG
+ EXTRA_CFLAGS += -DPAGEBUF_LOCK_TRACKING
+endif
+ifeq ($(CONFIG_XFS_TRACE),y)
+ EXTRA_CFLAGS += -DXFS_ALLOC_TRACE
+ EXTRA_CFLAGS += -DXFS_ATTR_TRACE
+ EXTRA_CFLAGS += -DXFS_BLI_TRACE
+ EXTRA_CFLAGS += -DXFS_BMAP_TRACE
+ EXTRA_CFLAGS += -DXFS_BMBT_TRACE
+ EXTRA_CFLAGS += -DXFS_DIR_TRACE
+ EXTRA_CFLAGS += -DXFS_DIR2_TRACE
+ EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
+ EXTRA_CFLAGS += -DXFS_ILOCK_TRACE
+ EXTRA_CFLAGS += -DXFS_LOG_TRACE
+ EXTRA_CFLAGS += -DXFS_RW_TRACE
+ EXTRA_CFLAGS += -DPAGEBUF_TRACE
+ EXTRA_CFLAGS += -DXFS_VNODE_TRACE
+endif
+
+obj-$(CONFIG_XFS_FS) += xfs.o
+obj-$(CONFIG_XFS_QUOTA) += quota/
+
+xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
+xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
+xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o
+xfs-$(CONFIG_SYSCTL) += $(XFS_LINUX)/xfs_sysctl.o
+xfs-$(CONFIG_COMPAT) += $(XFS_LINUX)/xfs_ioctl32.o
+xfs-$(CONFIG_XFS_EXPORT) += $(XFS_LINUX)/xfs_export.o
+
+
+xfs-y += xfs_alloc.o \
+ xfs_alloc_btree.o \
+ xfs_attr.o \
+ xfs_attr_leaf.o \
+ xfs_behavior.o \
+ xfs_bit.o \
+ xfs_bmap.o \
+ xfs_bmap_btree.o \
+ xfs_btree.o \
+ xfs_buf_item.o \
+ xfs_da_btree.o \
+ xfs_dir.o \
+ xfs_dir2.o \
+ xfs_dir2_block.o \
+ xfs_dir2_data.o \
+ xfs_dir2_leaf.o \
+ xfs_dir2_node.o \
+ xfs_dir2_sf.o \
+ xfs_dir_leaf.o \
+ xfs_error.o \
+ xfs_extfree_item.o \
+ xfs_fsops.o \
+ xfs_ialloc.o \
+ xfs_ialloc_btree.o \
+ xfs_iget.o \
+ xfs_inode.o \
+ xfs_inode_item.o \
+ xfs_iocore.o \
+ xfs_iomap.o \
+ xfs_itable.o \
+ xfs_dfrag.o \
+ xfs_log.o \
+ xfs_log_recover.o \
+ xfs_macros.o \
+ xfs_mount.o \
+ xfs_rename.o \
+ xfs_trans.o \
+ xfs_trans_ail.o \
+ xfs_trans_buf.o \
+ xfs_trans_extfree.o \
+ xfs_trans_inode.o \
+ xfs_trans_item.o \
+ xfs_utils.o \
+ xfs_vfsops.o \
+ xfs_vnodeops.o \
+ xfs_rw.o \
+ xfs_dmops.o \
+ xfs_qmops.o
+
+xfs-$(CONFIG_XFS_TRACE) += xfs_dir2_trace.o
+
+# Objects in linux/
+xfs-y += $(addprefix $(XFS_LINUX)/, \
+ kmem.o \
+ xfs_aops.o \
+ xfs_buf.o \
+ xfs_file.o \
+ xfs_fs_subr.o \
+ xfs_globals.o \
+ xfs_ioctl.o \
+ xfs_iops.o \
+ xfs_lrw.o \
+ xfs_super.o \
+ xfs_vfs.o \
+ xfs_vnode.o)
+
+# Objects in support/
+xfs-y += $(addprefix support/, \
+ debug.o \
+ move.o \
+ uuid.o)
+
+xfs-$(CONFIG_XFS_TRACE) += support/ktrace.o
+
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c
index 364ea8c..4b18455 100644
--- a/fs/xfs/linux-2.6/kmem.c
+++ b/fs/xfs/linux-2.6/kmem.c
@@ -45,11 +45,11 @@
void *
-kmem_alloc(size_t size, int flags)
+kmem_alloc(size_t size, unsigned int __nocast flags)
{
- int retries = 0;
- int lflags = kmem_flags_convert(flags);
- void *ptr;
+ int retries = 0;
+ unsigned int lflags = kmem_flags_convert(flags);
+ void *ptr;
do {
if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS)
@@ -67,7 +67,7 @@
}
void *
-kmem_zalloc(size_t size, int flags)
+kmem_zalloc(size_t size, unsigned int __nocast flags)
{
void *ptr;
@@ -89,7 +89,8 @@
}
void *
-kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags)
+kmem_realloc(void *ptr, size_t newsize, size_t oldsize,
+ unsigned int __nocast flags)
{
void *new;
@@ -104,11 +105,11 @@
}
void *
-kmem_zone_alloc(kmem_zone_t *zone, int flags)
+kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
{
- int retries = 0;
- int lflags = kmem_flags_convert(flags);
- void *ptr;
+ int retries = 0;
+ unsigned int lflags = kmem_flags_convert(flags);
+ void *ptr;
do {
ptr = kmem_cache_alloc(zone, lflags);
@@ -123,7 +124,7 @@
}
void *
-kmem_zone_zalloc(kmem_zone_t *zone, int flags)
+kmem_zone_zalloc(kmem_zone_t *zone, unsigned int __nocast flags)
{
void *ptr;
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
index 1397b66..109fcf2 100644
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/linux-2.6/kmem.h
@@ -39,10 +39,10 @@
/*
* memory management routines
*/
-#define KM_SLEEP 0x0001
-#define KM_NOSLEEP 0x0002
-#define KM_NOFS 0x0004
-#define KM_MAYFAIL 0x0008
+#define KM_SLEEP 0x0001u
+#define KM_NOSLEEP 0x0002u
+#define KM_NOFS 0x0004u
+#define KM_MAYFAIL 0x0008u
#define kmem_zone kmem_cache_s
#define kmem_zone_t kmem_cache_t
@@ -81,9 +81,9 @@
*(NSTATEP) = *(OSTATEP); \
} while (0)
-static __inline unsigned int kmem_flags_convert(int flags)
+static __inline unsigned int kmem_flags_convert(unsigned int __nocast flags)
{
- int lflags = __GFP_NOWARN; /* we'll report problems, if need be */
+ unsigned int lflags = __GFP_NOWARN; /* we'll report problems, if need be */
#ifdef DEBUG
if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL))) {
@@ -125,12 +125,13 @@
BUG();
}
-extern void *kmem_zone_zalloc(kmem_zone_t *, int);
-extern void *kmem_zone_alloc(kmem_zone_t *, int);
+extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
+extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
-extern void *kmem_alloc(size_t, int);
-extern void *kmem_realloc(void *, size_t, size_t, int);
-extern void *kmem_zalloc(size_t, int);
+extern void *kmem_alloc(size_t, unsigned int __nocast);
+extern void *kmem_realloc(void *, size_t, size_t,
+ unsigned int __nocast);
+extern void *kmem_zalloc(size_t, unsigned int __nocast);
extern void kmem_free(void *, size_t);
typedef struct shrinker *kmem_shaker_t;
diff --git a/fs/xfs/linux-2.6/spin.h b/fs/xfs/linux-2.6/spin.h
index bcf60a0..0039504 100644
--- a/fs/xfs/linux-2.6/spin.h
+++ b/fs/xfs/linux-2.6/spin.h
@@ -45,6 +45,9 @@
typedef spinlock_t lock_t;
#define SPLDECL(s) unsigned long s
+#ifndef DEFINE_SPINLOCK
+#define DEFINE_SPINLOCK(s) spinlock_t s = SPIN_LOCK_UNLOCKED
+#endif
#define spinlock_init(lock, name) spin_lock_init(lock)
#define spinlock_destroy(lock)
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index a3a4b5a..c6c0779 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -104,66 +104,114 @@
#define xfs_page_trace(tag, inode, page, mask)
#endif
+/*
+ * Schedule IO completion handling on a xfsdatad if this was
+ * the final hold on this ioend.
+ */
+STATIC void
+xfs_finish_ioend(
+ xfs_ioend_t *ioend)
+{
+ if (atomic_dec_and_test(&ioend->io_remaining))
+ queue_work(xfsdatad_workqueue, &ioend->io_work);
+}
+
+STATIC void
+xfs_destroy_ioend(
+ xfs_ioend_t *ioend)
+{
+ vn_iowake(ioend->io_vnode);
+ mempool_free(ioend, xfs_ioend_pool);
+}
+
+/*
+ * Issue transactions to convert a buffer range from unwritten
+ * to written extents.
+ */
+STATIC void
+xfs_end_bio_unwritten(
+ void *data)
+{
+ xfs_ioend_t *ioend = data;
+ vnode_t *vp = ioend->io_vnode;
+ xfs_off_t offset = ioend->io_offset;
+ size_t size = ioend->io_size;
+ struct buffer_head *bh, *next;
+ int error;
+
+ if (ioend->io_uptodate)
+ VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error);
+
+ /* ioend->io_buffer_head is only non-NULL for buffered I/O */
+ for (bh = ioend->io_buffer_head; bh; bh = next) {
+ next = bh->b_private;
+
+ bh->b_end_io = NULL;
+ clear_buffer_unwritten(bh);
+ end_buffer_async_write(bh, ioend->io_uptodate);
+ }
+
+ xfs_destroy_ioend(ioend);
+}
+
+/*
+ * Allocate and initialise an IO completion structure.
+ * We need to track unwritten extent write completion here initially.
+ * We'll need to extend this for updating the ondisk inode size later
+ * (vs. incore size).
+ */
+STATIC xfs_ioend_t *
+xfs_alloc_ioend(
+ struct inode *inode)
+{
+ xfs_ioend_t *ioend;
+
+ ioend = mempool_alloc(xfs_ioend_pool, GFP_NOFS);
+
+ /*
+ * Set the count to 1 initially, which will prevent an I/O
+ * completion callback from happening before we have started
+ * all the I/O from calling the completion routine too early.
+ */
+ atomic_set(&ioend->io_remaining, 1);
+ ioend->io_uptodate = 1; /* cleared if any I/O fails */
+ ioend->io_vnode = LINVFS_GET_VP(inode);
+ ioend->io_buffer_head = NULL;
+ atomic_inc(&ioend->io_vnode->v_iocount);
+ ioend->io_offset = 0;
+ ioend->io_size = 0;
+
+ INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend);
+
+ return ioend;
+}
+
void
linvfs_unwritten_done(
struct buffer_head *bh,
int uptodate)
{
- xfs_buf_t *pb = (xfs_buf_t *)bh->b_private;
+ xfs_ioend_t *ioend = bh->b_private;
+ static spinlock_t unwritten_done_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long flags;
ASSERT(buffer_unwritten(bh));
bh->b_end_io = NULL;
- clear_buffer_unwritten(bh);
+
if (!uptodate)
- pagebuf_ioerror(pb, EIO);
- if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) {
- pagebuf_iodone(pb, 1, 1);
- }
- end_buffer_async_write(bh, uptodate);
-}
+ ioend->io_uptodate = 0;
-/*
- * Issue transactions to convert a buffer range from unwritten
- * to written extents (buffered IO).
- */
-STATIC void
-linvfs_unwritten_convert(
- xfs_buf_t *bp)
-{
- vnode_t *vp = XFS_BUF_FSPRIVATE(bp, vnode_t *);
- int error;
+ /*
+ * Deep magic here. We reuse b_private in the buffer_heads to build
+ * a chain for completing the I/O from user context after we've issued
+ * a transaction to convert the unwritten extent.
+ */
+ spin_lock_irqsave(&unwritten_done_lock, flags);
+ bh->b_private = ioend->io_buffer_head;
+ ioend->io_buffer_head = bh;
+ spin_unlock_irqrestore(&unwritten_done_lock, flags);
- BUG_ON(atomic_read(&bp->pb_hold) < 1);
- VOP_BMAP(vp, XFS_BUF_OFFSET(bp), XFS_BUF_SIZE(bp),
- BMAPI_UNWRITTEN, NULL, NULL, error);
- XFS_BUF_SET_FSPRIVATE(bp, NULL);
- XFS_BUF_CLR_IODONE_FUNC(bp);
- XFS_BUF_UNDATAIO(bp);
- iput(LINVFS_GET_IP(vp));
- pagebuf_iodone(bp, 0, 0);
-}
-
-/*
- * Issue transactions to convert a buffer range from unwritten
- * to written extents (direct IO).
- */
-STATIC void
-linvfs_unwritten_convert_direct(
- struct kiocb *iocb,
- loff_t offset,
- ssize_t size,
- void *private)
-{
- struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
- ASSERT(!private || inode == (struct inode *)private);
-
- /* private indicates an unwritten extent lay beneath this IO */
- if (private && size > 0) {
- vnode_t *vp = LINVFS_GET_VP(inode);
- int error;
-
- VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error);
- }
+ xfs_finish_ioend(ioend);
}
STATIC int
@@ -255,7 +303,7 @@
struct address_space *mapping,
pgoff_t index,
xfs_iomap_t *iomapp,
- xfs_buf_t *pb,
+ xfs_ioend_t *ioend,
unsigned long max_offset,
unsigned long *fsbs,
unsigned int bbits)
@@ -283,7 +331,7 @@
break;
xfs_map_at_offset(page, bh, p_offset, bbits, iomapp);
set_buffer_unwritten_io(bh);
- bh->b_private = pb;
+ bh->b_private = ioend;
p_offset += bh->b_size;
(*fsbs)++;
} while ((bh = bh->b_this_page) != head);
@@ -434,34 +482,15 @@
{
struct buffer_head *bh = curr;
xfs_iomap_t *tmp;
- xfs_buf_t *pb;
- loff_t offset, size;
+ xfs_ioend_t *ioend;
+ loff_t offset;
unsigned long nblocks = 0;
offset = start_page->index;
offset <<= PAGE_CACHE_SHIFT;
offset += p_offset;
- /* get an "empty" pagebuf to manage IO completion
- * Proper values will be set before returning */
- pb = pagebuf_lookup(iomapp->iomap_target, 0, 0, 0);
- if (!pb)
- return -EAGAIN;
-
- /* Take a reference to the inode to prevent it from
- * being reclaimed while we have outstanding unwritten
- * extent IO on it.
- */
- if ((igrab(inode)) != inode) {
- pagebuf_free(pb);
- return -EAGAIN;
- }
-
- /* Set the count to 1 initially, this will stop an I/O
- * completion callout which happens before we have started
- * all the I/O from calling pagebuf_iodone too early.
- */
- atomic_set(&pb->pb_io_remaining, 1);
+ ioend = xfs_alloc_ioend(inode);
/* First map forwards in the page consecutive buffers
* covering this unwritten extent
@@ -474,12 +503,12 @@
break;
xfs_map_at_offset(start_page, bh, p_offset, block_bits, iomapp);
set_buffer_unwritten_io(bh);
- bh->b_private = pb;
+ bh->b_private = ioend;
p_offset += bh->b_size;
nblocks++;
} while ((bh = bh->b_this_page) != head);
- atomic_add(nblocks, &pb->pb_io_remaining);
+ atomic_add(nblocks, &ioend->io_remaining);
/* If we reached the end of the page, map forwards in any
* following pages which are also covered by this extent.
@@ -496,13 +525,13 @@
tloff = min(tlast, tloff);
for (tindex = start_page->index + 1; tindex < tloff; tindex++) {
page = xfs_probe_unwritten_page(mapping,
- tindex, iomapp, pb,
+ tindex, iomapp, ioend,
PAGE_CACHE_SIZE, &bs, bbits);
if (!page)
break;
nblocks += bs;
- atomic_add(bs, &pb->pb_io_remaining);
- xfs_convert_page(inode, page, iomapp, wbc, pb,
+ atomic_add(bs, &ioend->io_remaining);
+ xfs_convert_page(inode, page, iomapp, wbc, ioend,
startio, all_bh);
/* stop if converting the next page might add
* enough blocks that the corresponding byte
@@ -514,12 +543,12 @@
if (tindex == tlast &&
(pg_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)))) {
page = xfs_probe_unwritten_page(mapping,
- tindex, iomapp, pb,
+ tindex, iomapp, ioend,
pg_offset, &bs, bbits);
if (page) {
nblocks += bs;
- atomic_add(bs, &pb->pb_io_remaining);
- xfs_convert_page(inode, page, iomapp, wbc, pb,
+ atomic_add(bs, &ioend->io_remaining);
+ xfs_convert_page(inode, page, iomapp, wbc, ioend,
startio, all_bh);
if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> block_bits))
goto enough;
@@ -528,21 +557,9 @@
}
enough:
- size = nblocks; /* NB: using 64bit number here */
- size <<= block_bits; /* convert fsb's to byte range */
-
- XFS_BUF_DATAIO(pb);
- XFS_BUF_ASYNC(pb);
- XFS_BUF_SET_SIZE(pb, size);
- XFS_BUF_SET_COUNT(pb, size);
- XFS_BUF_SET_OFFSET(pb, offset);
- XFS_BUF_SET_FSPRIVATE(pb, LINVFS_GET_VP(inode));
- XFS_BUF_SET_IODONE_FUNC(pb, linvfs_unwritten_convert);
-
- if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) {
- pagebuf_iodone(pb, 1, 1);
- }
-
+ ioend->io_size = (xfs_off_t)nblocks << block_bits;
+ ioend->io_offset = offset;
+ xfs_finish_ioend(ioend);
return 0;
}
@@ -787,7 +804,7 @@
continue;
if (!iomp) {
err = xfs_map_blocks(inode, offset, len, &iomap,
- BMAPI_READ|BMAPI_IGNSTATE);
+ BMAPI_WRITE|BMAPI_IGNSTATE);
if (err) {
goto error;
}
@@ -1028,6 +1045,44 @@
create, 1, BMAPI_WRITE|BMAPI_DIRECT);
}
+STATIC void
+linvfs_end_io_direct(
+ struct kiocb *iocb,
+ loff_t offset,
+ ssize_t size,
+ void *private)
+{
+ xfs_ioend_t *ioend = iocb->private;
+
+ /*
+ * Non-NULL private data means we need to issue a transaction to
+ * convert a range from unwritten to written extents. This needs
+ * to happen from process contect but aio+dio I/O completion
+ * happens from irq context so we need to defer it to a workqueue.
+ * This is not nessecary for synchronous direct I/O, but we do
+ * it anyway to keep the code uniform and simpler.
+ *
+ * The core direct I/O code might be changed to always call the
+ * completion handler in the future, in which case all this can
+ * go away.
+ */
+ if (private && size > 0) {
+ ioend->io_offset = offset;
+ ioend->io_size = size;
+ xfs_finish_ioend(ioend);
+ } else {
+ ASSERT(size >= 0);
+ xfs_destroy_ioend(ioend);
+ }
+
+ /*
+ * blockdev_direct_IO can return an error even afer the I/O
+ * completion handler was called. Thus we need to protect
+ * against double-freeing.
+ */
+ iocb->private = NULL;
+}
+
STATIC ssize_t
linvfs_direct_IO(
int rw,
@@ -1042,16 +1097,23 @@
xfs_iomap_t iomap;
int maps = 1;
int error;
+ ssize_t ret;
VOP_BMAP(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps, error);
if (error)
return -error;
- return blockdev_direct_IO_own_locking(rw, iocb, inode,
+ iocb->private = xfs_alloc_ioend(inode);
+
+ ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
iomap.iomap_target->pbr_bdev,
iov, offset, nr_segs,
linvfs_get_blocks_direct,
- linvfs_unwritten_convert_direct);
+ linvfs_end_io_direct);
+
+ if (unlikely(ret <= 0 && iocb->private))
+ xfs_destroy_ioend(iocb->private);
+ return ret;
}
@@ -1202,6 +1264,16 @@
return error;
}
+STATIC int
+linvfs_invalidate_page(
+ struct page *page,
+ unsigned long offset)
+{
+ xfs_page_trace(XFS_INVALIDPAGE_ENTER,
+ page->mapping->host, page, offset);
+ return block_invalidatepage(page, offset);
+}
+
/*
* Called to move a page into cleanable state - and from there
* to be released. Possibly the page is already clean. We always
@@ -1279,6 +1351,7 @@
.writepage = linvfs_writepage,
.sync_page = block_sync_page,
.releasepage = linvfs_release_page,
+ .invalidatepage = linvfs_invalidate_page,
.prepare_write = linvfs_prepare_write,
.commit_write = generic_commit_write,
.bmap = linvfs_bmap,
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h
new file mode 100644
index 0000000..2fa6297
--- /dev/null
+++ b/fs/xfs/linux-2.6/xfs_aops.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_AOPS_H__
+#define __XFS_AOPS_H__
+
+extern struct workqueue_struct *xfsdatad_workqueue;
+extern mempool_t *xfs_ioend_pool;
+
+typedef void (*xfs_ioend_func_t)(void *);
+
+typedef struct xfs_ioend {
+ unsigned int io_uptodate; /* I/O status register */
+ atomic_t io_remaining; /* hold count */
+ struct vnode *io_vnode; /* file being written to */
+ struct buffer_head *io_buffer_head;/* buffer linked list head */
+ size_t io_size; /* size of the extent */
+ xfs_off_t io_offset; /* offset in the file */
+ struct work_struct io_work; /* xfsdatad work queue */
+} xfs_ioend_t;
+
+#endif /* __XFS_IOPS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index df0cba2..655bf4a 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -54,6 +54,7 @@
#include <linux/percpu.h>
#include <linux/blkdev.h>
#include <linux/hash.h>
+#include <linux/kthread.h>
#include "xfs_linux.h"
@@ -67,7 +68,7 @@
STATIC void pagebuf_delwri_queue(xfs_buf_t *, int);
STATIC struct workqueue_struct *xfslogd_workqueue;
-STATIC struct workqueue_struct *xfsdatad_workqueue;
+struct workqueue_struct *xfsdatad_workqueue;
/*
* Pagebuf debugging
@@ -590,8 +591,10 @@
PB_SET_OWNER(pb);
}
- if (pb->pb_flags & PBF_STALE)
+ if (pb->pb_flags & PBF_STALE) {
+ ASSERT((pb->pb_flags & _PBF_DELWRI_Q) == 0);
pb->pb_flags &= PBF_MAPPED;
+ }
PB_TRACE(pb, "got_lock", 0);
XFS_STATS_INC(pb_get_locked);
return (pb);
@@ -700,25 +703,6 @@
}
/*
- * Create a skeletal pagebuf (no pages associated with it).
- */
-xfs_buf_t *
-pagebuf_lookup(
- xfs_buftarg_t *target,
- loff_t ioff,
- size_t isize,
- page_buf_flags_t flags)
-{
- xfs_buf_t *pb;
-
- pb = pagebuf_allocate(flags);
- if (pb) {
- _pagebuf_initialize(pb, target, ioff, isize, flags);
- }
- return pb;
-}
-
-/*
* If we are not low on memory then do the readahead in a deadlock
* safe manner.
*/
@@ -913,22 +897,23 @@
do_free = 0;
}
- if (pb->pb_flags & PBF_DELWRI) {
- pb->pb_flags |= PBF_ASYNC;
- atomic_inc(&pb->pb_hold);
- pagebuf_delwri_queue(pb, 0);
- do_free = 0;
- } else if (pb->pb_flags & PBF_FS_MANAGED) {
+ if (pb->pb_flags & PBF_FS_MANAGED) {
do_free = 0;
}
if (do_free) {
+ ASSERT((pb->pb_flags & (PBF_DELWRI|_PBF_DELWRI_Q)) == 0);
list_del_init(&pb->pb_hash_list);
spin_unlock(&hash->bh_lock);
pagebuf_free(pb);
} else {
spin_unlock(&hash->bh_lock);
}
+ } else {
+ /*
+ * Catch reference count leaks
+ */
+ ASSERT(atomic_read(&pb->pb_hold) >= 0);
}
}
@@ -1006,13 +991,24 @@
* pagebuf_unlock
*
* pagebuf_unlock releases the lock on the buffer object created by
- * pagebuf_lock or pagebuf_cond_lock (not any
- * pinning of underlying pages created by pagebuf_pin).
+ * pagebuf_lock or pagebuf_cond_lock (not any pinning of underlying pages
+ * created by pagebuf_pin).
+ *
+ * If the buffer is marked delwri but is not queued, do so before we
+ * unlock the buffer as we need to set flags correctly. We also need to
+ * take a reference for the delwri queue because the unlocker is going to
+ * drop their's and they don't know we just queued it.
*/
void
pagebuf_unlock( /* unlock buffer */
xfs_buf_t *pb) /* buffer to unlock */
{
+ if ((pb->pb_flags & (PBF_DELWRI|_PBF_DELWRI_Q)) == PBF_DELWRI) {
+ atomic_inc(&pb->pb_hold);
+ pb->pb_flags |= PBF_ASYNC;
+ pagebuf_delwri_queue(pb, 0);
+ }
+
PB_CLEAR_OWNER(pb);
up(&pb->pb_sema);
PB_TRACE(pb, "unlock", 0);
@@ -1249,8 +1245,8 @@
int error)
{
xfs_buf_t *pb = (xfs_buf_t *)bio->bi_private;
- unsigned int i, blocksize = pb->pb_target->pbr_bsize;
- struct bio_vec *bvec = bio->bi_io_vec;
+ unsigned int blocksize = pb->pb_target->pbr_bsize;
+ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
if (bio->bi_size)
return 1;
@@ -1258,10 +1254,12 @@
if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
pb->pb_error = EIO;
- for (i = 0; i < bio->bi_vcnt; i++, bvec++) {
+ do {
struct page *page = bvec->bv_page;
- if (pb->pb_error) {
+ if (unlikely(pb->pb_error)) {
+ if (pb->pb_flags & PBF_READ)
+ ClearPageUptodate(page);
SetPageError(page);
} else if (blocksize == PAGE_CACHE_SIZE) {
SetPageUptodate(page);
@@ -1270,10 +1268,13 @@
set_page_region(page, bvec->bv_offset, bvec->bv_len);
}
+ if (--bvec >= bio->bi_io_vec)
+ prefetchw(&bvec->bv_page->flags);
+
if (_pagebuf_iolocked(pb)) {
unlock_page(page);
}
- }
+ } while (bvec >= bio->bi_io_vec);
_pagebuf_iodone(pb, 1);
bio_put(bio);
@@ -1511,6 +1512,11 @@
ASSERT(btp == bp->pb_target);
if (!(bp->pb_flags & PBF_FS_MANAGED)) {
spin_unlock(&hash->bh_lock);
+ /*
+ * Catch superblock reference count leaks
+ * immediately
+ */
+ BUG_ON(bp->pb_bn == 0);
delay(100);
goto again;
}
@@ -1686,17 +1692,20 @@
int unlock)
{
PB_TRACE(pb, "delwri_q", (long)unlock);
- ASSERT(pb->pb_flags & PBF_DELWRI);
+ ASSERT((pb->pb_flags & (PBF_DELWRI|PBF_ASYNC)) ==
+ (PBF_DELWRI|PBF_ASYNC));
spin_lock(&pbd_delwrite_lock);
/* If already in the queue, dequeue and place at tail */
if (!list_empty(&pb->pb_list)) {
+ ASSERT(pb->pb_flags & _PBF_DELWRI_Q);
if (unlock) {
atomic_dec(&pb->pb_hold);
}
list_del(&pb->pb_list);
}
+ pb->pb_flags |= _PBF_DELWRI_Q;
list_add_tail(&pb->pb_list, &pbd_delwrite_queue);
pb->pb_queuetime = jiffies;
spin_unlock(&pbd_delwrite_lock);
@@ -1713,10 +1722,11 @@
spin_lock(&pbd_delwrite_lock);
if ((pb->pb_flags & PBF_DELWRI) && !list_empty(&pb->pb_list)) {
+ ASSERT(pb->pb_flags & _PBF_DELWRI_Q);
list_del_init(&pb->pb_list);
dequeued = 1;
}
- pb->pb_flags &= ~PBF_DELWRI;
+ pb->pb_flags &= ~(PBF_DELWRI|_PBF_DELWRI_Q);
spin_unlock(&pbd_delwrite_lock);
if (dequeued)
@@ -1733,9 +1743,7 @@
}
/* Defines for pagebuf daemon */
-STATIC DECLARE_COMPLETION(xfsbufd_done);
STATIC struct task_struct *xfsbufd_task;
-STATIC int xfsbufd_active;
STATIC int xfsbufd_force_flush;
STATIC int xfsbufd_force_sleep;
@@ -1761,14 +1769,8 @@
xfs_buftarg_t *target;
xfs_buf_t *pb, *n;
- /* Set up the thread */
- daemonize("xfsbufd");
current->flags |= PF_MEMALLOC;
- xfsbufd_task = current;
- xfsbufd_active = 1;
- barrier();
-
INIT_LIST_HEAD(&tmp);
do {
if (unlikely(freezing(current))) {
@@ -1795,7 +1797,7 @@
break;
}
- pb->pb_flags &= ~PBF_DELWRI;
+ pb->pb_flags &= ~(PBF_DELWRI|_PBF_DELWRI_Q);
pb->pb_flags |= PBF_WRITE;
list_move(&pb->pb_list, &tmp);
}
@@ -1816,9 +1818,9 @@
purge_addresses();
xfsbufd_force_flush = 0;
- } while (xfsbufd_active);
+ } while (!kthread_should_stop());
- complete_and_exit(&xfsbufd_done, 0);
+ return 0;
}
/*
@@ -1845,15 +1847,13 @@
if (pb->pb_target != target)
continue;
- ASSERT(pb->pb_flags & PBF_DELWRI);
+ ASSERT(pb->pb_flags & (PBF_DELWRI|_PBF_DELWRI_Q));
PB_TRACE(pb, "walkq2", (long)pagebuf_ispin(pb));
if (pagebuf_ispin(pb)) {
pincount++;
continue;
}
- pb->pb_flags &= ~PBF_DELWRI;
- pb->pb_flags |= PBF_WRITE;
list_move(&pb->pb_list, &tmp);
}
spin_unlock(&pbd_delwrite_lock);
@@ -1862,12 +1862,14 @@
* Dropped the delayed write list lock, now walk the temporary list
*/
list_for_each_entry_safe(pb, n, &tmp, pb_list) {
+ pagebuf_lock(pb);
+ pb->pb_flags &= ~(PBF_DELWRI|_PBF_DELWRI_Q);
+ pb->pb_flags |= PBF_WRITE;
if (wait)
pb->pb_flags &= ~PBF_ASYNC;
else
list_del_init(&pb->pb_list);
- pagebuf_lock(pb);
pagebuf_iostrategy(pb);
}
@@ -1901,9 +1903,11 @@
if (!xfsdatad_workqueue)
goto out_destroy_xfslogd_workqueue;
- error = kernel_thread(xfsbufd, NULL, CLONE_FS|CLONE_FILES);
- if (error < 0)
+ xfsbufd_task = kthread_run(xfsbufd, NULL, "xfsbufd");
+ if (IS_ERR(xfsbufd_task)) {
+ error = PTR_ERR(xfsbufd_task);
goto out_destroy_xfsdatad_workqueue;
+ }
return 0;
out_destroy_xfsdatad_workqueue:
@@ -1920,10 +1924,7 @@
STATIC void
xfs_buf_daemons_stop(void)
{
- xfsbufd_active = 0;
- barrier();
- wait_for_completion(&xfsbufd_done);
-
+ kthread_stop(xfsbufd_task);
destroy_workqueue(xfslogd_workqueue);
destroy_workqueue(xfsdatad_workqueue);
}
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 3f8f69a..67c19f7 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -89,6 +89,7 @@
_PBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */
_PBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc() */
_PBF_RUN_QUEUES = (1 << 19),/* run block device task queue */
+ _PBF_DELWRI_Q = (1 << 21), /* buffer on delwri queue */
} page_buf_flags_t;
#define PBF_UPDATE (PBF_READ | PBF_WRITE)
@@ -206,13 +207,6 @@
#define xfs_buf_read(target, blkno, len, flags) \
xfs_buf_read_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
-extern xfs_buf_t *pagebuf_lookup(
- xfs_buftarg_t *,
- loff_t, /* starting offset of range */
- size_t, /* length of range */
- page_buf_flags_t); /* PBF_READ, PBF_WRITE, */
- /* PBF_FORCEIO, */
-
extern xfs_buf_t *pagebuf_get_empty( /* allocate pagebuf struct with */
/* no memory or disk address */
size_t len,
@@ -344,8 +338,6 @@
-
-
/* These are just for xfs_syncsub... it sets an internal variable
* then passes it to VOP_FLUSH_PAGES or adds the flags to a newly gotten buf_t
*/
@@ -452,7 +444,7 @@
#define XFS_BUF_PTR(bp) (xfs_caddr_t)((bp)->pb_addr)
-extern inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset)
+static inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset)
{
if (bp->pb_flags & PBF_MAPPED)
return XFS_BUF_PTR(bp) + offset;
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index f1ce432..3881622 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -311,6 +311,31 @@
#define nextdp(dp) ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen))
+#ifdef CONFIG_XFS_DMAPI
+
+STATIC struct page *
+linvfs_filemap_nopage(
+ struct vm_area_struct *area,
+ unsigned long address,
+ int *type)
+{
+ struct inode *inode = area->vm_file->f_dentry->d_inode;
+ vnode_t *vp = LINVFS_GET_VP(inode);
+ xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp);
+ int error;
+
+ ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
+
+ error = XFS_SEND_MMAP(mp, area, 0);
+ if (error)
+ return NULL;
+
+ return filemap_nopage(area, address, type);
+}
+
+#endif /* CONFIG_XFS_DMAPI */
+
+
STATIC int
linvfs_readdir(
struct file *filp,
@@ -390,14 +415,6 @@
return -error;
}
-#ifdef CONFIG_XFS_DMAPI
-STATIC void
-linvfs_mmap_close(
- struct vm_area_struct *vma)
-{
- xfs_dm_mm_put(vma);
-}
-#endif /* CONFIG_XFS_DMAPI */
STATIC int
linvfs_file_mmap(
@@ -411,16 +428,11 @@
vma->vm_ops = &linvfs_file_vm_ops;
- if (vp->v_vfsp->vfs_flag & VFS_DMI) {
- xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp);
-
- error = -XFS_SEND_MMAP(mp, vma, 0);
- if (error)
- return error;
#ifdef CONFIG_XFS_DMAPI
+ if (vp->v_vfsp->vfs_flag & VFS_DMI) {
vma->vm_ops = &linvfs_dmapi_file_vm_ops;
-#endif
}
+#endif /* CONFIG_XFS_DMAPI */
VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
if (!error)
@@ -474,6 +486,7 @@
return error;
}
+#ifdef CONFIG_XFS_DMAPI
#ifdef HAVE_VMOP_MPROTECT
STATIC int
linvfs_mprotect(
@@ -494,6 +507,7 @@
return error;
}
#endif /* HAVE_VMOP_MPROTECT */
+#endif /* CONFIG_XFS_DMAPI */
#ifdef HAVE_FOP_OPEN_EXEC
/* If the user is attempting to execute a file that is offline then
@@ -528,49 +542,10 @@
}
#endif /* HAVE_FOP_OPEN_EXEC */
-/*
- * Temporary workaround to the AIO direct IO write problem.
- * This code can go and we can revert to do_sync_write once
- * the writepage(s) rework is merged.
- */
-STATIC ssize_t
-linvfs_write(
- struct file *filp,
- const char __user *buf,
- size_t len,
- loff_t *ppos)
-{
- struct kiocb kiocb;
- ssize_t ret;
-
- init_sync_kiocb(&kiocb, filp);
- kiocb.ki_pos = *ppos;
- ret = __linvfs_write(&kiocb, buf, 0, len, kiocb.ki_pos);
- *ppos = kiocb.ki_pos;
- return ret;
-}
-STATIC ssize_t
-linvfs_write_invis(
- struct file *filp,
- const char __user *buf,
- size_t len,
- loff_t *ppos)
-{
- struct kiocb kiocb;
- ssize_t ret;
-
- init_sync_kiocb(&kiocb, filp);
- kiocb.ki_pos = *ppos;
- ret = __linvfs_write(&kiocb, buf, IO_INVIS, len, kiocb.ki_pos);
- *ppos = kiocb.ki_pos;
- return ret;
-}
-
-
struct file_operations linvfs_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
- .write = linvfs_write,
+ .write = do_sync_write,
.readv = linvfs_readv,
.writev = linvfs_writev,
.aio_read = linvfs_aio_read,
@@ -592,7 +567,7 @@
struct file_operations linvfs_invis_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
- .write = linvfs_write_invis,
+ .write = do_sync_write,
.readv = linvfs_readv_invis,
.writev = linvfs_writev_invis,
.aio_read = linvfs_aio_read_invis,
@@ -626,8 +601,7 @@
#ifdef CONFIG_XFS_DMAPI
static struct vm_operations_struct linvfs_dmapi_file_vm_ops = {
- .close = linvfs_mmap_close,
- .nopage = filemap_nopage,
+ .nopage = linvfs_filemap_nopage,
.populate = filemap_populate,
#ifdef HAVE_VMOP_MPROTECT
.mprotect = linvfs_mprotect,
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 05a447e..6a3326b 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -141,13 +141,19 @@
return -XFS_ERROR(EINVAL);
}
- /* we need the vnode */
- vp = LINVFS_GET_VP(inode);
- if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFDIR:
+ case S_IFLNK:
+ break;
+ default:
iput(inode);
return -XFS_ERROR(EBADF);
}
+ /* we need the vnode */
+ vp = LINVFS_GET_VP(inode);
+
/* now we can grab the fsid */
memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));
hsize = sizeof(xfs_fsid_t);
@@ -386,7 +392,7 @@
return -error;
/* Restrict this handle operation to symlinks only. */
- if (vp->v_type != VLNK) {
+ if (!S_ISLNK(inode->i_mode)) {
VN_RELE(vp);
return -XFS_ERROR(EINVAL);
}
@@ -982,10 +988,10 @@
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
return -XFS_ERROR(EPERM);
- if (!(filp->f_flags & FMODE_WRITE))
+ if (!(filp->f_mode & FMODE_WRITE))
return -XFS_ERROR(EBADF);
- if (vp->v_type != VREG)
+ if (!VN_ISREG(vp))
return -XFS_ERROR(EINVAL);
if (copy_from_user(&bf, arg, sizeof(bf)))
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index 0f8f138..4636b7f 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -47,8 +47,52 @@
#include "xfs_vnode.h"
#include "xfs_dfrag.h"
+#define _NATIVE_IOC(cmd, type) \
+ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
+
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
#define BROKEN_X86_ALIGNMENT
+/* on ia32 l_start is on a 32-bit boundary */
+typedef struct xfs_flock64_32 {
+ __s16 l_type;
+ __s16 l_whence;
+ __s64 l_start __attribute__((packed));
+ /* len == 0 means until end of file */
+ __s64 l_len __attribute__((packed));
+ __s32 l_sysid;
+ __u32 l_pid;
+ __s32 l_pad[4]; /* reserve area */
+} xfs_flock64_32_t;
+
+#define XFS_IOC_ALLOCSP_32 _IOW ('X', 10, struct xfs_flock64_32)
+#define XFS_IOC_FREESP_32 _IOW ('X', 11, struct xfs_flock64_32)
+#define XFS_IOC_ALLOCSP64_32 _IOW ('X', 36, struct xfs_flock64_32)
+#define XFS_IOC_FREESP64_32 _IOW ('X', 37, struct xfs_flock64_32)
+#define XFS_IOC_RESVSP_32 _IOW ('X', 40, struct xfs_flock64_32)
+#define XFS_IOC_UNRESVSP_32 _IOW ('X', 41, struct xfs_flock64_32)
+#define XFS_IOC_RESVSP64_32 _IOW ('X', 42, struct xfs_flock64_32)
+#define XFS_IOC_UNRESVSP64_32 _IOW ('X', 43, struct xfs_flock64_32)
+
+/* just account for different alignment */
+STATIC unsigned long
+xfs_ioctl32_flock(
+ unsigned long arg)
+{
+ xfs_flock64_32_t __user *p32 = (void __user *)arg;
+ xfs_flock64_t __user *p = compat_alloc_user_space(sizeof(*p));
+
+ if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) ||
+ copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) ||
+ copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) ||
+ copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) ||
+ copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) ||
+ copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) ||
+ copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32)))
+ return -EFAULT;
+
+ return (unsigned long)p;
+}
+
#else
typedef struct xfs_fsop_bulkreq32 {
@@ -103,7 +147,6 @@
/* not handled
case XFS_IOC_FD_TO_HANDLE:
case XFS_IOC_PATH_TO_HANDLE:
- case XFS_IOC_PATH_TO_HANDLE:
case XFS_IOC_PATH_TO_FSHANDLE:
case XFS_IOC_OPEN_BY_HANDLE:
case XFS_IOC_FSSETDM_BY_HANDLE:
@@ -124,8 +167,21 @@
case XFS_IOC_ERROR_CLEARALL:
break;
-#ifndef BROKEN_X86_ALIGNMENT
- /* xfs_flock_t and xfs_bstat_t have wrong u32 vs u64 alignment */
+#ifdef BROKEN_X86_ALIGNMENT
+ /* xfs_flock_t has wrong u32 vs u64 alignment */
+ case XFS_IOC_ALLOCSP_32:
+ case XFS_IOC_FREESP_32:
+ case XFS_IOC_ALLOCSP64_32:
+ case XFS_IOC_FREESP64_32:
+ case XFS_IOC_RESVSP_32:
+ case XFS_IOC_UNRESVSP_32:
+ case XFS_IOC_RESVSP64_32:
+ case XFS_IOC_UNRESVSP64_32:
+ arg = xfs_ioctl32_flock(arg);
+ cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
+ break;
+
+#else /* These are handled fine if no alignment issues */
case XFS_IOC_ALLOCSP:
case XFS_IOC_FREESP:
case XFS_IOC_RESVSP:
@@ -134,6 +190,9 @@
case XFS_IOC_FREESP64:
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64:
+ break;
+
+ /* xfs_bstat_t still has wrong u32 vs u64 alignment */
case XFS_IOC_SWAPEXT:
break;
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index f252605..77708a8 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -140,7 +140,6 @@
memset(&va, 0, sizeof(va));
va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
- va.va_type = IFTOVT(mode);
va.va_mode = mode;
switch (mode & S_IFMT) {
@@ -308,14 +307,13 @@
cvp = NULL;
memset(&va, 0, sizeof(va));
- va.va_type = VLNK;
- va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO;
+ va.va_mode = S_IFLNK |
+ (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
error = 0;
VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error);
if (!error && cvp) {
- ASSERT(cvp->v_type == VLNK);
ip = LINVFS_GET_IP(cvp);
d_instantiate(dentry, ip);
validate_fields(dir);
@@ -425,9 +423,14 @@
return NULL;
}
-static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
+STATIC void
+linvfs_put_link(
+ struct dentry *dentry,
+ struct nameidata *nd,
+ void *p)
{
- char *s = nd_get_link(nd);
+ char *s = nd_get_link(nd);
+
if (!IS_ERR(s))
kfree(s);
}
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 42dc5e4..68c5d88 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -64,7 +64,6 @@
#include <sema.h>
#include <time.h>
-#include <support/qsort.h>
#include <support/ktrace.h>
#include <support/debug.h>
#include <support/move.h>
@@ -104,6 +103,7 @@
#include <xfs_stats.h>
#include <xfs_sysctl.h>
#include <xfs_iops.h>
+#include <xfs_aops.h>
#include <xfs_super.h>
#include <xfs_globals.h>
#include <xfs_fs_subr.h>
@@ -254,11 +254,18 @@
#define MAX(a,b) (max(a,b))
#define howmany(x, y) (((x)+((y)-1))/(y))
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#define qsort(a,n,s,fn) sort(a,n,s,fn,NULL)
+/*
+ * Various platform dependent calls that don't fit anywhere else
+ */
#define xfs_stack_trace() dump_stack()
-
#define xfs_itruncate_data(ip, off) \
(-vmtruncate(LINVFS_GET_IP(XFS_ITOV(ip)), (off)))
+#define xfs_statvfs_fsid(statp, mp) \
+ ({ u64 id = huge_encode_dev((mp)->m_dev); \
+ __kernel_fsid_t *fsid = &(statp)->f_fsid; \
+ (fsid->val[0] = (u32)id, fsid->val[1] = (u32)(id >> 32)); })
/* Move the kernel do_div definition off to one side */
@@ -371,6 +378,4 @@
return(x * y);
}
-#define qsort(a, n, s, cmp) sort(a, n, s, cmp, NULL)
-
#endif /* __XFS_LINUX__ */
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index acab58c..3b5fabe 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -660,9 +660,6 @@
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
mp->m_rtdev_targp : mp->m_ddev_targp;
- if (ioflags & IO_ISAIO)
- return XFS_ERROR(-ENOSYS);
-
if ((pos & target->pbr_smask) || (count & target->pbr_smask))
return XFS_ERROR(-EINVAL);
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h
index f197a72..6294dcdb 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.h
+++ b/fs/xfs/linux-2.6/xfs_lrw.h
@@ -70,9 +70,10 @@
#define XFS_SENDFILE_ENTER 21
#define XFS_WRITEPAGE_ENTER 22
#define XFS_RELEASEPAGE_ENTER 23
-#define XFS_IOMAP_ALLOC_ENTER 24
-#define XFS_IOMAP_ALLOC_MAP 25
-#define XFS_IOMAP_UNWRITTEN 26
+#define XFS_INVALIDPAGE_ENTER 24
+#define XFS_IOMAP_ALLOC_ENTER 25
+#define XFS_IOMAP_ALLOC_MAP 26
+#define XFS_IOMAP_UNWRITTEN 27
extern void xfs_rw_enter_trace(int, struct xfs_iocore *,
void *, size_t, loff_t, int);
extern void xfs_inval_cached_trace(struct xfs_iocore *,
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index f6dd7de..0da87bf 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -70,11 +70,15 @@
#include <linux/namei.h>
#include <linux/init.h>
#include <linux/mount.h>
+#include <linux/mempool.h>
#include <linux/writeback.h>
+#include <linux/kthread.h>
STATIC struct quotactl_ops linvfs_qops;
STATIC struct super_operations linvfs_sops;
-STATIC kmem_zone_t *linvfs_inode_zone;
+STATIC kmem_zone_t *xfs_vnode_zone;
+STATIC kmem_zone_t *xfs_ioend_zone;
+mempool_t *xfs_ioend_pool;
STATIC struct xfs_mount_args *
xfs_args_allocate(
@@ -138,24 +142,25 @@
xfs_set_inodeops(
struct inode *inode)
{
- vnode_t *vp = LINVFS_GET_VP(inode);
-
- if (vp->v_type == VNON) {
- vn_mark_bad(vp);
- } else if (S_ISREG(inode->i_mode)) {
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFREG:
inode->i_op = &linvfs_file_inode_operations;
inode->i_fop = &linvfs_file_operations;
inode->i_mapping->a_ops = &linvfs_aops;
- } else if (S_ISDIR(inode->i_mode)) {
+ break;
+ case S_IFDIR:
inode->i_op = &linvfs_dir_inode_operations;
inode->i_fop = &linvfs_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
+ break;
+ case S_IFLNK:
inode->i_op = &linvfs_symlink_inode_operations;
if (inode->i_blocks)
inode->i_mapping->a_ops = &linvfs_aops;
- } else {
+ break;
+ default:
inode->i_op = &linvfs_file_inode_operations;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ break;
}
}
@@ -167,16 +172,23 @@
{
struct inode *inode = LINVFS_GET_IP(vp);
- inode->i_mode = (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
+ inode->i_mode = ip->i_d.di_mode;
inode->i_nlink = ip->i_d.di_nlink;
inode->i_uid = ip->i_d.di_uid;
inode->i_gid = ip->i_d.di_gid;
- if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ inode->i_rdev =
+ MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff,
+ sysv_minor(ip->i_df.if_u2.if_rdev));
+ break;
+ default:
inode->i_rdev = 0;
- } else {
- xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
- inode->i_rdev = MKDEV(sysv_major(dev) & 0x1ff, sysv_minor(dev));
+ break;
}
+
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_generation = ip->i_d.di_gen;
i_size_write(inode, ip->i_d.di_size);
@@ -231,7 +243,6 @@
* finish our work.
*/
if (ip->i_d.di_mode != 0 && unlock && (inode->i_state & I_NEW)) {
- vp->v_type = IFTOVT(ip->i_d.di_mode);
xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
xfs_set_inodeops(inode);
@@ -274,8 +285,7 @@
{
vnode_t *vp;
- vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_zone,
- kmem_flags_convert(KM_SLEEP));
+ vp = kmem_cache_alloc(xfs_vnode_zone, kmem_flags_convert(KM_SLEEP));
if (!vp)
return NULL;
return LINVFS_GET_IP(vp);
@@ -285,11 +295,11 @@
linvfs_destroy_inode(
struct inode *inode)
{
- kmem_cache_free(linvfs_inode_zone, LINVFS_GET_VP(inode));
+ kmem_zone_free(xfs_vnode_zone, LINVFS_GET_VP(inode));
}
STATIC void
-init_once(
+linvfs_inode_init_once(
void *data,
kmem_cache_t *cachep,
unsigned long flags)
@@ -302,21 +312,41 @@
}
STATIC int
-init_inodecache( void )
+linvfs_init_zones(void)
{
- linvfs_inode_zone = kmem_cache_create("linvfs_icache",
+ xfs_vnode_zone = kmem_cache_create("xfs_vnode",
sizeof(vnode_t), 0, SLAB_RECLAIM_ACCOUNT,
- init_once, NULL);
- if (linvfs_inode_zone == NULL)
- return -ENOMEM;
+ linvfs_inode_init_once, NULL);
+ if (!xfs_vnode_zone)
+ goto out;
+
+ xfs_ioend_zone = kmem_zone_init(sizeof(xfs_ioend_t), "xfs_ioend");
+ if (!xfs_ioend_zone)
+ goto out_destroy_vnode_zone;
+
+ xfs_ioend_pool = mempool_create(4 * MAX_BUF_PER_PAGE,
+ mempool_alloc_slab, mempool_free_slab,
+ xfs_ioend_zone);
+ if (!xfs_ioend_pool)
+ goto out_free_ioend_zone;
+
return 0;
+
+
+ out_free_ioend_zone:
+ kmem_zone_destroy(xfs_ioend_zone);
+ out_destroy_vnode_zone:
+ kmem_zone_destroy(xfs_vnode_zone);
+ out:
+ return -ENOMEM;
}
STATIC void
-destroy_inodecache( void )
+linvfs_destroy_zones(void)
{
- if (kmem_cache_destroy(linvfs_inode_zone))
- printk(KERN_WARNING "%s: cache still in use!\n", __FUNCTION__);
+ mempool_destroy(xfs_ioend_pool);
+ kmem_zone_destroy(xfs_vnode_zone);
+ kmem_zone_destroy(xfs_ioend_zone);
}
/*
@@ -354,17 +384,38 @@
struct inode *inode)
{
vnode_t *vp = LINVFS_GET_VP(inode);
+ int error, cache;
- if (vp) {
- vn_rele(vp);
- vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
- /*
- * Do all our cleanup, and remove this vnode.
- */
- vn_remove(vp);
+ vn_trace_entry(vp, "clear_inode", (inst_t *)__return_address);
+
+ XFS_STATS_INC(vn_rele);
+ XFS_STATS_INC(vn_remove);
+ XFS_STATS_INC(vn_reclaim);
+ XFS_STATS_DEC(vn_active);
+
+ /*
+ * This can happen because xfs_iget_core calls xfs_idestroy if we
+ * find an inode with di_mode == 0 but without IGET_CREATE set.
+ */
+ if (vp->v_fbhv)
+ VOP_INACTIVE(vp, NULL, cache);
+
+ VN_LOCK(vp);
+ vp->v_flag &= ~VMODIFIED;
+ VN_UNLOCK(vp, 0);
+
+ if (vp->v_fbhv) {
+ VOP_RECLAIM(vp, error);
+ if (error)
+ panic("vn_purge: cannot reclaim");
}
-}
+ ASSERT(vp->v_fbhv == NULL);
+
+#ifdef XFS_VNODE_TRACE
+ ktrace_free(vp->v_trace);
+#endif
+}
/*
* Enqueue a work item to be picked up by the vfs xfssyncd thread.
@@ -466,25 +517,16 @@
{
long timeleft;
vfs_t *vfsp = (vfs_t *) arg;
- struct list_head tmp;
struct vfs_sync_work *work, *n;
+ LIST_HEAD (tmp);
- daemonize("xfssyncd");
-
- vfsp->vfs_sync_work.w_vfs = vfsp;
- vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
- vfsp->vfs_sync_task = current;
- wmb();
- wake_up(&vfsp->vfs_wait_sync_task);
-
- INIT_LIST_HEAD(&tmp);
timeleft = (xfs_syncd_centisecs * HZ) / 100;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
timeleft = schedule_timeout(timeleft);
/* swsusp */
try_to_freeze();
- if (vfsp->vfs_flag & VFS_UMOUNT)
+ if (kthread_should_stop())
break;
spin_lock(&vfsp->vfs_sync_lock);
@@ -513,10 +555,6 @@
}
}
- vfsp->vfs_sync_task = NULL;
- wmb();
- wake_up(&vfsp->vfs_wait_sync_task);
-
return 0;
}
@@ -524,13 +562,11 @@
linvfs_start_syncd(
vfs_t *vfsp)
{
- int pid;
-
- pid = kernel_thread(xfssyncd, (void *) vfsp,
- CLONE_VM | CLONE_FS | CLONE_FILES);
- if (pid < 0)
- return -pid;
- wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task);
+ vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
+ vfsp->vfs_sync_work.w_vfs = vfsp;
+ vfsp->vfs_sync_task = kthread_run(xfssyncd, vfsp, "xfssyncd");
+ if (IS_ERR(vfsp->vfs_sync_task))
+ return -PTR_ERR(vfsp->vfs_sync_task);
return 0;
}
@@ -538,11 +574,7 @@
linvfs_stop_syncd(
vfs_t *vfsp)
{
- vfsp->vfs_flag |= VFS_UMOUNT;
- wmb();
-
- wake_up_process(vfsp->vfs_sync_task);
- wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task);
+ kthread_stop(vfsp->vfs_sync_task);
}
STATIC void
@@ -866,9 +898,9 @@
ktrace_init(64);
- error = init_inodecache();
+ error = linvfs_init_zones();
if (error < 0)
- goto undo_inodecache;
+ goto undo_zones;
error = pagebuf_init();
if (error < 0)
@@ -889,9 +921,9 @@
pagebuf_terminate();
undo_pagebuf:
- destroy_inodecache();
+ linvfs_destroy_zones();
-undo_inodecache:
+undo_zones:
return error;
}
@@ -903,7 +935,7 @@
unregister_filesystem(&xfs_fs_type);
xfs_cleanup();
pagebuf_terminate();
- destroy_inodecache();
+ linvfs_destroy_zones();
ktrace_uninit();
}
diff --git a/fs/xfs/linux-2.6/xfs_vfs.c b/fs/xfs/linux-2.6/xfs_vfs.c
index 669c616..34cc902 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.c
+++ b/fs/xfs/linux-2.6/xfs_vfs.c
@@ -251,7 +251,6 @@
bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
INIT_LIST_HEAD(&vfsp->vfs_sync_list);
spin_lock_init(&vfsp->vfs_sync_lock);
- init_waitqueue_head(&vfsp->vfs_wait_sync_task);
init_waitqueue_head(&vfsp->vfs_wait_single_sync_task);
return vfsp;
}
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
index 7ee1f71..f0ab574f 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -65,7 +65,6 @@
spinlock_t vfs_sync_lock; /* work item list lock */
int vfs_sync_seq; /* sync thread generation no. */
wait_queue_head_t vfs_wait_single_sync_task;
- wait_queue_head_t vfs_wait_sync_task;
} vfs_t;
#define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */
@@ -96,7 +95,6 @@
#define VFS_RDONLY 0x0001 /* read-only vfs */
#define VFS_GRPID 0x0002 /* group-ID assigned from directory */
#define VFS_DMI 0x0004 /* filesystem has the DMI enabled */
-#define VFS_UMOUNT 0x0008 /* unmount in progress */
#define VFS_END 0x0008 /* max flag */
#define SYNC_ATTR 0x0001 /* sync attributes */
diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c
index 250cad5..268f45b 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.c
+++ b/fs/xfs/linux-2.6/xfs_vnode.c
@@ -42,93 +42,33 @@
*/
#define NVSYNC 37
#define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC])
-sv_t vsync[NVSYNC];
-
-/*
- * Translate stat(2) file types to vnode types and vice versa.
- * Aware of numeric order of S_IFMT and vnode type values.
- */
-enum vtype iftovt_tab[] = {
- VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
- VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
-};
-
-u_short vttoif_tab[] = {
- 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 0, S_IFSOCK
-};
+STATIC wait_queue_head_t vsync[NVSYNC];
void
vn_init(void)
{
- register sv_t *svp;
- register int i;
+ int i;
- for (svp = vsync, i = 0; i < NVSYNC; i++, svp++)
- init_sv(svp, SV_DEFAULT, "vsy", i);
+ for (i = 0; i < NVSYNC; i++)
+ init_waitqueue_head(&vsync[i]);
}
-/*
- * Clean a vnode of filesystem-specific data and prepare it for reuse.
- */
-STATIC int
-vn_reclaim(
+void
+vn_iowait(
struct vnode *vp)
{
- int error;
+ wait_queue_head_t *wq = vptosync(vp);
- XFS_STATS_INC(vn_reclaim);
- vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address);
-
- /*
- * Only make the VOP_RECLAIM call if there are behaviors
- * to call.
- */
- if (vp->v_fbhv) {
- VOP_RECLAIM(vp, error);
- if (error)
- return -error;
- }
- ASSERT(vp->v_fbhv == NULL);
-
- VN_LOCK(vp);
- vp->v_flag &= (VRECLM|VWAIT);
- VN_UNLOCK(vp, 0);
-
- vp->v_type = VNON;
- vp->v_fbhv = NULL;
-
-#ifdef XFS_VNODE_TRACE
- ktrace_free(vp->v_trace);
- vp->v_trace = NULL;
-#endif
-
- return 0;
+ wait_event(*wq, (atomic_read(&vp->v_iocount) == 0));
}
-STATIC void
-vn_wakeup(
+void
+vn_iowake(
struct vnode *vp)
{
- VN_LOCK(vp);
- if (vp->v_flag & VWAIT)
- sv_broadcast(vptosync(vp));
- vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED);
- VN_UNLOCK(vp, 0);
-}
-
-int
-vn_wait(
- struct vnode *vp)
-{
- VN_LOCK(vp);
- if (vp->v_flag & (VINACT | VRECLM)) {
- vp->v_flag |= VWAIT;
- sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0);
- return 1;
- }
- VN_UNLOCK(vp, 0);
- return 0;
+ if (atomic_dec_and_test(&vp->v_iocount))
+ wake_up(vptosync(vp));
}
struct vnode *
@@ -154,6 +94,8 @@
/* Initialize the first behavior and the behavior chain head. */
vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode");
+ atomic_set(&vp->v_iocount, 0);
+
#ifdef XFS_VNODE_TRACE
vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
#endif /* XFS_VNODE_TRACE */
@@ -163,30 +105,6 @@
}
/*
- * Get a reference on a vnode.
- */
-vnode_t *
-vn_get(
- struct vnode *vp,
- vmap_t *vmap)
-{
- struct inode *inode;
-
- XFS_STATS_INC(vn_get);
- inode = LINVFS_GET_IP(vp);
- if (inode->i_state & I_FREEING)
- return NULL;
-
- inode = ilookup(vmap->v_vfsp->vfs_super, vmap->v_ino);
- if (!inode) /* Inode not present */
- return NULL;
-
- vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
-
- return vp;
-}
-
-/*
* Revalidate the Linux inode from the vattr.
* Note: i_size _not_ updated; we must hold the inode
* semaphore when doing that - callers responsibility.
@@ -198,7 +116,7 @@
{
struct inode *inode = LINVFS_GET_IP(vp);
- inode->i_mode = VTTOIF(vap->va_type) | vap->va_mode;
+ inode->i_mode = vap->va_mode;
inode->i_nlink = vap->va_nlink;
inode->i_uid = vap->va_uid;
inode->i_gid = vap->va_gid;
@@ -247,71 +165,6 @@
}
/*
- * purge a vnode from the cache
- * At this point the vnode is guaranteed to have no references (vn_count == 0)
- * The caller has to make sure that there are no ways someone could
- * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock).
- */
-void
-vn_purge(
- struct vnode *vp,
- vmap_t *vmap)
-{
- vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
-
-again:
- /*
- * Check whether vp has already been reclaimed since our caller
- * sampled its version while holding a filesystem cache lock that
- * its VOP_RECLAIM function acquires.
- */
- VN_LOCK(vp);
- if (vp->v_number != vmap->v_number) {
- VN_UNLOCK(vp, 0);
- return;
- }
-
- /*
- * If vp is being reclaimed or inactivated, wait until it is inert,
- * then proceed. Can't assume that vnode is actually reclaimed
- * just because the reclaimed flag is asserted -- a vn_alloc
- * reclaim can fail.
- */
- if (vp->v_flag & (VINACT | VRECLM)) {
- ASSERT(vn_count(vp) == 0);
- vp->v_flag |= VWAIT;
- sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0);
- goto again;
- }
-
- /*
- * Another process could have raced in and gotten this vnode...
- */
- if (vn_count(vp) > 0) {
- VN_UNLOCK(vp, 0);
- return;
- }
-
- XFS_STATS_DEC(vn_active);
- vp->v_flag |= VRECLM;
- VN_UNLOCK(vp, 0);
-
- /*
- * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells
- * vp's filesystem to flush and invalidate all cached resources.
- * When vn_reclaim returns, vp should have no private data,
- * either in a system cache or attached to v_data.
- */
- if (vn_reclaim(vp) != 0)
- panic("vn_purge: cannot reclaim");
-
- /*
- * Wakeup anyone waiting for vp to be reclaimed.
- */
- vn_wakeup(vp);
-}
-
-/*
* Add a reference to a referenced vnode.
*/
struct vnode *
@@ -330,80 +183,6 @@
return vp;
}
-/*
- * Call VOP_INACTIVE on last reference.
- */
-void
-vn_rele(
- struct vnode *vp)
-{
- int vcnt;
- int cache;
-
- XFS_STATS_INC(vn_rele);
-
- VN_LOCK(vp);
-
- vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address);
- vcnt = vn_count(vp);
-
- /*
- * Since we always get called from put_inode we know
- * that i_count won't be decremented after we
- * return.
- */
- if (!vcnt) {
- /*
- * As soon as we turn this on, noone can find us in vn_get
- * until we turn off VINACT or VRECLM
- */
- vp->v_flag |= VINACT;
- VN_UNLOCK(vp, 0);
-
- /*
- * Do not make the VOP_INACTIVE call if there
- * are no behaviors attached to the vnode to call.
- */
- if (vp->v_fbhv)
- VOP_INACTIVE(vp, NULL, cache);
-
- VN_LOCK(vp);
- if (vp->v_flag & VWAIT)
- sv_broadcast(vptosync(vp));
-
- vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VMODIFIED);
- }
-
- VN_UNLOCK(vp, 0);
-
- vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address);
-}
-
-/*
- * Finish the removal of a vnode.
- */
-void
-vn_remove(
- struct vnode *vp)
-{
- vmap_t vmap;
-
- /* Make sure we don't do this to the same vnode twice */
- if (!(vp->v_fbhv))
- return;
-
- XFS_STATS_INC(vn_remove);
- vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address);
-
- /*
- * After the following purge the vnode
- * will no longer exist.
- */
- VMAP(vp, vmap);
- vn_purge(vp, &vmap);
-}
-
-
#ifdef XFS_VNODE_TRACE
#define KTRACE_ENTER(vp, vk, s, line, ra) \
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index a6e57c6..35f306c 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -65,10 +65,6 @@
struct xfs_iomap;
struct attrlist_cursor_kern;
-/*
- * Vnode types. VNON means no type.
- */
-enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VFIFO, VBAD, VSOCK };
typedef xfs_ino_t vnumber_t;
typedef struct dentry vname_t;
@@ -77,15 +73,14 @@
/*
* MP locking protocols:
* v_flag, v_vfsp VN_LOCK/VN_UNLOCK
- * v_type read-only or fs-dependent
*/
typedef struct vnode {
__u32 v_flag; /* vnode flags (see below) */
- enum vtype v_type; /* vnode type */
struct vfs *v_vfsp; /* ptr to containing VFS */
vnumber_t v_number; /* in-core vnode number */
vn_bhv_head_t v_bh; /* behavior head */
spinlock_t v_lock; /* VN_LOCK/VN_UNLOCK */
+ atomic_t v_iocount; /* outstanding I/O count */
#ifdef XFS_VNODE_TRACE
struct ktrace *v_trace; /* trace header structure */
#endif
@@ -93,6 +88,12 @@
/* inode MUST be last */
} vnode_t;
+#define VN_ISLNK(vp) S_ISLNK((vp)->v_inode.i_mode)
+#define VN_ISREG(vp) S_ISREG((vp)->v_inode.i_mode)
+#define VN_ISDIR(vp) S_ISDIR((vp)->v_inode.i_mode)
+#define VN_ISCHR(vp) S_ISCHR((vp)->v_inode.i_mode)
+#define VN_ISBLK(vp) S_ISBLK((vp)->v_inode.i_mode)
+
#define v_fbhv v_bh.bh_first /* first behavior */
#define v_fops v_bh.bh_first->bd_ops /* first behavior ops */
@@ -133,22 +134,8 @@
#define LINVFS_GET_IP(vp) (&(vp)->v_inode)
/*
- * Convert between vnode types and inode formats (since POSIX.1
- * defines mode word of stat structure in terms of inode formats).
- */
-extern enum vtype iftovt_tab[];
-extern u_short vttoif_tab[];
-#define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
-#define VTTOIF(indx) (vttoif_tab[(int)(indx)])
-#define MAKEIMODE(indx, mode) (int)(VTTOIF(indx) | (mode))
-
-
-/*
* Vnode flags.
*/
-#define VINACT 0x1 /* vnode is being inactivated */
-#define VRECLM 0x2 /* vnode is being reclaimed */
-#define VWAIT 0x4 /* waiting for VINACT/VRECLM to end */
#define VMODIFIED 0x8 /* XFS inode state possibly differs */
/* to the Linux inode state. */
@@ -408,7 +395,6 @@
*/
typedef struct vattr {
int va_mask; /* bit-mask of attributes present */
- enum vtype va_type; /* vnode type (for create) */
mode_t va_mode; /* file access mode and type */
xfs_nlink_t va_nlink; /* number of references to file */
uid_t va_uid; /* owner user id */
@@ -498,27 +484,12 @@
* Check whether mandatory file locking is enabled.
*/
#define MANDLOCK(vp, mode) \
- ((vp)->v_type == VREG && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
+ (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
extern void vn_init(void);
-extern int vn_wait(struct vnode *);
extern vnode_t *vn_initialize(struct inode *);
/*
- * Acquiring and invalidating vnodes:
- *
- * if (vn_get(vp, version, 0))
- * ...;
- * vn_purge(vp, version);
- *
- * vn_get and vn_purge must be called with vmap_t arguments, sampled
- * while a lock that the vnode's VOP_RECLAIM function acquires is
- * held, to ensure that the vnode sampled with the lock held isn't
- * recycled (VOP_RECLAIMed) or deallocated between the release of the lock
- * and the subsequent vn_get or vn_purge.
- */
-
-/*
* vnode_map structures _must_ match vn_epoch and vnode structure sizes.
*/
typedef struct vnode_map {
@@ -531,11 +502,11 @@
(vmap).v_number = (vp)->v_number, \
(vmap).v_ino = (vp)->v_inode.i_ino; }
-extern void vn_purge(struct vnode *, vmap_t *);
-extern vnode_t *vn_get(struct vnode *, vmap_t *);
extern int vn_revalidate(struct vnode *);
extern void vn_revalidate_core(struct vnode *, vattr_t *);
-extern void vn_remove(struct vnode *);
+
+extern void vn_iowait(struct vnode *vp);
+extern void vn_iowake(struct vnode *vp);
static inline int vn_count(struct vnode *vp)
{
@@ -546,7 +517,6 @@
* Vnode reference counting functions (and macros for compatibility).
*/
extern vnode_t *vn_hold(struct vnode *);
-extern void vn_rele(struct vnode *);
#if defined(XFS_VNODE_TRACE)
#define VN_HOLD(vp) \
@@ -560,6 +530,12 @@
#define VN_RELE(vp) (iput(LINVFS_GET_IP(vp)))
#endif
+static inline struct vnode *vn_grab(struct vnode *vp)
+{
+ struct inode *inode = igrab(LINVFS_GET_IP(vp));
+ return inode ? LINVFS_GET_VP(inode) : NULL;
+}
+
/*
* Vname handling macros.
*/
diff --git a/fs/xfs/quota/Makefile b/fs/xfs/quota/Makefile
new file mode 100644
index 0000000..7a4f725
--- /dev/null
+++ b/fs/xfs/quota/Makefile
@@ -0,0 +1 @@
+include $(TOPDIR)/fs/xfs/quota/Makefile-linux-$(VERSION).$(PATCHLEVEL)
diff --git a/fs/xfs/quota/Makefile-linux-2.6 b/fs/xfs/quota/Makefile-linux-2.6
new file mode 100644
index 0000000..8b7b676
--- /dev/null
+++ b/fs/xfs/quota/Makefile-linux-2.6
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+EXTRA_CFLAGS += -I $(TOPDIR)/fs/xfs -I $(TOPDIR)/fs/xfs/linux-2.6
+
+ifeq ($(CONFIG_XFS_DEBUG),y)
+ EXTRA_CFLAGS += -g -DDEBUG
+ #EXTRA_CFLAGS += -DQUOTADEBUG
+endif
+ifeq ($(CONFIG_XFS_TRACE),y)
+ EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
+ EXTRA_CFLAGS += -DXFS_VNODE_TRACE
+endif
+
+obj-$(CONFIG_XFS_QUOTA) += xfs_quota.o
+
+xfs_quota-y += xfs_dquot.o \
+ xfs_dquot_item.o \
+ xfs_trans_dquot.o \
+ xfs_qm_syscalls.o \
+ xfs_qm_bhv.o \
+ xfs_qm.o
+
+xfs_quota-$(CONFIG_PROC_FS) += xfs_qm_stats.o
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index 46ce1e3..e2e8d35 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -421,7 +421,7 @@
*/
STATIC int
xfs_qm_dqalloc(
- xfs_trans_t *tp,
+ xfs_trans_t **tpp,
xfs_mount_t *mp,
xfs_dquot_t *dqp,
xfs_inode_t *quotip,
@@ -433,6 +433,7 @@
xfs_bmbt_irec_t map;
int nmaps, error, committed;
xfs_buf_t *bp;
+ xfs_trans_t *tp = *tpp;
ASSERT(tp != NULL);
xfs_dqtrace_entry(dqp, "DQALLOC");
@@ -492,10 +493,32 @@
xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
dqp->dq_flags & XFS_DQ_ALLTYPES, bp);
- if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
+ /*
+ * xfs_bmap_finish() may commit the current transaction and
+ * start a second transaction if the freelist is not empty.
+ *
+ * Since we still want to modify this buffer, we need to
+ * ensure that the buffer is not released on commit of
+ * the first transaction and ensure the buffer is added to the
+ * second transaction.
+ *
+ * If there is only one transaction then don't stop the buffer
+ * from being released when it commits later on.
+ */
+
+ xfs_trans_bhold(tp, bp);
+
+ if ((error = xfs_bmap_finish(tpp, &flist, firstblock, &committed))) {
goto error1;
}
+ if (committed) {
+ tp = *tpp;
+ xfs_trans_bjoin(tp, bp);
+ } else {
+ xfs_trans_bhold_release(tp, bp);
+ }
+
*O_bpp = bp;
return 0;
@@ -514,7 +537,7 @@
*/
STATIC int
xfs_qm_dqtobp(
- xfs_trans_t *tp,
+ xfs_trans_t **tpp,
xfs_dquot_t *dqp,
xfs_disk_dquot_t **O_ddpp,
xfs_buf_t **O_bpp,
@@ -528,6 +551,7 @@
xfs_disk_dquot_t *ddq;
xfs_dqid_t id;
boolean_t newdquot;
+ xfs_trans_t *tp = (tpp ? *tpp : NULL);
mp = dqp->q_mount;
id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
@@ -579,9 +603,10 @@
return (ENOENT);
ASSERT(tp);
- if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
+ if ((error = xfs_qm_dqalloc(tpp, mp, dqp, quotip,
dqp->q_fileoffset, &bp)))
return (error);
+ tp = *tpp;
newdquot = B_TRUE;
} else {
/*
@@ -645,7 +670,7 @@
/* ARGSUSED */
STATIC int
xfs_qm_dqread(
- xfs_trans_t *tp,
+ xfs_trans_t **tpp,
xfs_dqid_t id,
xfs_dquot_t *dqp, /* dquot to get filled in */
uint flags)
@@ -653,15 +678,19 @@
xfs_disk_dquot_t *ddqp;
xfs_buf_t *bp;
int error;
+ xfs_trans_t *tp;
+
+ ASSERT(tpp);
/*
* get a pointer to the on-disk dquot and the buffer containing it
* dqp already knows its own type (GROUP/USER).
*/
xfs_dqtrace_entry(dqp, "DQREAD");
- if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
+ if ((error = xfs_qm_dqtobp(tpp, dqp, &ddqp, &bp, flags))) {
return (error);
}
+ tp = *tpp;
/* copy everything from disk dquot to the incore dquot */
memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
@@ -740,7 +769,7 @@
* Read it from disk; xfs_dqread() takes care of
* all the necessary initialization of dquot's fields (locks, etc)
*/
- if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
+ if ((error = xfs_qm_dqread(&tp, id, dqp, flags))) {
/*
* This can happen if quotas got turned off (ESRCH),
* or if the dquot didn't exist on disk and we ask to
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h
index 3917510..8ebc871 100644
--- a/fs/xfs/quota/xfs_dquot.h
+++ b/fs/xfs/quota/xfs_dquot.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -113,20 +113,6 @@
#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++)
-/*
- * Quota Accounting/Enforcement flags
- */
-#define XFS_ALL_QUOTA_ACCT \
- (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
-
-#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
-#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
-#define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT)
-#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
-
#ifdef DEBUG
static inline int
XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
index f5271b7..e74eaa7 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -509,6 +509,7 @@
log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
log_vector->i_len = sizeof(xfs_qoff_logitem_t);
+ XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_QUOTAOFF);
qf->qql_format.qf_size = 1;
}
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index f665ca8f..efde16e 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -365,16 +365,6 @@
int error = 0;
uint sbf;
- /*
- * If a file system had quotas running earlier, but decided to
- * mount without -o uquota/pquota/gquota options, revoke the
- * quotachecked license, and bail out.
- */
- if (! XFS_IS_QUOTA_ON(mp) &&
- (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT)) {
- mp->m_qflags = 0;
- goto write_changes;
- }
/*
* If quotas on realtime volumes is not supported, we disable
@@ -388,11 +378,8 @@
goto write_changes;
}
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
- cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
-#endif
-
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
/*
* Allocate the quotainfo structure inside the mount struct, and
* create quotainode(s), and change/rev superblock if necessary.
@@ -410,19 +397,14 @@
*/
if (XFS_QM_NEED_QUOTACHECK(mp) &&
!(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) {
-#ifdef DEBUG
- cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
-#endif
if ((error = xfs_qm_quotacheck(mp))) {
/* Quotacheck has failed and quotas have
* been disabled.
*/
return XFS_ERROR(error);
}
-#ifdef DEBUG
- cmn_err(CE_NOTE, "Done quotacheck.");
-#endif
}
+
write_changes:
/*
* We actually don't have to acquire the SB_LOCK at all.
@@ -2010,7 +1992,7 @@
ASSERT(mp->m_quotainfo != NULL);
ASSERT(xfs_Gqm != NULL);
xfs_qm_destroy_quotainfo(mp);
- xfs_mount_reset_sbqflags(mp);
+ (void)xfs_mount_reset_sbqflags(mp);
} else {
cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
}
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h
index b03eecf..0b00b3c 100644
--- a/fs/xfs/quota/xfs_qm.h
+++ b/fs/xfs/quota/xfs_qm.h
@@ -184,8 +184,6 @@
#define XFS_QM_HOLD(xqm) ((xqm)->qm_nrefs++)
#define XFS_QM_RELE(xqm) ((xqm)->qm_nrefs--)
-extern void xfs_mount_reset_sbqflags(xfs_mount_t *);
-
extern void xfs_qm_destroy_quotainfo(xfs_mount_t *);
extern int xfs_qm_mount_quotas(xfs_mount_t *, int);
extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint);
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c
index dc3c37a..8890a18 100644
--- a/fs/xfs/quota/xfs_qm_bhv.c
+++ b/fs/xfs/quota/xfs_qm_bhv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -229,48 +229,6 @@
return error;
}
-/*
- * Clear the quotaflags in memory and in the superblock.
- */
-void
-xfs_mount_reset_sbqflags(
- xfs_mount_t *mp)
-{
- xfs_trans_t *tp;
- unsigned long s;
-
- mp->m_qflags = 0;
- /*
- * It is OK to look at sb_qflags here in mount path,
- * without SB_LOCK.
- */
- if (mp->m_sb.sb_qflags == 0)
- return;
- s = XFS_SB_LOCK(mp);
- mp->m_sb.sb_qflags = 0;
- XFS_SB_UNLOCK(mp, s);
-
- /*
- * if the fs is readonly, let the incore superblock run
- * with quotas off but don't flush the update out to disk
- */
- if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
- return;
-#ifdef QUOTADEBUG
- xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
-#endif
- tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
- if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
- XFS_DEFAULT_LOG_COUNT)) {
- xfs_trans_cancel(tp, 0);
- xfs_fs_cmn_err(CE_ALERT, mp,
- "xfs_mount_reset_sbqflags: Superblock update failed!");
- return;
- }
- xfs_mod_sb(tp, XFS_SB_QFLAGS);
- xfs_trans_commit(tp, 0, NULL);
-}
-
STATIC int
xfs_qm_newmount(
xfs_mount_t *mp,
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 68e9896..15e02e8 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -1053,7 +1053,6 @@
struct xfs_mount *mp,
uint flags)
{
- vmap_t vmap;
xfs_inode_t *ip, *topino;
uint ireclaims;
vnode_t *vp;
@@ -1061,8 +1060,8 @@
ASSERT(mp->m_quotainfo);
-again:
XFS_MOUNT_ILOCK(mp);
+again:
ip = mp->m_inodes;
if (ip == NULL) {
XFS_MOUNT_IUNLOCK(mp);
@@ -1090,18 +1089,14 @@
}
vnode_refd = B_FALSE;
if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
- /*
- * Sample vp mapping while holding the mplock, lest
- * we come across a non-existent vnode.
- */
- VMAP(vp, vmap);
ireclaims = mp->m_ireclaims;
topino = mp->m_inodes;
- XFS_MOUNT_IUNLOCK(mp);
-
- /* XXX restart limit ? */
- if ( ! (vp = vn_get(vp, &vmap)))
+ vp = vn_grab(vp);
+ if (!vp)
goto again;
+
+ XFS_MOUNT_IUNLOCK(mp);
+ /* XXX restart limit ? */
xfs_ilock(ip, XFS_ILOCK_EXCL);
vnode_refd = B_TRUE;
} else {
@@ -1137,7 +1132,6 @@
*/
if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
/* XXX use a sentinel */
- XFS_MOUNT_IUNLOCK(mp);
goto again;
}
ip = ip->i_mnext;
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 4ed7b69..4e1a5ec 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -31,6 +31,7 @@
*/
#include "debug.h"
+#include "spin.h"
#include <asm/page.h>
#include <linux/sched.h>
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 8d01dce..92fd1d6 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -85,7 +85,7 @@
{
int error;
- if (vp->v_type != VDIR)
+ if (!VN_ISDIR(vp))
return 0;
xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
return (error == 0);
@@ -389,7 +389,7 @@
if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
return EPERM;
- if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR)
+ if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp))
return ENOTDIR;
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
return EROFS;
@@ -750,7 +750,7 @@
* If the new file is a directory, its default ACL is a copy of
* the containing directory's default ACL.
*/
- if (vp->v_type == VDIR)
+ if (VN_ISDIR(vp))
xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
if (!error && !basicperms)
xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 6f5d283..3e76def 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -4754,10 +4754,20 @@
error = xfs_mod_incore_sb(mp,
XFS_SBS_FDBLOCKS,
-(alen), rsvd);
- if (!error)
+ if (!error) {
error = xfs_mod_incore_sb(mp,
XFS_SBS_FDBLOCKS,
-(indlen), rsvd);
+ if (error && rt) {
+ xfs_mod_incore_sb(ip->i_mount,
+ XFS_SBS_FREXTENTS,
+ extsz, rsvd);
+ } else if (error) {
+ xfs_mod_incore_sb(ip->i_mount,
+ XFS_SBS_FDBLOCKS,
+ alen, rsvd);
+ }
+ }
if (error) {
if (XFS_IS_QUOTA_ON(ip->i_mount))
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 30b8285..a264657 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -274,6 +274,7 @@
((bip->bli_format.blf_map_size - 1) * sizeof(uint)));
vecp->i_addr = (xfs_caddr_t)&bip->bli_format;
vecp->i_len = base_size;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BFORMAT);
vecp++;
nvecs = 1;
@@ -320,12 +321,14 @@
buffer_offset = first_bit * XFS_BLI_CHUNK;
vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
vecp->i_len = nbits * XFS_BLI_CHUNK;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK);
nvecs++;
break;
} else if (next_bit != last_bit + 1) {
buffer_offset = first_bit * XFS_BLI_CHUNK;
vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
vecp->i_len = nbits * XFS_BLI_CHUNK;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK);
nvecs++;
vecp++;
first_bit = next_bit;
@@ -337,6 +340,7 @@
buffer_offset = first_bit * XFS_BLI_CHUNK;
vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
vecp->i_len = nbits * XFS_BLI_CHUNK;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK);
/* You would think we need to bump the nvecs here too, but we do not
* this number is used by recovery, and it gets confused by the boundary
* split here
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h
index 55c17ad..19e8728 100644
--- a/fs/xfs/xfs_dmapi.h
+++ b/fs/xfs/xfs_dmapi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index db7cbd1..cc7d149 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -107,6 +107,7 @@
log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format);
log_vector->i_len = size;
+ XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFI_FORMAT);
ASSERT(size >= sizeof(xfs_efi_log_format_t));
}
@@ -426,6 +427,7 @@
log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format);
log_vector->i_len = size;
+ XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFD_FORMAT);
ASSERT(size >= sizeof(xfs_efd_log_format_t));
}
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index d3da000..0d9ae8f 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -30,6 +30,8 @@
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
+#include <linux/delay.h>
+
#include "xfs.h"
#include "xfs_macros.h"
@@ -505,17 +507,15 @@
vnode_t *vp = NULL;
int error;
-retry:
XFS_STATS_INC(xs_ig_attempts);
+retry:
if ((inode = iget_locked(XFS_MTOVFS(mp)->vfs_super, ino))) {
bhv_desc_t *bdp;
xfs_inode_t *ip;
- int newnode;
vp = LINVFS_GET_VP(inode);
if (inode->i_state & I_NEW) {
-inode_allocate:
vn_initialize(inode);
error = xfs_iget_core(vp, mp, tp, ino, flags,
lock_flags, ipp, bno);
@@ -526,32 +526,25 @@
iput(inode);
}
} else {
- /* These are true if the inode is in inactive or
- * reclaim. The linux inode is about to go away,
- * wait for that path to finish, and try again.
+ /*
+ * If the inode is not fully constructed due to
+ * filehandle mistmatches wait for the inode to go
+ * away and try again.
+ *
+ * iget_locked will call __wait_on_freeing_inode
+ * to wait for the inode to go away.
*/
- if (vp->v_flag & (VINACT | VRECLM)) {
- vn_wait(vp);
+ if (is_bad_inode(inode) ||
+ ((bdp = vn_bhv_lookup(VN_BHV_HEAD(vp),
+ &xfs_vnodeops)) == NULL)) {
iput(inode);
+ delay(1);
goto retry;
}
- if (is_bad_inode(inode)) {
- iput(inode);
- return EIO;
- }
-
- bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
- if (bdp == NULL) {
- XFS_STATS_INC(xs_ig_dup);
- goto inode_allocate;
- }
ip = XFS_BHVTOI(bdp);
if (lock_flags != 0)
xfs_ilock(ip, lock_flags);
- newnode = (ip->i_d.di_mode == 0);
- if (newnode)
- xfs_iocore_inode_reinit(ip);
XFS_STATS_INC(xs_ig_found);
*ipp = ip;
error = 0;
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 34bdf59..db43308 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1128,7 +1128,6 @@
ASSERT(ip != NULL);
vp = XFS_ITOV(ip);
- vp->v_type = IFTOVT(mode);
ip->i_d.di_mode = (__uint16_t)mode;
ip->i_d.di_onlink = 0;
ip->i_d.di_nlink = nlink;
@@ -1250,7 +1249,7 @@
*/
xfs_trans_log_inode(tp, ip, flags);
- /* now that we have a v_type we can set Linux inode ops (& unlock) */
+ /* now that we have an i_mode we can set Linux inode ops (& unlock) */
VFS_INIT_VNODE(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1);
*ipp = ip;
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 0eed30f..276ec70 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -248,6 +248,7 @@
vecp->i_addr = (xfs_caddr_t)&iip->ili_format;
vecp->i_len = sizeof(xfs_inode_log_format_t);
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IFORMAT);
vecp++;
nvecs = 1;
@@ -292,6 +293,7 @@
vecp->i_addr = (xfs_caddr_t)&ip->i_d;
vecp->i_len = sizeof(xfs_dinode_core_t);
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE);
vecp++;
nvecs++;
iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
@@ -349,6 +351,7 @@
vecp->i_addr =
(char *)(ip->i_df.if_u1.if_extents);
vecp->i_len = ip->i_df.if_bytes;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT);
} else
#endif
{
@@ -367,6 +370,7 @@
vecp->i_addr = (xfs_caddr_t)ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_DATA_FORK);
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT);
}
ASSERT(vecp->i_len <= ip->i_df.if_bytes);
iip->ili_format.ilf_dsize = vecp->i_len;
@@ -384,6 +388,7 @@
ASSERT(ip->i_df.if_broot != NULL);
vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot;
vecp->i_len = ip->i_df.if_broot_bytes;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IBROOT);
vecp++;
nvecs++;
iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes;
@@ -409,6 +414,7 @@
ASSERT((ip->i_df.if_real_bytes == 0) ||
(ip->i_df.if_real_bytes == data_bytes));
vecp->i_len = (int)data_bytes;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ILOCAL);
vecp++;
nvecs++;
iip->ili_format.ilf_dsize = (unsigned)data_bytes;
@@ -486,6 +492,7 @@
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_ATTR_FORK);
#endif
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_EXT);
iip->ili_format.ilf_asize = vecp->i_len;
vecp++;
nvecs++;
@@ -500,6 +507,7 @@
ASSERT(ip->i_afp->if_broot != NULL);
vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot;
vecp->i_len = ip->i_afp->if_broot_bytes;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_BROOT);
vecp++;
nvecs++;
iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes;
@@ -523,6 +531,7 @@
ASSERT((ip->i_afp->if_real_bytes == 0) ||
(ip->i_afp->if_real_bytes == data_bytes));
vecp->i_len = (int)data_bytes;
+ XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_LOCAL);
vecp++;
nvecs++;
iip->ili_format.ilf_asize = (unsigned)data_bytes;
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 2edd676..d0f5be6 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -226,13 +226,12 @@
xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count);
lockmode = XFS_LCK_MAP_SHARED(mp, io);
bmapi_flags = XFS_BMAPI_ENTIRE;
- if (flags & BMAPI_IGNSTATE)
- bmapi_flags |= XFS_BMAPI_IGSTATE;
break;
case BMAPI_WRITE:
xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count);
lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;
- bmapi_flags = 0;
+ if (flags & BMAPI_IGNSTATE)
+ bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE;
XFS_ILOCK(mp, io, lockmode);
break;
case BMAPI_ALLOCATE:
@@ -391,9 +390,9 @@
xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;
xfs_bmap_free_t free_list;
int aeof;
- xfs_filblks_t datablocks, qblocks, resblks;
+ xfs_filblks_t qblocks, resblks;
int committed;
- int numrtextents;
+ int resrtextents;
/*
* Make sure that the dquots are there. This doesn't hold
@@ -434,14 +433,14 @@
if (!(extsz = ip->i_d.di_extsize))
extsz = mp->m_sb.sb_rextsize;
- numrtextents = qblocks = (count_fsb + extsz - 1);
- do_div(numrtextents, mp->m_sb.sb_rextsize);
+ resrtextents = qblocks = (count_fsb + extsz - 1);
+ do_div(resrtextents, mp->m_sb.sb_rextsize);
+ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
quota_flag = XFS_QMOPT_RES_RTBLKS;
- datablocks = 0;
} else {
- datablocks = qblocks = count_fsb;
+ resrtextents = 0;
+ resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, count_fsb);
quota_flag = XFS_QMOPT_RES_REGBLKS;
- numrtextents = 0;
}
/*
@@ -449,9 +448,8 @@
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL);
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
- resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
error = xfs_trans_reserve(tp, resblks,
- XFS_WRITE_LOG_RES(mp), numrtextents,
+ XFS_WRITE_LOG_RES(mp), resrtextents,
XFS_TRANS_PERM_LOG_RES,
XFS_WRITE_LOG_COUNT);
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 1cd2ac1..54a6f11 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -159,11 +159,15 @@
void
xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string)
{
- if (! log->l_grant_trace) {
- log->l_grant_trace = ktrace_alloc(1024, KM_NOSLEEP);
- if (! log->l_grant_trace)
+ unsigned long cnts;
+
+ if (!log->l_grant_trace) {
+ log->l_grant_trace = ktrace_alloc(2048, KM_NOSLEEP);
+ if (!log->l_grant_trace)
return;
}
+ /* ticket counts are 1 byte each */
+ cnts = ((unsigned long)tic->t_ocnt) | ((unsigned long)tic->t_cnt) << 8;
ktrace_enter(log->l_grant_trace,
(void *)tic,
@@ -178,10 +182,10 @@
(void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn)),
(void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn)),
(void *)string,
- (void *)((unsigned long)13),
- (void *)((unsigned long)14),
- (void *)((unsigned long)15),
- (void *)((unsigned long)16));
+ (void *)((unsigned long)tic->t_trans_type),
+ (void *)cnts,
+ (void *)((unsigned long)tic->t_curr_res),
+ (void *)((unsigned long)tic->t_unit_res));
}
void
@@ -274,9 +278,11 @@
* Release ticket if not permanent reservation or a specifc
* request has been made to release a permanent reservation.
*/
+ xlog_trace_loggrant(log, ticket, "xfs_log_done: (non-permanent)");
xlog_ungrant_log_space(log, ticket);
xlog_state_put_ticket(log, ticket);
} else {
+ xlog_trace_loggrant(log, ticket, "xfs_log_done: (permanent)");
xlog_regrant_reserve_log_space(log, ticket);
}
@@ -399,7 +405,8 @@
int cnt,
xfs_log_ticket_t *ticket,
__uint8_t client,
- uint flags)
+ uint flags,
+ uint t_type)
{
xlog_t *log = mp->m_log;
xlog_ticket_t *internal_ticket;
@@ -421,13 +428,19 @@
if (*ticket != NULL) {
ASSERT(flags & XFS_LOG_PERM_RESERV);
internal_ticket = (xlog_ticket_t *)*ticket;
+ xlog_trace_loggrant(log, internal_ticket, "xfs_log_reserve: existing ticket (permanent trans)");
xlog_grant_push_ail(mp, internal_ticket->t_unit_res);
retval = xlog_regrant_write_log_space(log, internal_ticket);
} else {
/* may sleep if need to allocate more tickets */
internal_ticket = xlog_ticket_get(log, unit_bytes, cnt,
client, flags);
+ internal_ticket->t_trans_type = t_type;
*ticket = internal_ticket;
+ xlog_trace_loggrant(log, internal_ticket,
+ (internal_ticket->t_flags & XLOG_TIC_PERM_RESERV) ?
+ "xfs_log_reserve: create new ticket (permanent trans)" :
+ "xfs_log_reserve: create new ticket");
xlog_grant_push_ail(mp,
(internal_ticket->t_unit_res *
internal_ticket->t_cnt));
@@ -601,8 +614,9 @@
if (! (XLOG_FORCED_SHUTDOWN(log))) {
reg[0].i_addr = (void*)&magic;
reg[0].i_len = sizeof(magic);
+ XLOG_VEC_SET_TYPE(®[0], XLOG_REG_TYPE_UNMOUNT);
- error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0);
+ error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0, 0);
if (!error) {
/* remove inited flag */
((xlog_ticket_t *)tic)->t_flags = 0;
@@ -1272,6 +1286,7 @@
reg[0].i_addr = NULL;
reg[0].i_len = 0;
+ XLOG_VEC_SET_TYPE(®[0], XLOG_REG_TYPE_COMMIT);
ASSERT_ALWAYS(iclog);
if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp,
@@ -1605,6 +1620,117 @@
/*
+ * print out info relating to regions written which consume
+ * the reservation
+ */
+#if defined(XFS_LOG_RES_DEBUG)
+STATIC void
+xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket)
+{
+ uint i;
+ uint ophdr_spc = ticket->t_res_num_ophdrs * (uint)sizeof(xlog_op_header_t);
+
+ /* match with XLOG_REG_TYPE_* in xfs_log.h */
+ static char *res_type_str[XLOG_REG_TYPE_MAX] = {
+ "bformat",
+ "bchunk",
+ "efi_format",
+ "efd_format",
+ "iformat",
+ "icore",
+ "iext",
+ "ibroot",
+ "ilocal",
+ "iattr_ext",
+ "iattr_broot",
+ "iattr_local",
+ "qformat",
+ "dquot",
+ "quotaoff",
+ "LR header",
+ "unmount",
+ "commit",
+ "trans header"
+ };
+ static char *trans_type_str[XFS_TRANS_TYPE_MAX] = {
+ "SETATTR_NOT_SIZE",
+ "SETATTR_SIZE",
+ "INACTIVE",
+ "CREATE",
+ "CREATE_TRUNC",
+ "TRUNCATE_FILE",
+ "REMOVE",
+ "LINK",
+ "RENAME",
+ "MKDIR",
+ "RMDIR",
+ "SYMLINK",
+ "SET_DMATTRS",
+ "GROWFS",
+ "STRAT_WRITE",
+ "DIOSTRAT",
+ "WRITE_SYNC",
+ "WRITEID",
+ "ADDAFORK",
+ "ATTRINVAL",
+ "ATRUNCATE",
+ "ATTR_SET",
+ "ATTR_RM",
+ "ATTR_FLAG",
+ "CLEAR_AGI_BUCKET",
+ "QM_SBCHANGE",
+ "DUMMY1",
+ "DUMMY2",
+ "QM_QUOTAOFF",
+ "QM_DQALLOC",
+ "QM_SETQLIM",
+ "QM_DQCLUSTER",
+ "QM_QINOCREATE",
+ "QM_QUOTAOFF_END",
+ "SB_UNIT",
+ "FSYNC_TS",
+ "GROWFSRT_ALLOC",
+ "GROWFSRT_ZERO",
+ "GROWFSRT_FREE",
+ "SWAPEXT"
+ };
+
+ xfs_fs_cmn_err(CE_WARN, mp,
+ "xfs_log_write: reservation summary:\n"
+ " trans type = %s (%u)\n"
+ " unit res = %d bytes\n"
+ " current res = %d bytes\n"
+ " total reg = %u bytes (o/flow = %u bytes)\n"
+ " ophdrs = %u (ophdr space = %u bytes)\n"
+ " ophdr + reg = %u bytes\n"
+ " num regions = %u\n",
+ ((ticket->t_trans_type <= 0 ||
+ ticket->t_trans_type > XFS_TRANS_TYPE_MAX) ?
+ "bad-trans-type" : trans_type_str[ticket->t_trans_type-1]),
+ ticket->t_trans_type,
+ ticket->t_unit_res,
+ ticket->t_curr_res,
+ ticket->t_res_arr_sum, ticket->t_res_o_flow,
+ ticket->t_res_num_ophdrs, ophdr_spc,
+ ticket->t_res_arr_sum +
+ ticket->t_res_o_flow + ophdr_spc,
+ ticket->t_res_num);
+
+ for (i = 0; i < ticket->t_res_num; i++) {
+ uint r_type = ticket->t_res_arr[i].r_type;
+ cmn_err(CE_WARN,
+ "region[%u]: %s - %u bytes\n",
+ i,
+ ((r_type <= 0 || r_type > XLOG_REG_TYPE_MAX) ?
+ "bad-rtype" : res_type_str[r_type-1]),
+ ticket->t_res_arr[i].r_len);
+ }
+}
+#else
+#define xlog_print_tic_res(mp, ticket)
+#endif
+
+/*
* Write some region out to in-core log
*
* This will be called when writing externally provided regions or when
@@ -1677,16 +1803,21 @@
* xlog_op_header_t and may need to be double word aligned.
*/
len = 0;
- if (ticket->t_flags & XLOG_TIC_INITED) /* acct for start rec of xact */
+ if (ticket->t_flags & XLOG_TIC_INITED) { /* acct for start rec of xact */
len += sizeof(xlog_op_header_t);
+ XLOG_TIC_ADD_OPHDR(ticket);
+ }
for (index = 0; index < nentries; index++) {
len += sizeof(xlog_op_header_t); /* each region gets >= 1 */
+ XLOG_TIC_ADD_OPHDR(ticket);
len += reg[index].i_len;
+ XLOG_TIC_ADD_REGION(ticket, reg[index].i_len, reg[index].i_type);
}
contwr = *start_lsn = 0;
if (ticket->t_curr_res < len) {
+ xlog_print_tic_res(mp, ticket);
#ifdef DEBUG
xlog_panic(
"xfs_log_write: reservation ran out. Need to up reservation");
@@ -1790,6 +1921,7 @@
len += sizeof(xlog_op_header_t); /* from splitting of region */
/* account for new log op header */
ticket->t_curr_res -= sizeof(xlog_op_header_t);
+ XLOG_TIC_ADD_OPHDR(ticket);
}
xlog_verify_dest_ptr(log, ptr);
@@ -2282,6 +2414,9 @@
*/
if (log_offset == 0) {
ticket->t_curr_res -= log->l_iclog_hsize;
+ XLOG_TIC_ADD_REGION(ticket,
+ log->l_iclog_hsize,
+ XLOG_REG_TYPE_LRHEADER);
INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle);
ASSIGN_LSN(head->h_lsn, log);
ASSERT(log->l_curr_block >= 0);
@@ -2468,6 +2603,7 @@
#endif
tic->t_curr_res = tic->t_unit_res;
+ XLOG_TIC_RESET_RES(tic);
if (tic->t_cnt > 0)
return (0);
@@ -2608,6 +2744,7 @@
XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'w');
XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'r');
ticket->t_curr_res = ticket->t_unit_res;
+ XLOG_TIC_RESET_RES(ticket);
xlog_trace_loggrant(log, ticket,
"xlog_regrant_reserve_log_space: sub current res");
xlog_verify_grant_head(log, 1);
@@ -2624,6 +2761,7 @@
xlog_verify_grant_head(log, 0);
GRANT_UNLOCK(log, s);
ticket->t_curr_res = ticket->t_unit_res;
+ XLOG_TIC_RESET_RES(ticket);
} /* xlog_regrant_reserve_log_space */
@@ -3179,29 +3317,57 @@
* and their unit amount is the total amount of space required.
*
* The following lines of code account for non-transaction data
- * which occupy space in the on-disk log.
+ * which occupy space in the on-disk log.
+ *
+ * Normal form of a transaction is:
+ * <oph><trans-hdr><start-oph><reg1-oph><reg1><reg2-oph>...<commit-oph>
+ * and then there are LR hdrs, split-recs and roundoff at end of syncs.
+ *
+ * We need to account for all the leadup data and trailer data
+ * around the transaction data.
+ * And then we need to account for the worst case in terms of using
+ * more space.
+ * The worst case will happen if:
+ * - the placement of the transaction happens to be such that the
+ * roundoff is at its maximum
+ * - the transaction data is synced before the commit record is synced
+ * i.e. <transaction-data><roundoff> | <commit-rec><roundoff>
+ * Therefore the commit record is in its own Log Record.
+ * This can happen as the commit record is called with its
+ * own region to xlog_write().
+ * This then means that in the worst case, roundoff can happen for
+ * the commit-rec as well.
+ * The commit-rec is smaller than padding in this scenario and so it is
+ * not added separately.
*/
- /* for start-rec */
- unit_bytes += sizeof(xlog_op_header_t);
-
- /* for padding */
- if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) &&
- log->l_mp->m_sb.sb_logsunit > 1) {
- /* log su roundoff */
- unit_bytes += log->l_mp->m_sb.sb_logsunit;
- } else {
- /* BB roundoff */
- unit_bytes += BBSIZE;
- }
-
- /* for commit-rec */
+ /* for trans header */
unit_bytes += sizeof(xlog_op_header_t);
-
+ unit_bytes += sizeof(xfs_trans_header_t);
+
+ /* for start-rec */
+ unit_bytes += sizeof(xlog_op_header_t);
+
/* for LR headers */
num_headers = ((unit_bytes + log->l_iclog_size-1) >> log->l_iclog_size_log);
unit_bytes += log->l_iclog_hsize * num_headers;
+ /* for commit-rec LR header - note: padding will subsume the ophdr */
+ unit_bytes += log->l_iclog_hsize;
+
+ /* for split-recs - ophdrs added when data split over LRs */
+ unit_bytes += sizeof(xlog_op_header_t) * num_headers;
+
+ /* for roundoff padding for transaction data and one for commit record */
+ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) &&
+ log->l_mp->m_sb.sb_logsunit > 1) {
+ /* log su roundoff */
+ unit_bytes += 2*log->l_mp->m_sb.sb_logsunit;
+ } else {
+ /* BB roundoff */
+ unit_bytes += 2*BBSIZE;
+ }
+
tic->t_unit_res = unit_bytes;
tic->t_curr_res = unit_bytes;
tic->t_cnt = cnt;
@@ -3209,10 +3375,13 @@
tic->t_tid = (xlog_tid_t)((__psint_t)tic & 0xffffffff);
tic->t_clientid = client;
tic->t_flags = XLOG_TIC_INITED;
+ tic->t_trans_type = 0;
if (xflags & XFS_LOG_PERM_RESERV)
tic->t_flags |= XLOG_TIC_PERM_RESERV;
sv_init(&(tic->t_sema), SV_DEFAULT, "logtick");
+ XLOG_TIC_RESET_RES(tic);
+
return tic;
} /* xlog_ticket_get */
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 0db122d..1896111 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -114,9 +114,44 @@
#define XFS_VOLUME 0x2
#define XFS_LOG 0xaa
+
+/* Region types for iovec's i_type */
+#if defined(XFS_LOG_RES_DEBUG)
+#define XLOG_REG_TYPE_BFORMAT 1
+#define XLOG_REG_TYPE_BCHUNK 2
+#define XLOG_REG_TYPE_EFI_FORMAT 3
+#define XLOG_REG_TYPE_EFD_FORMAT 4
+#define XLOG_REG_TYPE_IFORMAT 5
+#define XLOG_REG_TYPE_ICORE 6
+#define XLOG_REG_TYPE_IEXT 7
+#define XLOG_REG_TYPE_IBROOT 8
+#define XLOG_REG_TYPE_ILOCAL 9
+#define XLOG_REG_TYPE_IATTR_EXT 10
+#define XLOG_REG_TYPE_IATTR_BROOT 11
+#define XLOG_REG_TYPE_IATTR_LOCAL 12
+#define XLOG_REG_TYPE_QFORMAT 13
+#define XLOG_REG_TYPE_DQUOT 14
+#define XLOG_REG_TYPE_QUOTAOFF 15
+#define XLOG_REG_TYPE_LRHEADER 16
+#define XLOG_REG_TYPE_UNMOUNT 17
+#define XLOG_REG_TYPE_COMMIT 18
+#define XLOG_REG_TYPE_TRANSHDR 19
+#define XLOG_REG_TYPE_MAX 19
+#endif
+
+#if defined(XFS_LOG_RES_DEBUG)
+#define XLOG_VEC_SET_TYPE(vecp, t) ((vecp)->i_type = (t))
+#else
+#define XLOG_VEC_SET_TYPE(vecp, t)
+#endif
+
+
typedef struct xfs_log_iovec {
xfs_caddr_t i_addr; /* beginning address of region */
int i_len; /* length in bytes of region */
+#if defined(XFS_LOG_RES_DEBUG)
+ uint i_type; /* type of region */
+#endif
} xfs_log_iovec_t;
typedef void* xfs_log_ticket_t;
@@ -159,7 +194,8 @@
int count,
xfs_log_ticket_t *ticket,
__uint8_t clientid,
- uint flags);
+ uint flags,
+ uint t_type);
int xfs_log_write(struct xfs_mount *mp,
xfs_log_iovec_t region[],
int nentries,
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 1a1d452..eb7fdc6 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -335,18 +335,66 @@
#define XLOG_COVER_OPS 5
+
+/* Ticket reservation region accounting */
+#if defined(XFS_LOG_RES_DEBUG)
+#define XLOG_TIC_LEN_MAX 15
+#define XLOG_TIC_RESET_RES(t) ((t)->t_res_num = \
+ (t)->t_res_arr_sum = (t)->t_res_num_ophdrs = 0)
+#define XLOG_TIC_ADD_OPHDR(t) ((t)->t_res_num_ophdrs++)
+#define XLOG_TIC_ADD_REGION(t, len, type) \
+ do { \
+ if ((t)->t_res_num == XLOG_TIC_LEN_MAX) { \
+ /* add to overflow and start again */ \
+ (t)->t_res_o_flow += (t)->t_res_arr_sum; \
+ (t)->t_res_num = 0; \
+ (t)->t_res_arr_sum = 0; \
+ } \
+ (t)->t_res_arr[(t)->t_res_num].r_len = (len); \
+ (t)->t_res_arr[(t)->t_res_num].r_type = (type); \
+ (t)->t_res_arr_sum += (len); \
+ (t)->t_res_num++; \
+ } while (0)
+
+/*
+ * Reservation region
+ * As would be stored in xfs_log_iovec but without the i_addr which
+ * we don't care about.
+ */
+typedef struct xlog_res {
+ uint r_len;
+ uint r_type;
+} xlog_res_t;
+#else
+#define XLOG_TIC_RESET_RES(t)
+#define XLOG_TIC_ADD_OPHDR(t)
+#define XLOG_TIC_ADD_REGION(t, len, type)
+#endif
+
+
typedef struct xlog_ticket {
- sv_t t_sema; /* sleep on this semaphore :20 */
- struct xlog_ticket *t_next; /* : 4 */
- struct xlog_ticket *t_prev; /* : 4 */
- xlog_tid_t t_tid; /* transaction identifier : 4 */
- int t_curr_res; /* current reservation in bytes : 4 */
- int t_unit_res; /* unit reservation in bytes : 4 */
- __uint8_t t_ocnt; /* original count : 1 */
- __uint8_t t_cnt; /* current count : 1 */
- __uint8_t t_clientid; /* who does this belong to; : 1 */
- __uint8_t t_flags; /* properties of reservation : 1 */
+ sv_t t_sema; /* sleep on this semaphore : 20 */
+ struct xlog_ticket *t_next; /* :4|8 */
+ struct xlog_ticket *t_prev; /* :4|8 */
+ xlog_tid_t t_tid; /* transaction identifier : 4 */
+ int t_curr_res; /* current reservation in bytes : 4 */
+ int t_unit_res; /* unit reservation in bytes : 4 */
+ char t_ocnt; /* original count : 1 */
+ char t_cnt; /* current count : 1 */
+ char t_clientid; /* who does this belong to; : 1 */
+ char t_flags; /* properties of reservation : 1 */
+ uint t_trans_type; /* transaction type : 4 */
+
+#if defined (XFS_LOG_RES_DEBUG)
+ /* reservation array fields */
+ uint t_res_num; /* num in array : 4 */
+ xlog_res_t t_res_arr[XLOG_TIC_LEN_MAX]; /* array of res : X */
+ uint t_res_num_ophdrs; /* num op hdrs : 4 */
+ uint t_res_arr_sum; /* array sum : 4 */
+ uint t_res_o_flow; /* sum overflow : 4 */
+#endif
} xlog_ticket_t;
+
#endif
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 0aac28d..14faaba 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1387,7 +1387,7 @@
old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
old_len = item->ri_buf[item->ri_cnt-1].i_len;
- ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0);
+ ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0u);
memcpy(&ptr[old_len], dp, len); /* d, s, l */
item->ri_buf[item->ri_cnt-1].i_len += len;
item->ri_buf[item->ri_cnt-1].i_addr = ptr;
diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c
index 4f40c92..a6cd6324 100644
--- a/fs/xfs/xfs_qmops.c
+++ b/fs/xfs/xfs_qmops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -42,7 +42,8 @@
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
-
+#include "xfs_quota.h"
+#include "xfs_error.h"
STATIC struct xfs_dquot *
xfs_dqvopchown_default(
@@ -54,8 +55,79 @@
return NULL;
}
+/*
+ * Clear the quotaflags in memory and in the superblock.
+ */
+int
+xfs_mount_reset_sbqflags(xfs_mount_t *mp)
+{
+ int error;
+ xfs_trans_t *tp;
+ unsigned long s;
+
+ mp->m_qflags = 0;
+ /*
+ * It is OK to look at sb_qflags here in mount path,
+ * without SB_LOCK.
+ */
+ if (mp->m_sb.sb_qflags == 0)
+ return 0;
+ s = XFS_SB_LOCK(mp);
+ mp->m_sb.sb_qflags = 0;
+ XFS_SB_UNLOCK(mp, s);
+
+ /*
+ * if the fs is readonly, let the incore superblock run
+ * with quotas off but don't flush the update out to disk
+ */
+ if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
+ return 0;
+#ifdef QUOTADEBUG
+ xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+#endif
+ tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+ if ((error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+ XFS_DEFAULT_LOG_COUNT))) {
+ xfs_trans_cancel(tp, 0);
+ xfs_fs_cmn_err(CE_ALERT, mp,
+ "xfs_mount_reset_sbqflags: Superblock update failed!");
+ return error;
+ }
+ xfs_mod_sb(tp, XFS_SB_QFLAGS);
+ error = xfs_trans_commit(tp, 0, NULL);
+ return error;
+}
+
+STATIC int
+xfs_noquota_init(
+ xfs_mount_t *mp,
+ uint *needquotamount,
+ uint *quotaflags)
+{
+ int error = 0;
+
+ *quotaflags = 0;
+ *needquotamount = B_FALSE;
+
+ ASSERT(!XFS_IS_QUOTA_ON(mp));
+
+ /*
+ * If a file system had quotas running earlier, but decided to
+ * mount without -o uquota/pquota/gquota options, revoke the
+ * quotachecked license.
+ */
+ if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
+ cmn_err(CE_NOTE,
+ "XFS resetting qflags for filesystem %s",
+ mp->m_fsname);
+
+ error = xfs_mount_reset_sbqflags(mp);
+ }
+ return error;
+}
+
xfs_qmops_t xfs_qmcore_stub = {
- .xfs_qminit = (xfs_qminit_t) fs_noerr,
+ .xfs_qminit = (xfs_qminit_t) xfs_noquota_init,
.xfs_qmdone = (xfs_qmdone_t) fs_noerr,
.xfs_qmmount = (xfs_qmmount_t) fs_noerr,
.xfs_qmunmount = (xfs_qmunmount_t) fs_noerr,
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 7134576..32cb797 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -160,6 +160,20 @@
#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */
/*
+ * Quota Accounting/Enforcement flags
+ */
+#define XFS_ALL_QUOTA_ACCT \
+ (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
+#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
+
+#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
+#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
+#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
+#define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT)
+#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
+
+/*
* Incore only flags for quotaoff - these bits get cleared when quota(s)
* are in the process of getting turned off. These flags are in m_qflags but
* never in sb_qflags.
@@ -362,6 +376,7 @@
f | XFS_QMOPT_RES_REGBLKS)
extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
+extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
extern struct bhv_vfsops xfs_qmops;
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 06dfca5..92efe27 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -276,7 +276,7 @@
error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
&tp->t_ticket,
- XFS_TRANSACTION, log_flags);
+ XFS_TRANSACTION, log_flags, tp->t_type);
if (error) {
goto undo_blocks;
}
@@ -1032,6 +1032,7 @@
tp->t_header.th_num_items = nitems;
log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
log_vector->i_len = sizeof(xfs_trans_header_t);
+ XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_TRANSHDR);
}
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index ec541d6..a263aec 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -112,6 +112,7 @@
#define XFS_TRANS_GROWFSRT_ZERO 38
#define XFS_TRANS_GROWFSRT_FREE 39
#define XFS_TRANS_SWAPEXT 40
+#define XFS_TRANS_TYPE_MAX 40
/* new transaction types need to be reflected in xfs_logprint(8) */
@@ -998,6 +999,7 @@
void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *);
+void xfs_trans_bhold_release(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 7bc5eab..2a71b4f 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -379,8 +379,8 @@
else {
xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
"xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL");
- xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
AIL_UNLOCK(mp, s);
+ xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
}
}
}
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 144da7a..e733293 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -714,6 +714,29 @@
}
/*
+ * Cancel the previous buffer hold request made on this buffer
+ * for this transaction.
+ */
+void
+xfs_trans_bhold_release(xfs_trans_t *tp,
+ xfs_buf_t *bp)
+{
+ xfs_buf_log_item_t *bip;
+
+ ASSERT(XFS_BUF_ISBUSY(bp));
+ ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
+ ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
+
+ bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
+ ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
+ ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
+ ASSERT(atomic_read(&bip->bli_refcount) > 0);
+ ASSERT(bip->bli_flags & XFS_BLI_HOLD);
+ bip->bli_flags &= ~XFS_BLI_HOLD;
+ xfs_buf_item_trace("BHOLD RELEASE", bip);
+}
+
+/*
* This is called to mark bytes first through last inclusive of the given
* buffer as needing to be logged when the transaction is committed.
* The buffer must already be associated with the given transaction.
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 42bcc02..f1a904e 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -795,7 +795,6 @@
xfs_mount_t *mp;
xfs_sb_t *sbp;
unsigned long s;
- u64 id;
mp = XFS_BHVTOM(bdp);
sbp = &(mp->m_sb);
@@ -823,9 +822,7 @@
statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree);
XFS_SB_UNLOCK(mp, s);
- id = huge_encode_dev(mp->m_dev);
- statp->f_fsid.val[0] = (u32)id;
- statp->f_fsid.val[1] = (u32)(id >> 32);
+ xfs_statvfs_fsid(statp, mp);
statp->f_namelen = MAXNAMELEN - 1;
return 0;
@@ -906,7 +903,6 @@
xfs_inode_t *ip_next;
xfs_buf_t *bp;
vnode_t *vp = NULL;
- vmap_t vmap;
int error;
int last_error;
uint64_t fflag;
@@ -1101,48 +1097,21 @@
* lock in xfs_ireclaim() after the inode is pulled from
* the mount list will sleep until we release it here.
* This keeps the vnode from being freed while we reference
- * it. It is also cheaper and simpler than actually doing
- * a vn_get() for every inode we touch here.
+ * it.
*/
if (xfs_ilock_nowait(ip, lock_flags) == 0) {
-
if ((flags & SYNC_BDFLUSH) || (vp == NULL)) {
ip = ip->i_mnext;
continue;
}
- /*
- * We need to unlock the inode list lock in order
- * to lock the inode. Insert a marker record into
- * the inode list to remember our position, dropping
- * the lock is now done inside the IPOINTER_INSERT
- * macro.
- *
- * We also use the inode list lock to protect us
- * in taking a snapshot of the vnode version number
- * for use in calling vn_get().
- */
- VMAP(vp, vmap);
- IPOINTER_INSERT(ip, mp);
-
- vp = vn_get(vp, &vmap);
+ vp = vn_grab(vp);
if (vp == NULL) {
- /*
- * The vnode was reclaimed once we let go
- * of the inode list lock. Skip to the
- * next list entry. Remove the marker.
- */
-
- XFS_MOUNT_ILOCK(mp);
-
- mount_locked = B_TRUE;
- vnode_refed = B_FALSE;
-
- IPOINTER_REMOVE(ip, mp);
-
+ ip = ip->i_mnext;
continue;
}
+ IPOINTER_INSERT(ip, mp);
xfs_ilock(ip, lock_flags);
ASSERT(vp == XFS_ITOV(ip));
@@ -1533,7 +1502,10 @@
* eventually kicked out of the cache.
*/
if (flags & SYNC_REFCACHE) {
- xfs_refcache_purge_some(mp);
+ if (flags & SYNC_WAIT)
+ xfs_refcache_purge_mp(mp);
+ else
+ xfs_refcache_purge_some(mp);
}
/*
@@ -1649,6 +1621,10 @@
#define MNTOPT_SWIDTH "swidth" /* data volume stripe width */
#define MNTOPT_NOUUID "nouuid" /* ignore filesystem UUID */
#define MNTOPT_MTPT "mtpt" /* filesystem mount point */
+#define MNTOPT_GRPID "grpid" /* group-ID from parent directory */
+#define MNTOPT_NOGRPID "nogrpid" /* group-ID from current process */
+#define MNTOPT_BSDGROUPS "bsdgroups" /* group-ID from parent directory */
+#define MNTOPT_SYSVGROUPS "sysvgroups" /* group-ID from current process */
#define MNTOPT_ALLOCSIZE "allocsize" /* preferred allocation size */
#define MNTOPT_IHASHSIZE "ihashsize" /* size of inode hash table */
#define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */
@@ -1769,6 +1745,12 @@
}
args->flags |= XFSMNT_IHASHSIZE;
args->ihashsize = simple_strtoul(value, &eov, 10);
+ } else if (!strcmp(this_char, MNTOPT_GRPID) ||
+ !strcmp(this_char, MNTOPT_BSDGROUPS)) {
+ vfsp->vfs_flag |= VFS_GRPID;
+ } else if (!strcmp(this_char, MNTOPT_NOGRPID) ||
+ !strcmp(this_char, MNTOPT_SYSVGROUPS)) {
+ vfsp->vfs_flag &= ~VFS_GRPID;
} else if (!strcmp(this_char, MNTOPT_WSYNC)) {
args->flags |= XFSMNT_WSYNC;
} else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
@@ -1890,6 +1872,7 @@
};
struct proc_xfs_info *xfs_infop;
struct xfs_mount *mp = XFS_BHVTOM(bhv);
+ struct vfs *vfsp = XFS_MTOVFS(mp);
for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
if (mp->m_flags & xfs_infop->flag)
@@ -1926,7 +1909,10 @@
if (!(mp->m_flags & XFS_MOUNT_32BITINOOPT))
seq_printf(m, "," MNTOPT_64BITINODE);
-
+
+ if (vfsp->vfs_flag & VFS_GRPID)
+ seq_printf(m, "," MNTOPT_GRPID);
+
return 0;
}
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 1377c86..58bfe62 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -104,7 +104,7 @@
* If it's a directory with any blocks, read-ahead block 0
* as we're almost certain to have the next operation be a read there.
*/
- if (vp->v_type == VDIR && ip->i_d.di_nextents > 0) {
+ if (VN_ISDIR(vp) && ip->i_d.di_nextents > 0) {
mode = xfs_ilock_map_shared(ip);
if (ip->i_d.di_nextents > 0)
(void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK);
@@ -163,18 +163,21 @@
/*
* Copy from in-core inode.
*/
- vap->va_type = vp->v_type;
- vap->va_mode = ip->i_d.di_mode & MODEMASK;
+ vap->va_mode = ip->i_d.di_mode;
vap->va_uid = ip->i_d.di_uid;
vap->va_gid = ip->i_d.di_gid;
vap->va_projid = ip->i_d.di_projid;
/*
* Check vnode type block/char vs. everything else.
- * Do it with bitmask because that's faster than looking
- * for multiple values individually.
*/
- if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+ switch (ip->i_d.di_mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ vap->va_rdev = ip->i_df.if_u2.if_rdev;
+ vap->va_blocksize = BLKDEV_IOSIZE;
+ break;
+ default:
vap->va_rdev = 0;
if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
@@ -224,9 +227,7 @@
(ip->i_d.di_extsize << mp->m_sb.sb_blocklog) :
(mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
}
- } else {
- vap->va_rdev = ip->i_df.if_u2.if_rdev;
- vap->va_blocksize = BLKDEV_IOSIZE;
+ break;
}
vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec;
@@ -468,7 +469,7 @@
m |= S_ISGID;
#if 0
/* Linux allows this, Irix doesn't. */
- if ((vap->va_mode & S_ISVTX) && vp->v_type != VDIR)
+ if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp))
m |= S_ISVTX;
#endif
if (m && !capable(CAP_FSETID))
@@ -546,10 +547,10 @@
goto error_return;
}
- if (vp->v_type == VDIR) {
+ if (VN_ISDIR(vp)) {
code = XFS_ERROR(EISDIR);
goto error_return;
- } else if (vp->v_type != VREG) {
+ } else if (!VN_ISREG(vp)) {
code = XFS_ERROR(EINVAL);
goto error_return;
}
@@ -1567,7 +1568,7 @@
vp = BHV_TO_VNODE(bdp);
ip = XFS_BHVTOI(bdp);
- if ((vp->v_type != VREG) || (ip->i_d.di_mode == 0)) {
+ if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) {
return 0;
}
@@ -1895,7 +1896,7 @@
dp = XFS_BHVTOI(dir_bdp);
mp = dp->i_mount;
- dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
+ dm_di_mode = vap->va_mode;
namelen = VNAMELEN(dentry);
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
@@ -1973,8 +1974,7 @@
(error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen)))
goto error_return;
rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0;
- error = xfs_dir_ialloc(&tp, dp,
- MAKEIMODE(vap->va_type,vap->va_mode), 1,
+ error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1,
rdev, credp, prid, resblks > 0,
&ip, &committed);
if (error) {
@@ -2620,7 +2620,7 @@
vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address);
target_namelen = VNAMELEN(dentry);
- if (src_vp->v_type == VDIR)
+ if (VN_ISDIR(src_vp))
return XFS_ERROR(EPERM);
src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops);
@@ -2805,7 +2805,7 @@
tp = NULL;
dp_joined_to_trans = B_FALSE;
- dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
+ dm_di_mode = vap->va_mode;
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
@@ -2879,8 +2879,7 @@
/*
* create the directory inode.
*/
- error = xfs_dir_ialloc(&tp, dp,
- MAKEIMODE(vap->va_type,vap->va_mode), 2,
+ error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 2,
0, credp, prid, resblks > 0,
&cdp, NULL);
if (error) {
@@ -3650,7 +3649,7 @@
vnode_t *vp;
vp = BHV_TO_VNODE(bdp);
- if (vp->v_type == VDIR)
+ if (VN_ISDIR(vp))
return 1;
ip = XFS_BHVTOI(bdp);
if (locktype == VRWLOCK_WRITE) {
@@ -3681,7 +3680,7 @@
vnode_t *vp;
vp = BHV_TO_VNODE(bdp);
- if (vp->v_type == VDIR)
+ if (VN_ISDIR(vp))
return;
ip = XFS_BHVTOI(bdp);
if (locktype == VRWLOCK_WRITE) {
@@ -3847,51 +3846,10 @@
return 0;
}
- if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
- if (ip->i_d.di_size > 0) {
- /*
- * Flush and invalidate any data left around that is
- * a part of this file.
- *
- * Get the inode's i/o lock so that buffers are pushed
- * out while holding the proper lock. We can't hold
- * the inode lock here since flushing out buffers may
- * cause us to try to get the lock in xfs_strategy().
- *
- * We don't have to call remapf() here, because there
- * cannot be any mapped file references to this vnode
- * since it is being reclaimed.
- */
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ vn_iowait(vp);
- /*
- * If we hit an IO error, we need to make sure that the
- * buffer and page caches of file data for
- * the file are tossed away. We don't want to use
- * VOP_FLUSHINVAL_PAGES here because we don't want dirty
- * pages to stay attached to the vnode, but be
- * marked P_BAD. pdflush/vnode_pagebad
- * hates that.
- */
- if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_NONE);
- } else {
- VOP_TOSS_PAGES(vp, 0, -1, FI_NONE);
- }
-
- ASSERT(VN_CACHED(vp) == 0);
- ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) ||
- ip->i_delayed_blks == 0);
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- } else if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- /*
- * di_size field may not be quite accurate if we're
- * shutting down.
- */
- VOP_TOSS_PAGES(vp, 0, -1, FI_NONE);
- ASSERT(VN_CACHED(vp) == 0);
- }
- }
+ ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
+ ASSERT(VN_CACHED(vp) == 0);
/* If we have nothing to flush with this inode then complete the
* teardown now, otherwise break the link between the xfs inode
@@ -4567,7 +4525,7 @@
/*
* must be a regular file and have write permission
*/
- if (vp->v_type != VREG)
+ if (!VN_ISREG(vp))
return XFS_ERROR(EINVAL);
xfs_ilock(ip, XFS_ILOCK_SHARED);
diff --git a/include/asm-alpha/auxvec.h b/include/asm-alpha/auxvec.h
new file mode 100644
index 0000000..e96fe88
--- /dev/null
+++ b/include/asm-alpha/auxvec.h
@@ -0,0 +1,24 @@
+#ifndef __ASM_ALPHA_AUXVEC_H
+#define __ASM_ALPHA_AUXVEC_H
+
+/* Reserve these numbers for any future use of a VDSO. */
+#if 0
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+#endif
+
+/* More complete cache descriptions than AT_[DIU]CACHEBSIZE. If the
+ value is -1, then the cache doesn't exist. Otherwise:
+
+ bit 0-3: Cache set-associativity; 0 means fully associative.
+ bit 4-7: Log2 of cacheline size.
+ bit 8-31: Size of the entire cache >> 8.
+ bit 32-63: Reserved.
+*/
+
+#define AT_L1I_CACHESHAPE 34
+#define AT_L1D_CACHESHAPE 35
+#define AT_L2_CACHESHAPE 36
+#define AT_L3_CACHESHAPE 37
+
+#endif /* __ASM_ALPHA_AUXVEC_H */
diff --git a/include/asm-alpha/elf.h b/include/asm-alpha/elf.h
index e94a945..6c2d78f 100644
--- a/include/asm-alpha/elf.h
+++ b/include/asm-alpha/elf.h
@@ -1,6 +1,8 @@
#ifndef __ASM_ALPHA_ELF_H
#define __ASM_ALPHA_ELF_H
+#include <asm/auxvec.h>
+
/* Special values for the st_other field in the symbol table. */
#define STO_ALPHA_NOPV 0x80
@@ -142,26 +144,6 @@
: amask (AMASK_CIX) ? "ev6" : "ev67"); \
})
-/* Reserve these numbers for any future use of a VDSO. */
-#if 0
-#define AT_SYSINFO 32
-#define AT_SYSINFO_EHDR 33
-#endif
-
-/* More complete cache descriptions than AT_[DIU]CACHEBSIZE. If the
- value is -1, then the cache doesn't exist. Otherwise:
-
- bit 0-3: Cache set-associativity; 0 means fully associative.
- bit 4-7: Log2 of cacheline size.
- bit 8-31: Size of the entire cache >> 8.
- bit 32-63: Reserved.
-*/
-
-#define AT_L1I_CACHESHAPE 34
-#define AT_L1D_CACHESHAPE 35
-#define AT_L2_CACHESHAPE 36
-#define AT_L3_CACHESHAPE 37
-
#ifdef __KERNEL__
#define SET_PERSONALITY(EX, IBCS2) \
diff --git a/include/asm-alpha/fcntl.h b/include/asm-alpha/fcntl.h
index 6b7d6c1..87f2cf4 100644
--- a/include/asm-alpha/fcntl.h
+++ b/include/asm-alpha/fcntl.h
@@ -3,10 +3,6 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
#define O_CREAT 01000 /* not fcntl */
#define O_TRUNC 02000 /* not fcntl */
#define O_EXCL 04000 /* not fcntl */
@@ -14,20 +10,13 @@
#define O_NONBLOCK 00004
#define O_APPEND 00010
-#define O_NDELAY O_NONBLOCK
#define O_SYNC 040000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECTORY 0100000 /* must be a directory */
#define O_NOFOLLOW 0200000 /* don't follow links */
#define O_LARGEFILE 0400000 /* will be set by the kernel on every open */
#define O_DIRECT 02000000 /* direct disk access - should check with OSF/1 */
#define O_NOATIME 04000000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
#define F_GETLK 7
#define F_SETLK 8
#define F_SETLKW 9
@@ -37,9 +26,6 @@
#define F_SETSIG 10 /* for sockets. */
#define F_GETSIG 11 /* for sockets. */
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
/* for posix fcntl() and lockf() */
#define F_RDLCK 1
#define F_WRLCK 2
@@ -51,25 +37,6 @@
#define F_INPROGRESS 64
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- __kernel_off_t l_start;
- __kernel_off_t l_len;
- __kernel_pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
+#include <asm-generic/fcntl.h>
#endif
diff --git a/include/asm-alpha/futex.h b/include/asm-alpha/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-alpha/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-alpha/hdreg.h b/include/asm-alpha/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-alpha/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h
index 0577daf..fa0b41b 100644
--- a/include/asm-alpha/page.h
+++ b/include/asm-alpha/page.h
@@ -63,20 +63,6 @@
#endif /* STRICT_MM_TYPECHECKS */
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#ifdef USE_48_BIT_KSEG
#define PAGE_OFFSET 0xffff800000000000UL
#else
@@ -112,4 +98,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _ALPHA_PAGE_H */
diff --git a/include/asm-alpha/types.h b/include/asm-alpha/types.h
index 43264d2..f571613 100644
--- a/include/asm-alpha/types.h
+++ b/include/asm-alpha/types.h
@@ -56,8 +56,6 @@
typedef u64 dma_addr_t;
typedef u64 dma64_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ALPHA_TYPES_H */
diff --git a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h
index 4c39ee7..22de3b4 100644
--- a/include/asm-alpha/uaccess.h
+++ b/include/asm-alpha/uaccess.h
@@ -48,12 +48,6 @@
__access_ok(((unsigned long)(addr)),(size),get_fs()); \
})
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index 7495026..e350dcb 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -383,39 +383,45 @@
*vaddr++ = inl(io_addr);
}
-#define __is_io_address(p) (((unsigned long)p >= 0x0) && \
- ((unsigned long)p <= 0x0000ffff))
+#define PIO_OFFSET 0x10000UL
+#define PIO_MASK 0x0ffffUL
+
+#define __is_io_address(p) (((unsigned long)p >= PIO_OFFSET) && \
+ ((unsigned long)p <= (PIO_MASK + PIO_OFFSET)))
static inline unsigned int
-__ixp4xx_ioread8(void __iomem *port)
+__ixp4xx_ioread8(void __iomem *addr)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- return (unsigned int)__ixp4xx_inb((unsigned int)port);
+ return (unsigned int)__ixp4xx_inb(port & PIO_MASK);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- return (unsigned int)__raw_readb((u32)port);
+ return (unsigned int)__raw_readb(port);
#else
- return (unsigned int)__ixp4xx_readb((u32)port);
+ return (unsigned int)__ixp4xx_readb(port);
#endif
}
static inline void
-__ixp4xx_ioread8_rep(u32 port, u8 *vaddr, u32 count)
+__ixp4xx_ioread8_rep(void __iomem *addr, void *vaddr, u32 count)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_insb(port, vaddr, count);
+ __ixp4xx_insb(port & PIO_MASK, vaddr, count);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_readsb((void __iomem *)port, vaddr, count);
+ __raw_readsb(addr, vaddr, count);
#else
__ixp4xx_readsb(port, vaddr, count);
#endif
}
static inline unsigned int
-__ixp4xx_ioread16(void __iomem *port)
+__ixp4xx_ioread16(void __iomem *addr)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- return (unsigned int)__ixp4xx_inw((unsigned int)port);
+ return (unsigned int)__ixp4xx_inw(port & PIO_MASK);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
return le16_to_cpu(__raw_readw((u32)port));
@@ -425,23 +431,25 @@
}
static inline void
-__ixp4xx_ioread16_rep(u32 port, u16 *vaddr, u32 count)
+__ixp4xx_ioread16_rep(void __iomem *addr, void *vaddr, u32 count)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_insw(port, vaddr, count);
+ __ixp4xx_insw(port & PIO_MASK, vaddr, count);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_readsw((void __iomem *)port, vaddr, count);
+ __raw_readsw(addr, vaddr, count);
#else
__ixp4xx_readsw(port, vaddr, count);
#endif
}
static inline unsigned int
-__ixp4xx_ioread32(void __iomem *port)
+__ixp4xx_ioread32(void __iomem *addr)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- return (unsigned int)__ixp4xx_inl((unsigned int)port);
+ return (unsigned int)__ixp4xx_inl(port & PIO_MASK);
else {
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
return le32_to_cpu(__raw_readl((u32)port));
@@ -452,90 +460,100 @@
}
static inline void
-__ixp4xx_ioread32_rep(u32 port, u32 *vaddr, u32 count)
+__ixp4xx_ioread32_rep(void __iomem *addr, void *vaddr, u32 count)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_insl(port, vaddr, count);
+ __ixp4xx_insl(port & PIO_MASK, vaddr, count);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_readsl((void __iomem *)port, vaddr, count);
+ __raw_readsl(addr, vaddr, count);
#else
__ixp4xx_readsl(port, vaddr, count);
#endif
}
static inline void
-__ixp4xx_iowrite8(u8 value, void __iomem *port)
+__ixp4xx_iowrite8(u8 value, void __iomem *addr)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_outb(value, (unsigned int)port);
+ __ixp4xx_outb(value, port & PIO_MASK);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_writeb(value, (u32)port);
+ __raw_writeb(value, port);
#else
- __ixp4xx_writeb(value, (u32)port);
+ __ixp4xx_writeb(value, port);
#endif
}
static inline void
-__ixp4xx_iowrite8_rep(u32 port, u8 *vaddr, u32 count)
+__ixp4xx_iowrite8_rep(void __iomem *addr, const void *vaddr, u32 count)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_outsb(port, vaddr, count);
+ __ixp4xx_outsb(port & PIO_MASK, vaddr, count);
+ else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_writesb((void __iomem *)port, vaddr, count);
+ __raw_writesb(addr, vaddr, count);
#else
__ixp4xx_writesb(port, vaddr, count);
#endif
}
static inline void
-__ixp4xx_iowrite16(u16 value, void __iomem *port)
+__ixp4xx_iowrite16(u16 value, void __iomem *addr)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_outw(value, (unsigned int)port);
+ __ixp4xx_outw(value, port & PIO_MASK);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_writew(cpu_to_le16(value), (u32)port);
+ __raw_writew(cpu_to_le16(value), addr);
#else
- __ixp4xx_writew(value, (u32)port);
+ __ixp4xx_writew(value, port);
#endif
}
static inline void
-__ixp4xx_iowrite16_rep(u32 port, u16 *vaddr, u32 count)
+__ixp4xx_iowrite16_rep(void __iomem *addr, const void *vaddr, u32 count)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_outsw(port, vaddr, count);
+ __ixp4xx_outsw(port & PIO_MASK, vaddr, count);
+ else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_readsw((void __iomem *)port, vaddr, count);
+ __raw_writesw(addr, vaddr, count);
#else
__ixp4xx_writesw(port, vaddr, count);
#endif
}
static inline void
-__ixp4xx_iowrite32(u32 value, void __iomem *port)
+__ixp4xx_iowrite32(u32 value, void __iomem *addr)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_outl(value, (unsigned int)port);
+ __ixp4xx_outl(value, port & PIO_MASK);
else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_writel(cpu_to_le32(value), (u32)port);
+ __raw_writel(cpu_to_le32(value), port);
#else
- __ixp4xx_writel(value, (u32)port);
+ __ixp4xx_writel(value, port);
#endif
}
static inline void
-__ixp4xx_iowrite32_rep(u32 port, u32 *vaddr, u32 count)
+__ixp4xx_iowrite32_rep(void __iomem *addr, const void *vaddr, u32 count)
{
+ unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
- __ixp4xx_outsl(port, vaddr, count);
+ __ixp4xx_outsl(port & PIO_MASK, vaddr, count);
+ else
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
- __raw_readsl((void __iomem *)port, vaddr, count);
+ __raw_writesl(addr, vaddr, count);
#else
- __ixp4xx_outsl(port, vaddr, count);
+ __ixp4xx_writesl(port, vaddr, count);
#endif
}
@@ -555,7 +573,7 @@
#define iowrite16_rep(p, v, c) __ixp4xx_iowrite16_rep(p, v, c)
#define iowrite32_rep(p, v, c) __ixp4xx_iowrite32_rep(p, v, c)
-#define ioport_map(port, nr) ((void __iomem*)port)
+#define ioport_map(port, nr) ((void __iomem*)(port + PIO_OFFSET))
#define ioport_unmap(addr)
#endif // __ASM_ARM_ARCH_IO_H
diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
index 3a626c0..d13ee7f 100644
--- a/include/asm-arm/arch-ixp4xx/platform.h
+++ b/include/asm-arm/arch-ixp4xx/platform.h
@@ -83,17 +83,6 @@
#define IXP4XX_GPIO_OUT 0x1
#define IXP4XX_GPIO_IN 0x2
-#define IXP4XX_GPIO_INTSTYLE_MASK 0x7C /* Bits [6:2] define interrupt style */
-
-/*
- * GPIO interrupt types.
- */
-#define IXP4XX_GPIO_ACTIVE_HIGH 0x4 /* Default */
-#define IXP4XX_GPIO_ACTIVE_LOW 0x8
-#define IXP4XX_GPIO_RISING_EDGE 0x10
-#define IXP4XX_GPIO_FALLING_EDGE 0x20
-#define IXP4XX_GPIO_TRANSITIONAL 0x40
-
/* GPIO signal types */
#define IXP4XX_GPIO_LOW 0
#define IXP4XX_GPIO_HIGH 1
@@ -102,7 +91,13 @@
#define IXP4XX_GPIO_CLK_0 14
#define IXP4XX_GPIO_CLK_1 15
-extern void gpio_line_config(u8 line, u32 style);
+static inline void gpio_line_config(u8 line, u32 direction)
+{
+ if (direction == IXP4XX_GPIO_OUT)
+ *IXP4XX_GPIO_GPOER |= (1 << line);
+ else
+ *IXP4XX_GPIO_GPOER &= ~(1 << line);
+}
static inline void gpio_line_get(u8 line, int *value)
{
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h
index 79138dcf..d64ee92 100644
--- a/include/asm-arm/arch-omap/board-h4.h
+++ b/include/asm-arm/arch-omap/board-h4.h
@@ -30,6 +30,9 @@
#define __ASM_ARCH_OMAP_H4_H
/* Placeholder for H4 specific defines */
+/* GPMC CS1 */
+#define OMAP24XX_ETHR_START 0x08000300
+#define OMAP24XX_ETHR_GPIO_IRQ 92
#endif /* __ASM_ARCH_OMAP_H4_H */
diff --git a/include/asm-arm/arch-omap/board-innovator.h b/include/asm-arm/arch-omap/board-innovator.h
index 0f1abae..79574e0 100644
--- a/include/asm-arm/arch-omap/board-innovator.h
+++ b/include/asm-arm/arch-omap/board-innovator.h
@@ -36,31 +36,6 @@
#define OMAP1510P1_EMIFS_PRI_VALUE 0x00
#define OMAP1510P1_EMIFF_PRI_VALUE 0x00
-/*
- * These definitions define an area of FLASH set aside
- * for the use of MTD/JFFS2. This is the area of flash
- * that a JFFS2 filesystem will reside which is mounted
- * at boot with the "root=/dev/mtdblock/0 rw"
- * command line option. The flash address used here must
- * fall within the legal range defined by rrload for storing
- * the filesystem component. This address will be sufficiently
- * deep into the overall flash range to avoid the other
- * components also stored in flash such as the bootloader,
- * the bootloader params, and the kernel.
- * The SW2 settings for the map below are:
- * 1 off, 2 off, 3 on, 4 off.
- */
-
-/* Intel flash_0, partitioned as expected by rrload */
-#define OMAP_FLASH_0_BASE 0xD8000000
-#define OMAP_FLASH_0_START 0x00000000
-#define OMAP_FLASH_0_SIZE SZ_16M
-
-/* Intel flash_1, used for cramfs or other flash file systems */
-#define OMAP_FLASH_1_BASE 0xD9000000
-#define OMAP_FLASH_1_START 0x01000000
-#define OMAP_FLASH_1_SIZE SZ_16M
-
#define NR_FPGA_IRQS 24
#define NR_IRQS IH_BOARD_BASE + NR_FPGA_IRQS
diff --git a/include/asm-arm/arch-omap/board-perseus2.h b/include/asm-arm/arch-omap/board-perseus2.h
index 0c224cc..691e52a 100644
--- a/include/asm-arm/arch-omap/board-perseus2.h
+++ b/include/asm-arm/arch-omap/board-perseus2.h
@@ -36,23 +36,14 @@
#define OMAP_SDRAM_DEVICE D256M_1X16_4B
#endif
-/*
- * These definitions define an area of FLASH set aside
- * for the use of MTD/JFFS2. This is the area of flash
- * that a JFFS2 filesystem will reside which is mounted
- * at boot with the "root=/dev/mtdblock/0 rw"
- * command line option.
- */
-
-/* Intel flash_0, partitioned as expected by rrload */
-#define OMAP_FLASH_0_BASE 0xD8000000 /* VA */
-#define OMAP_FLASH_0_START 0x00000000 /* PA */
-#define OMAP_FLASH_0_SIZE SZ_32M
-
#define MAXIRQNUM IH_BOARD_BASE
#define MAXFIQNUM MAXIRQNUM
#define MAXSWINUM MAXIRQNUM
#define NR_IRQS (MAXIRQNUM + 1)
+/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
+#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
+#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
+
#endif
diff --git a/include/asm-arm/arch-omap/board-voiceblue.h b/include/asm-arm/arch-omap/board-voiceblue.h
index 33977b8..ed6d346 100644
--- a/include/asm-arm/arch-omap/board-voiceblue.h
+++ b/include/asm-arm/arch-omap/board-voiceblue.h
@@ -11,11 +11,6 @@
#ifndef __ASM_ARCH_VOICEBLUE_H
#define __ASM_ARCH_VOICEBLUE_H
-#if (EXTERNAL_MAX_NR_PORTS < 4)
-#undef EXTERNAL_MAX_NR_PORTS
-#define EXTERNAL_MAX_NR_PORTS 4
-#endif
-
extern void voiceblue_wdt_enable(void);
extern void voiceblue_wdt_disable(void);
extern void voiceblue_wdt_ping(void);
diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h
index 95bd625..a0040cd 100644
--- a/include/asm-arm/arch-omap/board.h
+++ b/include/asm-arm/arch-omap/board.h
@@ -30,10 +30,23 @@
u8 system_clock_type;
};
+struct omap_mmc_conf {
+ unsigned enabled:1;
+ /* nomux means "standard" muxing is wrong on this board, and that
+ * board-specific code handled it before common init logic.
+ */
+ unsigned nomux:1;
+ /* switch pin can be for card detect (default) or card cover */
+ unsigned cover:1;
+ /* 4 wire signaling is optional, and is only used for SD/SDIO */
+ unsigned wire4:1;
+ s16 power_pin;
+ s16 switch_pin;
+ s16 wp_pin;
+};
+
struct omap_mmc_config {
- u8 mmc_blocks;
- s16 mmc1_power_pin, mmc2_power_pin;
- s16 mmc1_switch_pin, mmc2_switch_pin;
+ struct omap_mmc_conf mmc[2];
};
struct omap_serial_console_config {
diff --git a/include/asm-arm/arch-omap/cpu.h b/include/asm-arm/arch-omap/cpu.h
index e878671..1119e2b 100644
--- a/include/asm-arm/arch-omap/cpu.h
+++ b/include/asm-arm/arch-omap/cpu.h
@@ -38,146 +38,179 @@
/*
* Test if multicore OMAP support is needed
*/
-#undef MULTI_OMAP
+#undef MULTI_OMAP1
+#undef MULTI_OMAP2
#undef OMAP_NAME
#ifdef CONFIG_ARCH_OMAP730
# ifdef OMAP_NAME
-# undef MULTI_OMAP
-# define MULTI_OMAP
+# undef MULTI_OMAP1
+# define MULTI_OMAP1
# else
# define OMAP_NAME omap730
# endif
#endif
#ifdef CONFIG_ARCH_OMAP1510
# ifdef OMAP_NAME
-# undef MULTI_OMAP
-# define MULTI_OMAP
+# undef MULTI_OMAP1
+# define MULTI_OMAP1
# else
# define OMAP_NAME omap1510
# endif
#endif
#ifdef CONFIG_ARCH_OMAP16XX
# ifdef OMAP_NAME
-# undef MULTI_OMAP
-# define MULTI_OMAP
+# undef MULTI_OMAP1
+# define MULTI_OMAP1
# else
-# define OMAP_NAME omap1610
+# define OMAP_NAME omap16xx
# endif
#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-# ifdef OMAP_NAME
-# undef MULTI_OMAP
-# define MULTI_OMAP
+#ifdef CONFIG_ARCH_OMAP24XX
+# if (defined(OMAP_NAME) || defined(MULTI_OMAP1))
+# error "OMAP1 and OMAP2 can't be selected at the same time"
# else
-# define OMAP_NAME omap1710
+# undef MULTI_OMAP2
+# define OMAP_NAME omap24xx
# endif
#endif
/*
- * Generate various OMAP cpu specific macros, and cpu class
- * specific macros
+ * Macros to group OMAP into cpu classes.
+ * These can be used in most places.
+ * cpu_is_omap7xx(): True for OMAP730
+ * cpu_is_omap15xx(): True for OMAP1510 and OMAP5910
+ * cpu_is_omap16xx(): True for OMAP1610, OMAP5912 and OMAP1710
+ * cpu_is_omap24xx(): True for OMAP2420
*/
-#define GET_OMAP_TYPE ((system_rev >> 24) & 0xff)
#define GET_OMAP_CLASS (system_rev & 0xff)
-#define IS_OMAP_TYPE(type, id) \
-static inline int is_omap ##type (void) \
-{ \
- return (GET_OMAP_TYPE == (id)) ? 1 : 0; \
-}
-
#define IS_OMAP_CLASS(class, id) \
static inline int is_omap ##class (void) \
{ \
return (GET_OMAP_CLASS == (id)) ? 1 : 0; \
}
-IS_OMAP_TYPE(730, 0x07)
-IS_OMAP_TYPE(1510, 0x15)
-IS_OMAP_TYPE(1610, 0x16)
-IS_OMAP_TYPE(5912, 0x16)
-IS_OMAP_TYPE(1710, 0x17)
-IS_OMAP_TYPE(2420, 0x24)
-
IS_OMAP_CLASS(7xx, 0x07)
IS_OMAP_CLASS(15xx, 0x15)
IS_OMAP_CLASS(16xx, 0x16)
IS_OMAP_CLASS(24xx, 0x24)
-/*
- * Macros to group OMAP types into cpu classes.
- * These can be used in most places.
- * cpu_is_omap15xx(): True for 1510 and 5910
- * cpu_is_omap16xx(): True for 1610, 5912 and 1710
- */
-#if defined(MULTI_OMAP)
-# define cpu_is_omap7xx() is_omap7xx()
-# define cpu_is_omap15xx() is_omap15xx()
-# if !(defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_ARCH_OMAP730))
-# define cpu_is_omap16xx() 1
-# else
+#define cpu_is_omap7xx() 0
+#define cpu_is_omap15xx() 0
+#define cpu_is_omap16xx() 0
+#define cpu_is_omap24xx() 0
+
+#if defined(MULTI_OMAP1)
+# if defined(CONFIG_ARCH_OMAP730)
+# undef cpu_is_omap7xx
+# define cpu_is_omap7xx() is_omap7xx()
+# endif
+# if defined(CONFIG_ARCH_OMAP1510)
+# undef cpu_is_omap15xx
+# define cpu_is_omap15xx() is_omap15xx()
+# endif
+# if defined(CONFIG_ARCH_OMAP16XX)
+# undef cpu_is_omap16xx
# define cpu_is_omap16xx() is_omap16xx()
# endif
#else
# if defined(CONFIG_ARCH_OMAP730)
+# undef cpu_is_omap7xx
# define cpu_is_omap7xx() 1
-# else
-# define cpu_is_omap7xx() 0
# endif
# if defined(CONFIG_ARCH_OMAP1510)
+# undef cpu_is_omap15xx
# define cpu_is_omap15xx() 1
-# else
-# define cpu_is_omap15xx() 0
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
+# undef cpu_is_omap16xx
# define cpu_is_omap16xx() 1
-# else
-# define cpu_is_omap16xx() 0
+# endif
+# if defined(CONFIG_ARCH_OMAP24XX)
+# undef cpu_is_omap24xx
+# define cpu_is_omap24xx() 1
# endif
#endif
-#if defined(MULTI_OMAP)
-# define cpu_is_omap730() is_omap730()
-# define cpu_is_omap1510() is_omap1510()
-# define cpu_is_omap1610() is_omap1610()
-# define cpu_is_omap5912() is_omap5912()
-# define cpu_is_omap1710() is_omap1710()
-#else
+/*
+ * Macros to detect individual cpu types.
+ * These are only rarely needed.
+ * cpu_is_omap730(): True for OMAP730
+ * cpu_is_omap1510(): True for OMAP1510
+ * cpu_is_omap1610(): True for OMAP1610
+ * cpu_is_omap1611(): True for OMAP1611
+ * cpu_is_omap5912(): True for OMAP5912
+ * cpu_is_omap1621(): True for OMAP1621
+ * cpu_is_omap1710(): True for OMAP1710
+ * cpu_is_omap2420(): True for OMAP2420
+ */
+#define GET_OMAP_TYPE ((system_rev >> 16) & 0xffff)
+
+#define IS_OMAP_TYPE(type, id) \
+static inline int is_omap ##type (void) \
+{ \
+ return (GET_OMAP_TYPE == (id)) ? 1 : 0; \
+}
+
+IS_OMAP_TYPE(730, 0x0730)
+IS_OMAP_TYPE(1510, 0x1510)
+IS_OMAP_TYPE(1610, 0x1610)
+IS_OMAP_TYPE(1611, 0x1611)
+IS_OMAP_TYPE(5912, 0x1611)
+IS_OMAP_TYPE(1621, 0x1621)
+IS_OMAP_TYPE(1710, 0x1710)
+IS_OMAP_TYPE(2420, 0x2420)
+
+#define cpu_is_omap730() 0
+#define cpu_is_omap1510() 0
+#define cpu_is_omap1610() 0
+#define cpu_is_omap5912() 0
+#define cpu_is_omap1611() 0
+#define cpu_is_omap1621() 0
+#define cpu_is_omap1710() 0
+#define cpu_is_omap2420() 0
+
+#if defined(MULTI_OMAP1)
# if defined(CONFIG_ARCH_OMAP730)
-# define cpu_is_omap730() 1
-# else
-# define cpu_is_omap730() 0
+# undef cpu_is_omap730
+# define cpu_is_omap730() is_omap730()
# endif
# if defined(CONFIG_ARCH_OMAP1510)
+# undef cpu_is_omap1510
+# define cpu_is_omap1510() is_omap1510()
+# endif
+#else
+# if defined(CONFIG_ARCH_OMAP730)
+# undef cpu_is_omap730
+# define cpu_is_omap730() 1
+# endif
+# if defined(CONFIG_ARCH_OMAP1510)
+# undef cpu_is_omap1510
# define cpu_is_omap1510() 1
-# else
-# define cpu_is_omap1510() 0
# endif
-# if defined(CONFIG_ARCH_OMAP16XX)
-# define cpu_is_omap1610() 1
-# else
-# define cpu_is_omap1610() 0
-# endif
-# if defined(CONFIG_ARCH_OMAP16XX)
-# define cpu_is_omap5912() 1
-# else
-# define cpu_is_omap5912() 0
-# endif
-# if defined(CONFIG_ARCH_OMAP16XX)
+#endif
+
+/*
+ * Whether we have MULTI_OMAP1 or not, we still need to distinguish
+ * between 1611B/5912 and 1710.
+ */
+#if defined(CONFIG_ARCH_OMAP16XX)
+# undef cpu_is_omap1610
+# undef cpu_is_omap1611
+# undef cpu_is_omap5912
+# undef cpu_is_omap1621
+# undef cpu_is_omap1710
# define cpu_is_omap1610() is_omap1610()
+# define cpu_is_omap1611() is_omap1611()
# define cpu_is_omap5912() is_omap5912()
+# define cpu_is_omap1621() is_omap1621()
# define cpu_is_omap1710() is_omap1710()
-# else
-# define cpu_is_omap1610() 0
-# define cpu_is_omap5912() 0
-# define cpu_is_omap1710() 0
-# endif
-# if defined(CONFIG_ARCH_OMAP2420)
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
+# undef cpu_is_omap2420
# define cpu_is_omap2420() 1
-# else
-# define cpu_is_omap2420() 0
-# endif
#endif
#endif
diff --git a/include/asm-arm/arch-omap/debug-macro.S b/include/asm-arm/arch-omap/debug-macro.S
index 83bb458..ca4f577 100644
--- a/include/asm-arm/arch-omap/debug-macro.S
+++ b/include/asm-arm/arch-omap/debug-macro.S
@@ -14,6 +14,7 @@
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
+#ifdef CONFIG_ARCH_OMAP1
moveq \rx, #0xff000000 @ physical base address
movne \rx, #0xfe000000 @ virtual base
orr \rx, \rx, #0x00fb0000
@@ -23,6 +24,18 @@
#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
orr \rx, \rx, #0x00000800 @ UART 2 & 3
#endif
+
+#elif CONFIG_ARCH_OMAP2
+ moveq \rx, #0x48000000 @ physical base address
+ movne \rx, #0xd8000000 @ virtual base
+ orr \rx, \rx, #0x0006a000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
+ add \rx, \rx, #0x00002000 @ UART 2
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+ add \rx, \rx, #0x00004000 @ UART 3
+#endif
+#endif
.endm
.macro senduart,rd,rx
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index ce114ce..04ebef5 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -240,6 +240,7 @@
extern dma_addr_t omap_get_dma_src_pos(int lch);
extern dma_addr_t omap_get_dma_dst_pos(int lch);
+extern int omap_get_dma_src_addr_counter(int lch);
extern void omap_clear_dma(int lch);
extern int omap_dma_running(void);
diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h
new file mode 100644
index 0000000..11772c7
--- /dev/null
+++ b/include/asm-arm/arch-omap/dmtimer.h
@@ -0,0 +1,92 @@
+/*
+ * linux/include/asm-arm/arm/arch-omap/dmtimer.h
+ *
+ * OMAP Dual-Mode Timers
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_TIMER_H
+#define __ASM_ARCH_TIMER_H
+
+#include <linux/list.h>
+
+#define OMAP_TIMER_SRC_ARMXOR 0x00
+#define OMAP_TIMER_SRC_32_KHZ 0x01
+#define OMAP_TIMER_SRC_EXT_CLK 0x02
+
+/* timer control reg bits */
+#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
+#define OMAP_TIMER_CTRL_PT (1 << 12)
+#define OMAP_TIMER_CTRL_TRG_OVERFLOW (0x1 << 10)
+#define OMAP_TIMER_CTRL_TRG_OFANDMATCH (0x2 << 10)
+#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
+#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
+#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
+#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
+#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
+#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
+#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */
+#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
+#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
+
+/* timer interrupt enable bits */
+#define OMAP_TIMER_INT_CAPTURE (1 << 2)
+#define OMAP_TIMER_INT_OVERFLOW (1 << 1)
+#define OMAP_TIMER_INT_MATCH (1 << 0)
+
+
+struct omap_dm_timer {
+ struct list_head timer_list;
+
+ u32 base;
+ unsigned int irq;
+};
+
+u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg);
+void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value);
+
+struct omap_dm_timer * omap_dm_timer_request(void);
+void omap_dm_timer_free(struct omap_dm_timer *timer);
+void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
+
+void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
+void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value);
+void omap_dm_timer_enable_compare(struct omap_dm_timer *timer);
+void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer);
+
+void omap_dm_timer_trigger(struct omap_dm_timer *timer);
+void omap_dm_timer_start(struct omap_dm_timer *timer);
+void omap_dm_timer_stop(struct omap_dm_timer *timer);
+
+void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load);
+void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match);
+
+unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
+void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
+
+unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
+void omap_dm_timer_reset_counter(struct omap_dm_timer *timer);
+
+int omap_dm_timers_active(void);
+
+#endif /* __ASM_ARCH_TIMER_H */
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
new file mode 100644
index 0000000..57bf4f3
--- /dev/null
+++ b/include/asm-arm/arch-omap/dsp.h
@@ -0,0 +1,244 @@
+/*
+ * linux/include/asm-arm/arch-omap/dsp.h
+ *
+ * Header for OMAP DSP driver
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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
+ *
+ * 2005/06/01: DSP Gateway version 3.3
+ */
+
+#ifndef ASM_ARCH_DSP_H
+#define ASM_ARCH_DSP_H
+
+
+/*
+ * for /dev/dspctl/ctl
+ */
+#define OMAP_DSP_IOCTL_RESET 1
+#define OMAP_DSP_IOCTL_RUN 2
+#define OMAP_DSP_IOCTL_SETRSTVECT 3
+#define OMAP_DSP_IOCTL_CPU_IDLE 4
+#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5
+#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6
+#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7
+#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8
+#define OMAP_DSP_IOCTL_GBL_IDLE 9
+#define OMAP_DSP_IOCTL_DSPCFG 10
+#define OMAP_DSP_IOCTL_DSPUNCFG 11
+#define OMAP_DSP_IOCTL_TASKCNT 12
+#define OMAP_DSP_IOCTL_POLL 13
+#define OMAP_DSP_IOCTL_REGMEMR 40
+#define OMAP_DSP_IOCTL_REGMEMW 41
+#define OMAP_DSP_IOCTL_REGIOR 42
+#define OMAP_DSP_IOCTL_REGIOW 43
+#define OMAP_DSP_IOCTL_GETVAR 44
+#define OMAP_DSP_IOCTL_SETVAR 45
+#define OMAP_DSP_IOCTL_RUNLEVEL 50
+#define OMAP_DSP_IOCTL_SUSPEND 51
+#define OMAP_DSP_IOCTL_RESUME 52
+#define OMAP_DSP_IOCTL_FBEN 53
+#define OMAP_DSP_IOCTL_FBDIS 54
+#define OMAP_DSP_IOCTL_MBSEND 99
+
+/*
+ * for taskdev
+ * (ioctls below should be >= 0x10000)
+ */
+#define OMAP_DSP_TASK_IOCTL_BFLSH 0x10000
+#define OMAP_DSP_TASK_IOCTL_SETBSZ 0x10001
+#define OMAP_DSP_TASK_IOCTL_LOCK 0x10002
+#define OMAP_DSP_TASK_IOCTL_UNLOCK 0x10003
+#define OMAP_DSP_TASK_IOCTL_GETNAME 0x10004
+
+/*
+ * for /dev/dspctl/mem
+ */
+#define OMAP_DSP_MEM_IOCTL_EXMAP 1
+#define OMAP_DSP_MEM_IOCTL_EXUNMAP 2
+#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3
+#define OMAP_DSP_MEM_IOCTL_FBEXPORT 5
+#define OMAP_DSP_MEM_IOCTL_MMUITACK 7
+#define OMAP_DSP_MEM_IOCTL_MMUINIT 9
+#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE 11
+#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE 12
+
+struct omap_dsp_mapinfo {
+ unsigned long dspadr;
+ unsigned long size;
+};
+
+/*
+ * for /dev/dspctl/twch
+ */
+#define OMAP_DSP_TWCH_IOCTL_MKDEV 1
+#define OMAP_DSP_TWCH_IOCTL_RMDEV 2
+#define OMAP_DSP_TWCH_IOCTL_TADD 11
+#define OMAP_DSP_TWCH_IOCTL_TDEL 12
+#define OMAP_DSP_TWCH_IOCTL_TKILL 13
+
+#define OMAP_DSP_DEVSTATE_NOTASK 0x00000001
+#define OMAP_DSP_DEVSTATE_ATTACHED 0x00000002
+#define OMAP_DSP_DEVSTATE_GARBAGE 0x00000004
+#define OMAP_DSP_DEVSTATE_INVALID 0x00000008
+#define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100
+#define OMAP_DSP_DEVSTATE_DELREQ 0x00000200
+#define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000
+#define OMAP_DSP_DEVSTATE_ADDING 0x00010000
+#define OMAP_DSP_DEVSTATE_DELING 0x00020000
+#define OMAP_DSP_DEVSTATE_KILLING 0x00040000
+#define OMAP_DSP_DEVSTATE_STATE_MASK 0x7fffffff
+#define OMAP_DSP_DEVSTATE_STALE 0x80000000
+
+struct omap_dsp_taddinfo {
+ unsigned char minor;
+ unsigned long taskadr;
+};
+#define OMAP_DSP_TADD_ABORTADR 0xffffffff
+
+
+/*
+ * error cause definition (for error detection device)
+ */
+#define OMAP_DSP_ERRDT_WDT 0x00000001
+#define OMAP_DSP_ERRDT_MMU 0x00000002
+
+
+/*
+ * mailbox protocol definitions
+ */
+
+struct omap_dsp_mailbox_cmd {
+ unsigned short cmd;
+ unsigned short data;
+};
+
+struct omap_dsp_reginfo {
+ unsigned short adr;
+ unsigned short val;
+};
+
+struct omap_dsp_varinfo {
+ unsigned char varid;
+ unsigned short val[0];
+};
+
+#define OMAP_DSP_MBPROT_REVISION 0x0019
+
+#define OMAP_DSP_MBCMD_WDSND 0x10
+#define OMAP_DSP_MBCMD_WDREQ 0x11
+#define OMAP_DSP_MBCMD_BKSND 0x20
+#define OMAP_DSP_MBCMD_BKREQ 0x21
+#define OMAP_DSP_MBCMD_BKYLD 0x23
+#define OMAP_DSP_MBCMD_BKSNDP 0x24
+#define OMAP_DSP_MBCMD_BKREQP 0x25
+#define OMAP_DSP_MBCMD_TCTL 0x30
+#define OMAP_DSP_MBCMD_TCTLDATA 0x31
+#define OMAP_DSP_MBCMD_POLL 0x32
+#define OMAP_DSP_MBCMD_WDT 0x50 /* v3.3: obsolete */
+#define OMAP_DSP_MBCMD_RUNLEVEL 0x51
+#define OMAP_DSP_MBCMD_PM 0x52
+#define OMAP_DSP_MBCMD_SUSPEND 0x53
+#define OMAP_DSP_MBCMD_KFUNC 0x54
+#define OMAP_DSP_MBCMD_TCFG 0x60
+#define OMAP_DSP_MBCMD_TADD 0x62
+#define OMAP_DSP_MBCMD_TDEL 0x63
+#define OMAP_DSP_MBCMD_TSTOP 0x65
+#define OMAP_DSP_MBCMD_DSPCFG 0x70
+#define OMAP_DSP_MBCMD_REGRW 0x72
+#define OMAP_DSP_MBCMD_GETVAR 0x74
+#define OMAP_DSP_MBCMD_SETVAR 0x75
+#define OMAP_DSP_MBCMD_ERR 0x78
+#define OMAP_DSP_MBCMD_DBG 0x79
+
+#define OMAP_DSP_MBCMD_TCTL_TINIT 0x0000
+#define OMAP_DSP_MBCMD_TCTL_TEN 0x0001
+#define OMAP_DSP_MBCMD_TCTL_TDIS 0x0002
+#define OMAP_DSP_MBCMD_TCTL_TCLR 0x0003
+#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004
+
+#define OMAP_DSP_MBCMD_RUNLEVEL_USER 0x01
+#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER 0x0e
+#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY 0x10
+
+#define OMAP_DSP_MBCMD_PM_DISABLE 0x00
+#define OMAP_DSP_MBCMD_PM_ENABLE 0x01
+
+#define OMAP_DSP_MBCMD_KFUNC_FBCTL 0x00
+
+#define OMAP_DSP_MBCMD_FBCTL_ENABLE 0x0002
+#define OMAP_DSP_MBCMD_FBCTL_DISABLE 0x0003
+
+#define OMAP_DSP_MBCMD_TDEL_SAFE 0x0000
+#define OMAP_DSP_MBCMD_TDEL_KILL 0x0001
+
+#define OMAP_DSP_MBCMD_DSPCFG_REQ 0x00
+#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH 0x28
+#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL 0x29
+#define OMAP_DSP_MBCMD_DSPCFG_PROTREV 0x70
+#define OMAP_DSP_MBCMD_DSPCFG_ABORT 0x78
+#define OMAP_DSP_MBCMD_DSPCFG_LAST 0x80
+
+#define OMAP_DSP_MBCMD_REGRW_MEMR 0x00
+#define OMAP_DSP_MBCMD_REGRW_MEMW 0x01
+#define OMAP_DSP_MBCMD_REGRW_IOR 0x02
+#define OMAP_DSP_MBCMD_REGRW_IOW 0x03
+#define OMAP_DSP_MBCMD_REGRW_DATA 0x04
+
+#define OMAP_DSP_MBCMD_VARID_ICRMASK 0x00
+#define OMAP_DSP_MBCMD_VARID_LOADINFO 0x01
+
+#define OMAP_DSP_TTYP_ARCV 0x0001
+#define OMAP_DSP_TTYP_ASND 0x0002
+#define OMAP_DSP_TTYP_BKMD 0x0004
+#define OMAP_DSP_TTYP_BKDM 0x0008
+#define OMAP_DSP_TTYP_PVMD 0x0010
+#define OMAP_DSP_TTYP_PVDM 0x0020
+
+#define OMAP_DSP_EID_BADTID 0x10
+#define OMAP_DSP_EID_BADTCN 0x11
+#define OMAP_DSP_EID_BADBID 0x20
+#define OMAP_DSP_EID_BADCNT 0x21
+#define OMAP_DSP_EID_NOTLOCKED 0x22
+#define OMAP_DSP_EID_STVBUF 0x23
+#define OMAP_DSP_EID_BADADR 0x24
+#define OMAP_DSP_EID_BADTCTL 0x30
+#define OMAP_DSP_EID_BADPARAM 0x50
+#define OMAP_DSP_EID_FATAL 0x58
+#define OMAP_DSP_EID_NOMEM 0xc0
+#define OMAP_DSP_EID_NORES 0xc1
+#define OMAP_DSP_EID_IPBFULL 0xc2
+#define OMAP_DSP_EID_WDT 0xd0
+#define OMAP_DSP_EID_TASKNOTRDY 0xe0
+#define OMAP_DSP_EID_TASKBSY 0xe1
+#define OMAP_DSP_EID_TASKERR 0xef
+#define OMAP_DSP_EID_BADCFGTYP 0xf0
+#define OMAP_DSP_EID_DEBUG 0xf8
+#define OMAP_DSP_EID_BADSEQ 0xfe
+#define OMAP_DSP_EID_BADCMD 0xff
+
+#define OMAP_DSP_TNM_LEN 16
+
+#define OMAP_DSP_TID_FREE 0xff
+#define OMAP_DSP_TID_ANON 0xfe
+
+#define OMAP_DSP_BID_NULL 0xffff
+#define OMAP_DSP_BID_PVT 0xfffe
+
+#endif /* ASM_ARCH_DSP_H */
diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h
new file mode 100644
index 0000000..4fcce69
--- /dev/null
+++ b/include/asm-arm/arch-omap/dsp_common.h
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-omap/dsp_common.h
+ *
+ * Header for OMAP DSP subsystem control
+ *
+ * Copyright (C) 2004,2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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
+ *
+ * 2005/06/03: DSP Gateway version 3.3
+ */
+
+#ifndef ASM_ARCH_DSP_COMMON_H
+#define ASM_ARCH_DSP_COMMON_H
+
+void omap_dsp_pm_suspend(void);
+void omap_dsp_pm_resume(void);
+void omap_dsp_request_mpui(void);
+void omap_dsp_release_mpui(void);
+int omap_dsp_request_mem(void);
+int omap_dsp_release_mem(void);
+
+#endif /* ASM_ARCH_DSP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/entry-macro.S b/include/asm-arm/arch-omap/entry-macro.S
index 57b1268..0d29b9c 100644
--- a/include/asm-arm/arch-omap/entry-macro.S
+++ b/include/asm-arm/arch-omap/entry-macro.S
@@ -8,6 +8,8 @@
* warranty of any kind, whether express or implied.
*/
+#if defined(CONFIG_ARCH_OMAP1)
+
.macro disable_fiq
.endm
@@ -30,3 +32,29 @@
1510:
.endm
+#elif defined(CONFIG_ARCH_OMAP24XX)
+
+#include <asm/arch/omap24xx.h>
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \base, =VA_IC_BASE
+ ldr \irqnr, [\base, #0x98] /* IRQ pending reg 1 */
+ cmp \irqnr, #0x0
+ bne 2222f
+ ldr \irqnr, [\base, #0xb8] /* IRQ pending reg 2 */
+ cmp \irqnr, #0x0
+ bne 2222f
+ ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */
+ cmp \irqnr, #0x0
+2222:
+ ldrne \irqnr, [\base, #IRQ_SIR_IRQ]
+
+ .endm
+
+ .macro irq_prio_table
+ .endm
+
+#endif
diff --git a/include/asm-arm/arch-omap/gpio.h b/include/asm-arm/arch-omap/gpio.h
index fad2fc9..74cb2b9 100644
--- a/include/asm-arm/arch-omap/gpio.h
+++ b/include/asm-arm/arch-omap/gpio.h
@@ -3,7 +3,7 @@
*
* OMAP GPIO handling defines and functions
*
- * Copyright (C) 2003 Nokia Corporation
+ * Copyright (C) 2003-2005 Nokia Corporation
*
* Written by Juha Yrjölä <juha.yrjola@nokia.com>
*
@@ -30,7 +30,23 @@
#include <asm/arch/irqs.h>
#include <asm/io.h>
-#define OMAP_MPUIO_BASE 0xfffb5000
+#define OMAP_MPUIO_BASE (void __iomem *)0xfffb5000
+
+#ifdef CONFIG_ARCH_OMAP730
+#define OMAP_MPUIO_INPUT_LATCH 0x00
+#define OMAP_MPUIO_OUTPUT 0x02
+#define OMAP_MPUIO_IO_CNTL 0x04
+#define OMAP_MPUIO_KBR_LATCH 0x08
+#define OMAP_MPUIO_KBC 0x0a
+#define OMAP_MPUIO_GPIO_EVENT_MODE 0x0c
+#define OMAP_MPUIO_GPIO_INT_EDGE 0x0e
+#define OMAP_MPUIO_KBD_INT 0x10
+#define OMAP_MPUIO_GPIO_INT 0x12
+#define OMAP_MPUIO_KBD_MASKIT 0x14
+#define OMAP_MPUIO_GPIO_MASKIT 0x16
+#define OMAP_MPUIO_GPIO_DEBOUNCING 0x18
+#define OMAP_MPUIO_LATCH 0x1a
+#else
#define OMAP_MPUIO_INPUT_LATCH 0x00
#define OMAP_MPUIO_OUTPUT 0x04
#define OMAP_MPUIO_IO_CNTL 0x08
@@ -44,6 +60,7 @@
#define OMAP_MPUIO_GPIO_MASKIT 0x2c
#define OMAP_MPUIO_GPIO_DEBOUNCING 0x30
#define OMAP_MPUIO_LATCH 0x34
+#endif
#define OMAP_MPUIO(nr) (OMAP_MAX_GPIO_LINES + (nr))
#define OMAP_GPIO_IS_MPUIO(nr) ((nr) >= OMAP_MAX_GPIO_LINES)
@@ -52,18 +69,11 @@
IH_MPUIO_BASE + ((nr) & 0x0f) : \
IH_GPIO_BASE + ((nr) & 0x3f))
-/* For EDGECTRL */
-#define OMAP_GPIO_NO_EDGE 0x00
-#define OMAP_GPIO_FALLING_EDGE 0x01
-#define OMAP_GPIO_RISING_EDGE 0x02
-#define OMAP_GPIO_BOTH_EDGES 0x03
-
extern int omap_gpio_init(void); /* Call from board init only */
extern int omap_request_gpio(int gpio);
extern void omap_free_gpio(int gpio);
extern void omap_set_gpio_direction(int gpio, int is_input);
extern void omap_set_gpio_dataout(int gpio, int enable);
extern int omap_get_gpio_datain(int gpio);
-extern void omap_set_gpio_edge_ctrl(int gpio, int edge);
#endif
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 48258c7..60201e1 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -43,6 +43,7 @@
#include <asm/arch/cpu.h>
#endif
#include <asm/arch/io.h>
+#include <asm/arch/serial.h>
/*
* ---------------------------------------------------------------------------
@@ -89,11 +90,12 @@
/* DPLL control registers */
#define DPLL_CTL (0xfffecf00)
-/* DSP clock control */
+/* DSP clock control. Must use __raw_readw() and __raw_writew() with these */
#define DSP_CONFIG_REG_BASE (0xe1008000)
#define DSP_CKCTL (DSP_CONFIG_REG_BASE + 0x0)
#define DSP_IDLECT1 (DSP_CONFIG_REG_BASE + 0x4)
#define DSP_IDLECT2 (DSP_CONFIG_REG_BASE + 0x8)
+#define DSP_RSTCT2 (DSP_CONFIG_REG_BASE + 0x14)
/*
* ---------------------------------------------------------------------------
@@ -142,6 +144,13 @@
* Interrupts
* ---------------------------------------------------------------------------
*/
+#ifdef CONFIG_ARCH_OMAP1
+
+/*
+ * XXX: These probably want to be moved to arch/arm/mach-omap/omap1/irq.c
+ * or something similar.. -- PFM.
+ */
+
#define OMAP_IH1_BASE 0xfffecb00
#define OMAP_IH2_BASE 0xfffe0000
@@ -170,6 +179,8 @@
#define IRQ_ILR0_REG_OFFSET 0x1c
#define IRQ_GMR_REG_OFFSET 0xa0
+#endif
+
/*
* ----------------------------------------------------------------------------
* System control registers
@@ -260,32 +271,17 @@
/*
* ---------------------------------------------------------------------------
- * Serial ports
- * ---------------------------------------------------------------------------
- */
-#define OMAP_UART1_BASE (unsigned char *)0xfffb0000
-#define OMAP_UART2_BASE (unsigned char *)0xfffb0800
-#define OMAP_UART3_BASE (unsigned char *)0xfffb9800
-#define OMAP_MAX_NR_PORTS 3
-#define OMAP1510_BASE_BAUD (12000000/16)
-#define OMAP16XX_BASE_BAUD (48000000/16)
-
-#define is_omap_port(p) ({int __ret = 0; \
- if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
- p == IO_ADDRESS(OMAP_UART2_BASE) || \
- p == IO_ADDRESS(OMAP_UART3_BASE)) \
- __ret = 1; \
- __ret; \
- })
-
-/*
- * ---------------------------------------------------------------------------
* Processor specific defines
* ---------------------------------------------------------------------------
*/
#include "omap730.h"
#include "omap1510.h"
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#include "omap24xx.h"
+#endif
+
#include "omap16xx.h"
/*
@@ -312,7 +308,6 @@
#ifdef CONFIG_MACH_OMAP_H4
#include "board-h4.h"
-#error "Support for H4 board not yet implemented."
#endif
#ifdef CONFIG_MACH_OMAP_OSK
diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h
index 1c8c9fc..11fbf62 100644
--- a/include/asm-arm/arch-omap/io.h
+++ b/include/asm-arm/arch-omap/io.h
@@ -49,16 +49,24 @@
* I/O mapping
* ----------------------------------------------------------------------------
*/
-#define IO_PHYS 0xFFFB0000
-#define IO_OFFSET 0x01000000 /* Virtual IO = 0xfefb0000 */
-#define IO_VIRT (IO_PHYS - IO_OFFSET)
-#define IO_SIZE 0x40000
-#define IO_ADDRESS(x) ((x) - IO_OFFSET)
-#define PCIO_BASE 0
+#if defined(CONFIG_ARCH_OMAP1)
+#define IO_PHYS 0xFFFB0000
+#define IO_OFFSET -0x01000000 /* Virtual IO = 0xfefb0000 */
+#define IO_SIZE 0x40000
-#define io_p2v(x) ((x) - IO_OFFSET)
-#define io_v2p(x) ((x) + IO_OFFSET)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define IO_PHYS 0x48000000 /* L4 peripherals; other stuff has to be mapped *
+ * manually. */
+#define IO_OFFSET 0x90000000 /* Virtual IO = 0xd8000000 */
+#define IO_SIZE 0x08000000
+#endif
+
+#define IO_VIRT (IO_PHYS + IO_OFFSET)
+#define IO_ADDRESS(x) ((x) + IO_OFFSET)
+#define PCIO_BASE 0
+#define io_p2v(x) ((x) + IO_OFFSET)
+#define io_v2p(x) ((x) - IO_OFFSET)
#ifndef __ASSEMBLER__
@@ -96,6 +104,8 @@
->offset[((vaddr)&4095)>>2]
#define __REG32(paddr) __REGV32(io_p2v(paddr))
+extern void omap_map_common_io(void);
+
#else
#define __REG8(paddr) io_p2v(paddr)
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 0d05a7c..74e108c 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -135,7 +135,6 @@
/*
* OMAP-1510 specific IRQ numbers for interrupt handler 2
*/
-#define INT_1510_OS_32kHz_TIMER (22 + IH2_BASE)
#define INT_1510_COM_SPI_RO (31 + IH2_BASE)
/*
@@ -232,6 +231,11 @@
#define INT_730_DMA_CH15 (62 + IH2_BASE)
#define INT_730_NAND (63 + IH2_BASE)
+#define INT_24XX_GPIO_BANK1 29
+#define INT_24XX_GPIO_BANK2 30
+#define INT_24XX_GPIO_BANK3 31
+#define INT_24XX_GPIO_BANK4 32
+
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
* 16 MPUIO lines */
#define OMAP_MAX_GPIO_LINES 192
diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h
index f6b57dd..84f81e3 100644
--- a/include/asm-arm/arch-omap/memory.h
+++ b/include/asm-arm/arch-omap/memory.h
@@ -36,12 +36,11 @@
/*
* Physical DRAM offset.
*/
+#if defined(CONFIG_ARCH_OMAP1)
#define PHYS_OFFSET (0x10000000UL)
-
-/*
- * OMAP-1510 Local Bus address offset
- */
-#define OMAP1510_LB_OFFSET (0x30000000UL)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define PHYS_OFFSET (0x80000000UL)
+#endif
/*
* Conversion between SDRAM and fake PCI bus, used by USB
@@ -64,6 +63,11 @@
*/
#ifdef CONFIG_ARCH_OMAP1510
+/*
+ * OMAP-1510 Local Bus address offset
+ */
+#define OMAP1510_LB_OFFSET (0x30000000UL)
+
#define virt_to_lbus(x) ((x) - PAGE_OFFSET + OMAP1510_LB_OFFSET)
#define lbus_to_virt(x) ((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET)
#define is_lbus_device(dev) (cpu_is_omap1510() && dev && (strncmp(dev->bus_id, "ohci", 4) == 0))
diff --git a/include/asm-arm/arch-omap/mtd-xip.h b/include/asm-arm/arch-omap/mtd-xip.h
new file mode 100644
index 0000000..a73a285
--- /dev/null
+++ b/include/asm-arm/arch-omap/mtd-xip.h
@@ -0,0 +1,61 @@
+/*
+ * MTD primitives for XIP support. Architecture specific functions.
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ *
+ * (c) 2005 MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express or
+ * implied.
+ */
+
+#ifndef __ARCH_OMAP_MTD_XIP_H__
+#define __ARCH_OMAP_MTD_XIP_H__
+
+#include <asm/hardware.h>
+#define OMAP_MPU_TIMER_BASE (0xfffec500)
+#define OMAP_MPU_TIMER_OFFSET 0x100
+
+typedef struct {
+ u32 cntl; /* CNTL_TIMER, R/W */
+ u32 load_tim; /* LOAD_TIM, W */
+ u32 read_tim; /* READ_TIM, R */
+} xip_omap_mpu_timer_regs_t;
+
+#define xip_omap_mpu_timer_base(n) \
+((volatile xip_omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
+ (n)*OMAP_MPU_TIMER_OFFSET))
+
+static inline unsigned long xip_omap_mpu_timer_read(int nr)
+{
+ volatile xip_omap_mpu_timer_regs_t* timer = xip_omap_mpu_timer_base(nr);
+ return timer->read_tim;
+}
+
+#define xip_irqpending() \
+ (omap_readl(OMAP_IH1_ITR) & ~omap_readl(OMAP_IH1_MIR))
+#define xip_currtime() (~xip_omap_mpu_timer_read(0))
+
+/*
+ * It's permitted to do approxmation for xip_elapsed_since macro
+ * (see linux/mtd/xip.h)
+ */
+
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+#define xip_elapsed_since(x) (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 7)
+#else
+#define xip_elapsed_since(x) (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 6)
+#endif
+
+/*
+ * xip_cpu_idle() is used when waiting for a delay equal or larger than
+ * the system timer tick period. This should put the CPU into idle mode
+ * to save power and to be woken up only when some interrupts are pending.
+ * As above, this should not rely upon standard kernel code.
+ */
+
+#define xip_cpu_idle() asm volatile ("mcr p15, 0, %0, c7, c0, 4" :: "r" (1))
+
+#endif /* __ARCH_OMAP_MTD_XIP_H__ */
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 5bd3f00..1b1ad41 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -185,6 +185,7 @@
/* MPUIO */
MPUIO2,
+ N15_1610_MPUIO2,
MPUIO4,
MPUIO5,
T20_1610_MPUIO5,
@@ -210,6 +211,7 @@
/* Misc ballouts */
BALLOUT_V8_ARMIO3,
+ N20_HDQ,
/* OMAP-1610 MMC2 */
W8_1610_MMC2_DAT0,
@@ -235,6 +237,7 @@
P20_1610_GPIO4,
V9_1610_GPIO7,
W8_1610_GPIO9,
+ N20_1610_GPIO11,
N19_1610_GPIO13,
P10_1610_GPIO22,
V5_1610_GPIO24,
@@ -250,7 +253,7 @@
U18_1610_UWIRE_SDI,
W21_1610_UWIRE_SDO,
N14_1610_UWIRE_CS0,
- P15_1610_UWIRE_CS0,
+ P15_1610_UWIRE_CS3,
N15_1610_UWIRE_CS1,
/* OMAP-1610 Flash */
@@ -411,7 +414,8 @@
MUX_CFG("W15_1710_GPIO40", 9, 27, 7, 2, 5, 1, 2, 1, 1)
/* MPUIO */
-MUX_CFG("MPUIO2", 7, 18, 0, 1, 1, 1, NA, 0, 1)
+MUX_CFG("MPUIO2", 7, 18, 0, 1, 14, 1, NA, 0, 1)
+MUX_CFG("N15_1610_MPUIO2", 7, 18, 0, 1, 14, 1, 1, 0, 1)
MUX_CFG("MPUIO4", 7, 15, 0, 1, 13, 1, NA, 0, 1)
MUX_CFG("MPUIO5", 7, 12, 0, 1, 12, 1, NA, 0, 1)
@@ -438,6 +442,7 @@
/* Misc ballouts */
MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1)
+MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0)
/* OMAP-1610 MMC2 */
MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1)
@@ -463,6 +468,7 @@
MUX_CFG("P20_1610_GPIO4", 6, 27, 0, 1, 7, 0, 1, 1, 1)
MUX_CFG("V9_1610_GPIO7", B, 12, 1, 2, 20, 0, 2, 1, 1)
MUX_CFG("W8_1610_GPIO9", B, 21, 0, 2, 23, 0, 2, 1, 1)
+MUX_CFG("N20_1610_GPIO11", 6, 18, 0, 1, 4, 0, 1, 1, 1)
MUX_CFG("N19_1610_GPIO13", 6, 12, 0, 1, 2, 0, 1, 1, 1)
MUX_CFG("P10_1610_GPIO22", C, 0, 7, 2, 26, 0, 2, 1, 1)
MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1)
diff --git a/include/asm-arm/arch-omap/omap1510.h b/include/asm-arm/arch-omap/omap1510.h
index f491a48..f086a39 100644
--- a/include/asm-arm/arch-omap/omap1510.h
+++ b/include/asm-arm/arch-omap/omap1510.h
@@ -36,10 +36,6 @@
/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
-#define OMAP1510_SRAM_BASE 0xD0000000
-#define OMAP1510_SRAM_SIZE (SZ_128K + SZ_64K)
-#define OMAP1510_SRAM_START 0x20000000
-
#define OMAP1510_DSP_BASE 0xE0000000
#define OMAP1510_DSP_SIZE 0x28000
#define OMAP1510_DSP_START 0xE0000000
@@ -48,14 +44,5 @@
#define OMAP1510_DSPREG_SIZE SZ_128K
#define OMAP1510_DSPREG_START 0xE1000000
-/*
- * ----------------------------------------------------------------------------
- * Memory used by power management
- * ----------------------------------------------------------------------------
- */
-
-#define OMAP1510_SRAM_IDLE_SUSPEND (OMAP1510_SRAM_BASE + OMAP1510_SRAM_SIZE - 0x200)
-#define OMAP1510_SRAM_API_SUSPEND (OMAP1510_SRAM_IDLE_SUSPEND + 0x100)
-
#endif /* __ASM_ARCH_OMAP1510_H */
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
index 38a9b95..f0c7f0f 100644
--- a/include/asm-arm/arch-omap/omap16xx.h
+++ b/include/asm-arm/arch-omap/omap16xx.h
@@ -36,11 +36,6 @@
/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
-#define OMAP16XX_SRAM_BASE 0xD0000000
-#define OMAP1610_SRAM_SIZE (SZ_16K)
-#define OMAP5912_SRAM_SIZE 0x3E800
-#define OMAP16XX_SRAM_START 0x20000000
-
#define OMAP16XX_DSP_BASE 0xE0000000
#define OMAP16XX_DSP_SIZE 0x28000
#define OMAP16XX_DSP_START 0xE0000000
@@ -50,17 +45,6 @@
#define OMAP16XX_DSPREG_START 0xE1000000
/*
- * ----------------------------------------------------------------------------
- * Memory used by power management
- * ----------------------------------------------------------------------------
- */
-
-#define OMAP1610_SRAM_IDLE_SUSPEND (OMAP16XX_SRAM_BASE + OMAP1610_SRAM_SIZE - 0x200)
-#define OMAP1610_SRAM_API_SUSPEND (OMAP1610_SRAM_IDLE_SUSPEND + 0x100)
-#define OMAP5912_SRAM_IDLE_SUSPEND (OMAP16XX_SRAM_BASE + OMAP5912_SRAM_SIZE - 0x200)
-#define OMAP5912_SRAM_API_SUSPEND (OMAP5912_SRAM_IDLE_SUSPEND + 0x100)
-
-/*
* ---------------------------------------------------------------------------
* Interrupts
* ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h
new file mode 100644
index 0000000..a910546
--- /dev/null
+++ b/include/asm-arm/arch-omap/omap24xx.h
@@ -0,0 +1,15 @@
+#ifndef __ASM_ARCH_OMAP24XX_H
+#define __ASM_ARCH_OMAP24XX_H
+
+#define OMAP24XX_L4_IO_BASE 0x48000000
+
+/* interrupt controller */
+#define OMAP24XX_IC_BASE (OMAP24XX_L4_IO_BASE + 0xfe000)
+#define VA_IC_BASE IO_ADDRESS(OMAP24XX_IC_BASE)
+
+#define OMAP24XX_IVA_INTC_BASE 0x40000000
+
+#define IRQ_SIR_IRQ 0x0040
+
+#endif /* __ASM_ARCH_OMAP24XX_H */
+
diff --git a/include/asm-arm/arch-omap/omap730.h b/include/asm-arm/arch-omap/omap730.h
index 599ab00..755b64c 100644
--- a/include/asm-arm/arch-omap/omap730.h
+++ b/include/asm-arm/arch-omap/omap730.h
@@ -36,10 +36,6 @@
/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
-#define OMAP730_SRAM_BASE 0xD0000000
-#define OMAP730_SRAM_SIZE (SZ_128K + SZ_64K + SZ_8K)
-#define OMAP730_SRAM_START 0x20000000
-
#define OMAP730_DSP_BASE 0xE0000000
#define OMAP730_DSP_SIZE 0x50000
#define OMAP730_DSP_START 0xE0000000
diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h
index f209fc0..fbd742d 100644
--- a/include/asm-arm/arch-omap/pm.h
+++ b/include/asm-arm/arch-omap/pm.h
@@ -61,7 +61,10 @@
#define PER_EN 0x1
#define CPU_SUSPEND_SIZE 200
-#define ULPD_LOW_POWER_EN 0x0001
+#define ULPD_LOW_PWR_EN 0x0001
+#define ULPD_DEEP_SLEEP_TRANSITION_EN 0x0010
+#define ULPD_SETUP_ANALOG_CELL_3_VAL 0
+#define ULPD_POWER_CTRL_REG_VAL 0x0219
#define DSP_IDLE_DELAY 10
#define DSP_IDLE 0x0040
@@ -86,46 +89,35 @@
#define OMAP1510_BIG_SLEEP_REQUEST 0x0cc5
#define OMAP1510_IDLE_LOOP_REQUEST 0x0c00
#define OMAP1510_IDLE_CLOCK_DOMAINS 0x2
-#define OMAP1510_ULPD_LOW_POWER_REQ 0x0001
-#define OMAP1610_DEEP_SLEEP_REQUEST 0x17c7
-#define OMAP1610_BIG_SLEEP_REQUEST TBD
+/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
+#define OMAP1610_IDLECT1_SLEEP_VAL 0x13c7
+#define OMAP1610_IDLECT2_SLEEP_VAL 0x09c7
+#define OMAP1610_IDLECT3_VAL 0x3f
+#define OMAP1610_IDLECT3_SLEEP_ORMASK 0x2c
+#define OMAP1610_IDLECT3 0xfffece24
#define OMAP1610_IDLE_LOOP_REQUEST 0x0400
-#define OMAP1610_IDLE_CLOCK_DOMAINS 0x09c7
-#define OMAP1610_ULPD_LOW_POWER_REQ 0x3
-
-#ifndef OMAP1510_SRAM_IDLE_SUSPEND
-#define OMAP1510_SRAM_IDLE_SUSPEND 0
-#endif
-#ifndef OMAP1610_SRAM_IDLE_SUSPEND
-#define OMAP1610_SRAM_IDLE_SUSPEND 0
-#endif
-#ifndef OMAP5912_SRAM_IDLE_SUSPEND
-#define OMAP5912_SRAM_IDLE_SUSPEND 0
-#endif
-
-#ifndef OMAP1510_SRAM_API_SUSPEND
-#define OMAP1510_SRAM_API_SUSPEND 0
-#endif
-#ifndef OMAP1610_SRAM_API_SUSPEND
-#define OMAP1610_SRAM_API_SUSPEND 0
-#endif
-#ifndef OMAP5912_SRAM_API_SUSPEND
-#define OMAP5912_SRAM_API_SUSPEND 0
-#endif
#if !defined(CONFIG_ARCH_OMAP1510) && \
- !defined(CONFIG_ARCH_OMAP16XX)
+ !defined(CONFIG_ARCH_OMAP16XX) && \
+ !defined(CONFIG_ARCH_OMAP24XX)
#error "Power management for this processor not implemented yet"
#endif
#ifndef __ASSEMBLER__
extern void omap_pm_idle(void);
extern void omap_pm_suspend(void);
-extern int omap1510_cpu_suspend(unsigned short, unsigned short);
-extern int omap1610_cpu_suspend(unsigned short, unsigned short);
-extern int omap1510_idle_loop_suspend(void);
-extern int omap1610_idle_loop_suspend(void);
+extern void omap1510_cpu_suspend(unsigned short, unsigned short);
+extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap1510_idle_loop_suspend(void);
+extern void omap1610_idle_loop_suspend(void);
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+extern void omap_serial_wake_trigger(int enable);
+#else
+#define omap_serial_wake_trigger(x) {}
+#endif /* CONFIG_OMAP_SERIAL_WAKE */
+
extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz;
@@ -161,6 +153,7 @@
ARM_SLEEP_SAVE_ARM_CKCTL,
ARM_SLEEP_SAVE_ARM_IDLECT1,
ARM_SLEEP_SAVE_ARM_IDLECT2,
+ ARM_SLEEP_SAVE_ARM_IDLECT3,
ARM_SLEEP_SAVE_ARM_EWUPCT,
ARM_SLEEP_SAVE_ARM_RSTCT1,
ARM_SLEEP_SAVE_ARM_RSTCT2,
diff --git a/include/asm-arm/arch-omap/serial.h b/include/asm-arm/arch-omap/serial.h
new file mode 100644
index 0000000..79a5297
--- /dev/null
+++ b/include/asm-arm/arch-omap/serial.h
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-omap/serial.h
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+#if defined(CONFIG_ARCH_OMAP1)
+/* OMAP1 serial ports */
+#define OMAP_UART1_BASE 0xfffb0000
+#define OMAP_UART2_BASE 0xfffb0800
+#define OMAP_UART3_BASE 0xfffb9800
+#elif defined(CONFIG_ARCH_OMAP2)
+/* OMAP2 serial ports */
+#define OMAP_UART1_BASE 0x4806a000
+#define OMAP_UART2_BASE 0x4806c000
+#define OMAP_UART3_BASE 0x4806e000
+#endif
+
+#define OMAP_MAX_NR_PORTS 3
+#define OMAP1510_BASE_BAUD (12000000/16)
+#define OMAP16XX_BASE_BAUD (48000000/16)
+
+#define is_omap_port(p) ({int __ret = 0; \
+ if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
+ p == IO_ADDRESS(OMAP_UART2_BASE) || \
+ p == IO_ADDRESS(OMAP_UART3_BASE)) \
+ __ret = 1; \
+ __ret; \
+ })
+
+#endif
diff --git a/include/asm-arm/arch-omap/uncompress.h b/include/asm-arm/arch-omap/uncompress.h
index 3e640ab..3545c86 100644
--- a/include/asm-arm/arch-omap/uncompress.h
+++ b/include/asm-arm/arch-omap/uncompress.h
@@ -20,7 +20,7 @@
#include <linux/config.h>
#include <linux/types.h>
#include <linux/serial_reg.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch/serial.h>
unsigned int system_rev;
@@ -34,8 +34,9 @@
putstr(const char *s)
{
volatile u8 * uart = 0;
- int shift;
+ int shift = 2;
+#ifdef CONFIG_ARCH_OMAP
#ifdef CONFIG_OMAP_LL_DEBUG_UART3
uart = (volatile u8 *)(OMAP_UART3_BASE);
#elif CONFIG_OMAP_LL_DEBUG_UART2
@@ -44,6 +45,7 @@
uart = (volatile u8 *)(OMAP_UART1_BASE);
#endif
+#ifdef CONFIG_ARCH_OMAP1
/* Determine which serial port to use */
do {
/* MMU is not on, so cpu_is_omapXXXX() won't work here */
@@ -51,14 +53,14 @@
if (omap_id == OMAP_ID_730)
shift = 0;
- else
- shift = 2;
if (check_port(uart, shift))
break;
/* Silent boot if no serial ports are enabled. */
return;
} while (0);
+#endif /* CONFIG_ARCH_OMAP1 */
+#endif
/*
* Now, xmit each character
diff --git a/include/asm-arm/arch-pxa/corgi.h b/include/asm-arm/arch-pxa/corgi.h
index 324db06..4b7aa0b 100644
--- a/include/asm-arm/arch-pxa/corgi.h
+++ b/include/asm-arm/arch-pxa/corgi.h
@@ -103,18 +103,20 @@
* Shared data structures
*/
extern struct platform_device corgiscoop_device;
+extern struct platform_device corgissp_device;
+extern struct platform_device corgifb_device;
/*
* External Functions
*/
extern unsigned long corgi_ssp_ads7846_putget(unsigned long);
extern unsigned long corgi_ssp_ads7846_get(void);
-extern void corgi_ssp_ads7846_put(ulong data);
+extern void corgi_ssp_ads7846_put(unsigned long data);
extern void corgi_ssp_ads7846_lock(void);
extern void corgi_ssp_ads7846_unlock(void);
-extern void corgi_ssp_lcdtg_send (u8 adrs, u8 data);
+extern void corgi_ssp_lcdtg_send (unsigned char adrs, unsigned char data);
extern void corgi_ssp_blduty_set(int duty);
-extern int corgi_ssp_max1111_get(ulong data);
+extern int corgi_ssp_max1111_get(unsigned long data);
#endif /* __ASM_ARCH_CORGI_H */
diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
index 7492ea7..9718063 100644
--- a/include/asm-arm/arch-pxa/mmc.h
+++ b/include/asm-arm/arch-pxa/mmc.h
@@ -10,6 +10,7 @@
struct pxamci_platform_data {
unsigned int ocr_mask; /* available voltages */
int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *);
+ int (*get_ro)(struct device *);
void (*setpower)(struct device *, unsigned int);
void (*exit)(struct device *, void *);
};
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 51f0fe0..939d9e5 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -818,6 +818,23 @@
#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge
Interrupt Enable */
+#define UP2OCR __REG(0x40600020) /* USB Port 2 Output Control register */
+
+#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */
+#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */
+#define UP2OCR_DPPDE (1 << 2) /* Host Port 2 Transceiver D+ Pull Down Enable */
+#define UP2OCR_DMPDE (1 << 3) /* Host Port 2 Transceiver D- Pull Down Enable */
+#define UP2OCR_DPPUE (1 << 4) /* Host Port 2 Transceiver D+ Pull Up Enable */
+#define UP2OCR_DMPUE (1 << 5) /* Host Port 2 Transceiver D- Pull Up Enable */
+#define UP2OCR_DPPUBE (1 << 6) /* Host Port 2 Transceiver D+ Pull Up Bypass Enable */
+#define UP2OCR_DMPUBE (1 << 7) /* Host Port 2 Transceiver D- Pull Up Bypass Enable */
+#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */
+#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */
+#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */
+#define UP2OCR_HXS (1 << 16) /* Host Port 2 Transceiver Output Select */
+#define UP2OCR_HXOE (1 << 17) /* Host Port 2 Transceiver Output Enable */
+#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */
+
#define UDCCSN(x) __REG2(0x40600100, (x) << 2)
#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */
#define UDCCSR0_SA (1 << 7) /* Setup Active */
@@ -1423,6 +1440,7 @@
#define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN)
#define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT)
#define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT)
+#define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT)
#define GPIO109_MMCDAT1_MD (109 | GPIO_ALT_FN_1_OUT)
#define GPIO110_MMCDAT2_MD (110 | GPIO_ALT_FN_1_OUT)
#define GPIO110_MMCCS0_MD (110 | GPIO_ALT_FN_1_OUT)
@@ -1510,6 +1528,8 @@
#define PSSR_BFS (1 << 1) /* Battery Fault Status */
#define PSSR_SSS (1 << 0) /* Software Sleep Status */
+#define PSLR_SL_ROD (1 << 20) /* Sleep-Mode/Depp-Sleep Mode nRESET_OUT Disable */
+
#define PCFR_RO (1 << 15) /* RDH Override */
#define PCFR_PO (1 << 14) /* PH Override */
#define PCFR_GPROD (1 << 12) /* GPIO nRESET_OUT Disable */
@@ -1517,6 +1537,7 @@
#define PCFR_FVC (1 << 10) /* Frequency/Voltage Change */
#define PCFR_DC_EN (1 << 7) /* Sleep/deep-sleep DC-DC Converter Enable */
#define PCFR_PI2CEN (1 << 6) /* Enable PI2C controller */
+#define PCFR_GPR_EN (1 << 4) /* nRESET_GPIO Pin Enable */
#define PCFR_DS (1 << 3) /* Deep Sleep Mode */
#define PCFR_FS (1 << 2) /* Float Static Chip Selects */
#define PCFR_FP (1 << 1) /* Float PCMCIA controls */
@@ -1810,6 +1831,11 @@
#define LCCR0_PDD_S 12
#define LCCR0_BM (1 << 20) /* Branch mask */
#define LCCR0_OUM (1 << 21) /* Output FIFO underrun mask */
+#define LCCR0_LCDT (1 << 22) /* LCD panel type */
+#define LCCR0_RDSTM (1 << 23) /* Read status interrupt mask */
+#define LCCR0_CMDIM (1 << 24) /* Command interrupt mask */
+#define LCCR0_OUC (1 << 25) /* Overlay Underlay control bit */
+#define LCCR0_LDDALT (1 << 26) /* LDD alternate mapping control */
#define LCCR1_PPL Fld (10, 0) /* Pixels Per Line - 1 */
#define LCCR1_DisWdth(Pixel) /* Display Width [1..800 pix.] */ \
@@ -2062,7 +2088,10 @@
#define UHCFMN __REG(0x4C00003C) /* UHC Frame Number */
#define UHCPERS __REG(0x4C000040) /* UHC Periodic Start */
#define UHCLS __REG(0x4C000044) /* UHC Low Speed Threshold */
+
#define UHCRHDA __REG(0x4C000048) /* UHC Root Hub Descriptor A */
+#define UHCRHDA_NOCP (1 << 12) /* No over current protection */
+
#define UHCRHDB __REG(0x4C00004C) /* UHC Root Hub Descriptor B */
#define UHCRHS __REG(0x4C000050) /* UHC Root Hub Status */
#define UHCRHPS1 __REG(0x4C000054) /* UHC Root Hub Port 1 Status */
diff --git a/include/asm-arm/arch-s3c2410/anubis-cpld.h b/include/asm-arm/arch-s3c2410/anubis-cpld.h
new file mode 100644
index 0000000..5675b17
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/anubis-cpld.h
@@ -0,0 +1,24 @@
+/* linux/include/asm-arm/arch-s3c2410/anubis-cpld.h
+ *
+ * (c) 2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - CPLD control constants
+ *
+ * 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.
+ *
+ * Changelog:
+ *
+*/
+
+#ifndef __ASM_ARCH_ANUBISCPLD_H
+#define __ASM_ARCH_ANUBISCPLD_H
+
+/* CTRL2 - NAND WP control, IDE Reset assert/check */
+
+#define ANUBIS_CTRL1_NANDSEL (0x3)
+
+#endif /* __ASM_ARCH_ANUBISCPLD_H */
diff --git a/include/asm-arm/arch-s3c2410/anubis-irq.h b/include/asm-arm/arch-s3c2410/anubis-irq.h
new file mode 100644
index 0000000..82f15db
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/anubis-irq.h
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-s3c2410/anubis-irq.h
+ *
+ * (c) 2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - IRQ Number definitions
+ *
+ * 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.
+ *
+ * Changelog:
+ */
+
+#ifndef __ASM_ARCH_ANUBISIRQ_H
+#define __ASM_ARCH_ANUBISIRQ_H
+
+#define IRQ_IDE0 IRQ_EINT2
+#define IRQ_IDE1 IRQ_EINT3
+#define IRQ_ASIX IRQ_EINT1
+
+#endif /* __ASM_ARCH_ANUBISIRQ_H */
diff --git a/include/asm-arm/arch-s3c2410/anubis-map.h b/include/asm-arm/arch-s3c2410/anubis-map.h
new file mode 100644
index 0000000..97741d6
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/anubis-map.h
@@ -0,0 +1,46 @@
+/* linux/include/asm-arm/arch-s3c2410/anubis-map.h
+ *
+ * (c) 2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - Memory map definitions
+ *
+ * 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.
+ *
+ * Changelog:
+*/
+
+/* needs arch/map.h including with this */
+
+#ifndef __ASM_ARCH_ANUBISMAP_H
+#define __ASM_ARCH_ANUBISMAP_H
+
+/* start peripherals off after the S3C2410 */
+
+#define ANUBIS_IOADDR(x) (S3C2410_ADDR((x) + 0x02000000))
+
+#define ANUBIS_PA_CPLD (S3C2410_CS1 | (1<<26))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define ANUBIS_VA_CTRL1 ANUBIS_IOADDR(0x00000000) /* 0x01300000 */
+#define ANUBIS_PA_CTRL1 (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_CTRL2 ANUBIS_IOADDR(0x00100000) /* 0x01400000 */
+#define ANUBIS_PA_CTRL2 (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_CTRL3 ANUBIS_IOADDR(0x00200000) /* 0x01500000 */
+#define ANUBIS_PA_CTRL3 (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_CTRL4 ANUBIS_IOADDR(0x00300000) /* 0x01600000 */
+#define ANUBIS_PA_CTRL4 (ANUBIS_PA_CPLD)
+
+#define ANUBIS_IDEPRI ANUBIS_IOADDR(0x01000000)
+#define ANUBIS_IDEPRIAUX ANUBIS_IOADDR(0x01100000)
+#define ANUBIS_IDESEC ANUBIS_IOADDR(0x01200000)
+#define ANUBIS_IDESECAUX ANUBIS_IOADDR(0x01300000)
+
+#endif /* __ASM_ARCH_ANUBISMAP_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
index e5e938b..16f4c3c 100644
--- a/include/asm-arm/arch-s3c2410/regs-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-clock.h
@@ -1,7 +1,7 @@
/* linux/include/asm/arch-s3c2410/regs-clock.h
*
- * Copyright (c) 2003,2004 Simtec Electronics <linux@simtec.co.uk>
- * http://www.simtec.co.uk/products/SWLINUX/
+ * Copyright (c) 2003,2004,2005 Simtec Electronics <linux@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
*
* 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
@@ -17,6 +17,7 @@
* 29-Sep-2004 Ben Dooks Fixed usage for assembly inclusion
* 10-Feb-2005 Ben Dooks Fixed CAMDIVN address (Guillaume Gourat)
* 10-Mar-2005 Lucas Villa Real Changed S3C2410_VA to S3C24XX_VA
+ * 27-Aug-2005 Ben Dooks Add clock-slow info
*/
#ifndef __ASM_ARM_REGS_CLOCK
@@ -74,6 +75,12 @@
#define S3C2410_CLKDIVN_PDIVN (1<<0)
#define S3C2410_CLKDIVN_HDIVN (1<<1)
+#define S3C2410_CLKSLOW_UCLK_OFF (1<<7)
+#define S3C2410_CLKSLOW_MPLL_OFF (1<<5)
+#define S3C2410_CLKSLOW_SLOW (1<<4)
+#define S3C2410_CLKSLOW_SLOWVAL(x) (x)
+#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
+
#ifndef __ASSEMBLY__
static inline unsigned int
diff --git a/include/asm-arm/auxvec.h b/include/asm-arm/auxvec.h
new file mode 100644
index 0000000..c0536f6
--- /dev/null
+++ b/include/asm-arm/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMARM_AUXVEC_H
+#define __ASMARM_AUXVEC_H
+
+#endif
diff --git a/include/asm-arm/fcntl.h b/include/asm-arm/fcntl.h
index 485b6bd..a80b660 100644
--- a/include/asm-arm/fcntl.h
+++ b/include/asm-arm/fcntl.h
@@ -1,87 +1,11 @@
#ifndef _ARM_FCNTL_H
#define _ARM_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0400000
-#define O_NOATIME 01000000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
+#include <asm-generic/fcntl.h>
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
#endif
diff --git a/include/asm-arm/futex.h b/include/asm-arm/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-arm/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h
index 7ea771f..527404b 100644
--- a/include/asm-arm/hardware/scoop.h
+++ b/include/asm-arm/hardware/scoop.h
@@ -40,6 +40,19 @@
unsigned short io_dir;
};
+/* Structure for linking scoop devices to PCMCIA sockets */
+struct scoop_pcmcia_dev {
+ struct device *dev; /* Pointer to this socket's scoop device */
+ int irq; /* irq for socket */
+ int cd_irq;
+ const char *cd_irq_str;
+ unsigned char keep_vs;
+ unsigned char keep_rd;
+};
+
+extern int scoop_num;
+extern struct scoop_pcmcia_dev *scoop_devs;
+
void reset_scoop(struct device *dev);
unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit);
diff --git a/include/asm-arm/hdreg.h b/include/asm-arm/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-arm/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-arm/mach/irq.h b/include/asm-arm/mach/irq.h
index a43a353..0ce6ca5 100644
--- a/include/asm-arm/mach/irq.h
+++ b/include/asm-arm/mach/irq.h
@@ -42,11 +42,11 @@
/*
* Set the type of the IRQ.
*/
- int (*type)(unsigned int, unsigned int);
+ int (*set_type)(unsigned int, unsigned int);
/*
* Set wakeup-enable on the selected IRQ
*/
- int (*wake)(unsigned int, unsigned int);
+ int (*set_wake)(unsigned int, unsigned int);
#ifdef CONFIG_SMP
/*
@@ -92,6 +92,14 @@
extern struct irqdesc irq_desc[];
/*
+ * Helpful inline function for calling irq descriptor handlers.
+ */
+static inline void desc_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+ desc->handle(irq, desc, regs);
+}
+
+/*
* This is internal. Do not use it.
*/
extern void (*init_arch_irq)(void);
diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h
index 2cf279a..96c6db7 100644
--- a/include/asm-arm/mach/time.h
+++ b/include/asm-arm/mach/time.h
@@ -47,9 +47,7 @@
#ifdef CONFIG_NO_IDLE_HZ
-#define DYN_TICK_SKIPPING (1 << 2)
#define DYN_TICK_ENABLED (1 << 1)
-#define DYN_TICK_SUITABLE (1 << 0)
struct dyn_tick_timer {
unsigned int state; /* Current state */
diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h
index 019c45d..4da1d53 100644
--- a/include/asm-arm/page.h
+++ b/include/asm-arm/page.h
@@ -163,20 +163,6 @@
/* the upper-most page table pointer */
extern pmd_t *top_pmd;
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#include <asm/memory.h>
#endif /* !__ASSEMBLY__ */
@@ -186,4 +172,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif
diff --git a/include/asm-arm/types.h b/include/asm-arm/types.h
index f4c92e4..22992ee 100644
--- a/include/asm-arm/types.h
+++ b/include/asm-arm/types.h
@@ -52,8 +52,6 @@
typedef u32 dma_addr_t;
typedef u32 dma64_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h
index a7c018b..a2fdad0 100644
--- a/include/asm-arm/uaccess.h
+++ b/include/asm-arm/uaccess.h
@@ -77,12 +77,6 @@
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
/*
* Single-value transfer routines. They automatically use the right
* size if we just have the right pointer type. Note that the functions
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index abb36e5..278de61 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -295,7 +295,7 @@
#define __NR_fstatfs64 (__NR_SYSCALL_BASE+267)
#define __NR_tgkill (__NR_SYSCALL_BASE+268)
#define __NR_utimes (__NR_SYSCALL_BASE+269)
-#define __NR_fadvise64_64 (__NR_SYSCALL_BASE+270)
+#define __NR_arm_fadvise64_64 (__NR_SYSCALL_BASE+270)
#define __NR_pciconfig_iobase (__NR_SYSCALL_BASE+271)
#define __NR_pciconfig_read (__NR_SYSCALL_BASE+272)
#define __NR_pciconfig_write (__NR_SYSCALL_BASE+273)
@@ -515,7 +515,6 @@
#define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
diff --git a/include/asm-arm26/auxvec.h b/include/asm-arm26/auxvec.h
new file mode 100644
index 0000000..c0536f6
--- /dev/null
+++ b/include/asm-arm26/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMARM_AUXVEC_H
+#define __ASMARM_AUXVEC_H
+
+#endif
diff --git a/include/asm-arm26/fcntl.h b/include/asm-arm26/fcntl.h
index 485b6bd..d85995e 100644
--- a/include/asm-arm26/fcntl.h
+++ b/include/asm-arm26/fcntl.h
@@ -3,85 +3,11 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0400000
-#define O_NOATIME 01000000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
+#include <asm-generic/fcntl.h>
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
#endif
diff --git a/include/asm-arm26/futex.h b/include/asm-arm26/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-arm26/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-arm26/hdreg.h b/include/asm-arm26/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-arm26/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-arm26/page.h b/include/asm-arm26/page.h
index c334079..d3f23ac 100644
--- a/include/asm-arm26/page.h
+++ b/include/asm-arm26/page.h
@@ -89,20 +89,6 @@
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#include <asm/memory.h>
#endif /* !__ASSEMBLY__ */
@@ -112,4 +98,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif
diff --git a/include/asm-arm26/types.h b/include/asm-arm26/types.h
index 56cbe57..81bd357 100644
--- a/include/asm-arm26/types.h
+++ b/include/asm-arm26/types.h
@@ -52,8 +52,6 @@
typedef u32 dma_addr_t;
typedef u32 dma64_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-arm26/uaccess.h b/include/asm-arm26/uaccess.h
index ab9ce38..3f2dd10 100644
--- a/include/asm-arm26/uaccess.h
+++ b/include/asm-arm26/uaccess.h
@@ -40,12 +40,6 @@
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
/*
* Single-value transfer routines. They automatically use the right
* size if we just have the right pointer type. Note that the functions
diff --git a/include/asm-cris/auxvec.h b/include/asm-cris/auxvec.h
new file mode 100644
index 0000000..cb30b01
--- /dev/null
+++ b/include/asm-cris/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMCRIS_AUXVEC_H
+#define __ASMCRIS_AUXVEC_H
+
+#endif
diff --git a/include/asm-cris/fcntl.h b/include/asm-cris/fcntl.h
index 61c5632..46ab12d 100644
--- a/include/asm-cris/fcntl.h
+++ b/include/asm-cris/fcntl.h
@@ -1,90 +1 @@
-#ifndef _CRIS_FCNTL_H
-#define _CRIS_FCNTL_H
-
-/* verbatim copy of i386 version */
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint - currently ignored */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get f_flags */
-#define F_SETFD 2 /* set f_flags */
-#define F_GETFL 3 /* more flags (cloexec) */
-#define F_SETFL 4
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-
-#endif
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-cris/futex.h b/include/asm-cris/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-cris/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-cris/irq.h b/include/asm-cris/irq.h
index 8e787fd..4fab5c3 100644
--- a/include/asm-cris/irq.h
+++ b/include/asm-cris/irq.h
@@ -1,6 +1,11 @@
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
+/*
+ * IRQ line status macro IRQ_PER_CPU is used
+ */
+#define ARCH_HAS_IRQ_PER_CPU
+
#include <asm/arch/irq.h>
extern __inline__ int irq_canonicalize(int irq)
diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h
index bbf17bd..c99c478 100644
--- a/include/asm-cris/page.h
+++ b/include/asm-cris/page.h
@@ -70,19 +70,6 @@
#ifndef __ASSEMBLY__
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
#endif /* __ASSEMBLY__ */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
@@ -90,5 +77,7 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _CRIS_PAGE_H */
diff --git a/include/asm-cris/types.h b/include/asm-cris/types.h
index 8fa6d6c..84557c9 100644
--- a/include/asm-cris/types.h
+++ b/include/asm-cris/types.h
@@ -52,8 +52,6 @@
typedef u32 dma_addr_t;
typedef u32 dma64_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-cris/uaccess.h b/include/asm-cris/uaccess.h
index 6db1722..7d50086 100644
--- a/include/asm-cris/uaccess.h
+++ b/include/asm-cris/uaccess.h
@@ -91,13 +91,6 @@
#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
#include <asm/arch/uaccess.h>
/*
diff --git a/include/asm-frv/auxvec.h b/include/asm-frv/auxvec.h
new file mode 100644
index 0000000..0771077
--- /dev/null
+++ b/include/asm-frv/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __FRV_AUXVEC_H
+#define __FRV_AUXVEC_H
+
+#endif
diff --git a/include/asm-frv/fcntl.h b/include/asm-frv/fcntl.h
index d61b999..46ab12d 100644
--- a/include/asm-frv/fcntl.h
+++ b/include/asm-frv/fcntl.h
@@ -1,88 +1 @@
-#ifndef _ASM_FCNTL_H
-#define _ASM_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-#endif /* _ASM_FCNTL_H */
-
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-frv/futex.h b/include/asm-frv/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-frv/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-frv/page.h b/include/asm-frv/page.h
index f7914f1..4feba56 100644
--- a/include/asm-frv/page.h
+++ b/include/asm-frv/page.h
@@ -45,21 +45,6 @@
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size) __attribute_const__;
-static inline int get_order(unsigned long size)
-{
- int order;
-
- size = (size - 1) >> (PAGE_SHIFT - 1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#define devmem_is_allowed(pfn) 1
#define __pa(vaddr) virt_to_phys((void *) vaddr)
@@ -102,4 +87,6 @@
#define WANT_PAGE_VIRTUAL 1
#endif
+#include <asm-generic/page.h>
+
#endif /* _ASM_PAGE_H */
diff --git a/include/asm-frv/types.h b/include/asm-frv/types.h
index 1a5b654..50605df 100644
--- a/include/asm-frv/types.h
+++ b/include/asm-frv/types.h
@@ -65,8 +65,6 @@
typedef u32 dma_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h
index 32dc52e8..991b50f 100644
--- a/include/asm-frv/uaccess.h
+++ b/include/asm-frv/uaccess.h
@@ -67,12 +67,6 @@
#define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0)
#define __access_ok(addr,size) (__range_ok((addr), (size)) == 0)
-/* this function will go away soon - use access_ok() / __range_ok() instead */
-static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
- return __range_ok(addr, size);
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
new file mode 100644
index 0000000..b663520
--- /dev/null
+++ b/include/asm-generic/fcntl.h
@@ -0,0 +1,149 @@
+#ifndef _ASM_GENERIC_FCNTL_H
+#define _ASM_GENERIC_FCNTL_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+ located on an ext2 file system */
+#define O_ACCMODE 00000003
+#define O_RDONLY 00000000
+#define O_WRONLY 00000001
+#define O_RDWR 00000002
+#ifndef O_CREAT
+#define O_CREAT 00000100 /* not fcntl */
+#endif
+#ifndef O_EXCL
+#define O_EXCL 00000200 /* not fcntl */
+#endif
+#ifndef O_NOCTTY
+#define O_NOCTTY 00000400 /* not fcntl */
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC 00001000 /* not fcntl */
+#endif
+#ifndef O_APPEND
+#define O_APPEND 00002000
+#endif
+#ifndef O_NONBLOCK
+#define O_NONBLOCK 00004000
+#endif
+#ifndef O_SYNC
+#define O_SYNC 00010000
+#endif
+#ifndef FASYNC
+#define FASYNC 00020000 /* fcntl, for BSD compatibility */
+#endif
+#ifndef O_DIRECT
+#define O_DIRECT 00040000 /* direct disk access hint */
+#endif
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 00100000
+#endif
+#ifndef O_DIRECTORY
+#define O_DIRECTORY 00200000 /* must be a directory */
+#endif
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 00400000 /* don't follow links */
+#endif
+#ifndef O_NOATIME
+#define O_NOATIME 01000000
+#endif
+#ifndef O_NDELAY
+#define O_NDELAY O_NONBLOCK
+#endif
+
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get close_on_exec */
+#define F_SETFD 2 /* set/clear close_on_exec */
+#define F_GETFL 3 /* get file->f_flags */
+#define F_SETFL 4 /* set file->f_flags */
+#ifndef F_GETLK
+#define F_GETLK 5
+#define F_SETLK 6
+#define F_SETLKW 7
+#endif
+#ifndef F_SETOWN
+#define F_SETOWN 8 /* for sockets. */
+#define F_GETOWN 9 /* for sockets. */
+#endif
+#ifndef F_SETSIG
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */
+#endif
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#ifndef F_RDLCK
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+#endif
+
+/* for old implementation of bsd flock () */
+#ifndef F_EXLCK
+#define F_EXLCK 4 /* or 3 */
+#define F_SHLCK 8 /* or 4 */
+#endif
+
+/* for leases */
+#ifndef F_INPROGRESS
+#define F_INPROGRESS 16
+#endif
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* or'd with one of the above to prevent
+ blocking */
+#define LOCK_UN 8 /* remove lock */
+
+#define LOCK_MAND 32 /* This is a mandatory flock ... */
+#define LOCK_READ 64 /* which allows concurrent read operations */
+#define LOCK_WRITE 128 /* which allows concurrent write operations */
+#define LOCK_RW 192 /* which allows concurrent read & write ops */
+
+#define F_LINUX_SPECIFIC_BASE 1024
+
+#ifndef HAVE_ARCH_STRUCT_FLOCK
+#ifndef __ARCH_FLOCK_PAD
+#define __ARCH_FLOCK_PAD
+#endif
+
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+ __ARCH_FLOCK_PAD
+};
+#endif
+
+#ifndef CONFIG_64BIT
+
+#ifndef F_GETLK64
+#define F_GETLK64 12 /* using 'struct flock64' */
+#define F_SETLK64 13
+#define F_SETLKW64 14
+#endif
+
+#ifndef HAVE_ARCH_STRUCT_FLOCK64
+#ifndef __ARCH_FLOCK64_PAD
+#define __ARCH_FLOCK64_PAD
+#endif
+
+struct flock64 {
+ short l_type;
+ short l_whence;
+ loff_t l_start;
+ loff_t l_len;
+ pid_t l_pid;
+ __ARCH_FLOCK64_PAD
+};
+#endif
+#endif /* !CONFIG_64BIT */
+
+#endif /* _ASM_GENERIC_FCNTL_H */
diff --git a/include/asm-generic/hdreg.h b/include/asm-generic/hdreg.h
deleted file mode 100644
index 7051fba..0000000
--- a/include/asm-generic/hdreg.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#warning <asm/hdreg.h> is obsolete, please do not use it
-
-#ifndef __ASM_GENERIC_HDREG_H
-#define __ASM_GENERIC_HDREG_H
-
-typedef unsigned long ide_ioreg_t;
-
-#endif /* __ASM_GENERIC_HDREG_H */
diff --git a/include/asm-generic/page.h b/include/asm-generic/page.h
new file mode 100644
index 0000000..a96b5d9
--- /dev/null
+++ b/include/asm-generic/page.h
@@ -0,0 +1,26 @@
+#ifndef _ASM_GENERIC_PAGE_H
+#define _ASM_GENERIC_PAGE_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+
+/* Pure 2^n version of get_order */
+static __inline__ __attribute_const__ int get_order(unsigned long size)
+{
+ int order;
+
+ size = (size - 1) >> (PAGE_SHIFT - 1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_GENERIC_PAGE_H */
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index f405935..f86c1e5 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -101,6 +101,22 @@
})
#endif
+#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
+#define ptep_get_and_clear_full(__mm, __address, __ptep, __full) \
+({ \
+ pte_t __pte; \
+ __pte = ptep_get_and_clear((__mm), (__address), (__ptep)); \
+ __pte; \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
+#define pte_clear_full(__mm, __address, __ptep, __full) \
+do { \
+ pte_clear((__mm), (__address), (__ptep)); \
+} while (0)
+#endif
+
#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
#define ptep_clear_flush(__vma, __address, __ptep) \
({ \
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 450eae2..886dbd1 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -12,5 +12,6 @@
extern char _eextratext[] __attribute__((weak));
extern char _end[];
extern char __per_cpu_start[], __per_cpu_end[];
+extern char __kprobes_text_start[], __kprobes_text_end[];
#endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
index 6c90f0f..4dc8ddb 100644
--- a/include/asm-generic/unaligned.h
+++ b/include/asm-generic/unaligned.h
@@ -16,9 +16,9 @@
* The main single-value unaligned transfer routines.
*/
#define get_unaligned(ptr) \
- ((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
+ __get_unaligned((ptr), sizeof(*(ptr)))
#define put_unaligned(x,ptr) \
- __put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
+ __put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))
/*
* This function doesn't actually exist. The idea is that when
@@ -36,19 +36,19 @@
* Elemental unaligned loads
*/
-static inline unsigned long __uldq(const __u64 *addr)
+static inline __u64 __uldq(const __u64 *addr)
{
const struct __una_u64 *ptr = (const struct __una_u64 *) addr;
return ptr->x;
}
-static inline unsigned long __uldl(const __u32 *addr)
+static inline __u32 __uldl(const __u32 *addr)
{
const struct __una_u32 *ptr = (const struct __una_u32 *) addr;
return ptr->x;
}
-static inline unsigned long __uldw(const __u16 *addr)
+static inline __u16 __uldw(const __u16 *addr)
{
const struct __una_u16 *ptr = (const struct __una_u16 *) addr;
return ptr->x;
@@ -78,7 +78,7 @@
#define __get_unaligned(ptr, size) ({ \
const void *__gu_p = ptr; \
- unsigned long val; \
+ __typeof__(*(ptr)) val; \
switch (size) { \
case 1: \
val = *(const __u8 *)__gu_p; \
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index b3bb326..6f857be 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -6,6 +6,9 @@
#define VMLINUX_SYMBOL(_sym_) _sym_
#endif
+/* Align . to a 8 byte boundary equals to maximum function alignment. */
+#define ALIGN_FUNCTION() . = ALIGN(8)
+
#define RODATA \
.rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \
*(.rodata) *(.rodata.*) \
@@ -79,12 +82,24 @@
VMLINUX_SYMBOL(__security_initcall_end) = .; \
}
+/* sched.text is aling to function alignment to secure we have same
+ * address even at second ld pass when generating System.map */
#define SCHED_TEXT \
+ ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__sched_text_start) = .; \
*(.sched.text) \
VMLINUX_SYMBOL(__sched_text_end) = .;
+/* spinlock.text is aling to function alignment to secure we have same
+ * address even at second ld pass when generating System.map */
#define LOCK_TEXT \
+ ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__lock_text_start) = .; \
*(.spinlock.text) \
VMLINUX_SYMBOL(__lock_text_end) = .;
+
+#define KPROBES_TEXT \
+ ALIGN_FUNCTION(); \
+ VMLINUX_SYMBOL(__kprobes_text_start) = .; \
+ *(.kprobes.text) \
+ VMLINUX_SYMBOL(__kprobes_text_end) = .;
diff --git a/include/asm-h8300/auxvec.h b/include/asm-h8300/auxvec.h
new file mode 100644
index 0000000..1d36fe38
--- /dev/null
+++ b/include/asm-h8300/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMH8300_AUXVEC_H
+#define __ASMH8300_AUXVEC_H
+
+#endif
diff --git a/include/asm-h8300/fcntl.h b/include/asm-h8300/fcntl.h
index 355350a..1952cb2e 100644
--- a/include/asm-h8300/fcntl.h
+++ b/include/asm-h8300/fcntl.h
@@ -1,87 +1,11 @@
#ifndef _H8300_FCNTL_H
#define _H8300_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0400000
-#define O_NOATIME 01000000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
+#include <asm-generic/fcntl.h>
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
#endif /* _H8300_FCNTL_H */
diff --git a/include/asm-h8300/futex.h b/include/asm-h8300/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-h8300/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-h8300/hdreg.h b/include/asm-h8300/hdreg.h
deleted file mode 100644
index 36d0c06..0000000
--- a/include/asm-h8300/hdreg.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * linux/include/asm-h8300/hdreg.h
- *
- * Copyright (C) 1994-1996 Linus Torvalds & authors
- */
-
-#warning this file is obsolete, please do not use it
-
-#ifndef _H8300_HDREG_H
-#define _H8300_HDREG_H
-
-typedef unsigned int q40ide_ioreg_t;
-typedef unsigned char * ide_ioreg_t;
-
-#endif /* _H8300_HDREG_H */
diff --git a/include/asm-h8300/page.h b/include/asm-h8300/page.h
index e3b7960..e8c02b8 100644
--- a/include/asm-h8300/page.h
+++ b/include/asm-h8300/page.h
@@ -54,20 +54,6 @@
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
extern unsigned long memory_start;
extern unsigned long memory_end;
@@ -101,4 +87,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _H8300_PAGE_H */
diff --git a/include/asm-h8300/types.h b/include/asm-h8300/types.h
index 21f4fc0..bf91e0d 100644
--- a/include/asm-h8300/types.h
+++ b/include/asm-h8300/types.h
@@ -58,8 +58,6 @@
#define HAVE_SECTOR_T
typedef u64 sector_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-h8300/uaccess.h b/include/asm-h8300/uaccess.h
index 1480f30..ebe58c6 100644
--- a/include/asm-h8300/uaccess.h
+++ b/include/asm-h8300/uaccess.h
@@ -24,12 +24,6 @@
return(RANGE_CHECK_OK(addr, size, 0L, (unsigned long)&_ramend));
}
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void *addr, unsigned long size)
-{
- return access_ok(type,addr,size)?0:-EFAULT;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-i386/agp.h b/include/asm-i386/agp.h
index b82f5f3..9075083 100644
--- a/include/asm-i386/agp.h
+++ b/include/asm-i386/agp.h
@@ -19,7 +19,7 @@
/* Could use CLFLUSH here if the cpu supports it. But then it would
need to be called for each cacheline of the whole page so it may not be
worth it. Would need a page for it. */
-#define flush_agp_cache() asm volatile("wbinvd":::"memory")
+#define flush_agp_cache() wbinvd()
/* Convert a physical address to an address suitable for the GART. */
#define phys_to_gart(x) (x)
diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
index a96a8f4..03185ce 100644
--- a/include/asm-i386/apicdef.h
+++ b/include/asm-i386/apicdef.h
@@ -16,6 +16,7 @@
#define GET_APIC_VERSION(x) ((x)&0xFF)
#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF)
#define APIC_INTEGRATED(x) ((x)&0xF0)
+#define APIC_XAPIC(x) ((x) >= 0x14)
#define APIC_TASKPRI 0x80
#define APIC_TPRI_MASK 0xFF
#define APIC_ARBPRI 0x90
diff --git a/include/asm-i386/auxvec.h b/include/asm-i386/auxvec.h
new file mode 100644
index 0000000..395e130
--- /dev/null
+++ b/include/asm-i386/auxvec.h
@@ -0,0 +1,11 @@
+#ifndef __ASMi386_AUXVEC_H
+#define __ASMi386_AUXVEC_H
+
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them, start the x86-specific ones at 32.
+ */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+#endif
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index 6789fc2..ea54540 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -118,7 +118,10 @@
printk("disabled\n");
return;
}
- __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
+ halt();
+ halt();
+ halt();
+ halt();
printk("OK.\n");
}
diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h
index 11e6781..6df1a53 100644
--- a/include/asm-i386/desc.h
+++ b/include/asm-i386/desc.h
@@ -27,8 +27,18 @@
extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
-#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
-#define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
+#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
+#define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8))
+
+#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
+#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
+#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr))
+#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt))
+
+#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr))
+#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr))
+#define store_tr(tr) __asm__ ("str %0":"=mr" (tr))
+#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt))
/*
* This is the ldt that every process will get unless we need
@@ -39,14 +49,14 @@
#define _set_tssldt_desc(n,addr,limit,type) \
__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
- "movw %%ax,2(%2)\n\t" \
- "rorl $16,%%eax\n\t" \
- "movb %%al,4(%2)\n\t" \
+ "movw %w1,2(%2)\n\t" \
+ "rorl $16,%1\n\t" \
+ "movb %b1,4(%2)\n\t" \
"movb %4,5(%2)\n\t" \
"movb $0,6(%2)\n\t" \
- "movb %%ah,7(%2)\n\t" \
- "rorl $16,%%eax" \
- : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
+ "movb %h1,7(%2)\n\t" \
+ "rorl $16,%1" \
+ : "=m"(*(n)) : "q" (addr), "r"(n), "ir"(limit), "i"(type))
static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
{
@@ -86,6 +96,13 @@
(info)->seg_not_present == 1 && \
(info)->useable == 0 )
+static inline void write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b)
+{
+ __u32 *lp = (__u32 *)((char *)ldt + entry*8);
+ *lp = entry_a;
+ *(lp+1) = entry_b;
+}
+
#if TLS_SIZE != 24
# error update this code.
#endif
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index 130bdc8..fa11117 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -9,6 +9,7 @@
#include <asm/user.h>
#include <asm/processor.h>
#include <asm/system.h> /* for savesegment */
+#include <asm/auxvec.h>
#include <linux/utsname.h>
@@ -109,13 +110,6 @@
#define ELF_PLATFORM (system_utsname.machine)
-/*
- * Architecture-neutral AT_ values in 0-17, leave some room
- * for more of them, start the x86-specific ones at 32.
- */
-#define AT_SYSINFO 32
-#define AT_SYSINFO_EHDR 33
-
#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) do { } while (0)
diff --git a/include/asm-i386/fcntl.h b/include/asm-i386/fcntl.h
index 511cde9..46ab12d 100644
--- a/include/asm-i386/fcntl.h
+++ b/include/asm-i386/fcntl.h
@@ -1,88 +1 @@
-#ifndef _I386_FCNTL_H
-#define _I386_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-
-#endif
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h
new file mode 100644
index 0000000..44b9db8
--- /dev/null
+++ b/include/asm-i386/futex.h
@@ -0,0 +1,108 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
+ __asm__ __volatile ( \
+"1: " insn "\n" \
+"2: .section .fixup,\"ax\"\n\
+3: mov %3, %1\n\
+ jmp 2b\n\
+ .previous\n\
+ .section __ex_table,\"a\"\n\
+ .align 8\n\
+ .long 1b,3b\n\
+ .previous" \
+ : "=r" (oldval), "=r" (ret), "=m" (*uaddr) \
+ : "i" (-EFAULT), "m" (*uaddr), "0" (oparg), "1" (0))
+
+#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
+ __asm__ __volatile ( \
+"1: movl %2, %0\n\
+ movl %0, %3\n" \
+ insn "\n" \
+"2: " LOCK_PREFIX "cmpxchgl %3, %2\n\
+ jnz 1b\n\
+3: .section .fixup,\"ax\"\n\
+4: mov %5, %1\n\
+ jmp 3b\n\
+ .previous\n\
+ .section __ex_table,\"a\"\n\
+ .align 8\n\
+ .long 1b,4b,2b,4b\n\
+ .previous" \
+ : "=&a" (oldval), "=&r" (ret), "=m" (*uaddr), \
+ "=&r" (tem) \
+ : "r" (oparg), "i" (-EFAULT), "m" (*uaddr), "1" (0))
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ if (op == FUTEX_OP_SET)
+ __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
+ else {
+#ifndef CONFIG_X86_BSWAP
+ if (boot_cpu_data.x86 == 3)
+ ret = -ENOSYS;
+ else
+#endif
+ switch (op) {
+ case FUTEX_OP_ADD:
+ __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret,
+ oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr,
+ oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op2("andl %4, %3", ret, oldval, uaddr,
+ ~oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr,
+ oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-i386/hdreg.h b/include/asm-i386/hdreg.h
deleted file mode 100644
index 5989bbc..0000000
--- a/include/asm-i386/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
index b3f8d5f..316138e 100644
--- a/include/asm-i386/kdebug.h
+++ b/include/asm-i386/kdebug.h
@@ -41,9 +41,16 @@
DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig)
+static inline int notify_die(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig)
{
- struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig };
+ struct die_args args = {
+ .regs = regs,
+ .str = str,
+ .err = err,
+ .trapnr = trap,
+ .signr = sig
+ };
return notifier_call_chain(&i386die_chain, val, &args);
}
diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-i386/mach-es7000/mach_mpparse.h
index 85809e0..28a84f6 100644
--- a/include/asm-i386/mach-es7000/mach_mpparse.h
+++ b/include/asm-i386/mach-es7000/mach_mpparse.h
@@ -1,6 +1,8 @@
#ifndef __ASM_MACH_MPPARSE_H
#define __ASM_MACH_MPPARSE_H
+#include <linux/acpi.h>
+
static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
struct mpc_config_translation *translation)
{
@@ -12,8 +14,9 @@
{
}
-extern int parse_unisys_oem (char *oemptr, int oem_entries);
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length);
+extern int parse_unisys_oem (char *oemptr);
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void setup_unisys();
static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
char *productid)
@@ -22,18 +25,33 @@
struct mp_config_oemtable *oem_table =
(struct mp_config_oemtable *)mpc->mpc_oemptr;
if (!strncmp(oem, "UNISYS", 6))
- return parse_unisys_oem((char *)oem_table, oem_table->oem_length);
+ return parse_unisys_oem((char *)oem_table);
}
return 0;
}
+static inline int es7000_check_dsdt()
+{
+ struct acpi_table_header *header = NULL;
+ if(!acpi_get_table_header_early(ACPI_DSDT, &header))
+ acpi_table_print(header, 0);
+ if (!strncmp(header->oem_id, "UNISYS", 6))
+ return 1;
+ return 0;
+}
+
/* Hook from generic ACPI tables.c */
static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
unsigned long oem_addr;
- int oem_entries;
- if (!find_unisys_acpi_oem_table(&oem_addr, &oem_entries))
- return parse_unisys_oem((char *)oem_addr, oem_entries);
+ if (!find_unisys_acpi_oem_table(&oem_addr)) {
+ if (es7000_check_dsdt())
+ return parse_unisys_oem((char *)oem_addr);
+ else {
+ setup_unisys();
+ return 1;
+ }
+ }
return 0;
}
diff --git a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h
index b13767a..d9dc039 100644
--- a/include/asm-i386/mach-generic/mach_apic.h
+++ b/include/asm-i386/mach-generic/mach_apic.h
@@ -28,4 +28,6 @@
#define enable_apic_mode (genapic->enable_apic_mode)
#define phys_pkg_id (genapic->phys_pkg_id)
+extern void generic_bigsmp_probe(void);
+
#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
index d9fafba..d84a9c3 100644
--- a/include/asm-i386/mpspec.h
+++ b/include/asm-i386/mpspec.h
@@ -11,6 +11,7 @@
extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
+extern unsigned int def_to_bigsmp;
extern unsigned int boot_cpu_physical_apicid;
extern int smp_found_config;
extern void find_smp_config (void);
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index c76fce8..62b76cd 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -47,6 +47,21 @@
: "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
ret__; })
+/* rdmsr with exception handling */
+#define rdmsr_safe(msr,a,b) ({ int ret__; \
+ asm volatile("2: rdmsr ; xorl %0,%0\n" \
+ "1:\n\t" \
+ ".section .fixup,\"ax\"\n\t" \
+ "3: movl %4,%0 ; jmp 1b\n\t" \
+ ".previous\n\t" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n\t" \
+ " .long 2b,3b\n\t" \
+ ".previous" \
+ : "=r" (ret__), "=a" (*(a)), "=d" (*(b)) \
+ : "c" (msr), "i" (-EFAULT));\
+ ret__; })
+
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 8d93f73..73296d9 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -68,7 +68,6 @@
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
-#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
#endif
#define pgd_val(x) ((x).pgd)
@@ -104,20 +103,6 @@
*/
extern unsigned int __VMALLOC_RESERVE;
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
extern int sysctl_legacy_va_layout;
extern int page_is_ram(unsigned long pagenr);
@@ -156,4 +141,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
index d609f9c..2e3f4a3 100644
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -64,7 +64,7 @@
#define set_pmd(pmdptr,pmdval) \
set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval))
#define set_pud(pudptr,pudval) \
- set_64bit((unsigned long long *)(pudptr),pud_val(pudval))
+ (*(pudptr) = (pudval))
/*
* Pentium-II erratum A13: in PAE mode we explicitly have to flush
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index 77c6497f..47bc1ff 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -86,9 +86,7 @@
#endif
/*
- * The 4MB page is guessing.. Detailed in the infamous "Chapter H"
- * of the Pentium details, but assuming intel did the straightforward
- * thing, this bit set in the page directory entry just means that
+ * _PAGE_PSE set in the page directory entry just means that
* the page directory entry points directly to a 4MB-aligned block of
* memory.
*/
@@ -119,8 +117,10 @@
#define _PAGE_UNUSED2 0x400
#define _PAGE_UNUSED3 0x800
-#define _PAGE_FILE 0x040 /* set:pagecache unset:swap */
-#define _PAGE_PROTNONE 0x080 /* If not present */
+/* If _PAGE_PRESENT is clear, we use these: */
+#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */
+#define _PAGE_PROTNONE 0x080 /* if the user mapped it with PROT_NONE;
+ pte_present gives true */
#ifdef CONFIG_X86_PAE
#define _PAGE_NX (1ULL<<_PAGE_BIT_NX)
#else
@@ -215,11 +215,13 @@
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
+#define __LARGE_PTE (_PAGE_PSE | _PAGE_PRESENT)
static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
+static inline int pte_huge(pte_t pte) { return ((pte).pte_low & __LARGE_PTE) == __LARGE_PTE; }
/*
* The following only works if pte_present() is not true.
@@ -236,7 +238,7 @@
static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
-static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PRESENT | _PAGE_PSE; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= __LARGE_PTE; return pte; }
#ifdef CONFIG_X86_PAE
# include <asm/pgtable-3level.h>
@@ -258,12 +260,39 @@
return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
}
+static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
+{
+ pte_t pte;
+ if (full) {
+ pte = *ptep;
+ *ptep = __pte(0);
+ } else {
+ pte = ptep_get_and_clear(mm, addr, ptep);
+ }
+ return pte;
+}
+
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
}
/*
+ * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
+ *
+ * dst - pointer to pgd range anwhere on a pgd page
+ * src - ""
+ * count - the number of pgds to copy.
+ *
+ * dst and src can be on the same page, but the range must not overlap,
+ * and must not cross a page boundary.
+ */
+static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
+{
+ memcpy(dst, src, count * sizeof(pgd_t));
+}
+
+/*
* Macro to mark a page protection value as "uncacheable". On processors which do not support
* it, this is a no-op.
*/
@@ -415,6 +444,7 @@
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
#include <asm-generic/pgtable.h>
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index d0d8b01..37bef8e 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -203,9 +203,7 @@
return edx;
}
-#define load_cr3(pgdir) \
- asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)))
-
+#define load_cr3(pgdir) write_cr3(__pa(pgdir))
/*
* Intel CPU features in CR4
@@ -232,22 +230,20 @@
static inline void set_in_cr4 (unsigned long mask)
{
+ unsigned cr4;
mmu_cr4_features |= mask;
- __asm__("movl %%cr4,%%eax\n\t"
- "orl %0,%%eax\n\t"
- "movl %%eax,%%cr4\n"
- : : "irg" (mask)
- :"ax");
+ cr4 = read_cr4();
+ cr4 |= mask;
+ write_cr4(cr4);
}
static inline void clear_in_cr4 (unsigned long mask)
{
+ unsigned cr4;
mmu_cr4_features &= ~mask;
- __asm__("movl %%cr4,%%eax\n\t"
- "andl %0,%%eax\n\t"
- "movl %%eax,%%cr4\n"
- : : "irg" (~mask)
- :"ax");
+ cr4 = read_cr4();
+ cr4 &= ~mask;
+ write_cr4(cr4);
}
/*
@@ -281,6 +277,11 @@
outb((data), 0x23); \
} while (0)
+static inline void serialize_cpu(void)
+{
+ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+}
+
static inline void __monitor(const void *eax, unsigned long ecx,
unsigned long edx)
{
@@ -454,6 +455,7 @@
unsigned int saved_fs, saved_gs;
/* IO permissions */
unsigned long *io_bitmap_ptr;
+ unsigned long iopl;
/* max allowed port in the bitmap, in bytes: */
unsigned long io_bitmap_max;
};
@@ -474,7 +476,6 @@
.esp0 = sizeof(init_stack) + (long)&init_stack, \
.ss0 = __KERNEL_DS, \
.ss1 = __KERNEL_CS, \
- .ldt = GDT_ENTRY_LDT, \
.io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \
.io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \
}
@@ -511,6 +512,21 @@
: /* no output */ \
:"r" (value))
+/*
+ * Set IOPL bits in EFLAGS from given mask
+ */
+static inline void set_iopl_mask(unsigned mask)
+{
+ unsigned int reg;
+ __asm__ __volatile__ ("pushfl;"
+ "popl %0;"
+ "andl %1, %0;"
+ "orl %2, %0;"
+ "pushl %0;"
+ "popfl"
+ : "=&r" (reg)
+ : "i" (~X86_EFLAGS_IOPL), "r" (mask));
+}
/* Forward declaration, a strange C thing */
struct task_struct;
diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h
index 0553287..7e0f294 100644
--- a/include/asm-i386/ptrace.h
+++ b/include/asm-i386/ptrace.h
@@ -61,6 +61,13 @@
struct task_struct;
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
+/*
+ * user_mode_vm(regs) determines whether a register set came from user mode.
+ * This is true if V8086 mode was enabled OR if the register set was from
+ * protected mode with RPL-3 CS value. This tricky test checks that with
+ * one comparison. Many places in the kernel can bypass this full check
+ * if they have already ruled out V8086 mode, so user_mode(regs) can be used.
+ */
static inline int user_mode(struct pt_regs *regs)
{
return (regs->xcs & 3) != 0;
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
index 7a32184..826a8ca 100644
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -44,7 +44,7 @@
#define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
#define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
#define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
-#define EFI_MEMMAP ((efi_memory_desc_t *) *((unsigned long *)(PARAM+0x1d0)))
+#define EFI_MEMMAP ((void *) *((unsigned long *)(PARAM+0x1d0)))
#define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4)))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index a283738..1325019 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -59,7 +59,7 @@
extern cpumask_t cpu_callout_map;
extern cpumask_t cpu_callin_map;
-#define cpu_possible_map cpu_callout_map
+extern cpumask_t cpu_possible_map;
/* We don't mark CPUs online until __cpu_up(), so we need another measure */
static inline int num_booting_cpus(void)
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 3db717a..acd5c26 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -14,8 +14,7 @@
#define switch_to(prev,next,last) do { \
unsigned long esi,edi; \
- asm volatile("pushfl\n\t" \
- "pushl %%ebp\n\t" \
+ asm volatile("pushl %%ebp\n\t" \
"movl %%esp,%0\n\t" /* save ESP */ \
"movl %5,%%esp\n\t" /* restore ESP */ \
"movl $1f,%1\n\t" /* save EIP */ \
@@ -23,7 +22,6 @@
"jmp __switch_to\n" \
"1:\t" \
"popl %%ebp\n\t" \
- "popfl" \
:"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
"=a" (last),"=S" (esi),"=D" (edi) \
:"m" (next->thread.esp),"m" (next->thread.eip), \
@@ -93,13 +91,13 @@
".align 4\n\t" \
".long 1b,3b\n" \
".previous" \
- : :"m" (value))
+ : :"rm" (value))
/*
* Save a segment register away
*/
#define savesegment(seg, value) \
- asm volatile("mov %%" #seg ",%0":"=m" (value))
+ asm volatile("mov %%" #seg ",%0":"=rm" (value))
/*
* Clear and set 'TS' bit respectively
@@ -107,13 +105,33 @@
#define clts() __asm__ __volatile__ ("clts")
#define read_cr0() ({ \
unsigned int __dummy; \
- __asm__( \
+ __asm__ __volatile__( \
"movl %%cr0,%0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})
#define write_cr0(x) \
- __asm__("movl %0,%%cr0": :"r" (x));
+ __asm__ __volatile__("movl %0,%%cr0": :"r" (x));
+
+#define read_cr2() ({ \
+ unsigned int __dummy; \
+ __asm__ __volatile__( \
+ "movl %%cr2,%0\n\t" \
+ :"=r" (__dummy)); \
+ __dummy; \
+})
+#define write_cr2(x) \
+ __asm__ __volatile__("movl %0,%%cr2": :"r" (x));
+
+#define read_cr3() ({ \
+ unsigned int __dummy; \
+ __asm__ ( \
+ "movl %%cr3,%0\n\t" \
+ :"=r" (__dummy)); \
+ __dummy; \
+})
+#define write_cr3(x) \
+ __asm__ __volatile__("movl %0,%%cr3": :"r" (x));
#define read_cr4() ({ \
unsigned int __dummy; \
@@ -123,7 +141,7 @@
__dummy; \
})
#define write_cr4(x) \
- __asm__("movl %0,%%cr4": :"r" (x));
+ __asm__ __volatile__("movl %0,%%cr4": :"r" (x));
#define stts() write_cr0(8 | read_cr0())
#endif /* __KERNEL__ */
@@ -447,6 +465,8 @@
#define local_irq_enable() __asm__ __volatile__("sti": : :"memory")
/* used in the idle loop; sti takes one instruction cycle to complete */
#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory")
+/* used when interrupts are already enabled or to shutdown the processor */
+#define halt() __asm__ __volatile__("hlt": : :"memory")
#define irqs_disabled() \
({ \
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 95add81..e2cb9fa 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -139,6 +139,7 @@
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
#define TIF_IRET 5 /* return with iret */
+#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
@@ -150,13 +151,15 @@
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_IRET (1<<TIF_IRET)
+#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
+ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
+ _TIF_SECCOMP|_TIF_SYSCALL_EMU))
/* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index dcf1e07..aed1643 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -1,6 +1,7 @@
#ifndef _ASMi386_TIMER_H
#define _ASMi386_TIMER_H
#include <linux/init.h>
+#include <linux/pm.h>
/**
* struct timer_ops - used to define a timer source
@@ -23,6 +24,8 @@
unsigned long long (*monotonic_clock)(void);
void (*delay)(unsigned long);
unsigned long (*read_timer)(void);
+ int (*suspend)(pm_message_t state);
+ int (*resume)(void);
};
struct init_timer_opts {
diff --git a/include/asm-i386/types.h b/include/asm-i386/types.h
index 901b77c..ced00fe 100644
--- a/include/asm-i386/types.h
+++ b/include/asm-i386/types.h
@@ -63,8 +63,6 @@
#define HAVE_SECTOR_T
#endif
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 886867a..89ab7e2 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -83,30 +83,6 @@
*/
#define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
-/**
- * verify_area: - Obsolete/deprecated and will go away soon,
- * use access_ok() instead.
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only. This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-i386/xor.h b/include/asm-i386/xor.h
index f80e2db..23c86ce 100644
--- a/include/asm-i386/xor.h
+++ b/include/asm-i386/xor.h
@@ -535,14 +535,14 @@
#define XMMS_SAVE do { \
preempt_disable(); \
+ cr0 = read_cr0(); \
+ clts(); \
__asm__ __volatile__ ( \
- "movl %%cr0,%0 ;\n\t" \
- "clts ;\n\t" \
- "movups %%xmm0,(%1) ;\n\t" \
- "movups %%xmm1,0x10(%1) ;\n\t" \
- "movups %%xmm2,0x20(%1) ;\n\t" \
- "movups %%xmm3,0x30(%1) ;\n\t" \
- : "=&r" (cr0) \
+ "movups %%xmm0,(%0) ;\n\t" \
+ "movups %%xmm1,0x10(%0) ;\n\t" \
+ "movups %%xmm2,0x20(%0) ;\n\t" \
+ "movups %%xmm3,0x30(%0) ;\n\t" \
+ : \
: "r" (xmm_save) \
: "memory"); \
} while(0)
@@ -550,14 +550,14 @@
#define XMMS_RESTORE do { \
__asm__ __volatile__ ( \
"sfence ;\n\t" \
- "movups (%1),%%xmm0 ;\n\t" \
- "movups 0x10(%1),%%xmm1 ;\n\t" \
- "movups 0x20(%1),%%xmm2 ;\n\t" \
- "movups 0x30(%1),%%xmm3 ;\n\t" \
- "movl %0,%%cr0 ;\n\t" \
+ "movups (%0),%%xmm0 ;\n\t" \
+ "movups 0x10(%0),%%xmm1 ;\n\t" \
+ "movups 0x20(%0),%%xmm2 ;\n\t" \
+ "movups 0x30(%0),%%xmm3 ;\n\t" \
: \
- : "r" (cr0), "r" (xmm_save) \
+ : "r" (xmm_save) \
: "memory"); \
+ write_cr0(cr0); \
preempt_enable(); \
} while(0)
diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
index 4c06d45..3a544ff 100644
--- a/include/asm-ia64/acpi.h
+++ b/include/asm-ia64/acpi.h
@@ -116,6 +116,11 @@
extern u16 ia64_acpiid_to_sapicid[];
+/*
+ * Refer Intel ACPI _PDC support document for bit definitions
+ */
+#define ACPI_PDC_EST_CAPABILITY_SMP 0x8
+
#endif /*__KERNEL__*/
#endif /*_ASM_ACPI_H*/
diff --git a/include/asm-ia64/auxvec.h b/include/asm-ia64/auxvec.h
new file mode 100644
index 0000000..23cebe5
--- /dev/null
+++ b/include/asm-ia64/auxvec.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_IA64_AUXVEC_H
+#define _ASM_IA64_AUXVEC_H
+
+/*
+ * Architecture-neutral AT_ values are in the range 0-17. Leave some room for more of
+ * them, start the architecture-specific ones at 32.
+ */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+#endif /* _ASM_IA64_AUXVEC_H */
diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h
index 0c05e5b..aaf11f4 100644
--- a/include/asm-ia64/compat.h
+++ b/include/asm-ia64/compat.h
@@ -13,10 +13,10 @@
typedef s32 compat_clock_t;
typedef s32 compat_key_t;
typedef s32 compat_pid_t;
-typedef u16 compat_uid_t;
-typedef u16 compat_gid_t;
-typedef u32 compat_uid32_t;
-typedef u32 compat_gid32_t;
+typedef u16 __compat_uid_t;
+typedef u16 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u16 compat_dev_t;
@@ -50,8 +50,8 @@
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid_t st_uid;
+ __compat_gid_t st_gid;
compat_dev_t st_rdev;
u16 __pad2;
u32 st_size;
@@ -120,10 +120,10 @@
struct compat_ipc64_perm {
compat_key_t key;
- compat_uid32_t uid;
- compat_gid32_t gid;
- compat_uid32_t cuid;
- compat_gid32_t cgid;
+ __compat_uid32_t uid;
+ __compat_gid32_t gid;
+ __compat_uid32_t cuid;
+ __compat_gid32_t cgid;
unsigned short mode;
unsigned short __pad1;
unsigned short seq;
diff --git a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h
index 7d4ccc4..446fce0 100644
--- a/include/asm-ia64/elf.h
+++ b/include/asm-ia64/elf.h
@@ -12,6 +12,7 @@
#include <asm/fpu.h>
#include <asm/page.h>
+#include <asm/auxvec.h>
/*
* This is used to ensure we don't load something for the wrong architecture.
@@ -177,13 +178,6 @@
relevant until we have real hardware to play with... */
#define ELF_PLATFORM NULL
-/*
- * Architecture-neutral AT_ values are in the range 0-17. Leave some room for more of
- * them, start the architecture-specific ones at 32.
- */
-#define AT_SYSINFO 32
-#define AT_SYSINFO_EHDR 33
-
#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX)
#define elf_read_implies_exec(ex, executable_stack) \
diff --git a/include/asm-ia64/fcntl.h b/include/asm-ia64/fcntl.h
index c9f8d83..1dd275d 100644
--- a/include/asm-ia64/fcntl.h
+++ b/include/asm-ia64/fcntl.h
@@ -1,86 +1,13 @@
#ifndef _ASM_IA64_FCNTL_H
#define _ASM_IA64_FCNTL_H
/*
- * Based on <asm-i386/fcntl.h>.
- *
* Modified 1998-2000
* David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co.
*/
-/*
- * open/fcntl - O_SYNC is only implemented on blocks devices and on
- * files located on an ext2 file system
- */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint - currently ignored */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
+#define force_o_largefile() \
+ (personality(current->personality) != PER_LINUX32)
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-
-#define force_o_largefile() ( ! (current->personality & PER_LINUX32) )
+#include <asm-generic/fcntl.h>
#endif /* _ASM_IA64_FCNTL_H */
diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-ia64/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-ia64/hdreg.h b/include/asm-ia64/hdreg.h
deleted file mode 100644
index 83b5161..0000000
--- a/include/asm-ia64/hdreg.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * linux/include/asm-ia64/hdreg.h
- *
- * Copyright (C) 1994-1996 Linus Torvalds & authors
- */
-
-#warning this file is obsolete, please do not use it
-
-#ifndef __ASM_IA64_HDREG_H
-#define __ASM_IA64_HDREG_H
-
-typedef unsigned short ide_ioreg_t;
-
-#endif /* __ASM_IA64_HDREG_H */
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index 041ab8c..0cf119b 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -116,13 +116,6 @@
* and to obtain the irq descriptor for a given irq number.
*/
-/* Return a pointer to the irq descriptor for IRQ. */
-static inline irq_desc_t *
-irq_descp (int irq)
-{
- return irq_desc + irq;
-}
-
/* Extract the IA-64 vector that corresponds to IRQ. */
static inline ia64_vector
irq_to_vector (int irq)
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 54e7637..cf772a6 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -23,7 +23,7 @@
#define __SLOW_DOWN_IO do { } while (0)
#define SLOW_DOWN_IO do { } while (0)
-#define __IA64_UNCACHED_OFFSET 0xc000000000000000UL /* region 6 */
+#define __IA64_UNCACHED_OFFSET RGN_BASE(RGN_UNCACHED)
/*
* The legacy I/O space defined by the ia64 architecture supports only 65536 ports, but
@@ -41,7 +41,7 @@
#define IO_SPACE_BASE(space) ((space) << IO_SPACE_BITS)
#define IO_SPACE_PORT(port) ((port) & (IO_SPACE_SIZE - 1))
-#define IO_SPACE_SPARSE_ENCODING(p) ((((p) >> 2) << 12) | (p & 0xfff))
+#define IO_SPACE_SPARSE_ENCODING(p) ((((p) >> 2) << 12) | ((p) & 0xfff))
struct io_space {
unsigned long mmio_base; /* base in MMIO space */
diff --git a/include/asm-ia64/irq.h b/include/asm-ia64/irq.h
index bd07d11..cd984d0 100644
--- a/include/asm-ia64/irq.h
+++ b/include/asm-ia64/irq.h
@@ -14,6 +14,11 @@
#define NR_IRQS 256
#define NR_IRQ_VECTORS NR_IRQS
+/*
+ * IRQ line status macro IRQ_PER_CPU is used
+ */
+#define ARCH_HAS_IRQ_PER_CPU
+
static __inline__ int
irq_canonicalize (int irq)
{
@@ -30,12 +35,6 @@
extern void enable_irq (unsigned int);
extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
-#ifdef CONFIG_SMP
-extern void move_irq(int irq);
-#else
-#define move_irq(irq)
-#endif
-
struct irqaction;
struct pt_regs;
int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index bf36a32..573a357 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -92,6 +92,7 @@
kprobe_opcode_t insn;
#define INST_FLAG_FIX_RELATIVE_IP_ADDR 1
#define INST_FLAG_FIX_BRANCH_REG 2
+ #define INST_FLAG_BREAK_INST 4
unsigned long inst_flag;
unsigned short target_br_reg;
};
diff --git a/include/asm-ia64/mmu.h b/include/asm-ia64/mmu.h
index ae15253..611432b 100644
--- a/include/asm-ia64/mmu.h
+++ b/include/asm-ia64/mmu.h
@@ -2,10 +2,12 @@
#define __MMU_H
/*
- * Type for a context number. We declare it volatile to ensure proper ordering when it's
- * accessed outside of spinlock'd critical sections (e.g., as done in activate_mm() and
- * init_new_context()).
+ * Type for a context number. We declare it volatile to ensure proper
+ * ordering when it's accessed outside of spinlock'd critical sections
+ * (e.g., as done in activate_mm() and init_new_context()).
*/
typedef volatile unsigned long mm_context_t;
+typedef unsigned long nv_mm_context_t;
+
#endif
diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
index e3e5fed..8d6e72f 100644
--- a/include/asm-ia64/mmu_context.h
+++ b/include/asm-ia64/mmu_context.h
@@ -19,6 +19,7 @@
#define ia64_rid(ctx,addr) (((ctx) << 3) | (addr >> 61))
+# include <asm/page.h>
# ifndef __ASSEMBLY__
#include <linux/compiler.h>
@@ -55,34 +56,46 @@
delayed_tlb_flush (void)
{
extern void local_flush_tlb_all (void);
+ unsigned long flags;
if (unlikely(__ia64_per_cpu_var(ia64_need_tlb_flush))) {
- local_flush_tlb_all();
- __ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
+ spin_lock_irqsave(&ia64_ctx.lock, flags);
+ {
+ if (__ia64_per_cpu_var(ia64_need_tlb_flush)) {
+ local_flush_tlb_all();
+ __ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
+ }
+ }
+ spin_unlock_irqrestore(&ia64_ctx.lock, flags);
}
}
-static inline mm_context_t
+static inline nv_mm_context_t
get_mmu_context (struct mm_struct *mm)
{
unsigned long flags;
- mm_context_t context = mm->context;
+ nv_mm_context_t context = mm->context;
- if (context)
- return context;
-
- spin_lock_irqsave(&ia64_ctx.lock, flags);
- {
- /* re-check, now that we've got the lock: */
- context = mm->context;
- if (context == 0) {
- cpus_clear(mm->cpu_vm_mask);
- if (ia64_ctx.next >= ia64_ctx.limit)
- wrap_mmu_context(mm);
- mm->context = context = ia64_ctx.next++;
+ if (unlikely(!context)) {
+ spin_lock_irqsave(&ia64_ctx.lock, flags);
+ {
+ /* re-check, now that we've got the lock: */
+ context = mm->context;
+ if (context == 0) {
+ cpus_clear(mm->cpu_vm_mask);
+ if (ia64_ctx.next >= ia64_ctx.limit)
+ wrap_mmu_context(mm);
+ mm->context = context = ia64_ctx.next++;
+ }
}
+ spin_unlock_irqrestore(&ia64_ctx.lock, flags);
}
- spin_unlock_irqrestore(&ia64_ctx.lock, flags);
+ /*
+ * Ensure we're not starting to use "context" before any old
+ * uses of it are gone from our TLB.
+ */
+ delayed_tlb_flush();
+
return context;
}
@@ -104,13 +117,13 @@
}
static inline void
-reload_context (mm_context_t context)
+reload_context (nv_mm_context_t context)
{
unsigned long rid;
unsigned long rid_incr = 0;
unsigned long rr0, rr1, rr2, rr3, rr4, old_rr4;
- old_rr4 = ia64_get_rr(0x8000000000000000UL);
+ old_rr4 = ia64_get_rr(RGN_BASE(RGN_HPAGE));
rid = context << 3; /* make space for encoding the region number */
rid_incr = 1 << 8;
@@ -122,6 +135,10 @@
rr4 = rr0 + 4*rid_incr;
#ifdef CONFIG_HUGETLB_PAGE
rr4 = (rr4 & (~(0xfcUL))) | (old_rr4 & 0xfc);
+
+# if RGN_HPAGE != 4
+# error "reload_context assumes RGN_HPAGE is 4"
+# endif
#endif
ia64_set_rr(0x0000000000000000UL, rr0);
@@ -138,7 +155,7 @@
static inline void
activate_context (struct mm_struct *mm)
{
- mm_context_t context;
+ nv_mm_context_t context;
do {
context = get_mmu_context(mm);
@@ -157,8 +174,6 @@
static inline void
activate_mm (struct mm_struct *prev, struct mm_struct *next)
{
- delayed_tlb_flush();
-
/*
* We may get interrupts here, but that's OK because interrupt handlers cannot
* touch user-space.
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 08894f7..9edffad 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -13,6 +13,19 @@
#include <asm/types.h>
/*
+ * The top three bits of an IA64 address are its Region Number.
+ * Different regions are assigned to different purposes.
+ */
+#define RGN_SHIFT (61)
+#define RGN_BASE(r) (__IA64_UL_CONST(r)<<RGN_SHIFT)
+#define RGN_BITS (RGN_BASE(-1))
+
+#define RGN_KERNEL 7 /* Identity mapped region */
+#define RGN_UNCACHED 6 /* Identity mapped I/O region */
+#define RGN_GATE 5 /* Gate page, Kernel text, etc */
+#define RGN_HPAGE 4 /* For Huge TLB pages */
+
+/*
* PAGE_SHIFT determines the actual kernel page size.
*/
#if defined(CONFIG_IA64_PAGE_SIZE_4KB)
@@ -36,10 +49,9 @@
#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */
+
#ifdef CONFIG_HUGETLB_PAGE
-# define REGION_HPAGE (4UL) /* note: this is hardcoded in reload_context()!*/
-# define REGION_SHIFT 61
-# define HPAGE_REGION_BASE (REGION_HPAGE << REGION_SHIFT)
+# define HPAGE_REGION_BASE RGN_BASE(RGN_HPAGE)
# define HPAGE_SHIFT hpage_shift
# define HPAGE_SHIFT_DEFAULT 28 /* check ia64 SDM for architecture supported size */
# define HPAGE_SIZE (__IA64_UL_CONST(1) << HPAGE_SHIFT)
@@ -130,16 +142,13 @@
#define REGION_NUMBER(x) ({ia64_va _v; _v.l = (long) (x); _v.f.reg;})
#define REGION_OFFSET(x) ({ia64_va _v; _v.l = (long) (x); _v.f.off;})
-#define REGION_SIZE REGION_NUMBER(1)
-#define REGION_KERNEL 7
-
#ifdef CONFIG_HUGETLB_PAGE
# define htlbpage_to_page(x) (((unsigned long) REGION_NUMBER(x) << 61) \
| (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT)))
# define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
# define is_hugepage_only_range(mm, addr, len) \
- (REGION_NUMBER(addr) == REGION_HPAGE && \
- REGION_NUMBER((addr)+(len)-1) == REGION_HPAGE)
+ (REGION_NUMBER(addr) == RGN_HPAGE && \
+ REGION_NUMBER((addr)+(len)-1) == RGN_HPAGE)
extern unsigned int hpage_shift;
#endif
@@ -197,7 +206,7 @@
# define __pgprot(x) (x)
#endif /* !STRICT_MM_TYPECHECKS */
-#define PAGE_OFFSET __IA64_UL_CONST(0xe000000000000000)
+#define PAGE_OFFSET RGN_BASE(RGN_KERNEL)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | \
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 2303a10..e828377 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -75,6 +75,8 @@
#define PAL_CACHE_READ 259 /* read tag & data of cacheline for diagnostic testing */
#define PAL_CACHE_WRITE 260 /* write tag & data of cacheline for diagnostic testing */
#define PAL_VM_TR_READ 261 /* read contents of translation register */
+#define PAL_GET_PSTATE 262 /* get the current P-state */
+#define PAL_SET_PSTATE 263 /* set the P-state */
#ifndef __ASSEMBLY__
@@ -1111,6 +1113,25 @@
return iprv.status;
}
+/* Get the current P-state information */
+static inline s64
+ia64_pal_get_pstate (u64 *pstate_index)
+{
+ struct ia64_pal_retval iprv;
+ PAL_CALL_STK(iprv, PAL_GET_PSTATE, 0, 0, 0);
+ *pstate_index = iprv.v0;
+ return iprv.status;
+}
+
+/* Set the P-state */
+static inline s64
+ia64_pal_set_pstate (u64 pstate_index)
+{
+ struct ia64_pal_retval iprv;
+ PAL_CALL_STK(iprv, PAL_SET_PSTATE, pstate_index, 0, 0);
+ return iprv.status;
+}
+
/* Cause the processor to enter LIGHT HALT state, where prefetching and execution are
* suspended, but cache and TLB coherency is maintained.
*/
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 48586e0..2e34c06 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -204,21 +204,18 @@
#define set_pte(ptep, pteval) (*(ptep) = (pteval))
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-#define RGN_SIZE (1UL << 61)
-#define RGN_KERNEL 7
-
-#define VMALLOC_START 0xa000000200000000UL
+#define VMALLOC_START (RGN_BASE(RGN_GATE) + 0x200000000UL)
#ifdef CONFIG_VIRTUAL_MEM_MAP
-# define VMALLOC_END_INIT (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9)))
+# define VMALLOC_END_INIT (RGN_BASE(RGN_GATE) + (1UL << (4*PAGE_SHIFT - 9)))
# define VMALLOC_END vmalloc_end
extern unsigned long vmalloc_end;
#else
-# define VMALLOC_END (0xa000000000000000UL + (1UL << (4*PAGE_SHIFT - 9)))
+# define VMALLOC_END (RGN_BASE(RGN_GATE) + (1UL << (4*PAGE_SHIFT - 9)))
#endif
/* fs/proc/kcore.c */
-#define kc_vaddr_to_offset(v) ((v) - 0xa000000000000000UL)
-#define kc_offset_to_vaddr(o) ((o) + 0xa000000000000000UL)
+#define kc_vaddr_to_offset(v) ((v) - RGN_BASE(RGN_GATE))
+#define kc_offset_to_vaddr(o) ((o) + RGN_BASE(RGN_GATE))
/*
* Conversion functions: convert page frame number (pfn) and a protection value to a page
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 91bbd1f..94e07e7 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -20,9 +20,6 @@
#include <asm/ptrace.h>
#include <asm/ustack.h>
-/* Our arch specific arch_init_sched_domain is in arch/ia64/kernel/domain.c */
-#define ARCH_HAS_SCHED_DOMAIN
-
#define IA64_NUM_DBG_REGS 8
/*
* Limits for PMC and PMD are set to less than maximum architected values
diff --git a/include/asm-ia64/rwsem.h b/include/asm-ia64/rwsem.h
index 6ece506..e18b5ab 100644
--- a/include/asm-ia64/rwsem.h
+++ b/include/asm-ia64/rwsem.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2003 Ken Chen <kenneth.w.chen@intel.com>
* Copyright (C) 2003 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 2005 Christoph Lameter <clameter@sgi.com>
*
* Based on asm-i386/rwsem.h and other architecture implementation.
*
@@ -11,9 +12,9 @@
*
* The lock count is initialized to 0 (no active and no waiting lockers).
*
- * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case
- * of an uncontended lock. Readers increment by 1 and see a positive value
- * when uncontended, negative if there are writers (and maybe) readers
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffffffff00000001 for
+ * the case of an uncontended lock. Readers increment by 1 and see a positive
+ * value when uncontended, negative if there are writers (and maybe) readers
* waiting (in which case it goes to sleep).
*/
@@ -29,7 +30,7 @@
* the semaphore definition
*/
struct rw_semaphore {
- signed int count;
+ signed long count;
spinlock_t wait_lock;
struct list_head wait_list;
#if RWSEM_DEBUG
@@ -37,10 +38,10 @@
#endif
};
-#define RWSEM_UNLOCKED_VALUE 0x00000000
-#define RWSEM_ACTIVE_BIAS 0x00000001
-#define RWSEM_ACTIVE_MASK 0x0000ffff
-#define RWSEM_WAITING_BIAS (-0x00010000)
+#define RWSEM_UNLOCKED_VALUE __IA64_UL_CONST(0x0000000000000000)
+#define RWSEM_ACTIVE_BIAS __IA64_UL_CONST(0x0000000000000001)
+#define RWSEM_ACTIVE_MASK __IA64_UL_CONST(0x00000000ffffffff)
+#define RWSEM_WAITING_BIAS -__IA64_UL_CONST(0x0000000100000000)
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
@@ -83,7 +84,7 @@
static inline void
__down_read (struct rw_semaphore *sem)
{
- int result = ia64_fetchadd4_acq((unsigned int *)&sem->count, 1);
+ long result = ia64_fetchadd8_acq((unsigned long *)&sem->count, 1);
if (result < 0)
rwsem_down_read_failed(sem);
@@ -95,7 +96,7 @@
static inline void
__down_write (struct rw_semaphore *sem)
{
- int old, new;
+ long old, new;
do {
old = sem->count;
@@ -112,7 +113,7 @@
static inline void
__up_read (struct rw_semaphore *sem)
{
- int result = ia64_fetchadd4_rel((unsigned int *)&sem->count, -1);
+ long result = ia64_fetchadd8_rel((unsigned long *)&sem->count, -1);
if (result < 0 && (--result & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -124,7 +125,7 @@
static inline void
__up_write (struct rw_semaphore *sem)
{
- int old, new;
+ long old, new;
do {
old = sem->count;
@@ -141,7 +142,7 @@
static inline int
__down_read_trylock (struct rw_semaphore *sem)
{
- int tmp;
+ long tmp;
while ((tmp = sem->count) >= 0) {
if (tmp == cmpxchg_acq(&sem->count, tmp, tmp+1)) {
return 1;
@@ -156,7 +157,7 @@
static inline int
__down_write_trylock (struct rw_semaphore *sem)
{
- int tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE,
+ long tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE,
RWSEM_ACTIVE_WRITE_BIAS);
return tmp == RWSEM_UNLOCKED_VALUE;
}
@@ -167,7 +168,7 @@
static inline void
__downgrade_write (struct rw_semaphore *sem)
{
- int old, new;
+ long old, new;
do {
old = sem->count;
@@ -182,7 +183,7 @@
* Implement atomic add functionality. These used to be "inline" functions, but GCC v3.1
* doesn't quite optimize this stuff right and ends up with bad calls to fetchandadd.
*/
-#define rwsem_atomic_add(delta, sem) atomic_add(delta, (atomic_t *)(&(sem)->count))
-#define rwsem_atomic_update(delta, sem) atomic_add_return(delta, (atomic_t *)(&(sem)->count))
+#define rwsem_atomic_add(delta, sem) atomic64_add(delta, (atomic64_t *)(&(sem)->count))
+#define rwsem_atomic_update(delta, sem) atomic64_add_return(delta, (atomic64_t *)(&(sem)->count))
#endif /* _ASM_IA64_RWSEM_H */
diff --git a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h
index 103d745..2c32e4b 100644
--- a/include/asm-ia64/sn/addrs.h
+++ b/include/asm-ia64/sn/addrs.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (c) 1992-1999,2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 1992-1999,2001-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_ADDRS_H
@@ -65,7 +65,6 @@
#define NASID_MASK ((u64)NASID_BITMASK << NASID_SHIFT)
#define AS_MASK ((u64)AS_BITMASK << AS_SHIFT)
-#define REGION_BITS 0xe000000000000000UL
/*
@@ -79,38 +78,30 @@
#define AS_CAC_SPACE (AS_CAC_VAL << AS_SHIFT)
-/*
- * Base addresses for various address ranges.
- */
-#define CACHED 0xe000000000000000UL
-#define UNCACHED 0xc000000000000000UL
-#define UNCACHED_PHYS 0x8000000000000000UL
-
-
/*
* Virtual Mode Local & Global MMR space.
*/
#define SH1_LOCAL_MMR_OFFSET 0x8000000000UL
#define SH2_LOCAL_MMR_OFFSET 0x0200000000UL
#define LOCAL_MMR_OFFSET (is_shub2() ? SH2_LOCAL_MMR_OFFSET : SH1_LOCAL_MMR_OFFSET)
-#define LOCAL_MMR_SPACE (UNCACHED | LOCAL_MMR_OFFSET)
-#define LOCAL_PHYS_MMR_SPACE (UNCACHED_PHYS | LOCAL_MMR_OFFSET)
+#define LOCAL_MMR_SPACE (__IA64_UNCACHED_OFFSET | LOCAL_MMR_OFFSET)
+#define LOCAL_PHYS_MMR_SPACE (RGN_BASE(RGN_HPAGE) | LOCAL_MMR_OFFSET)
#define SH1_GLOBAL_MMR_OFFSET 0x0800000000UL
#define SH2_GLOBAL_MMR_OFFSET 0x0300000000UL
#define GLOBAL_MMR_OFFSET (is_shub2() ? SH2_GLOBAL_MMR_OFFSET : SH1_GLOBAL_MMR_OFFSET)
-#define GLOBAL_MMR_SPACE (UNCACHED | GLOBAL_MMR_OFFSET)
+#define GLOBAL_MMR_SPACE (__IA64_UNCACHED_OFFSET | GLOBAL_MMR_OFFSET)
/*
* Physical mode addresses
*/
-#define GLOBAL_PHYS_MMR_SPACE (UNCACHED_PHYS | GLOBAL_MMR_OFFSET)
+#define GLOBAL_PHYS_MMR_SPACE (RGN_BASE(RGN_HPAGE) | GLOBAL_MMR_OFFSET)
/*
* Clear region & AS bits.
*/
-#define TO_PHYS_MASK (~(REGION_BITS | AS_MASK))
+#define TO_PHYS_MASK (~(RGN_BITS | AS_MASK))
/*
@@ -126,6 +117,7 @@
#define GLOBAL_MMR_PHYS_ADDR(n,a) (GLOBAL_PHYS_MMR_SPACE | REMOTE_ADDR(n,a))
#define GLOBAL_CAC_ADDR(n,a) (CAC_BASE | REMOTE_ADDR(n,a))
#define CHANGE_NASID(n,x) ((void *)(((u64)(x) & ~NASID_MASK) | NASID_SPACE(n)))
+#define IS_TIO_NASID(n) ((n) & 1)
/* non-II mmr's start at top of big window space (4G) */
@@ -134,10 +126,10 @@
/*
* general address defines
*/
-#define CAC_BASE (CACHED | AS_CAC_SPACE)
-#define AMO_BASE (UNCACHED | AS_AMO_SPACE)
-#define AMO_PHYS_BASE (UNCACHED_PHYS | AS_AMO_SPACE)
-#define GET_BASE (CACHED | AS_GET_SPACE)
+#define CAC_BASE (PAGE_OFFSET | AS_CAC_SPACE)
+#define AMO_BASE (__IA64_UNCACHED_OFFSET | AS_AMO_SPACE)
+#define AMO_PHYS_BASE (RGN_BASE(RGN_HPAGE) | AS_AMO_SPACE)
+#define GET_BASE (PAGE_OFFSET | AS_GET_SPACE)
/*
* Convert Memory addresses between various addressing modes.
@@ -155,17 +147,35 @@
* the chiplet id is zero. If we implement TIO-TIO dma, we might need
* to insert a chiplet id into this macro. However, it is our belief
* right now that this chiplet id will be ICE, which is also zero.
- * Nasid starts on bit 40.
*/
-#define PHYS_TO_TIODMA(x) ( (((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x))
-#define PHYS_TO_DMA(x) ( (((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x))
+#define SH1_TIO_PHYS_TO_DMA(x) \
+ ((((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x))
+
+#define SH2_NETWORK_BANK_OFFSET(x) \
+ ((u64)(x) & ((1UL << (sn_hub_info->nasid_shift - 4)) -1))
+
+#define SH2_NETWORK_BANK_SELECT(x) \
+ ((((u64)(x) & (0x3UL << (sn_hub_info->nasid_shift - 4))) \
+ >> (sn_hub_info->nasid_shift - 4)) << 36)
+
+#define SH2_NETWORK_ADDRESS(x) \
+ (SH2_NETWORK_BANK_OFFSET(x) | SH2_NETWORK_BANK_SELECT(x))
+
+#define SH2_TIO_PHYS_TO_DMA(x) \
+ (((u64)(NASID_GET(x)) << 40) | SH2_NETWORK_ADDRESS(x))
+
+#define PHYS_TO_TIODMA(x) \
+ (is_shub1() ? SH1_TIO_PHYS_TO_DMA(x) : SH2_TIO_PHYS_TO_DMA(x))
+
+#define PHYS_TO_DMA(x) \
+ ((((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x))
/*
* Macros to test for address type.
*/
-#define IS_AMO_ADDRESS(x) (((u64)(x) & (REGION_BITS | AS_MASK)) == AMO_BASE)
-#define IS_AMO_PHYS_ADDRESS(x) (((u64)(x) & (REGION_BITS | AS_MASK)) == AMO_PHYS_BASE)
+#define IS_AMO_ADDRESS(x) (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_BASE)
+#define IS_AMO_PHYS_ADDRESS(x) (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_PHYS_BASE)
/*
@@ -180,18 +190,20 @@
#define TIO_SWIN_BASE(n, w) (TIO_IO_BASE(n) + \
((u64) (w) << TIO_SWIN_SIZE_BITS))
#define NODE_IO_BASE(n) (GLOBAL_MMR_SPACE | NASID_SPACE(n))
-#define TIO_IO_BASE(n) (UNCACHED | NASID_SPACE(n))
+#define TIO_IO_BASE(n) (__IA64_UNCACHED_OFFSET | NASID_SPACE(n))
#define BWIN_SIZE (1UL << BWIN_SIZE_BITS)
#define NODE_BWIN_BASE0(n) (NODE_IO_BASE(n) + BWIN_SIZE)
#define NODE_BWIN_BASE(n, w) (NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS))
#define RAW_NODE_SWIN_BASE(n, w) (NODE_IO_BASE(n) + ((u64) (w) << SWIN_SIZE_BITS))
#define BWIN_WIDGET_MASK 0x7
#define BWIN_WINDOWNUM(x) (((x) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK)
+#define SH1_IS_BIG_WINDOW_ADDR(x) ((x) & BWIN_TOP)
#define TIO_BWIN_WINDOW_SELECT_MASK 0x7
#define TIO_BWIN_WINDOWNUM(x) (((x) >> TIO_BWIN_SIZE_BITS) & TIO_BWIN_WINDOW_SELECT_MASK)
-
+#define TIO_HWIN_SHIFT_BITS 33
+#define TIO_HWIN(x) (NODE_OFFSET(x) >> TIO_HWIN_SHIFT_BITS)
/*
* The following definitions pertain to the IO special address
@@ -216,10 +228,6 @@
#define TIO_SWIN_WIDGETNUM(x) (((x) >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK)
-#define TIO_IOSPACE_ADDR(n,x) \
- /* Move in the Chiplet ID for TIO Local Block MMR */ \
- (REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2))
-
/*
* The following macros produce the correct base virtual address for
* the hub registers. The REMOTE_HUB_* macro produce
@@ -234,18 +242,40 @@
* Otherwise, the recommended approach is to use *_HUB_L() and *_HUB_S().
* They're always safe.
*/
+/* Shub1 TIO & MMR addressing macros */
+#define SH1_TIO_IOSPACE_ADDR(n,x) \
+ GLOBAL_MMR_ADDR(n,x)
+
+#define SH1_REMOTE_BWIN_MMR(n,x) \
+ GLOBAL_MMR_ADDR(n,x)
+
+#define SH1_REMOTE_SWIN_MMR(n,x) \
+ (NODE_SWIN_BASE(n,1) + 0x800000UL + (x))
+
+#define SH1_REMOTE_MMR(n,x) \
+ (SH1_IS_BIG_WINDOW_ADDR(x) ? SH1_REMOTE_BWIN_MMR(n,x) : \
+ SH1_REMOTE_SWIN_MMR(n,x))
+
+/* Shub1 TIO & MMR addressing macros */
+#define SH2_TIO_IOSPACE_ADDR(n,x) \
+ ((__IA64_UNCACHED_OFFSET | REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2)))
+
+#define SH2_REMOTE_MMR(n,x) \
+ GLOBAL_MMR_ADDR(n,x)
+
+
+/* TIO & MMR addressing macros that work on both shub1 & shub2 */
+#define TIO_IOSPACE_ADDR(n,x) \
+ ((u64 *)(is_shub1() ? SH1_TIO_IOSPACE_ADDR(n,x) : \
+ SH2_TIO_IOSPACE_ADDR(n,x)))
+
+#define SH_REMOTE_MMR(n,x) \
+ (is_shub1() ? SH1_REMOTE_MMR(n,x) : SH2_REMOTE_MMR(n,x))
+
#define REMOTE_HUB_ADDR(n,x) \
- ((n & 1) ? \
- /* TIO: */ \
- (is_shub2() ? \
- /* TIO on Shub2 */ \
- (volatile u64 *)(TIO_IOSPACE_ADDR(n,x)) \
- : /* TIO on shub1 */ \
- (volatile u64 *)(GLOBAL_MMR_ADDR(n,x))) \
- \
- : /* SHUB1 and SHUB2 MMRs: */ \
- (((x) & BWIN_TOP) ? ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x))) \
- : ((volatile u64 *)(NODE_SWIN_BASE(n,1) + 0x800000 + (x)))))
+ (IS_TIO_NASID(n) ? ((volatile u64*)TIO_IOSPACE_ADDR(n,x)) : \
+ ((volatile u64*)SH_REMOTE_MMR(n,x)))
+
#define HUB_L(x) (*((volatile typeof(*x) *)x))
#define HUB_S(x,d) (*((volatile typeof(*x) *)x) = (d))
diff --git a/include/asm-ia64/sn/geo.h b/include/asm-ia64/sn/geo.h
index 84b2546..f083c94 100644
--- a/include/asm-ia64/sn/geo.h
+++ b/include/asm-ia64/sn/geo.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_GEO_H
@@ -108,7 +108,6 @@
#define INVALID_SLAB (slabid_t)-1
#define INVALID_SLOT (slotid_t)-1
#define INVALID_MODULE ((moduleid_t)-1)
-#define INVALID_PARTID ((partid_t)-1)
static inline slabid_t geo_slab(geoid_t g)
{
diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h
index e190dd4..e35074f 100644
--- a/include/asm-ia64/sn/intr.h
+++ b/include/asm-ia64/sn/intr.h
@@ -12,13 +12,12 @@
#include <linux/rcupdate.h>
#define SGI_UART_VECTOR (0xe9)
-#define SGI_PCIBR_ERROR (0x33)
/* Reserved IRQs : Note, not to exceed IA64_SN2_FIRST_DEVICE_VECTOR */
#define SGI_XPC_ACTIVATE (0x30)
#define SGI_II_ERROR (0x31)
#define SGI_XBOW_ERROR (0x32)
-#define SGI_PCIBR_ERROR (0x33)
+#define SGI_PCIASIC_ERROR (0x33)
#define SGI_ACPI_SCI_INT (0x34)
#define SGI_TIOCA_ERROR (0x35)
#define SGI_TIO_ERROR (0x36)
diff --git a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h
index 7138b1e..47bb810 100644
--- a/include/asm-ia64/sn/nodepda.h
+++ b/include/asm-ia64/sn/nodepda.h
@@ -37,7 +37,6 @@
struct nodepda_s {
void *pdinfo; /* Platform-dependent per-node info */
- spinlock_t bist_lock;
/*
* The BTEs on this node are shared by the local cpus
@@ -55,6 +54,8 @@
* Array of physical cpu identifiers. Indexed by cpuid.
*/
struct phys_cpuid phys_cpuid[NR_CPUS];
+ spinlock_t ptc_lock ____cacheline_aligned_in_smp;
+ spinlock_t bist_lock;
};
typedef struct nodepda_s nodepda_t;
diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h
index 976f5ef..ad0e8e8 100644
--- a/include/asm-ia64/sn/pcibus_provider_defs.h
+++ b/include/asm-ia64/sn/pcibus_provider_defs.h
@@ -18,8 +18,9 @@
#define PCIIO_ASIC_TYPE_PIC 2
#define PCIIO_ASIC_TYPE_TIOCP 3
#define PCIIO_ASIC_TYPE_TIOCA 4
+#define PCIIO_ASIC_TYPE_TIOCE 5
-#define PCIIO_ASIC_MAX_TYPES 5
+#define PCIIO_ASIC_MAX_TYPES 6
/*
* Common pciio bus provider data. There should be one of these as the
@@ -30,7 +31,8 @@
struct pcibus_bussoft {
uint32_t bs_asic_type; /* chipset type */
uint32_t bs_xid; /* xwidget id */
- uint64_t bs_persist_busnum; /* Persistent Bus Number */
+ uint32_t bs_persist_busnum; /* Persistent Bus Number */
+ uint32_t bs_persist_segment; /* Segment Number */
uint64_t bs_legacy_io; /* legacy io pio addr */
uint64_t bs_legacy_mem; /* legacy mem pio addr */
uint64_t bs_base; /* widget base */
@@ -47,6 +49,8 @@
dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
void (*dma_unmap)(struct pci_dev *, dma_addr_t, int);
void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
+ void (*force_interrupt)(struct sn_irq_info *);
+ void (*target_interrupt)(struct sn_irq_info *);
};
extern struct sn_pcibus_provider *sn_pci_provider[];
diff --git a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h
index ea5590c..1c5108d 100644
--- a/include/asm-ia64/sn/pda.h
+++ b/include/asm-ia64/sn/pda.h
@@ -39,7 +39,6 @@
unsigned long pio_write_status_val;
volatile unsigned long *pio_shub_war_cam_addr;
- unsigned long sn_soft_irr[4];
unsigned long sn_in_service_ivecs[4];
int sn_lb_int_war_ticks;
int sn_last_irq;
diff --git a/include/asm-ia64/sn/sn2/sn_hwperf.h b/include/asm-ia64/sn/sn2/sn_hwperf.h
index df75f4c..291ef3d 100644
--- a/include/asm-ia64/sn/sn2/sn_hwperf.h
+++ b/include/asm-ia64/sn/sn2/sn_hwperf.h
@@ -43,6 +43,7 @@
/* macros for object classification */
#define SN_HWPERF_IS_NODE(x) ((x) && strstr((x)->name, "SHub"))
+#define SN_HWPERF_IS_NODE_SHUB2(x) ((x) && strstr((x)->name, "SHub 2."))
#define SN_HWPERF_IS_IONODE(x) ((x) && strstr((x)->name, "TIO"))
#define SN_HWPERF_IS_ROUTER(x) ((x) && strstr((x)->name, "Router"))
#define SN_HWPERF_IS_NL3ROUTER(x) ((x) && strstr((x)->name, "NL3Router"))
@@ -214,6 +215,15 @@
*/
#define SN_HWPERF_GET_NODE_NASID (102|SN_HWPERF_OP_MEM_COPYOUT)
+/*
+ * Given a node id, determine the id of the nearest node with CPUs
+ * and the id of the nearest node that has memory. The argument
+ * node would normally be a "headless" node, e.g. an "IO node".
+ * Return 0 on success.
+ */
+extern int sn_hwperf_get_nearest_node(cnodeid_t node,
+ cnodeid_t *near_mem, cnodeid_t *near_cpu);
+
/* return codes */
#define SN_HWPERF_OP_OK 0
#define SN_HWPERF_OP_NOMEM 1
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index 27976d2..e67825a 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -55,7 +55,6 @@
#define SN_SAL_BUS_CONFIG 0x02000037
#define SN_SAL_SYS_SERIAL_GET 0x02000038
#define SN_SAL_PARTITION_SERIAL_GET 0x02000039
-#define SN_SAL_SYSCTL_PARTITION_GET 0x0200003a
#define SN_SAL_SYSTEM_POWER_DOWN 0x0200003b
#define SN_SAL_GET_MASTER_BASEIO_NASID 0x0200003c
#define SN_SAL_COHERENCE 0x0200003d
@@ -78,7 +77,8 @@
#define SN_SAL_HUB_ERROR_INTERRUPT 0x02000060
#define SN_SAL_BTE_RECOVER 0x02000061
-#define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000062
+#define SN_SAL_RESERVED_DO_NOT_USE 0x02000062
+#define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000064
/*
* Service-specific constants
@@ -586,35 +586,6 @@
}
/*
- * Returns the partition id of the nasid passed in as an argument,
- * or INVALID_PARTID if the partition id cannot be retrieved.
- */
-static inline partid_t
-ia64_sn_sysctl_partition_get(nasid_t nasid)
-{
- struct ia64_sal_retval ret_stuff;
- ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid,
- 0, 0, 0, 0, 0, 0);
- if (ret_stuff.status != 0)
- return INVALID_PARTID;
- return ((partid_t)ret_stuff.v0);
-}
-
-/*
- * Returns the partition id of the current processor.
- */
-
-extern partid_t sn_partid;
-
-static inline partid_t
-sn_local_partid(void) {
- if (unlikely(sn_partid < 0)) {
- sn_partid = ia64_sn_sysctl_partition_get(cpuid_to_nasid(smp_processor_id()));
- }
- return sn_partid;
-}
-
-/*
* Returns the physical address of the partition's reserved page through
* an iterative number of calls.
*
@@ -749,7 +720,8 @@
{
struct ia64_sal_retval ret_stuff;
SAL_CALL(ret_stuff, SN_SAL_SYSTEM_POWER_DOWN, 0, 0, 0, 0, 0, 0, 0);
- while(1);
+ while(1)
+ cpu_relax();
/* never returns */
}
@@ -1018,24 +990,6 @@
ret_stuff.v2 = 0;
SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SN_INFO, fc, 0, 0, 0, 0, 0, 0);
-/***** BEGIN HACK - temp til old proms no longer supported ********/
- if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) {
- int nasid = get_sapicid() & 0xfff;;
-#define SH_SHUB_ID_NODES_PER_BIT_MASK 0x001f000000000000UL
-#define SH_SHUB_ID_NODES_PER_BIT_SHFT 48
- if (shubtype) *shubtype = 0;
- if (nasid_bitmask) *nasid_bitmask = 0x7ff;
- if (nasid_shift) *nasid_shift = 38;
- if (systemsize) *systemsize = 11;
- if (sharing_domain_size) *sharing_domain_size = 9;
- if (partid) *partid = ia64_sn_sysctl_partition_get(nasid);
- if (coher) *coher = nasid >> 9;
- if (reg) *reg = (HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_SHUB_ID)) & SH_SHUB_ID_NODES_PER_BIT_MASK) >>
- SH_SHUB_ID_NODES_PER_BIT_SHFT;
- return 0;
- }
-/***** END HACK *******/
-
if (ret_stuff.status < 0)
return ret_stuff.status;
@@ -1068,12 +1022,10 @@
}
static inline int
-ia64_sn_ioif_get_pci_topology(u64 rack, u64 bay, u64 slot, u64 slab,
- u64 buf, u64 len)
+ia64_sn_ioif_get_pci_topology(u64 buf, u64 len)
{
struct ia64_sal_retval rv;
- SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY,
- rack, bay, slot, slab, buf, len, 0);
+ SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY, buf, len, 0, 0, 0, 0, 0);
return (int) rv.status;
}
diff --git a/include/asm-ia64/sn/tioce.h b/include/asm-ia64/sn/tioce.h
new file mode 100644
index 0000000..2287985
--- /dev/null
+++ b/include/asm-ia64/sn/tioce.h
@@ -0,0 +1,740 @@
+/**************************************************************************
+ * *
+ * Unpublished copyright (c) 2005, Silicon Graphics, Inc. *
+ * THIS IS UNPUBLISHED CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF SGI. *
+ * *
+ * The copyright notice above does not evidence any actual or intended *
+ * publication or disclosure of this source code, which includes *
+ * information that is confidential and/or proprietary, and is a trade *
+ * secret, of Silicon Graphics, Inc. ANY REPRODUCTION, MODIFICATION, *
+ * DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC DISPLAY OF OR THROUGH *
+ * USE OF THIS SOURCE CODE WITHOUT THE EXPRESS WRITTEN CONSENT OF *
+ * SILICON GRAPHICS, INC. IS STRICTLY PROHIBITED, AND IN VIOLATION OF *
+ * APPLICABLE LAWS AND INTERNATIONAL TREATIES. THE RECEIPT OR *
+ * POSSESSION OF THIS SOURCE CODE AND/OR RELATED INFORMATION DOES NOT *
+ * CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE, DISCLOSE OR DISTRIBUTE ITS *
+ * CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING THAT IT MAY *
+ * DESCRIBE, IN WHOLE OR IN PART. *
+ * *
+ **************************************************************************/
+
+#ifndef __ASM_IA64_SN_TIOCE_H__
+#define __ASM_IA64_SN_TIOCE_H__
+
+/* CE ASIC part & mfgr information */
+#define TIOCE_PART_NUM 0xCE00
+#define TIOCE_MFGR_NUM 0x36
+#define TIOCE_REV_A 0x1
+
+/* CE Virtual PPB Vendor/Device IDs */
+#define CE_VIRT_PPB_VENDOR_ID 0x10a9
+#define CE_VIRT_PPB_DEVICE_ID 0x4002
+
+/* CE Host Bridge Vendor/Device IDs */
+#define CE_HOST_BRIDGE_VENDOR_ID 0x10a9
+#define CE_HOST_BRIDGE_DEVICE_ID 0x4003
+
+
+#define TIOCE_NUM_M40_ATES 4096
+#define TIOCE_NUM_M3240_ATES 2048
+#define TIOCE_NUM_PORTS 2
+
+/*
+ * Register layout for TIOCE. MMR offsets are shown at the far right of the
+ * structure definition.
+ */
+typedef volatile struct tioce {
+ /*
+ * ADMIN : Administration Registers
+ */
+ uint64_t ce_adm_id; /* 0x000000 */
+ uint64_t ce_pad_000008; /* 0x000008 */
+ uint64_t ce_adm_dyn_credit_status; /* 0x000010 */
+ uint64_t ce_adm_last_credit_status; /* 0x000018 */
+ uint64_t ce_adm_credit_limit; /* 0x000020 */
+ uint64_t ce_adm_force_credit; /* 0x000028 */
+ uint64_t ce_adm_control; /* 0x000030 */
+ uint64_t ce_adm_mmr_chn_timeout; /* 0x000038 */
+ uint64_t ce_adm_ssp_ure_timeout; /* 0x000040 */
+ uint64_t ce_adm_ssp_dre_timeout; /* 0x000048 */
+ uint64_t ce_adm_ssp_debug_sel; /* 0x000050 */
+ uint64_t ce_adm_int_status; /* 0x000058 */
+ uint64_t ce_adm_int_status_alias; /* 0x000060 */
+ uint64_t ce_adm_int_mask; /* 0x000068 */
+ uint64_t ce_adm_int_pending; /* 0x000070 */
+ uint64_t ce_adm_force_int; /* 0x000078 */
+ uint64_t ce_adm_ure_ups_buf_barrier_flush; /* 0x000080 */
+ uint64_t ce_adm_int_dest[15]; /* 0x000088 -- 0x0000F8 */
+ uint64_t ce_adm_error_summary; /* 0x000100 */
+ uint64_t ce_adm_error_summary_alias; /* 0x000108 */
+ uint64_t ce_adm_error_mask; /* 0x000110 */
+ uint64_t ce_adm_first_error; /* 0x000118 */
+ uint64_t ce_adm_error_overflow; /* 0x000120 */
+ uint64_t ce_adm_error_overflow_alias; /* 0x000128 */
+ uint64_t ce_pad_000130[2]; /* 0x000130 -- 0x000138 */
+ uint64_t ce_adm_tnum_error; /* 0x000140 */
+ uint64_t ce_adm_mmr_err_detail; /* 0x000148 */
+ uint64_t ce_adm_msg_sram_perr_detail; /* 0x000150 */
+ uint64_t ce_adm_bap_sram_perr_detail; /* 0x000158 */
+ uint64_t ce_adm_ce_sram_perr_detail; /* 0x000160 */
+ uint64_t ce_adm_ce_credit_oflow_detail; /* 0x000168 */
+ uint64_t ce_adm_tx_link_idle_max_timer; /* 0x000170 */
+ uint64_t ce_adm_pcie_debug_sel; /* 0x000178 */
+ uint64_t ce_pad_000180[16]; /* 0x000180 -- 0x0001F8 */
+
+ uint64_t ce_adm_pcie_debug_sel_top; /* 0x000200 */
+ uint64_t ce_adm_pcie_debug_lat_sel_lo_top; /* 0x000208 */
+ uint64_t ce_adm_pcie_debug_lat_sel_hi_top; /* 0x000210 */
+ uint64_t ce_adm_pcie_debug_trig_sel_top; /* 0x000218 */
+ uint64_t ce_adm_pcie_debug_trig_lat_sel_lo_top; /* 0x000220 */
+ uint64_t ce_adm_pcie_debug_trig_lat_sel_hi_top; /* 0x000228 */
+ uint64_t ce_adm_pcie_trig_compare_top; /* 0x000230 */
+ uint64_t ce_adm_pcie_trig_compare_en_top; /* 0x000238 */
+ uint64_t ce_adm_ssp_debug_sel_top; /* 0x000240 */
+ uint64_t ce_adm_ssp_debug_lat_sel_lo_top; /* 0x000248 */
+ uint64_t ce_adm_ssp_debug_lat_sel_hi_top; /* 0x000250 */
+ uint64_t ce_adm_ssp_debug_trig_sel_top; /* 0x000258 */
+ uint64_t ce_adm_ssp_debug_trig_lat_sel_lo_top; /* 0x000260 */
+ uint64_t ce_adm_ssp_debug_trig_lat_sel_hi_top; /* 0x000268 */
+ uint64_t ce_adm_ssp_trig_compare_top; /* 0x000270 */
+ uint64_t ce_adm_ssp_trig_compare_en_top; /* 0x000278 */
+ uint64_t ce_pad_000280[48]; /* 0x000280 -- 0x0003F8 */
+
+ uint64_t ce_adm_bap_ctrl; /* 0x000400 */
+ uint64_t ce_pad_000408[127]; /* 0x000408 -- 0x0007F8 */
+
+ uint64_t ce_msg_buf_data63_0[35]; /* 0x000800 -- 0x000918 */
+ uint64_t ce_pad_000920[29]; /* 0x000920 -- 0x0009F8 */
+
+ uint64_t ce_msg_buf_data127_64[35]; /* 0x000A00 -- 0x000B18 */
+ uint64_t ce_pad_000B20[29]; /* 0x000B20 -- 0x000BF8 */
+
+ uint64_t ce_msg_buf_parity[35]; /* 0x000C00 -- 0x000D18 */
+ uint64_t ce_pad_000D20[29]; /* 0x000D20 -- 0x000DF8 */
+
+ uint64_t ce_pad_000E00[576]; /* 0x000E00 -- 0x001FF8 */
+
+ /*
+ * LSI : LSI's PCI Express Link Registers (Link#1 and Link#2)
+ * Link#1 MMRs at start at 0x002000, Link#2 MMRs at 0x003000
+ * NOTE: the comment offsets at far right: let 'z' = {2 or 3}
+ */
+ #define ce_lsi(link_num) ce_lsi[link_num-1]
+ struct ce_lsi_reg {
+ uint64_t ce_lsi_lpu_id; /* 0x00z000 */
+ uint64_t ce_lsi_rst; /* 0x00z008 */
+ uint64_t ce_lsi_dbg_stat; /* 0x00z010 */
+ uint64_t ce_lsi_dbg_cfg; /* 0x00z018 */
+ uint64_t ce_lsi_ltssm_ctrl; /* 0x00z020 */
+ uint64_t ce_lsi_lk_stat; /* 0x00z028 */
+ uint64_t ce_pad_00z030[2]; /* 0x00z030 -- 0x00z038 */
+ uint64_t ce_lsi_int_and_stat; /* 0x00z040 */
+ uint64_t ce_lsi_int_mask; /* 0x00z048 */
+ uint64_t ce_pad_00z050[22]; /* 0x00z050 -- 0x00z0F8 */
+ uint64_t ce_lsi_lk_perf_cnt_sel; /* 0x00z100 */
+ uint64_t ce_pad_00z108; /* 0x00z108 */
+ uint64_t ce_lsi_lk_perf_cnt_ctrl; /* 0x00z110 */
+ uint64_t ce_pad_00z118; /* 0x00z118 */
+ uint64_t ce_lsi_lk_perf_cnt1; /* 0x00z120 */
+ uint64_t ce_lsi_lk_perf_cnt1_test; /* 0x00z128 */
+ uint64_t ce_lsi_lk_perf_cnt2; /* 0x00z130 */
+ uint64_t ce_lsi_lk_perf_cnt2_test; /* 0x00z138 */
+ uint64_t ce_pad_00z140[24]; /* 0x00z140 -- 0x00z1F8 */
+ uint64_t ce_lsi_lk_lyr_cfg; /* 0x00z200 */
+ uint64_t ce_lsi_lk_lyr_status; /* 0x00z208 */
+ uint64_t ce_lsi_lk_lyr_int_stat; /* 0x00z210 */
+ uint64_t ce_lsi_lk_ly_int_stat_test; /* 0x00z218 */
+ uint64_t ce_lsi_lk_ly_int_stat_mask; /* 0x00z220 */
+ uint64_t ce_pad_00z228[3]; /* 0x00z228 -- 0x00z238 */
+ uint64_t ce_lsi_fc_upd_ctl; /* 0x00z240 */
+ uint64_t ce_pad_00z248[3]; /* 0x00z248 -- 0x00z258 */
+ uint64_t ce_lsi_flw_ctl_upd_to_timer; /* 0x00z260 */
+ uint64_t ce_lsi_flw_ctl_upd_timer0; /* 0x00z268 */
+ uint64_t ce_lsi_flw_ctl_upd_timer1; /* 0x00z270 */
+ uint64_t ce_pad_00z278[49]; /* 0x00z278 -- 0x00z3F8 */
+ uint64_t ce_lsi_freq_nak_lat_thrsh; /* 0x00z400 */
+ uint64_t ce_lsi_ack_nak_lat_tmr; /* 0x00z408 */
+ uint64_t ce_lsi_rply_tmr_thr; /* 0x00z410 */
+ uint64_t ce_lsi_rply_tmr; /* 0x00z418 */
+ uint64_t ce_lsi_rply_num_stat; /* 0x00z420 */
+ uint64_t ce_lsi_rty_buf_max_addr; /* 0x00z428 */
+ uint64_t ce_lsi_rty_fifo_ptr; /* 0x00z430 */
+ uint64_t ce_lsi_rty_fifo_rd_wr_ptr; /* 0x00z438 */
+ uint64_t ce_lsi_rty_fifo_cred; /* 0x00z440 */
+ uint64_t ce_lsi_seq_cnt; /* 0x00z448 */
+ uint64_t ce_lsi_ack_sent_seq_num; /* 0x00z450 */
+ uint64_t ce_lsi_seq_cnt_fifo_max_addr; /* 0x00z458 */
+ uint64_t ce_lsi_seq_cnt_fifo_ptr; /* 0x00z460 */
+ uint64_t ce_lsi_seq_cnt_rd_wr_ptr; /* 0x00z468 */
+ uint64_t ce_lsi_tx_lk_ts_ctl; /* 0x00z470 */
+ uint64_t ce_pad_00z478; /* 0x00z478 */
+ uint64_t ce_lsi_mem_addr_ctl; /* 0x00z480 */
+ uint64_t ce_lsi_mem_d_ld0; /* 0x00z488 */
+ uint64_t ce_lsi_mem_d_ld1; /* 0x00z490 */
+ uint64_t ce_lsi_mem_d_ld2; /* 0x00z498 */
+ uint64_t ce_lsi_mem_d_ld3; /* 0x00z4A0 */
+ uint64_t ce_lsi_mem_d_ld4; /* 0x00z4A8 */
+ uint64_t ce_pad_00z4B0[2]; /* 0x00z4B0 -- 0x00z4B8 */
+ uint64_t ce_lsi_rty_d_cnt; /* 0x00z4C0 */
+ uint64_t ce_lsi_seq_buf_cnt; /* 0x00z4C8 */
+ uint64_t ce_lsi_seq_buf_bt_d; /* 0x00z4D0 */
+ uint64_t ce_pad_00z4D8; /* 0x00z4D8 */
+ uint64_t ce_lsi_ack_lat_thr; /* 0x00z4E0 */
+ uint64_t ce_pad_00z4E8[3]; /* 0x00z4E8 -- 0x00z4F8 */
+ uint64_t ce_lsi_nxt_rcv_seq_1_cntr; /* 0x00z500 */
+ uint64_t ce_lsi_unsp_dllp_rcvd; /* 0x00z508 */
+ uint64_t ce_lsi_rcv_lk_ts_ctl; /* 0x00z510 */
+ uint64_t ce_pad_00z518[29]; /* 0x00z518 -- 0x00z5F8 */
+ uint64_t ce_lsi_phy_lyr_cfg; /* 0x00z600 */
+ uint64_t ce_pad_00z608; /* 0x00z608 */
+ uint64_t ce_lsi_phy_lyr_int_stat; /* 0x00z610 */
+ uint64_t ce_lsi_phy_lyr_int_stat_test; /* 0x00z618 */
+ uint64_t ce_lsi_phy_lyr_int_mask; /* 0x00z620 */
+ uint64_t ce_pad_00z628[11]; /* 0x00z628 -- 0x00z678 */
+ uint64_t ce_lsi_rcv_phy_cfg; /* 0x00z680 */
+ uint64_t ce_lsi_rcv_phy_stat1; /* 0x00z688 */
+ uint64_t ce_lsi_rcv_phy_stat2; /* 0x00z690 */
+ uint64_t ce_lsi_rcv_phy_stat3; /* 0x00z698 */
+ uint64_t ce_lsi_rcv_phy_int_stat; /* 0x00z6A0 */
+ uint64_t ce_lsi_rcv_phy_int_stat_test; /* 0x00z6A8 */
+ uint64_t ce_lsi_rcv_phy_int_mask; /* 0x00z6B0 */
+ uint64_t ce_pad_00z6B8[9]; /* 0x00z6B8 -- 0x00z6F8 */
+ uint64_t ce_lsi_tx_phy_cfg; /* 0x00z700 */
+ uint64_t ce_lsi_tx_phy_stat; /* 0x00z708 */
+ uint64_t ce_lsi_tx_phy_int_stat; /* 0x00z710 */
+ uint64_t ce_lsi_tx_phy_int_stat_test; /* 0x00z718 */
+ uint64_t ce_lsi_tx_phy_int_mask; /* 0x00z720 */
+ uint64_t ce_lsi_tx_phy_stat2; /* 0x00z728 */
+ uint64_t ce_pad_00z730[10]; /* 0x00z730 -- 0x00z77F */
+ uint64_t ce_lsi_ltssm_cfg1; /* 0x00z780 */
+ uint64_t ce_lsi_ltssm_cfg2; /* 0x00z788 */
+ uint64_t ce_lsi_ltssm_cfg3; /* 0x00z790 */
+ uint64_t ce_lsi_ltssm_cfg4; /* 0x00z798 */
+ uint64_t ce_lsi_ltssm_cfg5; /* 0x00z7A0 */
+ uint64_t ce_lsi_ltssm_stat1; /* 0x00z7A8 */
+ uint64_t ce_lsi_ltssm_stat2; /* 0x00z7B0 */
+ uint64_t ce_lsi_ltssm_int_stat; /* 0x00z7B8 */
+ uint64_t ce_lsi_ltssm_int_stat_test; /* 0x00z7C0 */
+ uint64_t ce_lsi_ltssm_int_mask; /* 0x00z7C8 */
+ uint64_t ce_lsi_ltssm_stat_wr_en; /* 0x00z7D0 */
+ uint64_t ce_pad_00z7D8[5]; /* 0x00z7D8 -- 0x00z7F8 */
+ uint64_t ce_lsi_gb_cfg1; /* 0x00z800 */
+ uint64_t ce_lsi_gb_cfg2; /* 0x00z808 */
+ uint64_t ce_lsi_gb_cfg3; /* 0x00z810 */
+ uint64_t ce_lsi_gb_cfg4; /* 0x00z818 */
+ uint64_t ce_lsi_gb_stat; /* 0x00z820 */
+ uint64_t ce_lsi_gb_int_stat; /* 0x00z828 */
+ uint64_t ce_lsi_gb_int_stat_test; /* 0x00z830 */
+ uint64_t ce_lsi_gb_int_mask; /* 0x00z838 */
+ uint64_t ce_lsi_gb_pwr_dn1; /* 0x00z840 */
+ uint64_t ce_lsi_gb_pwr_dn2; /* 0x00z848 */
+ uint64_t ce_pad_00z850[246]; /* 0x00z850 -- 0x00zFF8 */
+ } ce_lsi[2];
+
+ uint64_t ce_pad_004000[10]; /* 0x004000 -- 0x004048 */
+
+ /*
+ * CRM: Coretalk Receive Module Registers
+ */
+ uint64_t ce_crm_debug_mux; /* 0x004050 */
+ uint64_t ce_pad_004058; /* 0x004058 */
+ uint64_t ce_crm_ssp_err_cmd_wrd; /* 0x004060 */
+ uint64_t ce_crm_ssp_err_addr; /* 0x004068 */
+ uint64_t ce_crm_ssp_err_syn; /* 0x004070 */
+
+ uint64_t ce_pad_004078[499]; /* 0x004078 -- 0x005008 */
+
+ /*
+ * CXM: Coretalk Xmit Module Registers
+ */
+ uint64_t ce_cxm_dyn_credit_status; /* 0x005010 */
+ uint64_t ce_cxm_last_credit_status; /* 0x005018 */
+ uint64_t ce_cxm_credit_limit; /* 0x005020 */
+ uint64_t ce_cxm_force_credit; /* 0x005028 */
+ uint64_t ce_cxm_disable_bypass; /* 0x005030 */
+ uint64_t ce_pad_005038[3]; /* 0x005038 -- 0x005048 */
+ uint64_t ce_cxm_debug_mux; /* 0x005050 */
+
+ uint64_t ce_pad_005058[501]; /* 0x005058 -- 0x005FF8 */
+
+ /*
+ * DTL: Downstream Transaction Layer Regs (Link#1 and Link#2)
+ * DTL: Link#1 MMRs at start at 0x006000, Link#2 MMRs at 0x008000
+ * DTL: the comment offsets at far right: let 'y' = {6 or 8}
+ *
+ * UTL: Downstream Transaction Layer Regs (Link#1 and Link#2)
+ * UTL: Link#1 MMRs at start at 0x007000, Link#2 MMRs at 0x009000
+ * UTL: the comment offsets at far right: let 'z' = {7 or 9}
+ */
+ #define ce_dtl(link_num) ce_dtl_utl[link_num-1]
+ #define ce_utl(link_num) ce_dtl_utl[link_num-1]
+ struct ce_dtl_utl_reg {
+ /* DTL */
+ uint64_t ce_dtl_dtdr_credit_limit; /* 0x00y000 */
+ uint64_t ce_dtl_dtdr_credit_force; /* 0x00y008 */
+ uint64_t ce_dtl_dyn_credit_status; /* 0x00y010 */
+ uint64_t ce_dtl_dtl_last_credit_stat; /* 0x00y018 */
+ uint64_t ce_dtl_dtl_ctrl; /* 0x00y020 */
+ uint64_t ce_pad_00y028[5]; /* 0x00y028 -- 0x00y048 */
+ uint64_t ce_dtl_debug_sel; /* 0x00y050 */
+ uint64_t ce_pad_00y058[501]; /* 0x00y058 -- 0x00yFF8 */
+
+ /* UTL */
+ uint64_t ce_utl_utl_ctrl; /* 0x00z000 */
+ uint64_t ce_utl_debug_sel; /* 0x00z008 */
+ uint64_t ce_pad_00z010[510]; /* 0x00z010 -- 0x00zFF8 */
+ } ce_dtl_utl[2];
+
+ uint64_t ce_pad_00A000[514]; /* 0x00A000 -- 0x00B008 */
+
+ /*
+ * URE: Upstream Request Engine
+ */
+ uint64_t ce_ure_dyn_credit_status; /* 0x00B010 */
+ uint64_t ce_ure_last_credit_status; /* 0x00B018 */
+ uint64_t ce_ure_credit_limit; /* 0x00B020 */
+ uint64_t ce_pad_00B028; /* 0x00B028 */
+ uint64_t ce_ure_control; /* 0x00B030 */
+ uint64_t ce_ure_status; /* 0x00B038 */
+ uint64_t ce_pad_00B040[2]; /* 0x00B040 -- 0x00B048 */
+ uint64_t ce_ure_debug_sel; /* 0x00B050 */
+ uint64_t ce_ure_pcie_debug_sel; /* 0x00B058 */
+ uint64_t ce_ure_ssp_err_cmd_wrd; /* 0x00B060 */
+ uint64_t ce_ure_ssp_err_addr; /* 0x00B068 */
+ uint64_t ce_ure_page_map; /* 0x00B070 */
+ uint64_t ce_ure_dir_map[TIOCE_NUM_PORTS]; /* 0x00B078 */
+ uint64_t ce_ure_pipe_sel1; /* 0x00B088 */
+ uint64_t ce_ure_pipe_mask1; /* 0x00B090 */
+ uint64_t ce_ure_pipe_sel2; /* 0x00B098 */
+ uint64_t ce_ure_pipe_mask2; /* 0x00B0A0 */
+ uint64_t ce_ure_pcie1_credits_sent; /* 0x00B0A8 */
+ uint64_t ce_ure_pcie1_credits_used; /* 0x00B0B0 */
+ uint64_t ce_ure_pcie1_credit_limit; /* 0x00B0B8 */
+ uint64_t ce_ure_pcie2_credits_sent; /* 0x00B0C0 */
+ uint64_t ce_ure_pcie2_credits_used; /* 0x00B0C8 */
+ uint64_t ce_ure_pcie2_credit_limit; /* 0x00B0D0 */
+ uint64_t ce_ure_pcie_force_credit; /* 0x00B0D8 */
+ uint64_t ce_ure_rd_tnum_val; /* 0x00B0E0 */
+ uint64_t ce_ure_rd_tnum_rsp_rcvd; /* 0x00B0E8 */
+ uint64_t ce_ure_rd_tnum_esent_timer; /* 0x00B0F0 */
+ uint64_t ce_ure_rd_tnum_error; /* 0x00B0F8 */
+ uint64_t ce_ure_rd_tnum_first_cl; /* 0x00B100 */
+ uint64_t ce_ure_rd_tnum_link_buf; /* 0x00B108 */
+ uint64_t ce_ure_wr_tnum_val; /* 0x00B110 */
+ uint64_t ce_ure_sram_err_addr0; /* 0x00B118 */
+ uint64_t ce_ure_sram_err_addr1; /* 0x00B120 */
+ uint64_t ce_ure_sram_err_addr2; /* 0x00B128 */
+ uint64_t ce_ure_sram_rd_addr0; /* 0x00B130 */
+ uint64_t ce_ure_sram_rd_addr1; /* 0x00B138 */
+ uint64_t ce_ure_sram_rd_addr2; /* 0x00B140 */
+ uint64_t ce_ure_sram_wr_addr0; /* 0x00B148 */
+ uint64_t ce_ure_sram_wr_addr1; /* 0x00B150 */
+ uint64_t ce_ure_sram_wr_addr2; /* 0x00B158 */
+ uint64_t ce_ure_buf_flush10; /* 0x00B160 */
+ uint64_t ce_ure_buf_flush11; /* 0x00B168 */
+ uint64_t ce_ure_buf_flush12; /* 0x00B170 */
+ uint64_t ce_ure_buf_flush13; /* 0x00B178 */
+ uint64_t ce_ure_buf_flush20; /* 0x00B180 */
+ uint64_t ce_ure_buf_flush21; /* 0x00B188 */
+ uint64_t ce_ure_buf_flush22; /* 0x00B190 */
+ uint64_t ce_ure_buf_flush23; /* 0x00B198 */
+ uint64_t ce_ure_pcie_control1; /* 0x00B1A0 */
+ uint64_t ce_ure_pcie_control2; /* 0x00B1A8 */
+
+ uint64_t ce_pad_00B1B0[458]; /* 0x00B1B0 -- 0x00BFF8 */
+
+ /* Upstream Data Buffer, Port1 */
+ struct ce_ure_maint_ups_dat1_data {
+ uint64_t data63_0[512]; /* 0x00C000 -- 0x00CFF8 */
+ uint64_t data127_64[512]; /* 0x00D000 -- 0x00DFF8 */
+ uint64_t parity[512]; /* 0x00E000 -- 0x00EFF8 */
+ } ce_ure_maint_ups_dat1;
+
+ /* Upstream Header Buffer, Port1 */
+ struct ce_ure_maint_ups_hdr1_data {
+ uint64_t data63_0[512]; /* 0x00F000 -- 0x00FFF8 */
+ uint64_t data127_64[512]; /* 0x010000 -- 0x010FF8 */
+ uint64_t parity[512]; /* 0x011000 -- 0x011FF8 */
+ } ce_ure_maint_ups_hdr1;
+
+ /* Upstream Data Buffer, Port2 */
+ struct ce_ure_maint_ups_dat2_data {
+ uint64_t data63_0[512]; /* 0x012000 -- 0x012FF8 */
+ uint64_t data127_64[512]; /* 0x013000 -- 0x013FF8 */
+ uint64_t parity[512]; /* 0x014000 -- 0x014FF8 */
+ } ce_ure_maint_ups_dat2;
+
+ /* Upstream Header Buffer, Port2 */
+ struct ce_ure_maint_ups_hdr2_data {
+ uint64_t data63_0[512]; /* 0x015000 -- 0x015FF8 */
+ uint64_t data127_64[512]; /* 0x016000 -- 0x016FF8 */
+ uint64_t parity[512]; /* 0x017000 -- 0x017FF8 */
+ } ce_ure_maint_ups_hdr2;
+
+ /* Downstream Data Buffer */
+ struct ce_ure_maint_dns_dat_data {
+ uint64_t data63_0[512]; /* 0x018000 -- 0x018FF8 */
+ uint64_t data127_64[512]; /* 0x019000 -- 0x019FF8 */
+ uint64_t parity[512]; /* 0x01A000 -- 0x01AFF8 */
+ } ce_ure_maint_dns_dat;
+
+ /* Downstream Header Buffer */
+ struct ce_ure_maint_dns_hdr_data {
+ uint64_t data31_0[64]; /* 0x01B000 -- 0x01B1F8 */
+ uint64_t data95_32[64]; /* 0x01B200 -- 0x01B3F8 */
+ uint64_t parity[64]; /* 0x01B400 -- 0x01B5F8 */
+ } ce_ure_maint_dns_hdr;
+
+ /* RCI Buffer Data */
+ struct ce_ure_maint_rci_data {
+ uint64_t data41_0[64]; /* 0x01B600 -- 0x01B7F8 */
+ uint64_t data69_42[64]; /* 0x01B800 -- 0x01B9F8 */
+ } ce_ure_maint_rci;
+
+ /* Response Queue */
+ uint64_t ce_ure_maint_rspq[64]; /* 0x01BA00 -- 0x01BBF8 */
+
+ uint64_t ce_pad_01C000[4224]; /* 0x01BC00 -- 0x023FF8 */
+
+ /* Admin Build-a-Packet Buffer */
+ struct ce_adm_maint_bap_buf_data {
+ uint64_t data63_0[258]; /* 0x024000 -- 0x024808 */
+ uint64_t data127_64[258]; /* 0x024810 -- 0x025018 */
+ uint64_t parity[258]; /* 0x025020 -- 0x025828 */
+ } ce_adm_maint_bap_buf;
+
+ uint64_t ce_pad_025830[5370]; /* 0x025830 -- 0x02FFF8 */
+
+ /* URE: 40bit PMU ATE Buffer */ /* 0x030000 -- 0x037FF8 */
+ uint64_t ce_ure_ate40[TIOCE_NUM_M40_ATES];
+
+ /* URE: 32/40bit PMU ATE Buffer */ /* 0x038000 -- 0x03BFF8 */
+ uint64_t ce_ure_ate3240[TIOCE_NUM_M3240_ATES];
+
+ uint64_t ce_pad_03C000[2050]; /* 0x03C000 -- 0x040008 */
+
+ /*
+ * DRE: Down Stream Request Engine
+ */
+ uint64_t ce_dre_dyn_credit_status1; /* 0x040010 */
+ uint64_t ce_dre_dyn_credit_status2; /* 0x040018 */
+ uint64_t ce_dre_last_credit_status1; /* 0x040020 */
+ uint64_t ce_dre_last_credit_status2; /* 0x040028 */
+ uint64_t ce_dre_credit_limit1; /* 0x040030 */
+ uint64_t ce_dre_credit_limit2; /* 0x040038 */
+ uint64_t ce_dre_force_credit1; /* 0x040040 */
+ uint64_t ce_dre_force_credit2; /* 0x040048 */
+ uint64_t ce_dre_debug_mux1; /* 0x040050 */
+ uint64_t ce_dre_debug_mux2; /* 0x040058 */
+ uint64_t ce_dre_ssp_err_cmd_wrd; /* 0x040060 */
+ uint64_t ce_dre_ssp_err_addr; /* 0x040068 */
+ uint64_t ce_dre_comp_err_cmd_wrd; /* 0x040070 */
+ uint64_t ce_dre_comp_err_addr; /* 0x040078 */
+ uint64_t ce_dre_req_status; /* 0x040080 */
+ uint64_t ce_dre_config1; /* 0x040088 */
+ uint64_t ce_dre_config2; /* 0x040090 */
+ uint64_t ce_dre_config_req_status; /* 0x040098 */
+ uint64_t ce_pad_0400A0[12]; /* 0x0400A0 -- 0x0400F8 */
+ uint64_t ce_dre_dyn_fifo; /* 0x040100 */
+ uint64_t ce_pad_040108[3]; /* 0x040108 -- 0x040118 */
+ uint64_t ce_dre_last_fifo; /* 0x040120 */
+
+ uint64_t ce_pad_040128[27]; /* 0x040128 -- 0x0401F8 */
+
+ /* DRE Downstream Head Queue */
+ struct ce_dre_maint_ds_head_queue {
+ uint64_t data63_0[32]; /* 0x040200 -- 0x0402F8 */
+ uint64_t data127_64[32]; /* 0x040300 -- 0x0403F8 */
+ uint64_t parity[32]; /* 0x040400 -- 0x0404F8 */
+ } ce_dre_maint_ds_head_q;
+
+ uint64_t ce_pad_040500[352]; /* 0x040500 -- 0x040FF8 */
+
+ /* DRE Downstream Data Queue */
+ struct ce_dre_maint_ds_data_queue {
+ uint64_t data63_0[256]; /* 0x041000 -- 0x0417F8 */
+ uint64_t ce_pad_041800[256]; /* 0x041800 -- 0x041FF8 */
+ uint64_t data127_64[256]; /* 0x042000 -- 0x0427F8 */
+ uint64_t ce_pad_042800[256]; /* 0x042800 -- 0x042FF8 */
+ uint64_t parity[256]; /* 0x043000 -- 0x0437F8 */
+ uint64_t ce_pad_043800[256]; /* 0x043800 -- 0x043FF8 */
+ } ce_dre_maint_ds_data_q;
+
+ /* DRE URE Upstream Response Queue */
+ struct ce_dre_maint_ure_us_rsp_queue {
+ uint64_t data63_0[8]; /* 0x044000 -- 0x044038 */
+ uint64_t ce_pad_044040[24]; /* 0x044040 -- 0x0440F8 */
+ uint64_t data127_64[8]; /* 0x044100 -- 0x044138 */
+ uint64_t ce_pad_044140[24]; /* 0x044140 -- 0x0441F8 */
+ uint64_t parity[8]; /* 0x044200 -- 0x044238 */
+ uint64_t ce_pad_044240[24]; /* 0x044240 -- 0x0442F8 */
+ } ce_dre_maint_ure_us_rsp_q;
+
+ uint64_t ce_dre_maint_us_wrt_rsp[32];/* 0x044300 -- 0x0443F8 */
+
+ uint64_t ce_end_of_struct; /* 0x044400 */
+} tioce_t;
+
+
+/* ce_adm_int_mask/ce_adm_int_status register bit defines */
+#define CE_ADM_INT_CE_ERROR_SHFT 0
+#define CE_ADM_INT_LSI1_IP_ERROR_SHFT 1
+#define CE_ADM_INT_LSI2_IP_ERROR_SHFT 2
+#define CE_ADM_INT_PCIE_ERROR_SHFT 3
+#define CE_ADM_INT_PORT1_HOTPLUG_EVENT_SHFT 4
+#define CE_ADM_INT_PORT2_HOTPLUG_EVENT_SHFT 5
+#define CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT 6
+#define CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT 7
+#define CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT 8
+#define CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT 9
+#define CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT 10
+#define CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT 11
+#define CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT 12
+#define CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT 13
+#define CE_ADM_INT_PCIE_MSG_SHFT 14 /*see int_dest_14*/
+#define CE_ADM_INT_PCIE_MSG_SLOT_0_SHFT 14
+#define CE_ADM_INT_PCIE_MSG_SLOT_1_SHFT 15
+#define CE_ADM_INT_PCIE_MSG_SLOT_2_SHFT 16
+#define CE_ADM_INT_PCIE_MSG_SLOT_3_SHFT 17
+#define CE_ADM_INT_PORT1_PM_PME_MSG_SHFT 22
+#define CE_ADM_INT_PORT2_PM_PME_MSG_SHFT 23
+
+/* ce_adm_force_int register bit defines */
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT 0
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT 1
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT 2
+#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT 3
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT 4
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT 5
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT 6
+#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT 7
+#define CE_ADM_FORCE_INT_ALWAYS_SHFT 8
+
+/* ce_adm_int_dest register bit masks & shifts */
+#define INTR_VECTOR_SHFT 56
+
+/* ce_adm_error_mask and ce_adm_error_summary register bit masks */
+#define CE_ADM_ERR_CRM_SSP_REQ_INVALID (0x1ULL << 0)
+#define CE_ADM_ERR_SSP_REQ_HEADER (0x1ULL << 1)
+#define CE_ADM_ERR_SSP_RSP_HEADER (0x1ULL << 2)
+#define CE_ADM_ERR_SSP_PROTOCOL_ERROR (0x1ULL << 3)
+#define CE_ADM_ERR_SSP_SBE (0x1ULL << 4)
+#define CE_ADM_ERR_SSP_MBE (0x1ULL << 5)
+#define CE_ADM_ERR_CXM_CREDIT_OFLOW (0x1ULL << 6)
+#define CE_ADM_ERR_DRE_SSP_REQ_INVAL (0x1ULL << 7)
+#define CE_ADM_ERR_SSP_REQ_LONG (0x1ULL << 8)
+#define CE_ADM_ERR_SSP_REQ_OFLOW (0x1ULL << 9)
+#define CE_ADM_ERR_SSP_REQ_SHORT (0x1ULL << 10)
+#define CE_ADM_ERR_SSP_REQ_SIDEBAND (0x1ULL << 11)
+#define CE_ADM_ERR_SSP_REQ_ADDR_ERR (0x1ULL << 12)
+#define CE_ADM_ERR_SSP_REQ_BAD_BE (0x1ULL << 13)
+#define CE_ADM_ERR_PCIE_COMPL_TIMEOUT (0x1ULL << 14)
+#define CE_ADM_ERR_PCIE_UNEXP_COMPL (0x1ULL << 15)
+#define CE_ADM_ERR_PCIE_ERR_COMPL (0x1ULL << 16)
+#define CE_ADM_ERR_DRE_CREDIT_OFLOW (0x1ULL << 17)
+#define CE_ADM_ERR_DRE_SRAM_PE (0x1ULL << 18)
+#define CE_ADM_ERR_SSP_RSP_INVALID (0x1ULL << 19)
+#define CE_ADM_ERR_SSP_RSP_LONG (0x1ULL << 20)
+#define CE_ADM_ERR_SSP_RSP_SHORT (0x1ULL << 21)
+#define CE_ADM_ERR_SSP_RSP_SIDEBAND (0x1ULL << 22)
+#define CE_ADM_ERR_URE_SSP_RSP_UNEXP (0x1ULL << 23)
+#define CE_ADM_ERR_URE_SSP_WR_REQ_TIMEOUT (0x1ULL << 24)
+#define CE_ADM_ERR_URE_SSP_RD_REQ_TIMEOUT (0x1ULL << 25)
+#define CE_ADM_ERR_URE_ATE3240_PAGE_FAULT (0x1ULL << 26)
+#define CE_ADM_ERR_URE_ATE40_PAGE_FAULT (0x1ULL << 27)
+#define CE_ADM_ERR_URE_CREDIT_OFLOW (0x1ULL << 28)
+#define CE_ADM_ERR_URE_SRAM_PE (0x1ULL << 29)
+#define CE_ADM_ERR_ADM_SSP_RSP_UNEXP (0x1ULL << 30)
+#define CE_ADM_ERR_ADM_SSP_REQ_TIMEOUT (0x1ULL << 31)
+#define CE_ADM_ERR_MMR_ACCESS_ERROR (0x1ULL << 32)
+#define CE_ADM_ERR_MMR_ADDR_ERROR (0x1ULL << 33)
+#define CE_ADM_ERR_ADM_CREDIT_OFLOW (0x1ULL << 34)
+#define CE_ADM_ERR_ADM_SRAM_PE (0x1ULL << 35)
+#define CE_ADM_ERR_DTL1_MIN_PDATA_CREDIT_ERR (0x1ULL << 36)
+#define CE_ADM_ERR_DTL1_INF_COMPL_CRED_UPDT_ERR (0x1ULL << 37)
+#define CE_ADM_ERR_DTL1_INF_POSTED_CRED_UPDT_ERR (0x1ULL << 38)
+#define CE_ADM_ERR_DTL1_INF_NPOSTED_CRED_UPDT_ERR (0x1ULL << 39)
+#define CE_ADM_ERR_DTL1_COMP_HD_CRED_MAX_ERR (0x1ULL << 40)
+#define CE_ADM_ERR_DTL1_COMP_D_CRED_MAX_ERR (0x1ULL << 41)
+#define CE_ADM_ERR_DTL1_NPOSTED_HD_CRED_MAX_ERR (0x1ULL << 42)
+#define CE_ADM_ERR_DTL1_NPOSTED_D_CRED_MAX_ERR (0x1ULL << 43)
+#define CE_ADM_ERR_DTL1_POSTED_HD_CRED_MAX_ERR (0x1ULL << 44)
+#define CE_ADM_ERR_DTL1_POSTED_D_CRED_MAX_ERR (0x1ULL << 45)
+#define CE_ADM_ERR_DTL2_MIN_PDATA_CREDIT_ERR (0x1ULL << 46)
+#define CE_ADM_ERR_DTL2_INF_COMPL_CRED_UPDT_ERR (0x1ULL << 47)
+#define CE_ADM_ERR_DTL2_INF_POSTED_CRED_UPDT_ERR (0x1ULL << 48)
+#define CE_ADM_ERR_DTL2_INF_NPOSTED_CRED_UPDT_ERR (0x1ULL << 49)
+#define CE_ADM_ERR_DTL2_COMP_HD_CRED_MAX_ERR (0x1ULL << 50)
+#define CE_ADM_ERR_DTL2_COMP_D_CRED_MAX_ERR (0x1ULL << 51)
+#define CE_ADM_ERR_DTL2_NPOSTED_HD_CRED_MAX_ERR (0x1ULL << 52)
+#define CE_ADM_ERR_DTL2_NPOSTED_D_CRED_MAX_ERR (0x1ULL << 53)
+#define CE_ADM_ERR_DTL2_POSTED_HD_CRED_MAX_ERR (0x1ULL << 54)
+#define CE_ADM_ERR_DTL2_POSTED_D_CRED_MAX_ERR (0x1ULL << 55)
+#define CE_ADM_ERR_PORT1_PCIE_COR_ERR (0x1ULL << 56)
+#define CE_ADM_ERR_PORT1_PCIE_NFAT_ERR (0x1ULL << 57)
+#define CE_ADM_ERR_PORT1_PCIE_FAT_ERR (0x1ULL << 58)
+#define CE_ADM_ERR_PORT2_PCIE_COR_ERR (0x1ULL << 59)
+#define CE_ADM_ERR_PORT2_PCIE_NFAT_ERR (0x1ULL << 60)
+#define CE_ADM_ERR_PORT2_PCIE_FAT_ERR (0x1ULL << 61)
+
+/* ce_adm_ure_ups_buf_barrier_flush register bit masks and shifts */
+#define FLUSH_SEL_PORT1_PIPE0_SHFT 0
+#define FLUSH_SEL_PORT1_PIPE1_SHFT 4
+#define FLUSH_SEL_PORT1_PIPE2_SHFT 8
+#define FLUSH_SEL_PORT1_PIPE3_SHFT 12
+#define FLUSH_SEL_PORT2_PIPE0_SHFT 16
+#define FLUSH_SEL_PORT2_PIPE1_SHFT 20
+#define FLUSH_SEL_PORT2_PIPE2_SHFT 24
+#define FLUSH_SEL_PORT2_PIPE3_SHFT 28
+
+/* ce_dre_config1 register bit masks and shifts */
+#define CE_DRE_RO_ENABLE (0x1ULL << 0)
+#define CE_DRE_DYN_RO_ENABLE (0x1ULL << 1)
+#define CE_DRE_SUP_CONFIG_COMP_ERROR (0x1ULL << 2)
+#define CE_DRE_SUP_IO_COMP_ERROR (0x1ULL << 3)
+#define CE_DRE_ADDR_MODE_SHFT 4
+
+/* ce_dre_config_req_status register bit masks */
+#define CE_DRE_LAST_CONFIG_COMPLETION (0x7ULL << 0)
+#define CE_DRE_DOWNSTREAM_CONFIG_ERROR (0x1ULL << 3)
+#define CE_DRE_CONFIG_COMPLETION_VALID (0x1ULL << 4)
+#define CE_DRE_CONFIG_REQUEST_ACTIVE (0x1ULL << 5)
+
+/* ce_ure_control register bit masks & shifts */
+#define CE_URE_RD_MRG_ENABLE (0x1ULL << 0)
+#define CE_URE_WRT_MRG_ENABLE1 (0x1ULL << 4)
+#define CE_URE_WRT_MRG_ENABLE2 (0x1ULL << 5)
+#define CE_URE_RSPQ_BYPASS_DISABLE (0x1ULL << 24)
+#define CE_URE_UPS_DAT1_PAR_DISABLE (0x1ULL << 32)
+#define CE_URE_UPS_HDR1_PAR_DISABLE (0x1ULL << 33)
+#define CE_URE_UPS_DAT2_PAR_DISABLE (0x1ULL << 34)
+#define CE_URE_UPS_HDR2_PAR_DISABLE (0x1ULL << 35)
+#define CE_URE_ATE_PAR_DISABLE (0x1ULL << 36)
+#define CE_URE_RCI_PAR_DISABLE (0x1ULL << 37)
+#define CE_URE_RSPQ_PAR_DISABLE (0x1ULL << 38)
+#define CE_URE_DNS_DAT_PAR_DISABLE (0x1ULL << 39)
+#define CE_URE_DNS_HDR_PAR_DISABLE (0x1ULL << 40)
+#define CE_URE_MALFORM_DISABLE (0x1ULL << 44)
+#define CE_URE_UNSUP_DISABLE (0x1ULL << 45)
+
+/* ce_ure_page_map register bit masks & shifts */
+#define CE_URE_ATE3240_ENABLE (0x1ULL << 0)
+#define CE_URE_ATE40_ENABLE (0x1ULL << 1)
+#define CE_URE_PAGESIZE_SHFT 4
+#define CE_URE_PAGESIZE_MASK (0x7ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_4K_PAGESIZE (0x0ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_16K_PAGESIZE (0x1ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_64K_PAGESIZE (0x2ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_128K_PAGESIZE (0x3ULL << CE_URE_PAGESIZE_SHFT)
+#define CE_URE_256K_PAGESIZE (0x4ULL << CE_URE_PAGESIZE_SHFT)
+
+/* ce_ure_pipe_sel register bit masks & shifts */
+#define PKT_TRAFIC_SHRT 16
+#define BUS_SRC_ID_SHFT 8
+#define DEV_SRC_ID_SHFT 3
+#define FNC_SRC_ID_SHFT 0
+#define CE_URE_TC_MASK (0x07ULL << PKT_TRAFIC_SHRT)
+#define CE_URE_BUS_MASK (0xFFULL << BUS_SRC_ID_SHFT)
+#define CE_URE_DEV_MASK (0x1FULL << DEV_SRC_ID_SHFT)
+#define CE_URE_FNC_MASK (0x07ULL << FNC_SRC_ID_SHFT)
+#define CE_URE_PIPE_BUS(b) (((uint64_t)(b) << BUS_SRC_ID_SHFT) & \
+ CE_URE_BUS_MASK)
+#define CE_URE_PIPE_DEV(d) (((uint64_t)(d) << DEV_SRC_ID_SHFT) & \
+ CE_URE_DEV_MASK)
+#define CE_URE_PIPE_FNC(f) (((uint64_t)(f) << FNC_SRC_ID_SHFT) & \
+ CE_URE_FNC_MASK)
+
+#define CE_URE_SEL1_SHFT 0
+#define CE_URE_SEL2_SHFT 20
+#define CE_URE_SEL3_SHFT 40
+#define CE_URE_SEL1_MASK (0x7FFFFULL << CE_URE_SEL1_SHFT)
+#define CE_URE_SEL2_MASK (0x7FFFFULL << CE_URE_SEL2_SHFT)
+#define CE_URE_SEL3_MASK (0x7FFFFULL << CE_URE_SEL3_SHFT)
+
+
+/* ce_ure_pipe_mask register bit masks & shifts */
+#define CE_URE_MASK1_SHFT 0
+#define CE_URE_MASK2_SHFT 20
+#define CE_URE_MASK3_SHFT 40
+#define CE_URE_MASK1_MASK (0x7FFFFULL << CE_URE_MASK1_SHFT)
+#define CE_URE_MASK2_MASK (0x7FFFFULL << CE_URE_MASK2_SHFT)
+#define CE_URE_MASK3_MASK (0x7FFFFULL << CE_URE_MASK3_SHFT)
+
+
+/* ce_ure_pcie_control1 register bit masks & shifts */
+#define CE_URE_SI (0x1ULL << 0)
+#define CE_URE_ELAL_SHFT 4
+#define CE_URE_ELAL_MASK (0x7ULL << CE_URE_ELAL_SHFT)
+#define CE_URE_ELAL1_SHFT 8
+#define CE_URE_ELAL1_MASK (0x7ULL << CE_URE_ELAL1_SHFT)
+#define CE_URE_SCC (0x1ULL << 12)
+#define CE_URE_PN1_SHFT 16
+#define CE_URE_PN1_MASK (0xFFULL << CE_URE_PN1_SHFT)
+#define CE_URE_PN2_SHFT 24
+#define CE_URE_PN2_MASK (0xFFULL << CE_URE_PN2_SHFT)
+#define CE_URE_PN1_SET(n) (((uint64_t)(n) << CE_URE_PN1_SHFT) & \
+ CE_URE_PN1_MASK)
+#define CE_URE_PN2_SET(n) (((uint64_t)(n) << CE_URE_PN2_SHFT) & \
+ CE_URE_PN2_MASK)
+
+/* ce_ure_pcie_control2 register bit masks & shifts */
+#define CE_URE_ABP (0x1ULL << 0)
+#define CE_URE_PCP (0x1ULL << 1)
+#define CE_URE_MSP (0x1ULL << 2)
+#define CE_URE_AIP (0x1ULL << 3)
+#define CE_URE_PIP (0x1ULL << 4)
+#define CE_URE_HPS (0x1ULL << 5)
+#define CE_URE_HPC (0x1ULL << 6)
+#define CE_URE_SPLV_SHFT 7
+#define CE_URE_SPLV_MASK (0xFFULL << CE_URE_SPLV_SHFT)
+#define CE_URE_SPLS_SHFT 15
+#define CE_URE_SPLS_MASK (0x3ULL << CE_URE_SPLS_SHFT)
+#define CE_URE_PSN1_SHFT 19
+#define CE_URE_PSN1_MASK (0x1FFFULL << CE_URE_PSN1_SHFT)
+#define CE_URE_PSN2_SHFT 32
+#define CE_URE_PSN2_MASK (0x1FFFULL << CE_URE_PSN2_SHFT)
+#define CE_URE_PSN1_SET(n) (((uint64_t)(n) << CE_URE_PSN1_SHFT) & \
+ CE_URE_PSN1_MASK)
+#define CE_URE_PSN2_SET(n) (((uint64_t)(n) << CE_URE_PSN2_SHFT) & \
+ CE_URE_PSN2_MASK)
+
+/*
+ * PIO address space ranges for CE
+ */
+
+/* Local CE Registers Space */
+#define CE_PIO_MMR 0x00000000
+#define CE_PIO_MMR_LEN 0x04000000
+
+/* PCI Compatible Config Space */
+#define CE_PIO_CONFIG_SPACE 0x04000000
+#define CE_PIO_CONFIG_SPACE_LEN 0x04000000
+
+/* PCI I/O Space Alias */
+#define CE_PIO_IO_SPACE_ALIAS 0x08000000
+#define CE_PIO_IO_SPACE_ALIAS_LEN 0x08000000
+
+/* PCI Enhanced Config Space */
+#define CE_PIO_E_CONFIG_SPACE 0x10000000
+#define CE_PIO_E_CONFIG_SPACE_LEN 0x10000000
+
+/* PCI I/O Space */
+#define CE_PIO_IO_SPACE 0x100000000
+#define CE_PIO_IO_SPACE_LEN 0x100000000
+
+/* PCI MEM Space */
+#define CE_PIO_MEM_SPACE 0x200000000
+#define CE_PIO_MEM_SPACE_LEN TIO_HWIN_SIZE
+
+
+/*
+ * CE PCI Enhanced Config Space shifts & masks
+ */
+#define CE_E_CONFIG_BUS_SHFT 20
+#define CE_E_CONFIG_BUS_MASK (0xFF << CE_E_CONFIG_BUS_SHFT)
+#define CE_E_CONFIG_DEVICE_SHFT 15
+#define CE_E_CONFIG_DEVICE_MASK (0x1F << CE_E_CONFIG_DEVICE_SHFT)
+#define CE_E_CONFIG_FUNC_SHFT 12
+#define CE_E_CONFIG_FUNC_MASK (0x7 << CE_E_CONFIG_FUNC_SHFT)
+
+#endif /* __ASM_IA64_SN_TIOCE_H__ */
diff --git a/include/asm-ia64/sn/tioce_provider.h b/include/asm-ia64/sn/tioce_provider.h
new file mode 100644
index 0000000..7f63dec
--- /dev/null
+++ b/include/asm-ia64/sn/tioce_provider.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+ * Copyright (C) 2005, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#ifndef _ASM_IA64_SN_CE_PROVIDER_H
+#define _ASM_IA64_SN_CE_PROVIDER_H
+
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioce.h>
+
+/*
+ * Common TIOCE structure shared between the prom and kernel
+ *
+ * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES TO THE
+ * PROM VERSION.
+ */
+struct tioce_common {
+ struct pcibus_bussoft ce_pcibus; /* common pciio header */
+
+ uint32_t ce_rev;
+ uint64_t ce_kernel_private;
+ uint64_t ce_prom_private;
+};
+
+struct tioce_kernel {
+ struct tioce_common *ce_common;
+ spinlock_t ce_lock;
+ struct list_head ce_dmamap_list;
+
+ uint64_t ce_ate40_shadow[TIOCE_NUM_M40_ATES];
+ uint64_t ce_ate3240_shadow[TIOCE_NUM_M3240_ATES];
+ uint32_t ce_ate3240_pagesize;
+
+ uint8_t ce_port1_secondary;
+
+ /* per-port resources */
+ struct {
+ int dirmap_refcnt;
+ uint64_t dirmap_shadow;
+ } ce_port[TIOCE_NUM_PORTS];
+};
+
+struct tioce_dmamap {
+ struct list_head ce_dmamap_list; /* headed by tioce_kernel */
+ uint32_t refcnt;
+
+ uint64_t nbytes; /* # bytes mapped */
+
+ uint64_t ct_start; /* coretalk start address */
+ uint64_t pci_start; /* bus start address */
+
+ uint64_t *ate_hw; /* hw ptr of first ate in map */
+ uint64_t *ate_shadow; /* shadow ptr of firat ate */
+ uint16_t ate_count; /* # ate's in the map */
+};
+
+extern int tioce_init_provider(void);
+
+#endif /* __ASM_IA64_SN_CE_PROVIDER_H */
diff --git a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h
index 909936f..d2430aa 100644
--- a/include/asm-ia64/spinlock.h
+++ b/include/asm-ia64/spinlock.h
@@ -93,7 +93,15 @@
# endif /* CONFIG_MCKINLEY */
#endif
}
+
#define _raw_spin_lock(lock) _raw_spin_lock_flags(lock, 0)
+
+/* Unlock by doing an ordered store and releasing the cacheline with nta */
+static inline void _raw_spin_unlock(spinlock_t *x) {
+ barrier();
+ asm volatile ("st4.rel.nta [%0] = r0\n\t" :: "r"(x));
+}
+
#else /* !ASM_SUPPORTED */
#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
# define _raw_spin_lock(x) \
@@ -109,16 +117,16 @@
} while (ia64_spinlock_val); \
} \
} while (0)
+#define _raw_spin_unlock(x) do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0)
#endif /* !ASM_SUPPORTED */
#define spin_is_locked(x) ((x)->lock != 0)
-#define _raw_spin_unlock(x) do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0)
#define _raw_spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0)
#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock)
typedef struct {
- volatile unsigned int read_counter : 31;
- volatile unsigned int write_lock : 1;
+ volatile unsigned int read_counter : 24;
+ volatile unsigned int write_lock : 8;
#ifdef CONFIG_PREEMPT
unsigned int break_lock;
#endif
@@ -174,6 +182,13 @@
(result == 0); \
})
+static inline void _raw_write_unlock(rwlock_t *x)
+{
+ u8 *y = (u8 *)x;
+ barrier();
+ asm volatile ("st1.rel.nta [%0] = r0\n\t" :: "r"(y+3) : "memory" );
+}
+
#else /* !ASM_SUPPORTED */
#define _raw_write_lock(l) \
@@ -195,14 +210,14 @@
(ia64_val == 0); \
})
+static inline void _raw_write_unlock(rwlock_t *x)
+{
+ barrier();
+ x->write_lock = 0;
+}
+
#endif /* !ASM_SUPPORTED */
#define _raw_read_trylock(lock) generic_raw_read_trylock(lock)
-#define _raw_write_unlock(x) \
-({ \
- smp_mb__before_clear_bit(); /* need barrier before releasing lock... */ \
- clear_bit(31, (x)); \
-})
-
#endif /* _ASM_IA64_SPINLOCK_H */
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
index cd2cf76..33256db 100644
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -19,12 +19,13 @@
#include <asm/pal.h>
#include <asm/percpu.h>
-#define GATE_ADDR __IA64_UL_CONST(0xa000000000000000)
+#define GATE_ADDR RGN_BASE(RGN_GATE)
+
/*
* 0xa000000000000000+2*PERCPU_PAGE_SIZE
* - 0xa000000000000000+3*PERCPU_PAGE_SIZE remain unmapped (guard page)
*/
-#define KERNEL_START __IA64_UL_CONST(0xa000000100000000)
+#define KERNEL_START (GATE_ADDR+0x100000000)
#define PERCPU_ADDR (-PERCPU_PAGE_SIZE)
#ifndef __ASSEMBLY__
diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
index 399bc29..a9f738b 100644
--- a/include/asm-ia64/topology.h
+++ b/include/asm-ia64/topology.h
@@ -98,29 +98,6 @@
.nr_balance_failed = 0, \
}
-/* sched_domains SD_ALLNODES_INIT for IA64 NUMA machines */
-#define SD_ALLNODES_INIT (struct sched_domain) { \
- .span = CPU_MASK_NONE, \
- .parent = NULL, \
- .groups = NULL, \
- .min_interval = 64, \
- .max_interval = 64*num_online_cpus(), \
- .busy_factor = 128, \
- .imbalance_pct = 133, \
- .cache_hot_time = (10*1000000), \
- .cache_nice_tries = 1, \
- .busy_idx = 3, \
- .idle_idx = 3, \
- .newidle_idx = 0, /* unused */ \
- .wake_idx = 0, /* unused */ \
- .forkexec_idx = 0, /* unused */ \
- .per_cpu_gain = 100, \
- .flags = SD_LOAD_BALANCE, \
- .last_balance = jiffies, \
- .balance_interval = 64, \
- .nr_balance_failed = 0, \
-}
-
#endif /* CONFIG_NUMA */
#include <asm-generic/topology.h>
diff --git a/include/asm-ia64/types.h b/include/asm-ia64/types.h
index a677565..902850d 100644
--- a/include/asm-ia64/types.h
+++ b/include/asm-ia64/types.h
@@ -67,8 +67,6 @@
typedef u64 dma_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
# endif /* __KERNEL__ */
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
index 8edd9a9..3a7829b 100644
--- a/include/asm-ia64/uaccess.h
+++ b/include/asm-ia64/uaccess.h
@@ -72,13 +72,6 @@
})
#define access_ok(type, addr, size) __access_ok((addr), (size), get_fs())
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated
-verify_area (int type, const void __user *addr, unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
diff --git a/include/asm-m32r/auxvec.h b/include/asm-m32r/auxvec.h
new file mode 100644
index 0000000..f76dcc8
--- /dev/null
+++ b/include/asm-m32r/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_M32R__AUXVEC_H
+#define _ASM_M32R__AUXVEC_H
+
+#endif /* _ASM_M32R__AUXVEC_H */
diff --git a/include/asm-m32r/fcntl.h b/include/asm-m32r/fcntl.h
index 3e30895..46ab12d 100644
--- a/include/asm-m32r/fcntl.h
+++ b/include/asm-m32r/fcntl.h
@@ -1,92 +1 @@
-#ifndef _ASM_M32R_FCNTL_H
-#define _ASM_M32R_FCNTL_H
-
-/* $Id$ */
-
-/* orig : i386 2.4.18 */
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-
-#endif /* _ASM_M32R_FCNTL_H */
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-m32r/futex.h b/include/asm-m32r/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-m32r/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-m32r/hdreg.h b/include/asm-m32r/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-m32r/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-m32r/page.h b/include/asm-m32r/page.h
index 1c6abb9..4ab5788 100644
--- a/include/asm-m32r/page.h
+++ b/include/asm-m32r/page.h
@@ -61,25 +61,6 @@
/* This handles the memory map.. */
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size - 1) >> (PAGE_SHIFT - 1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
-
- return order;
-}
-
-#endif /* __ASSEMBLY__ */
-
#define __MEMORY_START CONFIG_MEMORY_START
#define __MEMORY_SIZE CONFIG_MEMORY_SIZE
@@ -111,5 +92,7 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _ASM_M32R_PAGE_H */
diff --git a/include/asm-m32r/types.h b/include/asm-m32r/types.h
index ca0a887..fcf24c6 100644
--- a/include/asm-m32r/types.h
+++ b/include/asm-m32r/types.h
@@ -55,8 +55,6 @@
typedef u32 dma_addr_t;
typedef u64 dma64_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-m32r/uaccess.h b/include/asm-m32r/uaccess.h
index bbb8ac4..93d863c 100644
--- a/include/asm-m32r/uaccess.h
+++ b/include/asm-m32r/uaccess.h
@@ -120,31 +120,6 @@
}
#endif /* CONFIG_MMU */
-/**
- * verify_area: - Obsolete/deprecated and will go away soon,
- * use access_ok() instead.
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only. This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int __deprecated verify_area(int type, const void __user *addr,
- unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-m68k/auxvec.h b/include/asm-m68k/auxvec.h
new file mode 100644
index 0000000..844d6d5
--- /dev/null
+++ b/include/asm-m68k/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMm68k_AUXVEC_H
+#define __ASMm68k_AUXVEC_H
+
+#endif
diff --git a/include/asm-m68k/cacheflush.h b/include/asm-m68k/cacheflush.h
index e477394..8aba971 100644
--- a/include/asm-m68k/cacheflush.h
+++ b/include/asm-m68k/cacheflush.h
@@ -130,20 +130,25 @@
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
#define flush_icache_page(vma, page) __flush_page_to_ram(page_address(page))
-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
- do { \
- flush_cache_page(vma, vaddr, page_to_pfn(page));\
- memcpy(dst, src, len); \
- } while (0)
-
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
- do { \
- flush_cache_page(vma, vaddr, page_to_pfn(page));\
- memcpy(dst, src, len); \
- } while (0)
-
+extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+ unsigned long addr, int len);
extern void flush_icache_range(unsigned long address, unsigned long endaddr);
+static inline void copy_to_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr,
+ void *dst, void *src, int len)
+{
+ flush_cache_page(vma, vaddr, page_to_pfn(page));
+ memcpy(dst, src, len);
+ flush_icache_user_range(vma, page, vaddr, len);
+}
+static inline void copy_from_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr,
+ void *dst, void *src, int len)
+{
+ flush_cache_page(vma, vaddr, page_to_pfn(page));
+ memcpy(dst, src, len);
+}
+
#endif /* _M68K_CACHEFLUSH_H */
diff --git a/include/asm-m68k/fcntl.h b/include/asm-m68k/fcntl.h
index 0d42129..1c369b2 100644
--- a/include/asm-m68k/fcntl.h
+++ b/include/asm-m68k/fcntl.h
@@ -1,87 +1,11 @@
#ifndef _M68K_FCNTL_H
#define _M68K_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0400000
-#define O_NOATIME 01000000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
+#include <asm-generic/fcntl.h>
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
#endif /* _M68K_FCNTL_H */
diff --git a/include/asm-m68k/futex.h b/include/asm-m68k/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-m68k/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-m68k/hdreg.h b/include/asm-m68k/hdreg.h
deleted file mode 100644
index 5989bbc..0000000
--- a/include/asm-m68k/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
diff --git a/include/asm-m68k/page.h b/include/asm-m68k/page.h
index 206313e..f206dfb 100644
--- a/include/asm-m68k/page.h
+++ b/include/asm-m68k/page.h
@@ -107,20 +107,6 @@
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#endif /* !__ASSEMBLY__ */
#include <asm/page_offset.h>
@@ -192,4 +178,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _M68K_PAGE_H */
diff --git a/include/asm-m68k/string.h b/include/asm-m68k/string.h
index 44def07..6c59215 100644
--- a/include/asm-m68k/string.h
+++ b/include/asm-m68k/string.h
@@ -80,43 +80,6 @@
return( (char *) s);
}
-#if 0
-#define __HAVE_ARCH_STRPBRK
-static inline char *strpbrk(const char *cs,const char *ct)
-{
- const char *sc1,*sc2;
-
- for( sc1 = cs; *sc1 != '\0'; ++sc1)
- for( sc2 = ct; *sc2 != '\0'; ++sc2)
- if (*sc1 == *sc2)
- return((char *) sc1);
- return( NULL );
-}
-#endif
-
-#if 0
-#define __HAVE_ARCH_STRSPN
-static inline size_t strspn(const char *s, const char *accept)
-{
- const char *p;
- const char *a;
- size_t count = 0;
-
- for (p = s; *p != '\0'; ++p)
- {
- for (a = accept; *a != '\0'; ++a)
- if (*p == *a)
- break;
- if (*a == '\0')
- return count;
- else
- ++count;
- }
-
- return count;
-}
-#endif
-
/* strstr !! */
#define __HAVE_ARCH_STRLEN
@@ -173,370 +136,18 @@
}
#define __HAVE_ARCH_MEMSET
-/*
- * This is really ugly, but its highly optimizatiable by the
- * compiler and is meant as compensation for gcc's missing
- * __builtin_memset(). For the 680[23]0 it might be worth considering
- * the optimal number of misaligned writes compared to the number of
- * tests'n'branches needed to align the destination address. The
- * 680[46]0 doesn't really care due to their copy-back caches.
- * 10/09/96 - Jes Sorensen
- */
-static inline void * __memset_g(void * s, int c, size_t count)
-{
- void *xs = s;
- size_t temp;
-
- if (!count)
- return xs;
-
- c &= 0xff;
- c |= c << 8;
- c |= c << 16;
-
- if (count < 36){
- long *ls = s;
-
- switch(count){
- case 32: case 33: case 34: case 35:
- *ls++ = c;
- case 28: case 29: case 30: case 31:
- *ls++ = c;
- case 24: case 25: case 26: case 27:
- *ls++ = c;
- case 20: case 21: case 22: case 23:
- *ls++ = c;
- case 16: case 17: case 18: case 19:
- *ls++ = c;
- case 12: case 13: case 14: case 15:
- *ls++ = c;
- case 8: case 9: case 10: case 11:
- *ls++ = c;
- case 4: case 5: case 6: case 7:
- *ls++ = c;
- break;
- default:
- break;
- }
- s = ls;
- if (count & 0x02){
- short *ss = s;
- *ss++ = c;
- s = ss;
- }
- if (count & 0x01){
- char *cs = s;
- *cs++ = c;
- s = cs;
- }
- return xs;
- }
-
- if ((long) s & 1)
- {
- char *cs = s;
- *cs++ = c;
- s = cs;
- count--;
- }
- if (count > 2 && (long) s & 2)
- {
- short *ss = s;
- *ss++ = c;
- s = ss;
- count -= 2;
- }
- temp = count >> 2;
- if (temp)
- {
- long *ls = s;
- temp--;
- do
- *ls++ = c;
- while (temp--);
- s = ls;
- }
- if (count & 2)
- {
- short *ss = s;
- *ss++ = c;
- s = ss;
- }
- if (count & 1)
- {
- char *cs = s;
- *cs = c;
- }
- return xs;
-}
-
-/*
- * __memset_page assumes that data is longword aligned. Most, if not
- * all, of these page sized memsets are performed on page aligned
- * areas, thus we do not need to check if the destination is longword
- * aligned. Of course we suffer a serious performance loss if this is
- * not the case but I think the risk of this ever happening is
- * extremely small. We spend a lot of time clearing pages in
- * get_empty_page() so I think it is worth it anyway. Besides, the
- * 680[46]0 do not really care about misaligned writes due to their
- * copy-back cache.
- *
- * The optimized case for the 680[46]0 is implemented using the move16
- * instruction. My tests showed that this implementation is 35-45%
- * faster than the original implementation using movel, the only
- * caveat is that the destination address must be 16-byte aligned.
- * 01/09/96 - Jes Sorensen
- */
-static inline void * __memset_page(void * s,int c,size_t count)
-{
- unsigned long data, tmp;
- void *xs = s;
-
- c = c & 255;
- data = c | (c << 8);
- data |= data << 16;
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
- if (((unsigned long) s) & 0x0f)
- __memset_g(s, c, count);
- else{
- unsigned long *sp = s;
- *sp++ = data;
- *sp++ = data;
- *sp++ = data;
- *sp++ = data;
-
- __asm__ __volatile__("1:\t"
- ".chip 68040\n\t"
- "move16 %2@+,%0@+\n\t"
- ".chip 68k\n\t"
- "subqw #8,%2\n\t"
- "subqw #8,%2\n\t"
- "dbra %1,1b\n\t"
- : "=a" (sp), "=d" (tmp)
- : "a" (s), "0" (sp), "1" ((count - 16) / 16 - 1)
- );
- }
-
-#else
- __asm__ __volatile__("1:\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "movel %2,%0@+\n\t"
- "dbra %1,1b\n\t"
- : "=a" (s), "=d" (tmp)
- : "d" (data), "0" (s), "1" (count / 32 - 1)
- );
-#endif
-
- return xs;
-}
-
-extern void *memset(void *,int,__kernel_size_t);
-
-#define __memset_const(s,c,count) \
-((count==PAGE_SIZE) ? \
- __memset_page((s),(c),(count)) : \
- __memset_g((s),(c),(count)))
-
-#define memset(s, c, count) \
-(__builtin_constant_p(count) ? \
- __memset_const((s),(c),(count)) : \
- __memset_g((s),(c),(count)))
+extern void *memset(void *, int, __kernel_size_t);
+#define memset(d, c, n) __builtin_memset(d, c, n)
#define __HAVE_ARCH_MEMCPY
-extern void * memcpy(void *, const void *, size_t );
-/*
- * __builtin_memcpy() does not handle page-sized memcpys very well,
- * thus following the same assumptions as for page-sized memsets, this
- * function copies page-sized areas using an unrolled loop, without
- * considering alignment.
- *
- * For the 680[46]0 only kernels we use the move16 instruction instead
- * as it writes through the data-cache, invalidating the cache-lines
- * touched. In this way we do not use up the entire data-cache (well,
- * half of it on the 68060) by copying a page. An unrolled loop of two
- * move16 instructions seem to the fastest. The only caveat is that
- * both source and destination must be 16-byte aligned, if not we fall
- * back to the generic memcpy function. - Jes
- */
-static inline void * __memcpy_page(void * to, const void * from, size_t count)
-{
- unsigned long tmp;
- void *xto = to;
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
- if (((unsigned long) to | (unsigned long) from) & 0x0f)
- return memcpy(to, from, count);
-
- __asm__ __volatile__("1:\t"
- ".chip 68040\n\t"
- "move16 %1@+,%0@+\n\t"
- "move16 %1@+,%0@+\n\t"
- ".chip 68k\n\t"
- "dbra %2,1b\n\t"
- : "=a" (to), "=a" (from), "=d" (tmp)
- : "0" (to), "1" (from) , "2" (count / 32 - 1)
- );
-#else
- __asm__ __volatile__("1:\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+\n\t"
- "dbra %2,1b\n\t"
- : "=a" (to), "=a" (from), "=d" (tmp)
- : "0" (to), "1" (from) , "2" (count / 32 - 1)
- );
-#endif
- return xto;
-}
-
-#define __memcpy_const(to, from, n) \
-((n==PAGE_SIZE) ? \
- __memcpy_page((to),(from),(n)) : \
- __builtin_memcpy((to),(from),(n)))
-
-#define memcpy(to, from, n) \
-(__builtin_constant_p(n) ? \
- __memcpy_const((to),(from),(n)) : \
- memcpy((to),(from),(n)))
+extern void *memcpy(void *, const void *, __kernel_size_t);
+#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
#define __HAVE_ARCH_MEMMOVE
-static inline void * memmove(void * dest,const void * src, size_t n)
-{
- void *xdest = dest;
- size_t temp;
-
- if (!n)
- return xdest;
-
- if (dest < src)
- {
- if ((long) dest & 1)
- {
- char *cdest = dest;
- const char *csrc = src;
- *cdest++ = *csrc++;
- dest = cdest;
- src = csrc;
- n--;
- }
- if (n > 2 && (long) dest & 2)
- {
- short *sdest = dest;
- const short *ssrc = src;
- *sdest++ = *ssrc++;
- dest = sdest;
- src = ssrc;
- n -= 2;
- }
- temp = n >> 2;
- if (temp)
- {
- long *ldest = dest;
- const long *lsrc = src;
- temp--;
- do
- *ldest++ = *lsrc++;
- while (temp--);
- dest = ldest;
- src = lsrc;
- }
- if (n & 2)
- {
- short *sdest = dest;
- const short *ssrc = src;
- *sdest++ = *ssrc++;
- dest = sdest;
- src = ssrc;
- }
- if (n & 1)
- {
- char *cdest = dest;
- const char *csrc = src;
- *cdest = *csrc;
- }
- }
- else
- {
- dest = (char *) dest + n;
- src = (const char *) src + n;
- if ((long) dest & 1)
- {
- char *cdest = dest;
- const char *csrc = src;
- *--cdest = *--csrc;
- dest = cdest;
- src = csrc;
- n--;
- }
- if (n > 2 && (long) dest & 2)
- {
- short *sdest = dest;
- const short *ssrc = src;
- *--sdest = *--ssrc;
- dest = sdest;
- src = ssrc;
- n -= 2;
- }
- temp = n >> 2;
- if (temp)
- {
- long *ldest = dest;
- const long *lsrc = src;
- temp--;
- do
- *--ldest = *--lsrc;
- while (temp--);
- dest = ldest;
- src = lsrc;
- }
- if (n & 2)
- {
- short *sdest = dest;
- const short *ssrc = src;
- *--sdest = *--ssrc;
- dest = sdest;
- src = ssrc;
- }
- if (n & 1)
- {
- char *cdest = dest;
- const char *csrc = src;
- *--cdest = *--csrc;
- }
- }
- return xdest;
-}
+extern void *memmove(void *, const void *, __kernel_size_t);
#define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void * ,const void * ,size_t );
-#define memcmp(cs, ct, n) \
-(__builtin_constant_p(n) ? \
- __builtin_memcmp((cs),(ct),(n)) : \
- memcmp((cs),(ct),(n)))
-
-#define __HAVE_ARCH_MEMCHR
-static inline void *memchr(const void *cs, int c, size_t count)
-{
- /* Someone else can optimize this, I don't care - tonym@mac.linux-m68k.org */
- unsigned char *ret = (unsigned char *)cs;
- for(;count>0;count--,ret++)
- if(*ret == c) return ret;
-
- return NULL;
-}
+extern int memcmp(const void *, const void *, __kernel_size_t);
+#define memcmp(d, s, n) __builtin_memcmp(d, s, n)
#endif /* _M68K_STRING_H_ */
diff --git a/include/asm-m68k/types.h b/include/asm-m68k/types.h
index f391cbe..b5a1feb 100644
--- a/include/asm-m68k/types.h
+++ b/include/asm-m68k/types.h
@@ -60,8 +60,6 @@
typedef u32 dma_addr_t;
typedef u32 dma64_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
index 605e6cb..f5cedf1 100644
--- a/include/asm-m68k/uaccess.h
+++ b/include/asm-m68k/uaccess.h
@@ -14,12 +14,6 @@
/* We let the MMU do all checking */
#define access_ok(type,addr,size) 1
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void *addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-m68knommu/auxvec.h b/include/asm-m68knommu/auxvec.h
new file mode 100644
index 0000000..844d6d5
--- /dev/null
+++ b/include/asm-m68knommu/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMm68k_AUXVEC_H
+#define __ASMm68k_AUXVEC_H
+
+#endif
diff --git a/include/asm-m68knommu/futex.h b/include/asm-m68knommu/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-m68knommu/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-m68knommu/hdreg.h b/include/asm-m68knommu/hdreg.h
deleted file mode 100644
index 5cdd9b0..0000000
--- a/include/asm-m68knommu/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-m68k/hdreg.h>
diff --git a/include/asm-m68knommu/page.h b/include/asm-m68knommu/page.h
index 05e03df..942dfbe 100644
--- a/include/asm-m68knommu/page.h
+++ b/include/asm-m68knommu/page.h
@@ -48,20 +48,6 @@
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
extern unsigned long memory_start;
extern unsigned long memory_end;
@@ -73,8 +59,8 @@
#ifndef __ASSEMBLY__
-#define __pa(vaddr) virt_to_phys((void *)vaddr)
-#define __va(paddr) phys_to_virt((unsigned long)paddr)
+#define __pa(vaddr) virt_to_phys((void *)(vaddr))
+#define __va(paddr) phys_to_virt((unsigned long)(paddr))
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
@@ -84,6 +70,7 @@
#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn))
#define page_to_pfn(page) virt_to_pfn(page_to_virt(page))
+#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
((void *)(kaddr) < (void *)memory_end))
@@ -92,4 +79,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _M68KNOMMU_PAGE_H */
diff --git a/include/asm-m68knommu/uaccess.h b/include/asm-m68knommu/uaccess.h
index f0be74b..05be951 100644
--- a/include/asm-m68knommu/uaccess.h
+++ b/include/asm-m68knommu/uaccess.h
@@ -23,12 +23,6 @@
(is_in_rom(addr) && is_in_rom(addr+size)));
}
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
- return access_ok(type,addr,size)?0:-EFAULT;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-mips/a.out.h b/include/asm-mips/a.out.h
index e42b309..2b3dc3b 100644
--- a/include/asm-mips/a.out.h
+++ b/include/asm-mips/a.out.h
@@ -35,10 +35,10 @@
#ifdef __KERNEL__
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define STACK_TOP TASK_SIZE
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define STACK_TOP (current->thread.mflags & MF_32BIT_ADDR ? TASK_SIZE32 : TASK_SIZE)
#endif
diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h
index 2caa8c4..7dc2619 100644
--- a/include/asm-mips/addrspace.h
+++ b/include/asm-mips/addrspace.h
@@ -48,7 +48,7 @@
#define CPHYSADDR(a) ((_ACAST32_ (a)) & 0x1fffffff)
#define XPHYSADDR(a) ((_ACAST64_ (a)) & 0x000000ffffffffff)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* Memory segments (64bit kernel mode addresses)
diff --git a/include/asm-mips/asmmacro.h b/include/asm-mips/asmmacro.h
index 37a460a..30b18ea 100644
--- a/include/asm-mips/asmmacro.h
+++ b/include/asm-mips/asmmacro.h
@@ -7,14 +7,14 @@
*/
#ifndef _ASM_ASMMACRO_H
#define _ASM_ASMMACRO_H
-
+
#include <linux/config.h>
#include <asm/hazards.h>
-
-#ifdef CONFIG_MIPS32
+
+#ifdef CONFIG_32BIT
#include <asm/asmmacro-32.h>
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#include <asm/asmmacro-64.h>
#endif
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 7d89e87..c0bd8d0 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -334,7 +334,7 @@
*/
#define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
typedef struct { volatile __s64 counter; } atomic64_t;
@@ -639,7 +639,7 @@
*/
#define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0)
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/*
* atomic*_return operations are serializing but not the non-*_return
diff --git a/include/asm-mips/auxvec.h b/include/asm-mips/auxvec.h
new file mode 100644
index 0000000..7cf7f2d
--- /dev/null
+++ b/include/asm-mips/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_AUXVEC_H
+#define _ASM_AUXVEC_H
+
+#endif /* _ASM_AUXVEC_H */
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index 779d218..eb8d79d 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -20,13 +20,13 @@
#define SZLONG_MASK 31UL
#define __LL "ll "
#define __SC "sc "
-#define cpu_to_lelongp(x) cpu_to_le32p((__u32 *) (x))
+#define cpu_to_lelongp(x) cpu_to_le32p((__u32 *) (x))
#elif (_MIPS_SZLONG == 64)
#define SZLONG_LOG 6
#define SZLONG_MASK 63UL
#define __LL "lld "
#define __SC "scd "
-#define cpu_to_lelongp(x) cpu_to_le64p((__u64 *) (x))
+#define cpu_to_lelongp(x) cpu_to_le64p((__u64 *) (x))
#endif
#ifdef __KERNEL__
@@ -533,14 +533,14 @@
int b = 0, s;
word = ~word;
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
s = 16; if (word << 16 != 0) s = 0; b += s; word >>= s;
s = 8; if (word << 24 != 0) s = 0; b += s; word >>= s;
s = 4; if (word << 28 != 0) s = 0; b += s; word >>= s;
s = 2; if (word << 30 != 0) s = 0; b += s; word >>= s;
s = 1; if (word << 31 != 0) s = 0; b += s;
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
s = 32; if (word << 32 != 0) s = 0; b += s; word >>= s;
s = 16; if (word << 48 != 0) s = 0; b += s; word >>= s;
s = 8; if (word << 56 != 0) s = 0; b += s; word >>= s;
@@ -683,7 +683,7 @@
*/
static inline int sched_find_first_bit(const unsigned long *b)
{
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
if (unlikely(b[0]))
return __ffs(b[0]);
if (unlikely(b[1]))
@@ -694,7 +694,7 @@
return __ffs(b[3]) + 96;
return __ffs(b[4]) + 128;
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
if (unlikely(b[0]))
return __ffs(b[0]);
if (unlikely(b[1]))
diff --git a/include/asm-mips/bugs.h b/include/asm-mips/bugs.h
index 18cced1..b14b961 100644
--- a/include/asm-mips/bugs.h
+++ b/include/asm-mips/bugs.h
@@ -15,7 +15,7 @@
static inline void check_bugs(void)
{
check_bugs32();
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
check_bugs64();
#endif
}
diff --git a/include/asm-mips/checksum.h b/include/asm-mips/checksum.h
index c25cc92..c1ea5a8 100644
--- a/include/asm-mips/checksum.h
+++ b/include/asm-mips/checksum.h
@@ -128,7 +128,7 @@
{
__asm__(
".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t"
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
"addu\t%0, %2\n\t"
"sltu\t$1, %0, %2\n\t"
"addu\t%0, $1\n\t"
@@ -141,7 +141,7 @@
"sltu\t$1, %0, %4\n\t"
"addu\t%0, $1\n\t"
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
"daddu\t%0, %2\n\t"
"daddu\t%0, %3\n\t"
"daddu\t%0, %4\n\t"
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index d78002a..2c084cd 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -15,8 +15,10 @@
typedef s32 compat_suseconds_t;
typedef s32 compat_pid_t;
-typedef s32 compat_uid_t;
-typedef s32 compat_gid_t;
+typedef u32 __compat_uid_t;
+typedef u32 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u32 compat_mode_t;
typedef u32 compat_ino_t;
typedef u32 compat_dev_t;
@@ -52,8 +54,8 @@
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid32_t st_uid;
+ __compat_gid32_t st_gid;
compat_dev_t st_rdev;
s32 st_pad2[2];
compat_off_t st_size;
diff --git a/include/asm-mips/cpu-features.h b/include/asm-mips/cpu-features.h
index 1df2c29..9a2de64 100644
--- a/include/asm-mips/cpu-features.h
+++ b/include/asm-mips/cpu-features.h
@@ -106,7 +106,7 @@
#define PLAT_TRAMPOLINE_STUFF_LINE 0UL
#endif
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
# ifndef cpu_has_nofpuex
# define cpu_has_nofpuex (cpu_data[0].options & MIPS_CPU_NOFPUEX)
# endif
@@ -124,7 +124,7 @@
# endif
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
# ifndef cpu_has_nofpuex
# define cpu_has_nofpuex 0
# endif
diff --git a/include/asm-mips/ddb5xxx/ddb5477.h b/include/asm-mips/ddb5xxx/ddb5477.h
index ae3e2a3..a438548 100644
--- a/include/asm-mips/ddb5xxx/ddb5477.h
+++ b/include/asm-mips/ddb5xxx/ddb5477.h
@@ -247,7 +247,7 @@
* All PCI irq but INTC are active low.
*/
-/*
+/*
* irq number block assignment
*/
@@ -285,7 +285,7 @@
#define VRC5477_IRQ_IOPCI_INTB (17 + VRC5477_IRQ_BASE) /* USB-P */
#define VRC5477_IRQ_IOPCI_INTC (18 + VRC5477_IRQ_BASE) /* AC97 */
#define VRC5477_IRQ_IOPCI_INTD (19 + VRC5477_IRQ_BASE) /* Reserved */
-#define VRC5477_IRQ_UART1 (20 + VRC5477_IRQ_BASE)
+#define VRC5477_IRQ_UART1 (20 + VRC5477_IRQ_BASE)
#define VRC5477_IRQ_SPT0 (21 + VRC5477_IRQ_BASE) /* special purpose timer 0 */
#define VRC5477_IRQ_GPT0 (22 + VRC5477_IRQ_BASE) /* general purpose timer 0 */
#define VRC5477_IRQ_GPT1 (23 + VRC5477_IRQ_BASE) /* general purpose timer 1 */
@@ -301,7 +301,7 @@
/*
* i2859 irq assignment
*/
-#define I8259_IRQ_RESERVED_0 (0 + I8259_IRQ_BASE)
+#define I8259_IRQ_RESERVED_0 (0 + I8259_IRQ_BASE)
#define I8259_IRQ_KEYBOARD (1 + I8259_IRQ_BASE) /* M1543 default */
#define I8259_IRQ_CASCADE (2 + I8259_IRQ_BASE)
#define I8259_IRQ_UART_B (3 + I8259_IRQ_BASE) /* M1543 default, may conflict with RTC according to schematic diagram */
diff --git a/include/asm-mips/dec/prom.h b/include/asm-mips/dec/prom.h
index b63e2f2..a05d6d3 100644
--- a/include/asm-mips/dec/prom.h
+++ b/include/asm-mips/dec/prom.h
@@ -48,15 +48,15 @@
*/
#define REX_PROM_MAGIC 0x30464354
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define prom_is_rex(magic) 1 /* KN04 and KN05 are REX PROMs. */
-#else /* !CONFIG_MIPS64 */
+#else /* !CONFIG_64BIT */
#define prom_is_rex(magic) ((magic) == REX_PROM_MAGIC)
-#endif /* !CONFIG_MIPS64 */
+#endif /* !CONFIG_64BIT */
/*
@@ -105,7 +105,7 @@
extern int (*__pmax_close)(int);
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* On MIPS64 we have to call PROM functions via a helper
@@ -138,7 +138,7 @@
#define prom_getenv(x) _prom_getenv(__prom_getenv, x)
#define prom_printf(x...) _prom_printf(__prom_printf, x)
-#else /* !CONFIG_MIPS64 */
+#else /* !CONFIG_64BIT */
/*
* On plain MIPS we just call PROM functions directly.
@@ -160,7 +160,7 @@
#define pmax_read __pmax_read
#define pmax_close __pmax_close
-#endif /* !CONFIG_MIPS64 */
+#endif /* !CONFIG_64BIT */
extern void prom_meminit(u32);
diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h
index d0f6844..a606dbe 100644
--- a/include/asm-mips/delay.h
+++ b/include/asm-mips/delay.h
@@ -57,11 +57,11 @@
* The common rates of 1000 and 128 are rounded wrongly by the
* catchall case for 64-bit. Excessive precission? Probably ...
*/
-#if defined(CONFIG_MIPS64) && (HZ == 128)
+#if defined(CONFIG_64BIT) && (HZ == 128)
usecs *= 0x0008637bd05af6c7UL; /* 2**64 / (1000000 / HZ) */
-#elif defined(CONFIG_MIPS64) && (HZ == 1000)
+#elif defined(CONFIG_64BIT) && (HZ == 1000)
usecs *= 0x004189374BC6A7f0UL; /* 2**64 / (1000000 / HZ) */
-#elif defined(CONFIG_MIPS64)
+#elif defined(CONFIG_64BIT)
usecs *= (0x8000000000000000UL / (500000 / HZ));
#else /* 32-bit junk follows here */
usecs *= (unsigned long) (((0x8000000000000000ULL / (500000 / HZ)) +
diff --git a/include/asm-mips/elf.h b/include/asm-mips/elf.h
index 7b92c80..e488114 100644
--- a/include/asm-mips/elf.h
+++ b/include/asm-mips/elf.h
@@ -125,7 +125,7 @@
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
/*
* This is used to ensure we don't load something for the wrong architecture.
@@ -153,9 +153,9 @@
*/
#define ELF_CLASS ELFCLASS32
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
@@ -177,7 +177,7 @@
*/
#define ELF_CLASS ELFCLASS64
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/*
* These are used to set parameters in the core dumps.
@@ -193,7 +193,7 @@
#ifdef __KERNEL__
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define SET_PERSONALITY(ex, ibcs2) \
do { \
@@ -202,9 +202,9 @@
set_personality(PER_LINUX); \
} while (0)
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define SET_PERSONALITY(ex, ibcs2) \
do { current->thread.mflags &= ~MF_ABI_MASK; \
@@ -222,7 +222,7 @@
set_personality(PER_LINUX); \
} while (0)
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
extern void dump_regs(elf_greg_t *, struct pt_regs *regs);
extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
diff --git a/include/asm-mips/fcntl.h b/include/asm-mips/fcntl.h
index 2436392..06c5d13 100644
--- a/include/asm-mips/fcntl.h
+++ b/include/asm-mips/fcntl.h
@@ -8,33 +8,16 @@
#ifndef _ASM_FCNTL_H
#define _ASM_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0x0003
-#define O_RDONLY 0x0000
-#define O_WRONLY 0x0001
-#define O_RDWR 0x0002
#define O_APPEND 0x0008
#define O_SYNC 0x0010
#define O_NONBLOCK 0x0080
#define O_CREAT 0x0100 /* not fcntl */
-#define O_TRUNC 0x0200 /* not fcntl */
#define O_EXCL 0x0400 /* not fcntl */
#define O_NOCTTY 0x0800 /* not fcntl */
#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
#define O_LARGEFILE 0x2000 /* allow large file opens */
#define O_DIRECT 0x8000 /* direct disk access hint */
-#define O_DIRECTORY 0x10000 /* must be a directory */
-#define O_NOFOLLOW 0x20000 /* don't follow links */
-#define O_NOATIME 0x40000
-#define O_NDELAY O_NONBLOCK
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
#define F_GETLK 14
#define F_SETLK 6
#define F_SETLKW 7
@@ -50,33 +33,6 @@
#define F_SETLKW64 35
#endif
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
/*
* The flavours of struct flock. "struct flock" is the ABI compliant
* variant. Finally struct flock64 is the LFS variant of struct flock. As
@@ -86,7 +42,7 @@
#ifndef __mips64
-typedef struct flock {
+struct flock {
short l_type;
short l_whence;
__kernel_off_t l_start;
@@ -94,32 +50,17 @@
long l_sysid;
__kernel_pid_t l_pid;
long pad[4];
-} flock_t;
+};
-typedef struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-} flock64_t;
-
-#else /* 64-bit definitions */
-
-typedef struct flock {
- short l_type;
- short l_whence;
- __kernel_off_t l_start;
- __kernel_off_t l_len;
- __kernel_pid_t l_pid;
-} flock_t;
-
-#ifdef __KERNEL__
-#define flock64 flock
-#endif
+#define HAVE_ARCH_STRUCT_FLOCK
#endif
-#define F_LINUX_SPECIFIC_BASE 1024
+#include <asm-generic/fcntl.h>
+
+typedef struct flock flock_t;
+#ifndef __mips64
+typedef struct flock64 flock64_t;
+#endif
#endif /* _ASM_FCNTL_H */
diff --git a/include/asm-mips/fpregdef.h b/include/asm-mips/fpregdef.h
index 1d9aa09..2b5fddc 100644
--- a/include/asm-mips/fpregdef.h
+++ b/include/asm-mips/fpregdef.h
@@ -13,7 +13,7 @@
#define _ASM_FPREGDEF_H
#include <asm/sgidefs.h>
-
+
#if _MIPS_SIM == _MIPS_SIM_ABI32
/*
@@ -56,7 +56,7 @@
#define fcr31 $31 /* FPU status register */
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
-
+
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
#define fv0 $f0 /* return value */
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
index 6cb38d5..ea24e73 100644
--- a/include/asm-mips/fpu.h
+++ b/include/asm-mips/fpu.h
@@ -82,7 +82,7 @@
static inline int is_fpu_owner(void)
{
- return cpu_has_fpu && test_thread_flag(TIF_USEDFPU);
+ return cpu_has_fpu && test_thread_flag(TIF_USEDFPU);
}
static inline void own_fpu(void)
@@ -90,7 +90,7 @@
if (cpu_has_fpu) {
__enable_fpu();
KSTK_STATUS(current) |= ST0_CU1;
- set_thread_flag(TIF_USEDFPU);
+ set_thread_flag(TIF_USEDFPU);
}
}
@@ -98,7 +98,7 @@
{
if (cpu_has_fpu) {
KSTK_STATUS(current) &= ~ST0_CU1;
- clear_thread_flag(TIF_USEDFPU);
+ clear_thread_flag(TIF_USEDFPU);
__disable_fpu();
}
}
@@ -127,7 +127,7 @@
static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
{
if (cpu_has_fpu) {
- if ((tsk == current) && is_fpu_owner())
+ if ((tsk == current) && is_fpu_owner())
_save_fp(current);
return tsk->thread.fpu.hard.fpr;
}
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
new file mode 100644
index 0000000..9feff4ce
--- /dev/null
+++ b/include/asm-mips/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-mips/hdreg.h b/include/asm-mips/hdreg.h
deleted file mode 100644
index 5989bbc..0000000
--- a/include/asm-mips/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
diff --git a/include/asm-mips/hp-lj/asic.h b/include/asm-mips/hp-lj/asic.h
deleted file mode 100644
index fc2ca65..0000000
--- a/include/asm-mips/hp-lj/asic.h
+++ /dev/null
@@ -1,7 +0,0 @@
-
-typedef enum { IllegalAsic, UnknownAsic, AndrosAsic, HarmonyAsic } AsicId;
-
-AsicId GetAsicId(void);
-
-const char* const GetAsicName(void);
-
diff --git a/include/asm-mips/ip32/mace.h b/include/asm-mips/ip32/mace.h
index 2b7b0fd..432011b 100644
--- a/include/asm-mips/ip32/mace.h
+++ b/include/asm-mips/ip32/mace.h
@@ -94,7 +94,7 @@
unsigned long xxx; /* later... */
};
-/*
+/*
* Ethernet interface
*/
struct mace_ethernet {
@@ -129,7 +129,7 @@
volatile unsigned long rx_fifo;
};
-/*
+/*
* Peripherals
*/
@@ -251,7 +251,7 @@
timer_reg audio_out2;
timer_reg video_in1;
timer_reg video_in2;
- timer_reg video_out;
+ timer_reg video_out;
};
struct mace_perif {
@@ -272,7 +272,7 @@
};
-/*
+/*
* ISA peripherals
*/
diff --git a/include/asm-mips/lasat/serial.h b/include/asm-mips/lasat/serial.h
index 21d0fb7..9e88c76 100644
--- a/include/asm-mips/lasat/serial.h
+++ b/include/asm-mips/lasat/serial.h
@@ -1,13 +1,13 @@
#include <asm/lasat/lasat.h>
/* Lasat 100 boards serial configuration */
-#define LASAT_BASE_BAUD_100 ( 7372800 / 16 )
+#define LASAT_BASE_BAUD_100 ( 7372800 / 16 )
#define LASAT_UART_REGS_BASE_100 0x1c8b0000
#define LASAT_UART_REGS_SHIFT_100 2
#define LASATINT_UART_100 8
/* * LASAT 200 boards serial configuration */
-#define LASAT_BASE_BAUD_200 (100000000 / 16 / 12)
+#define LASAT_BASE_BAUD_200 (100000000 / 16 / 12)
#define LASAT_UART_REGS_BASE_200 (Vrc5074_PHYS_BASE + 0x0300)
#define LASAT_UART_REGS_SHIFT_200 3
#define LASATINT_UART_200 13
diff --git a/include/asm-mips/local.h b/include/asm-mips/local.h
index 7eb6bf6..c38844f 100644
--- a/include/asm-mips/local.h
+++ b/include/asm-mips/local.h
@@ -5,7 +5,7 @@
#include <linux/percpu.h>
#include <asm/atomic.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
typedef atomic_t local_t;
@@ -20,7 +20,7 @@
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
typedef atomic64_t local_t;
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 2b36ea3..148bae2 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -1383,7 +1383,7 @@
#define PCI_IO_START 0
#define PCI_IO_END 0
#define PCI_MEM_START 0
-#define PCI_MEM_END 0
+#define PCI_MEM_END 0
#define PCI_FIRST_DEVFN 0
#define PCI_LAST_DEVFN 0
#endif
diff --git a/include/asm-mips/mach-db1x00/db1x00.h b/include/asm-mips/mach-db1x00/db1x00.h
index 4691398..efafe65 100644
--- a/include/asm-mips/mach-db1x00/db1x00.h
+++ b/include/asm-mips/mach-db1x00/db1x00.h
@@ -23,7 +23,7 @@
*
* ########################################################################
*
- *
+ *
*/
#ifndef __ASM_DB1X00_H
#define __ASM_DB1X00_H
diff --git a/include/asm-mips/mach-generic/spaces.h b/include/asm-mips/mach-generic/spaces.h
index 63c0a81..5a2c1ef 100644
--- a/include/asm-mips/mach-generic/spaces.h
+++ b/include/asm-mips/mach-generic/spaces.h
@@ -12,7 +12,7 @@
#include <linux/config.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define CAC_BASE 0x80000000
#define IO_BASE 0xa0000000
@@ -32,9 +32,9 @@
#define HIGHMEM_START 0x20000000UL
#endif
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* This handles the memory map.
@@ -67,6 +67,6 @@
#define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK))
#define TO_UNCAC(x) (UNCAC_BASE | ((x) & TO_PHYS_MASK))
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
#endif /* __ASM_MACH_GENERIC_SPACES_H */
diff --git a/include/asm-mips/mach-ip22/spaces.h b/include/asm-mips/mach-ip22/spaces.h
index 30d42fc..e96166f 100644
--- a/include/asm-mips/mach-ip22/spaces.h
+++ b/include/asm-mips/mach-ip22/spaces.h
@@ -12,7 +12,7 @@
#include <linux/config.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define CAC_BASE 0x80000000
#define IO_BASE 0xa0000000
@@ -32,9 +32,9 @@
#define HIGHMEM_START 0x20000000UL
#endif
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define PAGE_OFFSET 0xffffffff80000000UL
#ifndef HIGHMEM_START
@@ -50,6 +50,6 @@
#define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK))
#define TO_UNCAC(x) (UNCAC_BASE | ((x) & TO_PHYS_MASK))
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
#endif /* __ASM_MACH_IP22_SPACES_H */
diff --git a/include/asm-mips/mach-ip32/cpu-feature-overrides.h b/include/asm-mips/mach-ip32/cpu-feature-overrides.h
index b932237..0471397 100644
--- a/include/asm-mips/mach-ip32/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip32/cpu-feature-overrides.h
@@ -18,7 +18,7 @@
* so, for 64bit IP32 kernel we just don't use ll/sc.
* This does not affect luserland.
*/
-#if defined(CONFIG_CPU_R5000) && defined(CONFIG_MIPS64)
+#if defined(CONFIG_CPU_R5000) && defined(CONFIG_64BIT)
#define cpu_has_llsc 0
#else
#define cpu_has_llsc 1
diff --git a/include/asm-mips/mach-jazz/floppy.h b/include/asm-mips/mach-jazz/floppy.h
index 8cf0d04..c9dad99 100644
--- a/include/asm-mips/mach-jazz/floppy.h
+++ b/include/asm-mips/mach-jazz/floppy.h
@@ -92,7 +92,7 @@
return request_irq(FLOPPY_IRQ, floppy_interrupt,
SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
}
-
+
static inline void fd_free_irq(void)
{
free_irq(FLOPPY_IRQ, NULL);
diff --git a/include/asm-mips/mach-pb1x00/pb1500.h b/include/asm-mips/mach-pb1x00/pb1500.h
index d6c77974..ff6d40c 100644
--- a/include/asm-mips/mach-pb1x00/pb1500.h
+++ b/include/asm-mips/mach-pb1x00/pb1500.h
@@ -33,11 +33,11 @@
#define PCI_BOARD_REG 0xAE000010
#define PCMCIA_BOARD_REG 0xAE000010
#define PC_DEASSERT_RST 0x80
- #define PC_DRV_EN 0x10
+ #define PC_DRV_EN 0x10
#define PB1500_G_CONTROL 0xAE000014
#define PB1500_RST_VDDI 0xAE00001C
#define PB1500_LEDS 0xAE000018
-
+
#define PB1500_HEX_LED 0xAF000004
#define PB1500_HEX_LED_BLANK 0xAF000008
diff --git a/include/asm-mips/mach-qemu/cpu-feature-overrides.h b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
new file mode 100644
index 0000000..f4e370e
--- /dev/null
+++ b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
@@ -0,0 +1,31 @@
+/*
+ * 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) 2003 Ralf Baechle
+ */
+#ifndef __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * QEMU only comes with a hazard-free MIPS32 processor, so things are easy.
+ */
+#define cpu_has_mips16 0
+#define cpu_has_divec 0
+#define cpu_has_cache_cdex_p 0
+#define cpu_has_prefetch 0
+#define cpu_has_mcheck 0
+#define cpu_has_ejtag 0
+
+#define cpu_has_llsc 1
+#define cpu_has_vtag_icache 0
+#define cpu_has_dc_aliases (PAGE_SIZE < 0x4000)
+#define cpu_has_ic_fills_f_dc 0
+
+#define cpu_has_dsp 0
+
+#define cpu_has_nofpuex 0
+#define cpu_has_64bits 0
+
+#endif /* __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-qemu/param.h b/include/asm-mips/mach-qemu/param.h
new file mode 100644
index 0000000..cb30ee4
--- /dev/null
+++ b/include/asm-mips/mach-qemu/param.h
@@ -0,0 +1,13 @@
+/*
+ * 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) 2005 by Ralf Baechle
+ */
+#ifndef __ASM_MACH_QEMU_PARAM_H
+#define __ASM_MACH_QEMU_PARAM_H
+
+#define HZ 100 /* Internal kernel timer frequency */
+
+#endif /* __ASM_MACH_QEMU_PARAM_H */
diff --git a/include/asm-mips/mach-vr41xx/timex.h b/include/asm-mips/mach-vr41xx/timex.h
deleted file mode 100644
index 8d71485..0000000
--- a/include/asm-mips/mach-vr41xx/timex.h
+++ /dev/null
@@ -1,18 +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) 2003 by Ralf Baechle
- */
-/*
- * Changes:
- * Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
- * - CLOCK_TICK_RATE is changed into 32768 from 6144000.
- */
-#ifndef __ASM_MACH_VR41XX_TIMEX_H
-#define __ASM_MACH_VR41XX_TIMEX_H
-
-#define CLOCK_TICK_RATE 32768
-
-#endif /* __ASM_MACH_VR41XX_TIMEX_H */
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index 48b77c9..45cd72d 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -28,17 +28,17 @@
#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
pgd_current[smp_processor_id()] = (unsigned long)(pgd)
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define TLBMISS_HANDLER_SETUP() \
write_c0_context((unsigned long) smp_processor_id() << 23); \
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
#define TLBMISS_HANDLER_SETUP() \
write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif
-#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
#define TLBMISS_HANDLER_SETUP() \
write_c0_context((unsigned long) smp_processor_id() << 23); \
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
diff --git a/include/asm-mips/module.h b/include/asm-mips/module.h
index 90ee24a..0be58b2 100644
--- a/include/asm-mips/module.h
+++ b/include/asm-mips/module.h
@@ -25,7 +25,7 @@
Elf64_Sxword r_addend; /* Addend. */
} Elf64_Mips_Rela;
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
@@ -33,7 +33,7 @@
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
diff --git a/include/asm-mips/msgbuf.h b/include/asm-mips/msgbuf.h
index 513b282..a153395 100644
--- a/include/asm-mips/msgbuf.h
+++ b/include/asm-mips/msgbuf.h
@@ -15,25 +15,25 @@
struct msqid64_ds {
struct ipc64_perm msg_perm;
-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
unsigned long __unused1;
#endif
__kernel_time_t msg_stime; /* last msgsnd time */
-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
unsigned long __unused1;
#endif
-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
unsigned long __unused2;
#endif
__kernel_time_t msg_rtime; /* last msgrcv time */
-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
unsigned long __unused2;
#endif
-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
unsigned long __unused3;
#endif
__kernel_time_t msg_ctime; /* last change time */
-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
unsigned long __unused3;
#endif
unsigned long msg_cbytes; /* current number of bytes on queue */
diff --git a/include/asm-mips/paccess.h b/include/asm-mips/paccess.h
index 36cec9e..309bc30 100644
--- a/include/asm-mips/paccess.h
+++ b/include/asm-mips/paccess.h
@@ -16,10 +16,10 @@
#include <linux/config.h>
#include <linux/errno.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define __PA_ADDR ".word"
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define __PA_ADDR ".dword"
#endif
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index 5cae35c..652b6d6 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -103,20 +103,6 @@
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
@@ -148,4 +134,6 @@
#define WANT_PAGE_VIRTUAL
#endif
+#include <asm-generic/page.h>
+
#endif /* _ASM_PAGE_H */
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h
index d70dc35..c9a00ca 100644
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -94,7 +94,7 @@
*/
extern unsigned int PCI_DMA_BUS_IS_PHYS;
-#ifdef CONFIG_MAPPED_DMA_IO
+#ifdef CONFIG_DMA_NEED_PCI_MAP_STATE
/* pci_unmap_{single,page} is not a nop, thus... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME;
@@ -104,7 +104,7 @@
#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
-#else /* CONFIG_MAPPED_DMA_IO */
+#else /* CONFIG_DMA_NEED_PCI_MAP_STATE */
/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
@@ -114,7 +114,7 @@
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-#endif /* CONFIG_MAPPED_DMA_IO */
+#endif /* CONFIG_DMA_NEED_PCI_MAP_STATE */
/* This is always fine. */
#define pci_dac_dma_supported(pci_dev, mask) (1)
@@ -142,6 +142,8 @@
extern void pcibios_resource_to_bus(struct pci_dev *dev,
struct pci_bus_region *region, struct resource *res);
+extern void pcibios_bus_to_resource(struct pci_dev *dev,
+ struct resource *res, struct pci_bus_region *region);
#ifdef CONFIG_PCI_DOMAINS
@@ -167,4 +169,17 @@
/* Do platform specific device initialization at pci_enable_device() time */
extern int pcibios_plat_dev_init(struct pci_dev *dev);
+static inline struct resource *
+pcibios_select_root(struct pci_dev *pdev, struct resource *res)
+{
+ struct resource *root = NULL;
+
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ if (res->flags & IORESOURCE_MEM)
+ root = &iomem_resource;
+
+ return root;
+}
+
#endif /* _ASM_PCI_H */
diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h
index 2d63f5b..ce57288 100644
--- a/include/asm-mips/pgalloc.h
+++ b/include/asm-mips/pgalloc.h
@@ -85,7 +85,7 @@
#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define pgd_populate(mm, pmd, pte) BUG()
/*
@@ -97,7 +97,7 @@
#define __pmd_free_tlb(tlb,x) do { } while (0)
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define pgd_populate(mm, pgd, pmd) set_pgd(pgd, __pgd(pmd))
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index e76ccd6..dbe13da 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -11,10 +11,10 @@
#include <asm-generic/4level-fixup.h>
#include <linux/config.h>
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#include <asm/pgtable-32.h>
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#include <asm/pgtable-64.h>
#endif
diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h
index 13c54d5..d6466aa 100644
--- a/include/asm-mips/processor.h
+++ b/include/asm-mips/processor.h
@@ -33,7 +33,7 @@
extern unsigned int vced_count, vcei_count;
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
/*
* User space process size: 2GB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing.
@@ -47,7 +47,7 @@
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
/*
* User space process size: 1TB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing. TASK_SIZE
diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
index d3c46d6..2b5c624 100644
--- a/include/asm-mips/ptrace.h
+++ b/include/asm-mips/ptrace.h
@@ -28,7 +28,7 @@
* system call/exception. As usual the registers k0/k1 aren't being saved.
*/
struct pt_regs {
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
/* Pad bytes for argument save space on the stack. */
unsigned long pad0[6];
#endif
diff --git a/include/asm-mips/qemu.h b/include/asm-mips/qemu.h
new file mode 100644
index 0000000..905c395
--- /dev/null
+++ b/include/asm-mips/qemu.h
@@ -0,0 +1,24 @@
+/*
+ * 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) 2005 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#ifndef __ASM_QEMU_H
+#define __ASM_QEMU_H
+
+/*
+ * Interrupt numbers
+ */
+#define Q_PIC_IRQ_BASE 0
+#define Q_COUNT_COMPARE_IRQ 16
+
+/*
+ * Qemu clock rate. Unlike on real MIPS this has no relation to the
+ * instruction issue rate, so the choosen value is pure fiction, just needs
+ * to match the value in Qemu itself.
+ */
+#define QEMU_C0_COUNTER_CLOCK 100000000
+
+#endif /* __ASM_QEMU_H */
diff --git a/include/asm-mips/r4kcache.h b/include/asm-mips/r4kcache.h
index da03a32..5bea49f 100644
--- a/include/asm-mips/r4kcache.h
+++ b/include/asm-mips/r4kcache.h
@@ -171,11 +171,11 @@
unsigned long start = INDEX_BASE;
unsigned long end = start + current_cpu_data.dcache.waysize;
unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
- unsigned long ws_end = current_cpu_data.dcache.ways <<
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
current_cpu_data.dcache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
for (addr = start; addr < end; addr += 0x200)
cache16_unroll32(addr|ws,Index_Writeback_Inv_D);
}
@@ -200,8 +200,8 @@
current_cpu_data.dcache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x200)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x200)
cache16_unroll32(addr|ws,Index_Writeback_Inv_D);
}
@@ -214,8 +214,8 @@
current_cpu_data.icache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x200)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x200)
cache16_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -239,8 +239,8 @@
current_cpu_data.icache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x200)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x200)
cache16_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -249,11 +249,11 @@
unsigned long start = INDEX_BASE;
unsigned long end = start + current_cpu_data.scache.waysize;
unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
- unsigned long ws_end = current_cpu_data.scache.ways <<
+ unsigned long ws_end = current_cpu_data.scache.ways <<
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
for (addr = start; addr < end; addr += 0x200)
cache16_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -278,8 +278,8 @@
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x200)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x200)
cache16_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -318,8 +318,8 @@
current_cpu_data.dcache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
}
@@ -343,8 +343,8 @@
current_cpu_data.dcache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
}
@@ -357,8 +357,8 @@
current_cpu_data.icache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
cache32_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -383,7 +383,7 @@
unsigned long ws, addr;
for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400)
+ for (addr = start; addr < end; addr += 0x400)
cache32_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -392,11 +392,11 @@
unsigned long start = INDEX_BASE;
unsigned long end = start + current_cpu_data.scache.waysize;
unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
- unsigned long ws_end = current_cpu_data.scache.ways <<
+ unsigned long ws_end = current_cpu_data.scache.ways <<
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
for (addr = start; addr < end; addr += 0x400)
cache32_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -421,8 +421,8 @@
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x400)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
cache32_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -461,8 +461,8 @@
current_cpu_data.icache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x800)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x800)
cache64_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -487,7 +487,7 @@
unsigned long ws, addr;
for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x800)
+ for (addr = start; addr < end; addr += 0x800)
cache64_unroll32(addr|ws,Index_Invalidate_I);
}
@@ -496,11 +496,11 @@
unsigned long start = INDEX_BASE;
unsigned long end = start + current_cpu_data.scache.waysize;
unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
- unsigned long ws_end = current_cpu_data.scache.ways <<
+ unsigned long ws_end = current_cpu_data.scache.ways <<
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
for (addr = start; addr < end; addr += 0x800)
cache64_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -525,8 +525,8 @@
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x800)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x800)
cache64_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -561,11 +561,11 @@
unsigned long start = INDEX_BASE;
unsigned long end = start + current_cpu_data.scache.waysize;
unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit;
- unsigned long ws_end = current_cpu_data.scache.ways <<
+ unsigned long ws_end = current_cpu_data.scache.ways <<
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
for (addr = start; addr < end; addr += 0x1000)
cache128_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
@@ -590,8 +590,8 @@
current_cpu_data.scache.waybit;
unsigned long ws, addr;
- for (ws = 0; ws < ws_end; ws += ws_inc)
- for (addr = start; addr < end; addr += 0x1000)
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x1000)
cache128_unroll32(addr|ws,Index_Writeback_Inv_SD);
}
diff --git a/include/asm-mips/reg.h b/include/asm-mips/reg.h
index 7b33bbc..6173004 100644
--- a/include/asm-mips/reg.h
+++ b/include/asm-mips/reg.h
@@ -14,7 +14,7 @@
#include <linux/config.h>
-#if defined(CONFIG_MIPS32) || defined(WANT_COMPAT_REG_H)
+#if defined(CONFIG_32BIT) || defined(WANT_COMPAT_REG_H)
#define EF_R0 6
#define EF_R1 7
@@ -70,7 +70,7 @@
#endif
-#if CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define EF_R0 0
#define EF_R1 1
@@ -124,6 +124,6 @@
#define EF_SIZE 304 /* size in bytes */
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
#endif /* __ASM_MIPS_REG_H */
diff --git a/include/asm-mips/resource.h b/include/asm-mips/resource.h
index fd3c6d1..1fba00c 100644
--- a/include/asm-mips/resource.h
+++ b/include/asm-mips/resource.h
@@ -27,7 +27,7 @@
* but we keep the old value on MIPS32,
* for compatibility:
*/
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
# define RLIM_INFINITY 0x7fffffffUL
#endif
diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h
index 31c0c23..3c4b637 100644
--- a/include/asm-mips/rtc.h
+++ b/include/asm-mips/rtc.h
@@ -1,5 +1,5 @@
/*
- * include/asm-mips/rtc.h
+ * include/asm-mips/rtc.h
*
* (Really an interface for drivers/char/genrtc.c)
*
diff --git a/include/asm-mips/sgi/gio.h b/include/asm-mips/sgi/gio.h
index a38d66f..889cf02 100644
--- a/include/asm-mips/sgi/gio.h
+++ b/include/asm-mips/sgi/gio.h
@@ -16,7 +16,7 @@
*
* The Indigo and Indy have two GIO bus connectors. Indigo2 (all models) have
* three physical connectors, but only two slots, GFX and EXP0.
- *
+ *
* There is 10MB of GIO address space for GIO64 slot devices
* slot# slot type address range size
* ----- --------- ----------------------- -----
diff --git a/include/asm-mips/sgi/hpc3.h b/include/asm-mips/sgi/hpc3.h
index a5b988d..ac3dfc7 100644
--- a/include/asm-mips/sgi/hpc3.h
+++ b/include/asm-mips/sgi/hpc3.h
@@ -221,7 +221,7 @@
#define HPC3_BESTAT_PIDMASK 0x3f700 /* DMA channel parity identifier */
u32 _unused1[0x14000/4 - 5]; /* padding */
-
+
/* Now direct PIO per-HPC3 peripheral access to external regs. */
volatile u32 scsi0_ext[256]; /* SCSI channel 0 external regs */
u32 _unused2[0x7c00/4];
@@ -304,7 +304,7 @@
volatile u32 bbram[8192-50-14]; /* Battery backed ram */
};
-/*
+/*
* It is possible to have two HPC3's within the address space on
* one machine, though only having one is more likely on an Indy.
*/
diff --git a/include/asm-mips/sgi/ioc.h b/include/asm-mips/sgi/ioc.h
index 169187f..f3e3dc9 100644
--- a/include/asm-mips/sgi/ioc.h
+++ b/include/asm-mips/sgi/ioc.h
@@ -16,7 +16,7 @@
#include <linux/types.h>
#include <asm/sgi/pi1.h>
-/*
+/*
* All registers are 8-bit wide alligned on 32-bit boundary. Bad things
* happen if you try word access them. You have been warned.
*/
@@ -138,7 +138,7 @@
u8 _sysid[3];
volatile u8 sysid;
#define SGIOC_SYSID_FULLHOUSE 0x01
-#define SGIOC_SYSID_BOARDREV(x) ((x & 0xe0) > 5)
+#define SGIOC_SYSID_BOARDREV(x) ((x & 0xe0) > 5)
#define SGIOC_SYSID_CHIPREV(x) ((x & 0x1e) > 1)
u32 _unused2;
u8 _read[3];
diff --git a/include/asm-mips/sgi/ip22.h b/include/asm-mips/sgi/ip22.h
index 97d73ad..bbfc05c 100644
--- a/include/asm-mips/sgi/ip22.h
+++ b/include/asm-mips/sgi/ip22.h
@@ -12,7 +12,7 @@
#ifndef _SGI_IP22_H
#define _SGI_IP22_H
-/*
+/*
* These are the virtual IRQ numbers, we divide all IRQ's into
* 'spaces', the 'space' determines where and how to enable/disable
* that particular IRQ on an SGI machine. HPC DMA and MC DMA interrups
diff --git a/include/asm-mips/sgi/mc.h b/include/asm-mips/sgi/mc.h
index fd98f93..c52f783 100644
--- a/include/asm-mips/sgi/mc.h
+++ b/include/asm-mips/sgi/mc.h
@@ -182,14 +182,14 @@
volatile u32 dtlb_hi3;
u32 _unused33;
volatile u32 dtlb_lo3;
-
+
u32 _unused34[0x0392];
-
+
u32 _unused35;
volatile u32 rpsscounter; /* Chirps at 100ns */
u32 _unused36[0x1000/4-2*4];
-
+
u32 _unused37;
volatile u32 maddronly; /* Address DMA goes at */
u32 _unused38;
diff --git a/include/asm-mips/sgiarcs.h b/include/asm-mips/sgiarcs.h
index 5945033..722b77a 100644
--- a/include/asm-mips/sgiarcs.h
+++ b/include/asm-mips/sgiarcs.h
@@ -367,7 +367,7 @@
* Macros for calling a 32-bit ARC implementation from 64-bit code
*/
-#if defined(CONFIG_MIPS64) && defined(CONFIG_ARC32)
+#if defined(CONFIG_64BIT) && defined(CONFIG_ARC32)
#define __arc_clobbers \
"$2","$3" /* ... */, "$8","$9","$10","$11", \
@@ -476,10 +476,10 @@
__res; \
})
-#endif /* defined(CONFIG_MIPS64) && defined(CONFIG_ARC32) */
+#endif /* defined(CONFIG_64BIT) && defined(CONFIG_ARC32) */
-#if (defined(CONFIG_MIPS32) && defined(CONFIG_ARC32)) || \
- (defined(CONFIG_MIPS64) && defined(CONFIG_ARC64))
+#if (defined(CONFIG_32BIT) && defined(CONFIG_ARC32)) || \
+ (defined(CONFIG_64BIT) && defined(CONFIG_ARC64))
#define ARC_CALL0(dest) \
({ long __res; \
diff --git a/include/asm-mips/sibyte/carmel.h b/include/asm-mips/sibyte/carmel.h
index 7ac5da1..b5e7dae 100644
--- a/include/asm-mips/sibyte/carmel.h
+++ b/include/asm-mips/sibyte/carmel.h
@@ -25,12 +25,12 @@
#define SIBYTE_BOARD_NAME "Carmel"
-#define GPIO_PHY_INTERRUPT 2
-#define GPIO_NONMASKABLE_INT 3
-#define GPIO_CF_INSERTED 6
-#define GPIO_MONTEREY_RESET 7
-#define GPIO_QUADUART_INT 8
-#define GPIO_CF_INT 9
+#define GPIO_PHY_INTERRUPT 2
+#define GPIO_NONMASKABLE_INT 3
+#define GPIO_CF_INSERTED 6
+#define GPIO_MONTEREY_RESET 7
+#define GPIO_QUADUART_INT 8
+#define GPIO_CF_INT 9
#define GPIO_FPGA_CCLK 10
#define GPIO_FPGA_DOUT 11
#define GPIO_FPGA_DIN 12
diff --git a/include/asm-mips/sibyte/sb1250_defs.h b/include/asm-mips/sibyte/sb1250_defs.h
index 96088fb..40ef97c 100644
--- a/include/asm-mips/sibyte/sb1250_defs.h
+++ b/include/asm-mips/sibyte/sb1250_defs.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
- * Global constants and macros File: sb1250_defs.h
- *
+ *
+ * Global constants and macros File: sb1250_defs.h
+ *
* This file contains macros and definitions used by the other
* include files.
*
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -105,7 +105,7 @@
#define SIBYTE_HDR_FMASK_112x_ALL 0x0000f00
#define SIBYTE_HDR_FMASK_112x_PASS1 0x0000100
-/* Bit mask for chip/revision. (use _ALL for all revisions of a chip). */
+/* Bit mask for chip/revision. (use _ALL for all revisions of a chip). */
#define SIBYTE_HDR_FMASK(chip, pass) \
(SIBYTE_HDR_FMASK_ ## chip ## _ ## pass)
#define SIBYTE_HDR_FMASK_ALLREVS(chip) \
@@ -150,31 +150,31 @@
/* *********************************************************************
* Naming schemes for constants in these files:
- *
- * M_xxx MASK constant (identifies bits in a register).
+ *
+ * M_xxx MASK constant (identifies bits in a register).
* For multi-bit fields, all bits in the field will
* be set.
*
* K_xxx "Code" constant (value for data in a multi-bit
* field). The value is right justified.
*
- * V_xxx "Value" constant. This is the same as the
+ * V_xxx "Value" constant. This is the same as the
* corresponding "K_xxx" constant, except it is
* shifted to the correct position in the register.
*
* S_xxx SHIFT constant. This is the number of bits that
- * a field value (code) needs to be shifted
+ * a field value (code) needs to be shifted
* (towards the left) to put the value in the right
* position for the register.
*
- * A_xxx ADDRESS constant. This will be a physical
+ * A_xxx ADDRESS constant. This will be a physical
* address. Use the PHYS_TO_K1 macro to generate
* a K1SEG address.
*
* R_xxx RELATIVE offset constant. This is an offset from
* an A_xxx constant (usually the first register in
* a group).
- *
+ *
* G_xxx(X) GET value. This macro obtains a multi-bit field
* from a register, masks it, and shifts it to
* the bottom of the register (retrieving a K_xxx
@@ -189,7 +189,7 @@
/*
- * Cast to 64-bit number. Presumably the syntax is different in
+ * Cast to 64-bit number. Presumably the syntax is different in
* assembly language.
*
* Note: you'll need to define uint32_t and uint64_t in your headers.
diff --git a/include/asm-mips/sibyte/sb1250_dma.h b/include/asm-mips/sibyte/sb1250_dma.h
index f1b08d32..3cdb48f 100644
--- a/include/asm-mips/sibyte/sb1250_dma.h
+++ b/include/asm-mips/sibyte/sb1250_dma.h
@@ -1,24 +1,24 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* DMA definitions File: sb1250_dma.h
- *
+ *
* This module contains constants and macros useful for
* programming the SB1250's DMA controllers, both the data mover
* and the Ethernet DMA.
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -28,7 +28,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -43,9 +43,9 @@
* DMA Registers
********************************************************************* */
-/*
+/*
* Ethernet and Serial DMA Configuration Register 0 (Table 7-4)
- * Registers: DMA_CONFIG0_MAC_x_RX_CH_0
+ * Registers: DMA_CONFIG0_MAC_x_RX_CH_0
* Registers: DMA_CONFIG0_MAC_x_TX_CH_0
* Registers: DMA_CONFIG0_SER_x_RX
* Registers: DMA_CONFIG0_SER_x_TX
@@ -98,7 +98,7 @@
/*
* Ethernet and Serial DMA Configuration Register 1 (Table 7-5)
- * Registers: DMA_CONFIG1_MAC_x_RX_CH_0
+ * Registers: DMA_CONFIG1_MAC_x_RX_CH_0
* Registers: DMA_CONFIG1_DMA_x_TX_CH_0
* Registers: DMA_CONFIG1_SER_x_RX
* Registers: DMA_CONFIG1_SER_x_TX
@@ -152,11 +152,11 @@
/*
* DMA Descriptor Count Registers (Table 7-8)
*/
-
+
/* No bitfields */
-/*
+/*
* Current Descriptor Address Register (Table 7-11)
*/
@@ -275,14 +275,14 @@
#define V_DMA_DSCRB_STATUS(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_STATUS)
#define G_DMA_DSCRB_STATUS(x) _SB_GETVALUE(x,S_DMA_DSCRB_STATUS,M_DMA_DSCRB_STATUS)
-/*
+/*
* Ethernet Descriptor Status Bits (Table 7-15)
*/
#define M_DMA_ETHRX_BADIP4CS _SB_MAKEMASK1(51)
#define M_DMA_ETHRX_DSCRERR _SB_MAKEMASK1(52)
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
/* Note: BADTCPCS is actually in DSCR_B options field */
#define M_DMA_ETHRX_BADTCPCS _SB_MAKEMASK1(0)
#endif /* 1250 PASS2 || 112x PASS1 */
@@ -324,7 +324,7 @@
#define M_DMA_ETHTX_SOP _SB_MAKEMASK1(63)
-/*
+/*
* Ethernet Transmit Options (Table 7-17)
*/
@@ -377,7 +377,7 @@
* Data Mover Registers
********************************************************************* */
-/*
+/*
* Data Mover Descriptor Base Address Register (Table 7-22)
* Register: DM_DSCR_BASE_0
* Register: DM_DSCR_BASE_1
@@ -414,7 +414,7 @@
#define M_DM_DSCR_BASE_ABORT _SB_MAKEMASK1(62)
#define M_DM_DSCR_BASE_ENABL _SB_MAKEMASK1(63)
-/*
+/*
* Data Mover Descriptor Count Register (Table 7-25)
*/
diff --git a/include/asm-mips/sibyte/sb1250_genbus.h b/include/asm-mips/sibyte/sb1250_genbus.h
index 0d9dfac..f1f509f 100644
--- a/include/asm-mips/sibyte/sb1250_genbus.h
+++ b/include/asm-mips/sibyte/sb1250_genbus.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* Generic Bus Constants File: sb1250_genbus.h
- *
- * This module contains constants and macros useful for
+ *
+ * This module contains constants and macros useful for
* manipulating the SB1250's Generic Bus interface
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
diff --git a/include/asm-mips/sibyte/sb1250_int.h b/include/asm-mips/sibyte/sb1250_int.h
index c3f74df..e173e2e 100644
--- a/include/asm-mips/sibyte/sb1250_int.h
+++ b/include/asm-mips/sibyte/sb1250_int.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* Interrupt Mapper definitions File: sb1250_int.h
- *
+ *
* This module contains constants for manipulating the SB1250's
* interrupt mapper and definitions for the interrupt sources.
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -43,7 +43,7 @@
/*
* Interrupt sources (Table 4-8, UM 0.2)
- *
+ *
* First, the interrupt numbers.
*/
diff --git a/include/asm-mips/sibyte/sb1250_l2c.h b/include/asm-mips/sibyte/sb1250_l2c.h
index 799db82..8afe8e0 100644
--- a/include/asm-mips/sibyte/sb1250_l2c.h
+++ b/include/asm-mips/sibyte/sb1250_l2c.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* L2 Cache constants and macros File: sb1250_l2c.h
- *
+ *
* This module contains constants useful for manipulating the
* level 2 cache.
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
diff --git a/include/asm-mips/sibyte/sb1250_ldt.h b/include/asm-mips/sibyte/sb1250_ldt.h
index d875388..f2617de 100644
--- a/include/asm-mips/sibyte/sb1250_ldt.h
+++ b/include/asm-mips/sibyte/sb1250_ldt.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* LDT constants File: sb1250_ldt.h
- *
- * This module contains constants and macros to describe
- * the LDT interface on the SB1250.
- *
+ *
+ * This module contains constants and macros to describe
+ * the LDT interface on the SB1250.
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -155,7 +155,7 @@
/*
* LDT Status Register (Table 8-14). Note that these constants
- * assume you've read the command and status register
+ * assume you've read the command and status register
* together (32-bit read at offset 0x04)
*
* These bits also apply to the secondary status
@@ -183,8 +183,8 @@
#define M_LDT_STATUS_DETPARERR _SB_MAKEMASK1_32(31)
/*
- * Bridge Control Register (Table 8-16). Note that these
- * constants assume you've read the register as a 32-bit
+ * Bridge Control Register (Table 8-16). Note that these
+ * constants assume you've read the register as a 32-bit
* read (offset 0x3C)
*/
diff --git a/include/asm-mips/sibyte/sb1250_mac.h b/include/asm-mips/sibyte/sb1250_mac.h
index 81f603f..18e74e4 100644
--- a/include/asm-mips/sibyte/sb1250_mac.h
+++ b/include/asm-mips/sibyte/sb1250_mac.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* MAC constants and macros File: sb1250_mac.h
- *
+ *
* This module contains constants and macros for the SB1250's
* ethernet controllers.
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -311,7 +311,7 @@
/*
* These constants are used to configure the fields within the Frame
- * Configuration Register.
+ * Configuration Register.
*/
#define K_MAC_IFG_RX_10 _SB_MAKE64(0) /* See table 176, not used */
@@ -393,7 +393,7 @@
* Register: MAC_INT_MASK_2
*/
-/*
+/*
* Use these constants to shift the appropriate channel
* into the CH0 position so the same tests can be used
* on each channel.
diff --git a/include/asm-mips/sibyte/sb1250_mc.h b/include/asm-mips/sibyte/sb1250_mc.h
index 93a4833..1dd41c9 100644
--- a/include/asm-mips/sibyte/sb1250_mc.h
+++ b/include/asm-mips/sibyte/sb1250_mc.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
- * Memory Controller constants File: sb1250_mc.h
- *
+ *
+ * Memory Controller constants File: sb1250_mc.h
+ *
* This module contains constants and macros useful for
* programming the memory controller.
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -166,7 +166,7 @@
#define K_MC_REF_RATE_100MHz 0x62
#define K_MC_REF_RATE_133MHz 0x81
-#define K_MC_REF_RATE_200MHz 0xC4
+#define K_MC_REF_RATE_200MHz 0xC4
#define V_MC_REF_RATE_100MHz V_MC_REF_RATE(K_MC_REF_RATE_100MHz)
#define V_MC_REF_RATE_133MHz V_MC_REF_RATE(K_MC_REF_RATE_133MHz)
@@ -228,7 +228,7 @@
V_MC_ADDR_DRIVE_DEFAULT | \
V_MC_DATA_DRIVE_DEFAULT | \
V_MC_CLOCK_DRIVE_DEFAULT | \
- V_MC_REF_RATE_DEFAULT
+ V_MC_REF_RATE_DEFAULT
diff --git a/include/asm-mips/sibyte/sb1250_regs.h b/include/asm-mips/sibyte/sb1250_regs.h
index 5d496c6..9db80cd 100644
--- a/include/asm-mips/sibyte/sb1250_regs.h
+++ b/include/asm-mips/sibyte/sb1250_regs.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* Register Definitions File: sb1250_regs.h
- *
+ *
* This module contains the addresses of the on-chip peripherals
* on the SB1250.
- *
+ *
* SB1250 specification level: 01/02/2002
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -40,20 +40,20 @@
/* *********************************************************************
* Some general notes:
- *
+ *
* For the most part, when there is more than one peripheral
* of the same type on the SOC, the constants below will be
* offsets from the base of each peripheral. For example,
* the MAC registers are described as offsets from the first
* MAC register, and there will be a MAC_REGISTER() macro
- * to calculate the base address of a given MAC.
- *
+ * to calculate the base address of a given MAC.
+ *
* The information in this file is based on the SB1250 SOC
* manual version 0.2, July 2000.
********************************************************************* */
-/* *********************************************************************
+/* *********************************************************************
* Memory Controller Registers
********************************************************************* */
@@ -101,7 +101,7 @@
#define R_MC_TEST_ECC 0x0000000420
#define R_MC_MCLK_CFG 0x0000000500
-/* *********************************************************************
+/* *********************************************************************
* L2 Cache Control Registers
********************************************************************* */
@@ -126,7 +126,7 @@
#define A_L2_EEC_ADDRESS A_L2_ECC_TAG
-/* *********************************************************************
+/* *********************************************************************
* PCI Interface Registers
********************************************************************* */
@@ -134,7 +134,7 @@
#define A_PCI_TYPE01_HEADER 0x00DE000800
-/* *********************************************************************
+/* *********************************************************************
* Ethernet DMA and MACs
********************************************************************* */
@@ -184,7 +184,7 @@
(R_MAC_DMA_CHANNEL_BASE(txrx,chan) + \
(reg))
-/*
+/*
* DMA channel registers, relative to A_MAC_DMA_CHANNEL_BASE
*/
@@ -259,7 +259,7 @@
#define MAC_CHMAP_COUNT 4
-/* *********************************************************************
+/* *********************************************************************
* DUART Registers
********************************************************************* */
@@ -363,7 +363,7 @@
#endif /* 1250 PASS2 || 112x PASS1 */
-/* *********************************************************************
+/* *********************************************************************
* Synchronous Serial Registers
********************************************************************* */
@@ -397,7 +397,7 @@
(reg))
-/*
+/*
* DMA channel registers, relative to A_SER_DMA_CHANNEL_BASE
*/
@@ -457,7 +457,7 @@
#define R_SER_RMON_RX_ERRORS 0x000001F0
#define R_SER_RMON_RX_BADADDR 0x000001F8
-/* *********************************************************************
+/* *********************************************************************
* Generic Bus Registers
********************************************************************* */
@@ -513,7 +513,7 @@
#define R_IO_PCMCIA_CFG 0x0A60
#define R_IO_PCMCIA_STATUS 0x0A70
-/* *********************************************************************
+/* *********************************************************************
* GPIO Registers
********************************************************************* */
@@ -537,7 +537,7 @@
#define R_GPIO_PIN_CLR 0x30
#define R_GPIO_PIN_SET 0x38
-/* *********************************************************************
+/* *********************************************************************
* SMBus Registers
********************************************************************* */
@@ -573,7 +573,7 @@
#define R_SMB_CONTROL 0x0000000060
#define R_SMB_PEC 0x0000000070
-/* *********************************************************************
+/* *********************************************************************
* Timer Registers
********************************************************************* */
@@ -641,7 +641,7 @@
#endif /* 1250 PASS2 || 112x PASS1 */
-/* *********************************************************************
+/* *********************************************************************
* System Control Registers
********************************************************************* */
@@ -649,7 +649,7 @@
#define A_SCD_SYSTEM_CFG 0x0010020008
#define A_SCD_SYSTEM_MANUF 0x0010038000
-/* *********************************************************************
+/* *********************************************************************
* System Address Trap Registers
********************************************************************* */
@@ -672,7 +672,7 @@
#endif /* 1250 PASS2 || 112x PASS1 */
-/* *********************************************************************
+/* *********************************************************************
* System Interrupt Mapper Registers
********************************************************************* */
@@ -701,7 +701,7 @@
#define R_IMR_INTERRUPT_MAP_BASE 0x0200
#define R_IMR_INTERRUPT_MAP_COUNT 64
-/* *********************************************************************
+/* *********************************************************************
* System Performance Counter Registers
********************************************************************* */
@@ -711,7 +711,7 @@
#define A_SCD_PERF_CNT_2 0x00100204E0
#define A_SCD_PERF_CNT_3 0x00100204E8
-/* *********************************************************************
+/* *********************************************************************
* System Bus Watcher Registers
********************************************************************* */
@@ -726,13 +726,13 @@
#define A_BUS_L2_ERRORS 0x00100208C0
#define A_BUS_MEM_IO_ERRORS 0x00100208C8
-/* *********************************************************************
+/* *********************************************************************
* System Debug Controller Registers
********************************************************************* */
#define A_SCD_JTAG_BASE 0x0010000000
-/* *********************************************************************
+/* *********************************************************************
* System Trace Buffer Registers
********************************************************************* */
@@ -755,7 +755,7 @@
#define A_SCD_TRACE_SEQUENCE_6 0x0010020A90
#define A_SCD_TRACE_SEQUENCE_7 0x0010020A98
-/* *********************************************************************
+/* *********************************************************************
* System Generic DMA Registers
********************************************************************* */
diff --git a/include/asm-mips/sibyte/sb1250_scd.h b/include/asm-mips/sibyte/sb1250_scd.h
index 22e8041..dbbd682 100644
--- a/include/asm-mips/sibyte/sb1250_scd.h
+++ b/include/asm-mips/sibyte/sb1250_scd.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* SCD Constants and Macros File: sb1250_scd.h
- *
+ *
* This module contains constants and macros useful for
* manipulating the System Control and Debug module on the 1250.
- *
+ *
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -130,40 +130,40 @@
/* System Manufacturing Register
* Register: SCD_SYSTEM_MANUF
*/
-
+
/* Wafer ID: bits 31:0 */
#define S_SYS_WAFERID1_200 _SB_MAKE64(0)
#define M_SYS_WAFERID1_200 _SB_MAKEMASK(32,S_SYS_WAFERID1_200)
#define V_SYS_WAFERID1_200(x) _SB_MAKEVALUE(x,S_SYS_WAFERID1_200)
#define G_SYS_WAFERID1_200(x) _SB_GETVALUE(x,S_SYS_WAFERID1_200,M_SYS_WAFERID1_200)
-
+
#define S_SYS_BIN _SB_MAKE64(32)
#define M_SYS_BIN _SB_MAKEMASK(4,S_SYS_BIN)
#define V_SYS_BIN _SB_MAKEVALUE(x,S_SYS_BIN)
#define G_SYS_BIN _SB_GETVALUE(x,S_SYS_BIN,M_SYS_BIN)
-
+
/* Wafer ID: bits 39:36 */
#define S_SYS_WAFERID2_200 _SB_MAKE64(36)
#define M_SYS_WAFERID2_200 _SB_MAKEMASK(4,S_SYS_WAFERID2_200)
#define V_SYS_WAFERID2_200(x) _SB_MAKEVALUE(x,S_SYS_WAFERID2_200)
#define G_SYS_WAFERID2_200(x) _SB_GETVALUE(x,S_SYS_WAFERID2_200,M_SYS_WAFERID2_200)
-
+
/* Wafer ID: bits 39:0 */
#define S_SYS_WAFERID_300 _SB_MAKE64(0)
#define M_SYS_WAFERID_300 _SB_MAKEMASK(40,S_SYS_WAFERID_300)
#define V_SYS_WAFERID_300(x) _SB_MAKEVALUE(x,S_SYS_WAFERID_300)
#define G_SYS_WAFERID_300(x) _SB_GETVALUE(x,S_SYS_WAFERID_300,M_SYS_WAFERID_300)
-
+
#define S_SYS_XPOS _SB_MAKE64(40)
#define M_SYS_XPOS _SB_MAKEMASK(6,S_SYS_XPOS)
#define V_SYS_XPOS(x) _SB_MAKEVALUE(x,S_SYS_XPOS)
#define G_SYS_XPOS(x) _SB_GETVALUE(x,S_SYS_XPOS,M_SYS_XPOS)
-
+
#define S_SYS_YPOS _SB_MAKE64(46)
#define M_SYS_YPOS _SB_MAKEMASK(6,S_SYS_YPOS)
#define V_SYS_YPOS(x) _SB_MAKEVALUE(x,S_SYS_YPOS)
#define G_SYS_YPOS(x) _SB_GETVALUE(x,S_SYS_YPOS,M_SYS_YPOS)
-
+
/*
* System Config Register (Table 4-2)
* Register: SCD_SYSTEM_CFG
diff --git a/include/asm-mips/sibyte/sb1250_smbus.h b/include/asm-mips/sibyte/sb1250_smbus.h
index 287cbfe..335c53e 100644
--- a/include/asm-mips/sibyte/sb1250_smbus.h
+++ b/include/asm-mips/sibyte/sb1250_smbus.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* SMBUS Constants File: sb1250_smbus.h
- *
- * This module contains constants and macros useful for
+ *
+ * This module contains constants and macros useful for
* manipulating the SB1250's SMbus devices.
- *
+ *
* SB1250 specification level: 01/02/2002
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
diff --git a/include/asm-mips/sibyte/sb1250_syncser.h b/include/asm-mips/sibyte/sb1250_syncser.h
index 8d5e8edd..fa2760d3 100644
--- a/include/asm-mips/sibyte/sb1250_syncser.h
+++ b/include/asm-mips/sibyte/sb1250_syncser.h
@@ -7,17 +7,17 @@
* manipulating the SB1250's Synchronous Serial
*
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
*
*********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
diff --git a/include/asm-mips/sibyte/sb1250_uart.h b/include/asm-mips/sibyte/sb1250_uart.h
index 7655d69..923ea4f 100644
--- a/include/asm-mips/sibyte/sb1250_uart.h
+++ b/include/asm-mips/sibyte/sb1250_uart.h
@@ -1,23 +1,23 @@
/* *********************************************************************
* SB1250 Board Support Package
- *
+ *
* UART Constants File: sb1250_uart.h
- *
- * This module contains constants and macros useful for
+ *
+ * This module contains constants and macros useful for
* manipulating the SB1250's UARTs
*
* SB1250 specification level: User's manual 1/02/02
- *
+ *
* Author: Mitch Lichtenberg
- *
- *********************************************************************
+ *
+ *********************************************************************
*
* Copyright 2000,2001,2002,2003
* Broadcom Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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,
@@ -27,7 +27,7 @@
*
* 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,
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
********************************************************************* */
@@ -37,7 +37,7 @@
#include "sb1250_defs.h"
-/* **********************************************************************
+/* **********************************************************************
* DUART Registers
********************************************************************** */
@@ -145,7 +145,7 @@
#define V_DUART_MISC_CMD_START_BREAK V_DUART_MISC_CMD(K_DUART_MISC_CMD_START_BREAK)
#define V_DUART_MISC_CMD_STOP_BREAK V_DUART_MISC_CMD(K_DUART_MISC_CMD_STOP_BREAK)
-#define M_DUART_CMD_RESERVED _SB_MAKEMASK1(7)
+#define M_DUART_CMD_RESERVED _SB_MAKEMASK1(7)
/*
* DUART Status Register (Table 10-6)
@@ -165,7 +165,7 @@
/*
* DUART Baud Rate Register (Table 10-7)
- * Register: DUART_CLK_SEL_A
+ * Register: DUART_CLK_SEL_A
* Register: DUART_CLK_SEL_B
*/
@@ -332,7 +332,7 @@
(chan == 0 ? M_DUART_OUT_PIN_CLR0 : M_DUART_OUT_PIN_CLR1)
#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
-/*
+/*
* Full Interrupt Control Register
*/
diff --git a/include/asm-mips/sigcontext.h b/include/asm-mips/sigcontext.h
index 18939e8..f7fbeba 100644
--- a/include/asm-mips/sigcontext.h
+++ b/include/asm-mips/sigcontext.h
@@ -10,7 +10,7 @@
#define _ASM_SIGCONTEXT_H
#include <asm/sgidefs.h>
-
+
#if _MIPS_SIM == _MIPS_SIM_ABI32
/*
@@ -38,7 +38,7 @@
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
-
+
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
/*
diff --git a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h
index a0e26e6..698beca 100644
--- a/include/asm-mips/siginfo.h
+++ b/include/asm-mips/siginfo.h
@@ -25,10 +25,10 @@
/*
* Careful to keep union _sifields from shifting ...
*/
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
#endif
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#endif
diff --git a/include/asm-mips/sim.h b/include/asm-mips/sim.h
index 6333169..3ccfe09 100644
--- a/include/asm-mips/sim.h
+++ b/include/asm-mips/sim.h
@@ -16,7 +16,7 @@
#define __str2(x) #x
#define __str(x) __str2(x)
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define save_static_function(symbol) \
__asm__ ( \
@@ -42,9 +42,9 @@
#define nabi_no_regargs
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define save_static_function(symbol) \
__asm__ ( \
@@ -78,6 +78,6 @@
unsigned long __dummy6, \
unsigned long __dummy7,
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
#endif /* _ASM_SIM_H */
diff --git a/include/asm-mips/socket.h b/include/asm-mips/socket.h
index d478a86..753b662 100644
--- a/include/asm-mips/socket.h
+++ b/include/asm-mips/socket.h
@@ -82,7 +82,7 @@
* @SOCK_STREAM - stream (connection) socket
* @SOCK_RAW - raw socket
* @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
+ * @SOCK_SEQPACKET - sequential packet socket
* @SOCK_PACKET - linux specific way of getting packets at the dev level.
* For writing rarp and other similar things on the user level.
*/
diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
index 86283c2..fb42f99 100644
--- a/include/asm-mips/stackframe.h
+++ b/include/asm-mips/stackframe.h
@@ -26,7 +26,7 @@
.macro SAVE_TEMP
mfhi v1
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp)
#endif
@@ -56,7 +56,7 @@
#ifdef CONFIG_SMP
.macro get_saved_sp /* SMP variation */
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
mfc0 k0, CP0_CONTEXT
lui k1, %hi(kernelsp)
srl k0, k0, 23
@@ -64,7 +64,7 @@
addu k1, k0
LONG_L k1, %lo(kernelsp)(k1)
#endif
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
MFC0 k1, CP0_CONTEXT
dsra k1, 23
lui k0, %hi(pgd_current)
@@ -74,7 +74,7 @@
daddu k1, k0
LONG_L k1, %lo(kernelsp)(k1)
#endif
-#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
MFC0 k1, CP0_CONTEXT
dsrl k1, 23
dsll k1, k1, 3
@@ -83,20 +83,20 @@
.endm
.macro set_saved_sp stackp temp temp2
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
mfc0 \temp, CP0_CONTEXT
srl \temp, 23
sll \temp, 2
LONG_S \stackp, kernelsp(\temp)
#endif
-#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
lw \temp, TI_CPU(gp)
dsll \temp, 3
lui \temp2, %hi(kernelsp)
daddu \temp, \temp2
LONG_S \stackp, %lo(kernelsp)(\temp)
#endif
-#if defined(CONFIG_MIPS64) && defined(CONFIG_BUILD_ELF64)
+#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
lw \temp, TI_CPU(gp)
dsll \temp, 3
LONG_S \stackp, kernelsp(\temp)
@@ -140,7 +140,7 @@
LONG_S $6, PT_R6(sp)
MFC0 v1, CP0_EPC
LONG_S $7, PT_R7(sp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp)
#endif
@@ -169,7 +169,7 @@
.macro RESTORE_TEMP
LONG_L $24, PT_LO(sp)
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
LONG_L $8, PT_R8(sp)
LONG_L $9, PT_R9(sp)
#endif
@@ -217,7 +217,7 @@
LONG_L $31, PT_R31(sp)
LONG_L $28, PT_R28(sp)
LONG_L $25, PT_R25(sp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
LONG_L $8, PT_R8(sp)
LONG_L $9, PT_R9(sp)
#endif
@@ -262,7 +262,7 @@
LONG_L $31, PT_R31(sp)
LONG_L $28, PT_R28(sp)
LONG_L $25, PT_R25(sp)
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
LONG_L $8, PT_R8(sp)
LONG_L $9, PT_R9(sp)
#endif
diff --git a/include/asm-mips/statfs.h b/include/asm-mips/statfs.h
index 5076fec..c3ddf97 100644
--- a/include/asm-mips/statfs.h
+++ b/include/asm-mips/statfs.h
@@ -57,7 +57,7 @@
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
-
+
#if _MIPS_SIM == _MIPS_SIM_ABI64
struct statfs64 { /* Same as struct statfs */
diff --git a/include/asm-mips/string.h b/include/asm-mips/string.h
index b183455..5a06f6d 100644
--- a/include/asm-mips/string.h
+++ b/include/asm-mips/string.h
@@ -16,7 +16,7 @@
* Most of the inline functions are rather naive implementations so I just
* didn't bother updating them for 64-bit ...
*/
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#ifndef IN_STRING_C
@@ -130,7 +130,7 @@
return __res;
}
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
#define __HAVE_ARCH_MEMSET
extern void *memset(void *__s, int __c, size_t __count);
@@ -141,7 +141,7 @@
#define __HAVE_ARCH_MEMMOVE
extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define __HAVE_ARCH_MEMSCAN
static __inline__ void *memscan(void *__addr, int __c, size_t __size)
{
@@ -161,6 +161,6 @@
return __addr;
}
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
#endif /* _ASM_STRING_H */
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 169f3d4..6663efd 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -208,7 +208,7 @@
return retval;
}
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
{
__u64 retval;
@@ -330,7 +330,7 @@
return retval;
}
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
unsigned long new)
{
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
index 42fcd6f..a70cb08 100644
--- a/include/asm-mips/thread_info.h
+++ b/include/asm-mips/thread_info.h
@@ -62,10 +62,10 @@
#define current_thread_info() __current_thread_info
/* thread information allocation */
-#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS32)
+#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
#define THREAD_SIZE_ORDER (1)
#endif
-#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS64)
+#if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_64BIT)
#define THREAD_SIZE_ORDER (2)
#endif
#ifdef CONFIG_PAGE_SIZE_8KB
diff --git a/include/asm-mips/titan_dep.h b/include/asm-mips/titan_dep.h
index fd9599e..fee1908 100644
--- a/include/asm-mips/titan_dep.h
+++ b/include/asm-mips/titan_dep.h
@@ -228,4 +228,4 @@
#define RM9K_READ_8(ofs, val) *(val) = *(volatile u8 *)(RM9000x2_BASE_ADDR+ofs)
#define RM9K_READ_16(ofs, val) *(val) = *(volatile u16 *)(RM9000x2_BASE_ADDR+ofs)
-#endif
+#endif
diff --git a/include/asm-mips/tx4927/tx4927.h b/include/asm-mips/tx4927/tx4927.h
index 5d939db..3bb7f00 100644
--- a/include/asm-mips/tx4927/tx4927.h
+++ b/include/asm-mips/tx4927/tx4927.h
@@ -45,14 +45,14 @@
/* TX4927 SDRAM controller (64-bit registers) */
-#define TX4927_SDRAMC_BASE 0x8000
-#define TX4927_SDRAMC_SDCCR0 0x8000
+#define TX4927_SDRAMC_BASE 0x8000
+#define TX4927_SDRAMC_SDCCR0 0x8000
#define TX4927_SDRAMC_SDCCR1 0x8008
#define TX4927_SDRAMC_SDCCR2 0x8010
#define TX4927_SDRAMC_SDCCR3 0x8018
#define TX4927_SDRAMC_SDCTR 0x8040
#define TX4927_SDRAMC_SDCMD 0x8058
-#define TX4927_SDRAMC_LIMIT 0x8fff
+#define TX4927_SDRAMC_LIMIT 0x8fff
/* TX4927 external bus controller (64-bit registers) */
@@ -289,8 +289,8 @@
/* TX4927 serial port 0 (32-bit registers) */
-#define TX4927_SIO0_BASE 0xf300
-#define TX4927_SIO0_SILCR0 0xf300
+#define TX4927_SIO0_BASE 0xf300
+#define TX4927_SIO0_SILCR0 0xf300
#define TX4927_SIO0_SILCR0_RESERVED_16_31 BM_16_31
#define TX4927_SIO0_SILCR0_RWUB BM_15_15
#define TX4927_SIO0_SILCR0_TWUB BM_14_14
@@ -309,7 +309,7 @@
#define TX4927_SIO0_SILCR0_UMODE_DATA_7_BIT (~BM_00_01)
#define TX4927_SIO0_SILCR0_UMODE_DATA_8_BIT_MC BM_01_01
#define TX4927_SIO0_SILCR0_UMODE_DATA_7_BIT_MC BM_00_01
-#define TX4927_SIO0_SIDICR0 0xf304
+#define TX4927_SIO0_SIDICR0 0xf304
#define TX4927_SIO0_SIDICR0_RESERVED_16_31 BM_16_31
#define TX4927_SIO0_SIDICR0_TDE BM_15_15
#define TX4927_SIO0_SIDICR0_RDE BM_14_14
@@ -330,7 +330,7 @@
#define TX4927_SIO0_SIDICR0_STIE_TRDY BM_02_02
#define TX4927_SIO0_SIDICR0_STIE_TXALS BM_01_01
#define TX4927_SIO0_SIDICR0_STIE_UBRKD BM_00_00
-#define TX4927_SIO0_SIDISR0 0xf308
+#define TX4927_SIO0_SIDISR0 0xf308
#define TX4927_SIO0_SIDISR0_RESERVED_16_31 BM_16_31
#define TX4927_SIO0_SIDISR0_UBRK BM_15_15
#define TX4927_SIO0_SIDISR0_UVALID BM_14_14
@@ -344,7 +344,7 @@
#define TX4927_SIO0_SIDISR0_STIS BM_06_06
#define TX4927_SIO0_SIDISR0_RESERVED_05_05 BM_05_05
#define TX4927_SIO0_SIDISR0_RFDN BM_00_04
-#define TX4927_SIO0_SISCISR0 0xf30c
+#define TX4927_SIO0_SISCISR0 0xf30c
#define TX4927_SIO0_SISCISR0_RESERVED_06_31 BM_06_31
#define TX4927_SIO0_SISCISR0_OERS BM_05_05
#define TX4927_SIO0_SISCISR0_CTSS BM_04_04
@@ -352,7 +352,7 @@
#define TX4927_SIO0_SISCISR0_TRDY BM_02_02
#define TX4927_SIO0_SISCISR0_TXALS BM_01_01
#define TX4927_SIO0_SISCISR0_UBRKD BM_00_00
-#define TX4927_SIO0_SIFCR0 0xf310
+#define TX4927_SIO0_SIFCR0 0xf310
#define TX4927_SIO0_SIFCR0_RESERVED_16_31 BM_16_31
#define TX4927_SIO0_SIFCR0_SWRST BM_16_31
#define TX4927_SIO0_SIFCR0_RESERVED_09_14 BM_09_14
@@ -370,7 +370,7 @@
#define TX4927_SIO0_SIFCR0_TFRST BM_02_02
#define TX4927_SIO0_SIFCR0_RFRST BM_01_01
#define TX4927_SIO0_SIFCR0_FRSTE BM_00_00
-#define TX4927_SIO0_SIFLCR0 0xf314
+#define TX4927_SIO0_SIFLCR0 0xf314
#define TX4927_SIO0_SIFLCR0_RESERVED_13_31 BM_13_31
#define TX4927_SIO0_SIFLCR0_RCS BM_12_12
#define TX4927_SIO0_SIFLCR0_TES BM_11_11
@@ -381,7 +381,7 @@
#define TX4927_SIO0_SIFLCR0_RESERVED_05_06 BM_05_06
#define TX4927_SIO0_SIFLCR0_RTSTL BM_01_04
#define TX4927_SIO0_SIFLCR0_TBRK BM_00_00
-#define TX4927_SIO0_SIBGR0 0xf318
+#define TX4927_SIO0_SIBGR0 0xf318
#define TX4927_SIO0_SIBGR0_RESERVED_10_31 BM_10_31
#define TX4927_SIO0_SIBGR0_BCLK BM_08_09
#define TX4927_SIO0_SIBGR0_BCLK_T0 (~BM_08_09)
@@ -389,28 +389,28 @@
#define TX4927_SIO0_SIBGR0_BCLK_T4 BM_09_09
#define TX4927_SIO0_SIBGR0_BCLK_T6 BM_08_09
#define TX4927_SIO0_SIBGR0_BRD BM_00_07
-#define TX4927_SIO0_SITFIF00 0xf31c
+#define TX4927_SIO0_SITFIF00 0xf31c
#define TX4927_SIO0_SITFIF00_RESERVED_08_31 BM_08_31
#define TX4927_SIO0_SITFIF00_TXD BM_00_07
-#define TX4927_SIO0_SIRFIFO0 0xf320
+#define TX4927_SIO0_SIRFIFO0 0xf320
#define TX4927_SIO0_SIRFIFO0_RESERVED_08_31 BM_08_31
#define TX4927_SIO0_SIRFIFO0_RXD BM_00_07
-#define TX4927_SIO0_SIRFIFO0 0xf320
-#define TX4927_SIO0_LIMIT 0xf3ff
+#define TX4927_SIO0_SIRFIFO0 0xf320
+#define TX4927_SIO0_LIMIT 0xf3ff
/* TX4927 serial port 1 (32-bit registers) */
-#define TX4927_SIO1_BASE 0xf400
-#define TX4927_SIO1_SILCR1 0xf400
-#define TX4927_SIO1_SIDICR1 0xf404
-#define TX4927_SIO1_SIDISR1 0xf408
-#define TX4927_SIO1_SISCISR1 0xf40c
-#define TX4927_SIO1_SIFCR1 0xf410
-#define TX4927_SIO1_SIFLCR1 0xf414
-#define TX4927_SIO1_SIBGR1 0xf418
-#define TX4927_SIO1_SITFIF01 0xf41c
-#define TX4927_SIO1_SIRFIFO1 0xf420
-#define TX4927_SIO1_LIMIT 0xf4ff
+#define TX4927_SIO1_BASE 0xf400
+#define TX4927_SIO1_SILCR1 0xf400
+#define TX4927_SIO1_SIDICR1 0xf404
+#define TX4927_SIO1_SIDISR1 0xf408
+#define TX4927_SIO1_SISCISR1 0xf40c
+#define TX4927_SIO1_SIFCR1 0xf410
+#define TX4927_SIO1_SIFLCR1 0xf414
+#define TX4927_SIO1_SIBGR1 0xf418
+#define TX4927_SIO1_SITFIF01 0xf41c
+#define TX4927_SIO1_SIRFIFO1 0xf420
+#define TX4927_SIO1_LIMIT 0xf4ff
/* TX4927 parallel port (32-bit registers) */
diff --git a/include/asm-mips/tx4927/tx4927_pci.h b/include/asm-mips/tx4927/tx4927_pci.h
index 1704334..165f6b8 100644
--- a/include/asm-mips/tx4927/tx4927_pci.h
+++ b/include/asm-mips/tx4927/tx4927_pci.h
@@ -5,8 +5,8 @@
*
* Copyright (C) 2000-2001 Toshiba Corporation
*/
-#ifndef __ASM_TX4927_TX4927_PCI_H
-#define __ASM_TX4927_TX4927_PCI_H
+#ifndef __ASM_TX4927_TX4927_PCI_H
+#define __ASM_TX4927_TX4927_PCI_H
#define TX4927_CCFG_TOE 0x00004000
diff --git a/include/asm-mips/types.h b/include/asm-mips/types.h
index d2f0c76..421b3ae 100644
--- a/include/asm-mips/types.h
+++ b/include/asm-mips/types.h
@@ -78,7 +78,7 @@
#endif
#if (defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) \
- || defined(CONFIG_MIPS64)
+ || defined(CONFIG_64BIT)
typedef u64 dma_addr_t;
#else
typedef u32 dma_addr_t;
@@ -99,8 +99,6 @@
#define HAVE_SECTOR_T
#endif
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h
index 0711489..5c2c983 100644
--- a/include/asm-mips/uaccess.h
+++ b/include/asm-mips/uaccess.h
@@ -22,7 +22,7 @@
*
* For historical reasons, these macros are grossly misnamed.
*/
-#ifdef CONFIG_MIPS32
+#ifdef CONFIG_32BIT
#define __UA_LIMIT 0x80000000UL
@@ -32,9 +32,9 @@
#define __UA_t0 "$8"
#define __UA_t1 "$9"
-#endif /* CONFIG_MIPS32 */
+#endif /* CONFIG_32BIT */
-#ifdef CONFIG_MIPS64
+#ifdef CONFIG_64BIT
#define __UA_LIMIT (- TASK_SIZE)
@@ -44,7 +44,7 @@
#define __UA_t0 "$12"
#define __UA_t1 "$13"
-#endif /* CONFIG_MIPS64 */
+#endif /* CONFIG_64BIT */
/*
* USER_DS is a bitmask that has the bits set that may not be set in a valid
@@ -112,29 +112,6 @@
likely(__access_ok((unsigned long)(addr), (size),__access_mask))
/*
- * verify_area: - Obsolete/deprecated and will go away soon,
- * use access_ok() instead.
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only. This function may sleep.
- *
- * This function has been replaced by access_ok().
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns zero if the memory block may be valid, -EFAULT
- * if it is definitely invalid.
- *
- * See access_ok() for more details.
- */
-static inline int __deprecated verify_area(int type, const void * addr, unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
-/*
* put_user: - Write a simple value into user space.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
index 6d21cc9..ad4d480 100644
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -1124,7 +1124,7 @@
# ifndef __mips64
# define __ARCH_WANT_STAT64
# endif
-# ifdef CONFIG_MIPS32
+# ifdef CONFIG_32BIT
# define __ARCH_WANT_SYS_TIME
# endif
# ifdef CONFIG_MIPS32_O32
diff --git a/include/asm-mips/vr4181/irq.h b/include/asm-mips/vr4181/irq.h
deleted file mode 100644
index 4bf0ea9..0000000
--- a/include/asm-mips/vr4181/irq.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Macros for vr4181 IRQ numbers.
- *
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-/*
- * Strategy:
- *
- * Vr4181 has conceptually three levels of interrupt controllers:
- * 1. the CPU itself with 8 intr level.
- * 2. system interrupt controller, cascaded from int0 pin in CPU, 32 intrs
- * 3. GPIO interrupts : forwarding external interrupts to sys intr controller
- */
-
-/* decide the irq block assignment */
-#define VR4181_NUM_CPU_IRQ 8
-#define VR4181_NUM_SYS_IRQ 32
-#define VR4181_NUM_GPIO_IRQ 16
-
-#define VR4181_IRQ_BASE 0
-
-#define VR4181_CPU_IRQ_BASE VR4181_IRQ_BASE
-#define VR4181_SYS_IRQ_BASE (VR4181_CPU_IRQ_BASE + VR4181_NUM_CPU_IRQ)
-#define VR4181_GPIO_IRQ_BASE (VR4181_SYS_IRQ_BASE + VR4181_NUM_SYS_IRQ)
-
-/* CPU interrupts */
-
-/*
- IP0 - Software interrupt
- IP1 - Software interrupt
- IP2 - All but battery, high speed modem, and real time clock
- IP3 - RTC Long1 (system timer)
- IP4 - RTC Long2
- IP5 - High Speed Modem (unused on VR4181)
- IP6 - Unused
- IP7 - Timer interrupt from CPO_COMPARE
-*/
-
-#define VR4181_IRQ_SW1 (VR4181_CPU_IRQ_BASE + 0)
-#define VR4181_IRQ_SW2 (VR4181_CPU_IRQ_BASE + 1)
-#define VR4181_IRQ_INT0 (VR4181_CPU_IRQ_BASE + 2)
-#define VR4181_IRQ_INT1 (VR4181_CPU_IRQ_BASE + 3)
-#define VR4181_IRQ_INT2 (VR4181_CPU_IRQ_BASE + 4)
-#define VR4181_IRQ_INT3 (VR4181_CPU_IRQ_BASE + 5)
-#define VR4181_IRQ_INT4 (VR4181_CPU_IRQ_BASE + 6)
-#define VR4181_IRQ_TIMER (VR4181_CPU_IRQ_BASE + 7)
-
-
-/* Cascaded from VR4181_IRQ_INT0 (ICU mapped interrupts) */
-
-/*
- IP2 - same as VR4181_IRQ_INT1
- IP8 - This is a cascade to GPIO IRQ's. Do not use.
- IP16 - same as VR4181_IRQ_INT2
- IP18 - CompactFlash
-*/
-
-#define VR4181_IRQ_BATTERY (VR4181_SYS_IRQ_BASE + 0)
-#define VR4181_IRQ_POWER (VR4181_SYS_IRQ_BASE + 1)
-#define VR4181_IRQ_RTCL1 (VR4181_SYS_IRQ_BASE + 2)
-#define VR4181_IRQ_ETIMER (VR4181_SYS_IRQ_BASE + 3)
-#define VR4181_IRQ_RFU12 (VR4181_SYS_IRQ_BASE + 4)
-#define VR4181_IRQ_PIU (VR4181_SYS_IRQ_BASE + 5)
-#define VR4181_IRQ_AIU (VR4181_SYS_IRQ_BASE + 6)
-#define VR4181_IRQ_KIU (VR4181_SYS_IRQ_BASE + 7)
-#define VR4181_IRQ_GIU (VR4181_SYS_IRQ_BASE + 8)
-#define VR4181_IRQ_SIU (VR4181_SYS_IRQ_BASE + 9)
-#define VR4181_IRQ_RFU18 (VR4181_SYS_IRQ_BASE + 10)
-#define VR4181_IRQ_SOFT (VR4181_SYS_IRQ_BASE + 11)
-#define VR4181_IRQ_RFU20 (VR4181_SYS_IRQ_BASE + 12)
-#define VR4181_IRQ_DOZEPIU (VR4181_SYS_IRQ_BASE + 13)
-#define VR4181_IRQ_RFU22 (VR4181_SYS_IRQ_BASE + 14)
-#define VR4181_IRQ_RFU23 (VR4181_SYS_IRQ_BASE + 15)
-#define VR4181_IRQ_RTCL2 (VR4181_SYS_IRQ_BASE + 16)
-#define VR4181_IRQ_LED (VR4181_SYS_IRQ_BASE + 17)
-#define VR4181_IRQ_ECU (VR4181_SYS_IRQ_BASE + 18)
-#define VR4181_IRQ_CSU (VR4181_SYS_IRQ_BASE + 19)
-#define VR4181_IRQ_USB (VR4181_SYS_IRQ_BASE + 20)
-#define VR4181_IRQ_DMA (VR4181_SYS_IRQ_BASE + 21)
-#define VR4181_IRQ_LCD (VR4181_SYS_IRQ_BASE + 22)
-#define VR4181_IRQ_RFU31 (VR4181_SYS_IRQ_BASE + 23)
-#define VR4181_IRQ_RFU32 (VR4181_SYS_IRQ_BASE + 24)
-#define VR4181_IRQ_RFU33 (VR4181_SYS_IRQ_BASE + 25)
-#define VR4181_IRQ_RFU34 (VR4181_SYS_IRQ_BASE + 26)
-#define VR4181_IRQ_RFU35 (VR4181_SYS_IRQ_BASE + 27)
-#define VR4181_IRQ_RFU36 (VR4181_SYS_IRQ_BASE + 28)
-#define VR4181_IRQ_RFU37 (VR4181_SYS_IRQ_BASE + 29)
-#define VR4181_IRQ_RFU38 (VR4181_SYS_IRQ_BASE + 30)
-#define VR4181_IRQ_RFU39 (VR4181_SYS_IRQ_BASE + 31)
-
-/* Cascaded from VR4181_IRQ_GIU */
-#define VR4181_IRQ_GPIO0 (VR4181_GPIO_IRQ_BASE + 0)
-#define VR4181_IRQ_GPIO1 (VR4181_GPIO_IRQ_BASE + 1)
-#define VR4181_IRQ_GPIO2 (VR4181_GPIO_IRQ_BASE + 2)
-#define VR4181_IRQ_GPIO3 (VR4181_GPIO_IRQ_BASE + 3)
-#define VR4181_IRQ_GPIO4 (VR4181_GPIO_IRQ_BASE + 4)
-#define VR4181_IRQ_GPIO5 (VR4181_GPIO_IRQ_BASE + 5)
-#define VR4181_IRQ_GPIO6 (VR4181_GPIO_IRQ_BASE + 6)
-#define VR4181_IRQ_GPIO7 (VR4181_GPIO_IRQ_BASE + 7)
-#define VR4181_IRQ_GPIO8 (VR4181_GPIO_IRQ_BASE + 8)
-#define VR4181_IRQ_GPIO9 (VR4181_GPIO_IRQ_BASE + 9)
-#define VR4181_IRQ_GPIO10 (VR4181_GPIO_IRQ_BASE + 10)
-#define VR4181_IRQ_GPIO11 (VR4181_GPIO_IRQ_BASE + 11)
-#define VR4181_IRQ_GPIO12 (VR4181_GPIO_IRQ_BASE + 12)
-#define VR4181_IRQ_GPIO13 (VR4181_GPIO_IRQ_BASE + 13)
-#define VR4181_IRQ_GPIO14 (VR4181_GPIO_IRQ_BASE + 14)
-#define VR4181_IRQ_GPIO15 (VR4181_GPIO_IRQ_BASE + 15)
-
-
-// Alternative to above GPIO IRQ defines
-#define VR4181_IRQ_GPIO(pin) ((VR4181_IRQ_GPIO0) + (pin))
-
-#define VR4181_IRQ_MAX (VR4181_IRQ_BASE + VR4181_NUM_CPU_IRQ + \
- VR4181_NUM_SYS_IRQ + VR4181_NUM_GPIO_IRQ)
diff --git a/include/asm-mips/vr4181/vr4181.h b/include/asm-mips/vr4181/vr4181.h
deleted file mode 100644
index 5c5d607..0000000
--- a/include/asm-mips/vr4181/vr4181.h
+++ /dev/null
@@ -1,413 +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) 1999 by Michael Klar
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- */
-#ifndef __ASM_VR4181_VR4181_H
-#define __ASM_VR4181_VR4181_H
-
-#include <asm/addrspace.h>
-
-#include <asm/vr4181/irq.h>
-
-#ifndef __ASSEMBLY__
-#define __preg8 (volatile unsigned char*)
-#define __preg16 (volatile unsigned short*)
-#define __preg32 (volatile unsigned int*)
-#else
-#define __preg8
-#define __preg16
-#define __preg32
-#endif
-
-// Embedded CPU peripheral registers
-// Note that many of the registers have different physical address for VR4181
-
-// Bus Control Unit (BCU)
-#define VR4181_BCUCNTREG1 __preg16(KSEG1 + 0x0A000000) /* BCU control register 1 (R/W) */
-#define VR4181_CMUCLKMSK __preg16(KSEG1 + 0x0A000004) /* Clock mask register (R/W) */
-#define VR4181_CMUCLKMSK_MSKCSUPCLK 0x0040
-#define VR4181_CMUCLKMSK_MSKAIUPCLK 0x0020
-#define VR4181_CMUCLKMSK_MSKPIUPCLK 0x0010
-#define VR4181_CMUCLKMSK_MSKADUPCLK 0x0008
-#define VR4181_CMUCLKMSK_MSKSIU18M 0x0004
-#define VR4181_CMUCLKMSK_MSKADU18M 0x0002
-#define VR4181_CMUCLKMSK_MSKUSB 0x0001
-#define VR4181_CMUCLKMSK_MSKSIU VR4181_CMUCLKMSK_MSKSIU18M
-#define VR4181_BCUSPEEDREG __preg16(KSEG1 + 0x0A00000C) /* BCU access time parameter (R/W) */
-#define VR4181_BCURFCNTREG __preg16(KSEG1 + 0x0A000010) /* BCU refresh control register (R/W) */
-#define VR4181_REVIDREG __preg16(KSEG1 + 0x0A000014) /* Revision ID register (R) */
-#define VR4181_CLKSPEEDREG __preg16(KSEG1 + 0x0A000018) /* Clock speed register (R) */
-#define VR4181_EDOMCYTREG __preg16(KSEG1 + 0x0A000300) /* Memory cycle timing register (R/W) */
-#define VR4181_MEMCFG_REG __preg16(KSEG1 + 0x0A000304) /* Memory configuration register (R/W) */
-#define VR4181_MODE_REG __preg16(KSEG1 + 0x0A000308) /* SDRAM mode register (R/W) */
-#define VR4181_SDTIMINGREG __preg16(KSEG1 + 0x0A00030C) /* SDRAM timing register (R/W) */
-
-// DMA Control Unit (DCU)
-#define VR4181_MICDEST1REG1 __preg16(KSEG1 + 0x0A000020) /* Microphone destination 1 address register 1 (R/W) */
-#define VR4181_MICDEST1REG2 __preg16(KSEG1 + 0x0A000022) /* Microphone destination 1 address register 2 (R/W) */
-#define VR4181_MICDEST2REG1 __preg16(KSEG1 + 0x0A000024) /* Microphone destination 2 address register 1 (R/W) */
-#define VR4181_MICDEST2REG2 __preg16(KSEG1 + 0x0A000026) /* Microphone destination 2 address register 2 (R/W) */
-#define VR4181_SPKRRC1REG1 __preg16(KSEG1 + 0x0A000028) /* Speaker Source 1 address register 1 (R/W) */
-#define VR4181_SPKRRC1REG2 __preg16(KSEG1 + 0x0A00002A) /* Speaker Source 1 address register 2 (R/W) */
-#define VR4181_SPKRRC2REG1 __preg16(KSEG1 + 0x0A00002C) /* Speaker Source 2 address register 1 (R/W) */
-#define VR4181_SPKRRC2REG2 __preg16(KSEG1 + 0x0A00002E) /* Speaker Source 2 address register 2 (R/W) */
-#define VR4181_DMARSTREG __preg16(KSEG1 + 0x0A000040) /* DMA Reset register (R/W) */
-#define VR4181_AIUDMAMSKREG __preg16(KSEG1 + 0x0A000046) /* Audio DMA mask register (R/W) */
-#define VR4181_USBDMAMSKREG __preg16(KSEG1 + 0x0A000600) /* USB DMA Mask register (R/W) */
-#define VR4181_USBRXS1AREG1 __preg16(KSEG1 + 0x0A000602) /* USB Rx source 1 address register 1 (R/W) */
-#define VR4181_USBRXS1AREG2 __preg16(KSEG1 + 0x0A000604) /* USB Rx source 1 address register 2 (R/W) */
-#define VR4181_USBRXS2AREG1 __preg16(KSEG1 + 0x0A000606) /* USB Rx source 2 address register 1 (R/W) */
-#define VR4181_USBRXS2AREG2 __preg16(KSEG1 + 0x0A000608) /* USB Rx source 2 address register 2 (R/W) */
-#define VR4181_USBTXS1AREG1 __preg16(KSEG1 + 0x0A00060A) /* USB Tx source 1 address register 1 (R/W) */
-#define VR4181_USBTXS1AREG2 __preg16(KSEG1 + 0x0A00060C) /* USB Tx source 1 address register 2 (R/W) */
-#define VR4181_USBTXS2AREG1 __preg16(KSEG1 + 0x0A00060E) /* USB Tx source 2 address register 1 (R/W) */
-#define VR4181_USBTXS2AREG2 __preg16(KSEG1 + 0x0A000610) /* USB Tx source 2 address register 2 (R/W) */
-#define VR4181_USBRXD1AREG1 __preg16(KSEG1 + 0x0A00062A) /* USB Rx destination 1 address register 1 (R/W) */
-#define VR4181_USBRXD1AREG2 __preg16(KSEG1 + 0x0A00062C) /* USB Rx destination 1 address register 2 (R/W) */
-#define VR4181_USBRXD2AREG1 __preg16(KSEG1 + 0x0A00062E) /* USB Rx destination 2 address register 1 (R/W) */
-#define VR4181_USBRXD2AREG2 __preg16(KSEG1 + 0x0A000630) /* USB Rx destination 2 address register 2 (R/W) */
-#define VR4181_USBTXD1AREG1 __preg16(KSEG1 + 0x0A000632) /* USB Tx destination 1 address register 1 (R/W) */
-#define VR4181_USBTXD1AREG2 __preg16(KSEG1 + 0x0A000634) /* USB Tx destination 1 address register 2 (R/W) */
-#define VR4181_USBTXD2AREG1 __preg16(KSEG1 + 0x0A000636) /* USB Tx destination 2 address register 1 (R/W) */
-#define VR4181_USBTXD2AREG2 __preg16(KSEG1 + 0x0A000638) /* USB Tx destination 2 address register 2 (R/W) */
-#define VR4181_RxRCLENREG __preg16(KSEG1 + 0x0A000652) /* USB Rx record length register (R/W) */
-#define VR4181_TxRCLENREG __preg16(KSEG1 + 0x0A000654) /* USB Tx record length register (R/W) */
-#define VR4181_MICRCLENREG __preg16(KSEG1 + 0x0A000658) /* Microphone record length register (R/W) */
-#define VR4181_SPKRCLENREG __preg16(KSEG1 + 0x0A00065A) /* Speaker record length register (R/W) */
-#define VR4181_USBCFGREG __preg16(KSEG1 + 0x0A00065C) /* USB configuration register (R/W) */
-#define VR4181_MICDMACFGREG __preg16(KSEG1 + 0x0A00065E) /* Microphone DMA configuration register (R/W) */
-#define VR4181_SPKDMACFGREG __preg16(KSEG1 + 0x0A000660) /* Speaker DMA configuration register (R/W) */
-#define VR4181_DMAITRQREG __preg16(KSEG1 + 0x0A000662) /* DMA interrupt request register (R/W) */
-#define VR4181_DMACLTREG __preg16(KSEG1 + 0x0A000664) /* DMA control register (R/W) */
-#define VR4181_DMAITMKREG __preg16(KSEG1 + 0x0A000666) /* DMA interrupt mask register (R/W) */
-
-// ISA Bridge
-#define VR4181_ISABRGCTL __preg16(KSEG1 + 0x0B0002C0) /* ISA Bridge Control Register (R/W) */
-#define VR4181_ISABRGSTS __preg16(KSEG1 + 0x0B0002C2) /* ISA Bridge Status Register (R/W) */
-#define VR4181_XISACTL __preg16(KSEG1 + 0x0B0002C4) /* External ISA Control Register (R/W) */
-
-// Clocked Serial Interface (CSI)
-#define VR4181_CSIMODE __preg16(KSEG1 + 0x0B000900) /* CSI Mode Register (R/W) */
-#define VR4181_CSIRXDATA __preg16(KSEG1 + 0x0B000902) /* CSI Receive Data Register (R) */
-#define VR4181_CSITXDATA __preg16(KSEG1 + 0x0B000904) /* CSI Transmit Data Register (R/W) */
-#define VR4181_CSILSTAT __preg16(KSEG1 + 0x0B000906) /* CSI Line Status Register (R/W) */
-#define VR4181_CSIINTMSK __preg16(KSEG1 + 0x0B000908) /* CSI Interrupt Mask Register (R/W) */
-#define VR4181_CSIINTSTAT __preg16(KSEG1 + 0x0B00090a) /* CSI Interrupt Status Register (R/W) */
-#define VR4181_CSITXBLEN __preg16(KSEG1 + 0x0B00090c) /* CSI Transmit Burst Length Register (R/W) */
-#define VR4181_CSIRXBLEN __preg16(KSEG1 + 0x0B00090e) /* CSI Receive Burst Length Register (R/W) */
-
-// Interrupt Control Unit (ICU)
-#define VR4181_SYSINT1REG __preg16(KSEG1 + 0x0A000080) /* Level 1 System interrupt register 1 (R) */
-#define VR4181_MSYSINT1REG __preg16(KSEG1 + 0x0A00008C) /* Level 1 mask system interrupt register 1 (R/W) */
-#define VR4181_NMIREG __preg16(KSEG1 + 0x0A000098) /* NMI register (R/W) */
-#define VR4181_SOFTINTREG __preg16(KSEG1 + 0x0A00009A) /* Software interrupt register (R/W) */
-#define VR4181_SYSINT2REG __preg16(KSEG1 + 0x0A000200) /* Level 1 System interrupt register 2 (R) */
-#define VR4181_MSYSINT2REG __preg16(KSEG1 + 0x0A000206) /* Level 1 mask system interrupt register 2 (R/W) */
-#define VR4181_PIUINTREGro __preg16(KSEG1 + 0x0B000082) /* Level 2 PIU interrupt register (R) */
-#define VR4181_AIUINTREG __preg16(KSEG1 + 0x0B000084) /* Level 2 AIU interrupt register (R) */
-#define VR4181_MPIUINTREG __preg16(KSEG1 + 0x0B00008E) /* Level 2 mask PIU interrupt register (R/W) */
-#define VR4181_MAIUINTREG __preg16(KSEG1 + 0x0B000090) /* Level 2 mask AIU interrupt register (R/W) */
-#define VR4181_MKIUINTREG __preg16(KSEG1 + 0x0B000092) /* Level 2 mask KIU interrupt register (R/W) */
-#define VR4181_KIUINTREG __preg16(KSEG1 + 0x0B000198) /* Level 2 KIU interrupt register (R) */
-
-// Power Management Unit (PMU)
-#define VR4181_PMUINTREG __preg16(KSEG1 + 0x0B0000A0) /* PMU Status Register (R/W) */
-#define VR4181_PMUINT_POWERSW 0x1 /* Power switch */
-#define VR4181_PMUINT_BATT 0x2 /* Low batt during normal operation */
-#define VR4181_PMUINT_DEADMAN 0x4 /* Deadman's switch */
-#define VR4181_PMUINT_RESET 0x8 /* Reset switch */
-#define VR4181_PMUINT_RTCRESET 0x10 /* RTC Reset */
-#define VR4181_PMUINT_TIMEOUT 0x20 /* HAL Timer Reset */
-#define VR4181_PMUINT_BATTLOW 0x100 /* Battery low */
-#define VR4181_PMUINT_RTC 0x200 /* RTC Alarm */
-#define VR4181_PMUINT_DCD 0x400 /* DCD# */
-#define VR4181_PMUINT_GPIO0 0x1000 /* GPIO0 */
-#define VR4181_PMUINT_GPIO1 0x2000 /* GPIO1 */
-#define VR4181_PMUINT_GPIO2 0x4000 /* GPIO2 */
-#define VR4181_PMUINT_GPIO3 0x8000 /* GPIO3 */
-
-#define VR4181_PMUCNTREG __preg16(KSEG1 + 0x0B0000A2) /* PMU Control Register (R/W) */
-#define VR4181_PMUWAITREG __preg16(KSEG1 + 0x0B0000A8) /* PMU Wait Counter Register (R/W) */
-#define VR4181_PMUDIVREG __preg16(KSEG1 + 0x0B0000AC) /* PMU Divide Mode Register (R/W) */
-#define VR4181_DRAMHIBCTL __preg16(KSEG1 + 0x0B0000B2) /* DRAM Hibernate Control Register (R/W) */
-
-// Real Time Clock Unit (RTC)
-#define VR4181_ETIMELREG __preg16(KSEG1 + 0x0B0000C0) /* Elapsed Time L Register (R/W) */
-#define VR4181_ETIMEMREG __preg16(KSEG1 + 0x0B0000C2) /* Elapsed Time M Register (R/W) */
-#define VR4181_ETIMEHREG __preg16(KSEG1 + 0x0B0000C4) /* Elapsed Time H Register (R/W) */
-#define VR4181_ECMPLREG __preg16(KSEG1 + 0x0B0000C8) /* Elapsed Compare L Register (R/W) */
-#define VR4181_ECMPMREG __preg16(KSEG1 + 0x0B0000CA) /* Elapsed Compare M Register (R/W) */
-#define VR4181_ECMPHREG __preg16(KSEG1 + 0x0B0000CC) /* Elapsed Compare H Register (R/W) */
-#define VR4181_RTCL1LREG __preg16(KSEG1 + 0x0B0000D0) /* RTC Long 1 L Register (R/W) */
-#define VR4181_RTCL1HREG __preg16(KSEG1 + 0x0B0000D2) /* RTC Long 1 H Register (R/W) */
-#define VR4181_RTCL1CNTLREG __preg16(KSEG1 + 0x0B0000D4) /* RTC Long 1 Count L Register (R) */
-#define VR4181_RTCL1CNTHREG __preg16(KSEG1 + 0x0B0000D6) /* RTC Long 1 Count H Register (R) */
-#define VR4181_RTCL2LREG __preg16(KSEG1 + 0x0B0000D8) /* RTC Long 2 L Register (R/W) */
-#define VR4181_RTCL2HREG __preg16(KSEG1 + 0x0B0000DA) /* RTC Long 2 H Register (R/W) */
-#define VR4181_RTCL2CNTLREG __preg16(KSEG1 + 0x0B0000DC) /* RTC Long 2 Count L Register (R) */
-#define VR4181_RTCL2CNTHREG __preg16(KSEG1 + 0x0B0000DE) /* RTC Long 2 Count H Register (R) */
-#define VR4181_RTCINTREG __preg16(KSEG1 + 0x0B0001DE) /* RTC Interrupt Register (R/W) */
-
-// Deadman's Switch Unit (DSU)
-#define VR4181_DSUCNTREG __preg16(KSEG1 + 0x0B0000E0) /* DSU Control Register (R/W) */
-#define VR4181_DSUSETREG __preg16(KSEG1 + 0x0B0000E2) /* DSU Dead Time Set Register (R/W) */
-#define VR4181_DSUCLRREG __preg16(KSEG1 + 0x0B0000E4) /* DSU Clear Register (W) */
-#define VR4181_DSUTIMREG __preg16(KSEG1 + 0x0B0000E6) /* DSU Elapsed Time Register (R/W) */
-
-// General Purpose I/O Unit (GIU)
-#define VR4181_GPMD0REG __preg16(KSEG1 + 0x0B000300) /* GPIO Mode 0 Register (R/W) */
-#define VR4181_GPMD1REG __preg16(KSEG1 + 0x0B000302) /* GPIO Mode 1 Register (R/W) */
-#define VR4181_GPMD2REG __preg16(KSEG1 + 0x0B000304) /* GPIO Mode 2 Register (R/W) */
-#define VR4181_GPMD3REG __preg16(KSEG1 + 0x0B000306) /* GPIO Mode 3 Register (R/W) */
-#define VR4181_GPDATHREG __preg16(KSEG1 + 0x0B000308) /* GPIO Data High Register (R/W) */
-#define VR4181_GPDATHREG_GPIO16 0x0001
-#define VR4181_GPDATHREG_GPIO17 0x0002
-#define VR4181_GPDATHREG_GPIO18 0x0004
-#define VR4181_GPDATHREG_GPIO19 0x0008
-#define VR4181_GPDATHREG_GPIO20 0x0010
-#define VR4181_GPDATHREG_GPIO21 0x0020
-#define VR4181_GPDATHREG_GPIO22 0x0040
-#define VR4181_GPDATHREG_GPIO23 0x0080
-#define VR4181_GPDATHREG_GPIO24 0x0100
-#define VR4181_GPDATHREG_GPIO25 0x0200
-#define VR4181_GPDATHREG_GPIO26 0x0400
-#define VR4181_GPDATHREG_GPIO27 0x0800
-#define VR4181_GPDATHREG_GPIO28 0x1000
-#define VR4181_GPDATHREG_GPIO29 0x2000
-#define VR4181_GPDATHREG_GPIO30 0x4000
-#define VR4181_GPDATHREG_GPIO31 0x8000
-#define VR4181_GPDATLREG __preg16(KSEG1 + 0x0B00030A) /* GPIO Data Low Register (R/W) */
-#define VR4181_GPDATLREG_GPIO0 0x0001
-#define VR4181_GPDATLREG_GPIO1 0x0002
-#define VR4181_GPDATLREG_GPIO2 0x0004
-#define VR4181_GPDATLREG_GPIO3 0x0008
-#define VR4181_GPDATLREG_GPIO4 0x0010
-#define VR4181_GPDATLREG_GPIO5 0x0020
-#define VR4181_GPDATLREG_GPIO6 0x0040
-#define VR4181_GPDATLREG_GPIO7 0x0080
-#define VR4181_GPDATLREG_GPIO8 0x0100
-#define VR4181_GPDATLREG_GPIO9 0x0200
-#define VR4181_GPDATLREG_GPIO10 0x0400
-#define VR4181_GPDATLREG_GPIO11 0x0800
-#define VR4181_GPDATLREG_GPIO12 0x1000
-#define VR4181_GPDATLREG_GPIO13 0x2000
-#define VR4181_GPDATLREG_GPIO14 0x4000
-#define VR4181_GPDATLREG_GPIO15 0x8000
-#define VR4181_GPINTEN __preg16(KSEG1 + 0x0B00030C) /* GPIO Interrupt Enable Register (R/W) */
-#define VR4181_GPINTMSK __preg16(KSEG1 + 0x0B00030E) /* GPIO Interrupt Mask Register (R/W) */
-#define VR4181_GPINTTYPH __preg16(KSEG1 + 0x0B000310) /* GPIO Interrupt Type High Register (R/W) */
-#define VR4181_GPINTTYPL __preg16(KSEG1 + 0x0B000312) /* GPIO Interrupt Type Low Register (R/W) */
-#define VR4181_GPINTSTAT __preg16(KSEG1 + 0x0B000314) /* GPIO Interrupt Status Register (R/W) */
-#define VR4181_GPHIBSTH __preg16(KSEG1 + 0x0B000316) /* GPIO Hibernate Pin State High Register (R/W) */
-#define VR4181_GPHIBSTL __preg16(KSEG1 + 0x0B000318) /* GPIO Hibernate Pin State Low Register (R/W) */
-#define VR4181_GPSICTL __preg16(KSEG1 + 0x0B00031A) /* GPIO Serial Interface Control Register (R/W) */
-#define VR4181_KEYEN __preg16(KSEG1 + 0x0B00031C) /* Keyboard Scan Pin Enable Register (R/W) */
-#define VR4181_PCS0STRA __preg16(KSEG1 + 0x0B000320) /* Programmable Chip Select [0] Start Address Register (R/W) */
-#define VR4181_PCS0STPA __preg16(KSEG1 + 0x0B000322) /* Programmable Chip Select [0] Stop Address Register (R/W) */
-#define VR4181_PCS0HIA __preg16(KSEG1 + 0x0B000324) /* Programmable Chip Select [0] High Address Register (R/W) */
-#define VR4181_PCS1STRA __preg16(KSEG1 + 0x0B000326) /* Programmable Chip Select [1] Start Address Register (R/W) */
-#define VR4181_PCS1STPA __preg16(KSEG1 + 0x0B000328) /* Programmable Chip Select [1] Stop Address Register (R/W) */
-#define VR4181_PCS1HIA __preg16(KSEG1 + 0x0B00032A) /* Programmable Chip Select [1] High Address Register (R/W) */
-#define VR4181_PCSMODE __preg16(KSEG1 + 0x0B00032C) /* Programmable Chip Select Mode Register (R/W) */
-#define VR4181_LCDGPMODE __preg16(KSEG1 + 0x0B00032E) /* LCD General Purpose Mode Register (R/W) */
-#define VR4181_MISCREG0 __preg16(KSEG1 + 0x0B000330) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG1 __preg16(KSEG1 + 0x0B000332) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG2 __preg16(KSEG1 + 0x0B000334) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG3 __preg16(KSEG1 + 0x0B000336) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG4 __preg16(KSEG1 + 0x0B000338) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG5 __preg16(KSEG1 + 0x0B00033A) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG6 __preg16(KSEG1 + 0x0B00033C) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG7 __preg16(KSEG1 + 0x0B00033D) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG8 __preg16(KSEG1 + 0x0B000340) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG9 __preg16(KSEG1 + 0x0B000342) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG10 __preg16(KSEG1 + 0x0B000344) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG11 __preg16(KSEG1 + 0x0B000346) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG12 __preg16(KSEG1 + 0x0B000348) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG13 __preg16(KSEG1 + 0x0B00034A) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG14 __preg16(KSEG1 + 0x0B00034C) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_MISCREG15 __preg16(KSEG1 + 0x0B00034E) /* Misc. R/W Battery Backed Registers for Non-Volatile Storage (R/W) */
-#define VR4181_SECIRQMASKL VR4181_GPINTEN
-// No SECIRQMASKH for VR4181
-
-// Touch Panel Interface Unit (PIU)
-#define VR4181_PIUCNTREG __preg16(KSEG1 + 0x0B000122) /* PIU Control register (R/W) */
-#define VR4181_PIUCNTREG_PIUSEQEN 0x0004
-#define VR4181_PIUCNTREG_PIUPWR 0x0002
-#define VR4181_PIUCNTREG_PADRST 0x0001
-
-#define VR4181_PIUINTREG __preg16(KSEG1 + 0x0B000124) /* PIU Interrupt cause register (R/W) */
-#define VR4181_PIUINTREG_OVP 0x8000
-#define VR4181_PIUINTREG_PADCMD 0x0040
-#define VR4181_PIUINTREG_PADADP 0x0020
-#define VR4181_PIUINTREG_PADPAGE1 0x0010
-#define VR4181_PIUINTREG_PADPAGE0 0x0008
-#define VR4181_PIUINTREG_PADDLOST 0x0004
-#define VR4181_PIUINTREG_PENCHG 0x0001
-
-#define VR4181_PIUSIVLREG __preg16(KSEG1 + 0x0B000126) /* PIU Data sampling interval register (R/W) */
-#define VR4181_PIUSTBLREG __preg16(KSEG1 + 0x0B000128) /* PIU A/D converter start delay register (R/W) */
-#define VR4181_PIUCMDREG __preg16(KSEG1 + 0x0B00012A) /* PIU A/D command register (R/W) */
-#define VR4181_PIUASCNREG __preg16(KSEG1 + 0x0B000130) /* PIU A/D port scan register (R/W) */
-#define VR4181_PIUAMSKREG __preg16(KSEG1 + 0x0B000132) /* PIU A/D scan mask register (R/W) */
-#define VR4181_PIUCIVLREG __preg16(KSEG1 + 0x0B00013E) /* PIU Check interval register (R) */
-#define VR4181_PIUPB00REG __preg16(KSEG1 + 0x0B0002A0) /* PIU Page 0 Buffer 0 register (R/W) */
-#define VR4181_PIUPB01REG __preg16(KSEG1 + 0x0B0002A2) /* PIU Page 0 Buffer 1 register (R/W) */
-#define VR4181_PIUPB02REG __preg16(KSEG1 + 0x0B0002A4) /* PIU Page 0 Buffer 2 register (R/W) */
-#define VR4181_PIUPB03REG __preg16(KSEG1 + 0x0B0002A6) /* PIU Page 0 Buffer 3 register (R/W) */
-#define VR4181_PIUPB10REG __preg16(KSEG1 + 0x0B0002A8) /* PIU Page 1 Buffer 0 register (R/W) */
-#define VR4181_PIUPB11REG __preg16(KSEG1 + 0x0B0002AA) /* PIU Page 1 Buffer 1 register (R/W) */
-#define VR4181_PIUPB12REG __preg16(KSEG1 + 0x0B0002AC) /* PIU Page 1 Buffer 2 register (R/W) */
-#define VR4181_PIUPB13REG __preg16(KSEG1 + 0x0B0002AE) /* PIU Page 1 Buffer 3 register (R/W) */
-#define VR4181_PIUAB0REG __preg16(KSEG1 + 0x0B0002B0) /* PIU A/D scan Buffer 0 register (R/W) */
-#define VR4181_PIUAB1REG __preg16(KSEG1 + 0x0B0002B2) /* PIU A/D scan Buffer 1 register (R/W) */
-#define VR4181_PIUAB2REG __preg16(KSEG1 + 0x0B0002B4) /* PIU A/D scan Buffer 2 register (R/W) */
-#define VR4181_PIUAB3REG __preg16(KSEG1 + 0x0B0002B6) /* PIU A/D scan Buffer 3 register (R/W) */
-#define VR4181_PIUPB04REG __preg16(KSEG1 + 0x0B0002BC) /* PIU Page 0 Buffer 4 register (R/W) */
-#define VR4181_PIUPB14REG __preg16(KSEG1 + 0x0B0002BE) /* PIU Page 1 Buffer 4 register (R/W) */
-
-// Audio Interface Unit (AIU)
-#define VR4181_SODATREG __preg16(KSEG1 + 0x0B000166) /* Speaker Output Data Register (R/W) */
-#define VR4181_SCNTREG __preg16(KSEG1 + 0x0B000168) /* Speaker Output Control Register (R/W) */
-#define VR4181_MIDATREG __preg16(KSEG1 + 0x0B000170) /* Mike Input Data Register (R/W) */
-#define VR4181_MCNTREG __preg16(KSEG1 + 0x0B000172) /* Mike Input Control Register (R/W) */
-#define VR4181_DVALIDREG __preg16(KSEG1 + 0x0B000178) /* Data Valid Register (R/W) */
-#define VR4181_SEQREG __preg16(KSEG1 + 0x0B00017A) /* Sequential Register (R/W) */
-#define VR4181_INTREG __preg16(KSEG1 + 0x0B00017C) /* Interrupt Register (R/W) */
-#define VR4181_SDMADATREG __preg16(KSEG1 + 0x0B000160) /* Speaker DMA Data Register (R/W) */
-#define VR4181_MDMADATREG __preg16(KSEG1 + 0x0B000162) /* Microphone DMA Data Register (R/W) */
-#define VR4181_DAVREF_SETUP __preg16(KSEG1 + 0x0B000164) /* DAC Vref setup register (R/W) */
-#define VR4181_SCNVC_END __preg16(KSEG1 + 0x0B00016E) /* Speaker sample rate control (R/W) */
-#define VR4181_MIDATREG __preg16(KSEG1 + 0x0B000170) /* Microphone Input Data Register (R/W) */
-#define VR4181_MCNTREG __preg16(KSEG1 + 0x0B000172) /* Microphone Input Control Register (R/W) */
-#define VR4181_MCNVC_END __preg16(KSEG1 + 0x0B00017E) /* Microphone sample rate control (R/W) */
-
-// Keyboard Interface Unit (KIU)
-#define VR4181_KIUDAT0 __preg16(KSEG1 + 0x0B000180) /* KIU Data0 Register (R/W) */
-#define VR4181_KIUDAT1 __preg16(KSEG1 + 0x0B000182) /* KIU Data1 Register (R/W) */
-#define VR4181_KIUDAT2 __preg16(KSEG1 + 0x0B000184) /* KIU Data2 Register (R/W) */
-#define VR4181_KIUDAT3 __preg16(KSEG1 + 0x0B000186) /* KIU Data3 Register (R/W) */
-#define VR4181_KIUDAT4 __preg16(KSEG1 + 0x0B000188) /* KIU Data4 Register (R/W) */
-#define VR4181_KIUDAT5 __preg16(KSEG1 + 0x0B00018A) /* KIU Data5 Register (R/W) */
-#define VR4181_KIUSCANREP __preg16(KSEG1 + 0x0B000190) /* KIU Scan/Repeat Register (R/W) */
-#define VR4181_KIUSCANREP_KEYEN 0x8000
-#define VR4181_KIUSCANREP_SCANSTP 0x0008
-#define VR4181_KIUSCANREP_SCANSTART 0x0004
-#define VR4181_KIUSCANREP_ATSTP 0x0002
-#define VR4181_KIUSCANREP_ATSCAN 0x0001
-#define VR4181_KIUSCANS __preg16(KSEG1 + 0x0B000192) /* KIU Scan Status Register (R) */
-#define VR4181_KIUWKS __preg16(KSEG1 + 0x0B000194) /* KIU Wait Keyscan Stable Register (R/W) */
-#define VR4181_KIUWKI __preg16(KSEG1 + 0x0B000196) /* KIU Wait Keyscan Interval Register (R/W) */
-#define VR4181_KIUINT __preg16(KSEG1 + 0x0B000198) /* KIU Interrupt Register (R/W) */
-#define VR4181_KIUINT_KDATLOST 0x0004
-#define VR4181_KIUINT_KDATRDY 0x0002
-#define VR4181_KIUINT_SCANINT 0x0001
-#define VR4181_KIUDAT6 __preg16(KSEG1 + 0x0B00018C) /* Scan Line 6 Key Data Register (R) */
-#define VR4181_KIUDAT7 __preg16(KSEG1 + 0x0B00018E) /* Scan Line 7 Key Data Register (R) */
-
-// CompactFlash Controller
-#define VR4181_PCCARDINDEX __preg8(KSEG1 + 0x0B0008E0) /* PC Card Controller Index Register */
-#define VR4181_PCCARDDATA __preg8(KSEG1 + 0x0B0008E1) /* PC Card Controller Data Register */
-#define VR4181_INTSTATREG __preg16(KSEG1 + 0x0B0008F8) /* Interrupt Status Register (R/W) */
-#define VR4181_INTMSKREG __preg16(KSEG1 + 0x0B0008FA) /* Interrupt Mask Register (R/W) */
-#define VR4181_CFG_REG_1 __preg16(KSEG1 + 0x0B0008FE) /* Configuration Register 1 */
-
-// LED Control Unit (LED)
-#define VR4181_LEDHTSREG __preg16(KSEG1 + 0x0B000240) /* LED H Time Set register (R/W) */
-#define VR4181_LEDLTSREG __preg16(KSEG1 + 0x0B000242) /* LED L Time Set register (R/W) */
-#define VR4181_LEDCNTREG __preg16(KSEG1 + 0x0B000248) /* LED Control register (R/W) */
-#define VR4181_LEDASTCREG __preg16(KSEG1 + 0x0B00024A) /* LED Auto Stop Time Count register (R/W) */
-#define VR4181_LEDINTREG __preg16(KSEG1 + 0x0B00024C) /* LED Interrupt register (R/W) */
-
-// Serial Interface Unit (SIU / SIU1 and SIU2)
-#define VR4181_SIURB __preg8(KSEG1 + 0x0C000010) /* Receiver Buffer Register (Read) DLAB = 0 (R) */
-#define VR4181_SIUTH __preg8(KSEG1 + 0x0C000010) /* Transmitter Holding Register (Write) DLAB = 0 (W) */
-#define VR4181_SIUDLL __preg8(KSEG1 + 0x0C000010) /* Divisor Latch (Least Significant Byte) DLAB = 1 (R/W) */
-#define VR4181_SIUIE __preg8(KSEG1 + 0x0C000011) /* Interrupt Enable DLAB = 0 (R/W) */
-#define VR4181_SIUDLM __preg8(KSEG1 + 0x0C000011) /* Divisor Latch (Most Significant Byte) DLAB = 1 (R/W) */
-#define VR4181_SIUIID __preg8(KSEG1 + 0x0C000012) /* Interrupt Identification Register (Read) (R) */
-#define VR4181_SIUFC __preg8(KSEG1 + 0x0C000012) /* FIFO Control Register (Write) (W) */
-#define VR4181_SIULC __preg8(KSEG1 + 0x0C000013) /* Line Control Register (R/W) */
-#define VR4181_SIUMC __preg8(KSEG1 + 0x0C000014) /* MODEM Control Register (R/W) */
-#define VR4181_SIULS __preg8(KSEG1 + 0x0C000015) /* Line Status Register (R/W) */
-#define VR4181_SIUMS __preg8(KSEG1 + 0x0C000016) /* MODEM Status Register (R/W) */
-#define VR4181_SIUSC __preg8(KSEG1 + 0x0C000017) /* Scratch Register (R/W) */
-#define VR4181_SIURESET __preg8(KSEG1 + 0x0C000019) /* SIU Reset Register (R/W) */
-#define VR4181_SIUACTMSK __preg8(KSEG1 + 0x0C00001C) /* SIU Activity Mask (R/W) */
-#define VR4181_SIUACTTMR __preg8(KSEG1 + 0x0C00001E) /* SIU Activity Timer (R/W) */
-#define VR4181_SIURB_2 __preg8(KSEG1 + 0x0C000000) /* Receive Buffer Register (Read) (R) */
-#define VR4181_SIUTH_2 __preg8(KSEG1 + 0x0C000000) /* Transmitter Holding Register (Write) (W) */
-#define VR4181_SIUDLL_2 __preg8(KSEG1 + 0x0C000000) /* Divisor Latch (Least Significant Byte) (R/W) */
-#define VR4181_SIUIE_2 __preg8(KSEG1 + 0x0C000001) /* Interrupt Enable (DLAB = 0) (R/W) */
-#define VR4181_SIUDLM_2 __preg8(KSEG1 + 0x0C000001) /* Divisor Latch (Most Significant Byte) (DLAB = 1) (R/W) */
-#define VR4181_SIUIID_2 __preg8(KSEG1 + 0x0C000002) /* Interrupt Identification Register (Read) (R) */
-#define VR4181_SIUFC_2 __preg8(KSEG1 + 0x0C000002) /* FIFO Control Register (Write) (W) */
-#define VR4181_SIULC_2 __preg8(KSEG1 + 0x0C000003) /* Line Control Register (R/W) */
-#define VR4181_SIUMC_2 __preg8(KSEG1 + 0x0C000004) /* Modem Control Register (R/W) */
-#define VR4181_SIULS_2 __preg8(KSEG1 + 0x0C000005) /* Line Status Register (R/W) */
-#define VR4181_SIUMS_2 __preg8(KSEG1 + 0x0C000006) /* Modem Status Register (R/W) */
-#define VR4181_SIUSC_2 __preg8(KSEG1 + 0x0C000007) /* Scratch Register (R/W) */
-#define VR4181_SIUIRSEL_2 __preg8(KSEG1 + 0x0C000008) /* SIU IrDA Selectot (R/W) */
-#define VR4181_SIURESET_2 __preg8(KSEG1 + 0x0C000009) /* SIU Reset Register (R/W) */
-#define VR4181_SIUCSEL_2 __preg8(KSEG1 + 0x0C00000A) /* IrDA Echo-back Control (R/W) */
-#define VR4181_SIUACTMSK_2 __preg8(KSEG1 + 0x0C00000C) /* SIU Activity Mask Register (R/W) */
-#define VR4181_SIUACTTMR_2 __preg8(KSEG1 + 0x0C00000E) /* SIU Activity Timer Register (R/W) */
-
-
-// USB Module
-#define VR4181_USBINFIFO __preg16(KSEG1 + 0x0B000780) /* USB Bulk Input FIFO (Bulk In End Point) (W) */
-#define VR4181_USBOUTFIFO __preg16(KSEG1 + 0x0B000782) /* USB Bulk Output FIFO (Bulk Out End Point) (R) */
-#define VR4181_USBCTLFIFO __preg16(KSEG1 + 0x0B000784) /* USB Control FIFO (Control End Point) (W) */
-#define VR4181_USBSTAT __preg16(KSEG1 + 0x0B000786) /* Interrupt Status Register (R/W) */
-#define VR4181_USBINTMSK __preg16(KSEG1 + 0x0B000788) /* Interrupt Mask Register (R/W) */
-#define VR4181_USBCTLREG __preg16(KSEG1 + 0x0B00078A) /* Control Register (R/W) */
-#define VR4181_USBSTPREG __preg16(KSEG1 + 0x0B00078C) /* USB Transfer Stop Register (R/W) */
-
-// LCD Controller
-#define VR4181_HRTOTALREG __preg16(KSEG1 + 0x0A000400) /* Horizontal total Register (R/W) */
-#define VR4181_HRVISIBREG __preg16(KSEG1 + 0x0A000402) /* Horizontal Visible Register (R/W) */
-#define VR4181_LDCLKSTREG __preg16(KSEG1 + 0x0A000404) /* Load clock start Register (R/W) */
-#define VR4181_LDCLKNDREG __preg16(KSEG1 + 0x0A000406) /* Load clock end Register (R/W) */
-#define VR4181_VRTOTALREG __preg16(KSEG1 + 0x0A000408) /* Vertical Total Register (R/W) */
-#define VR4181_VRVISIBREG __preg16(KSEG1 + 0x0A00040A) /* Vertical Visible Register (R/W) */
-#define VR4181_FVSTARTREG __preg16(KSEG1 + 0x0A00040C) /* FLM vertical start Register (R/W) */
-#define VR4181_FVENDREG __preg16(KSEG1 + 0x0A00040E) /* FLM vertical end Register (R/W) */
-#define VR4181_LCDCTRLREG __preg16(KSEG1 + 0x0A000410) /* LCD control Register (R/W) */
-#define VR4181_LCDINRQREG __preg16(KSEG1 + 0x0A000412) /* LCD Interrupt request Register (R/W) */
-#define VR4181_LCDCFGREG0 __preg16(KSEG1 + 0x0A000414) /* LCD Configuration Register 0 (R/W) */
-#define VR4181_LCDCFGREG1 __preg16(KSEG1 + 0x0A000416) /* LCD Configuration Register 1 (R/W) */
-#define VR4181_FBSTAD1REG __preg16(KSEG1 + 0x0A000418) /* Frame Buffer Start Address 1 Register (R/W) */
-#define VR4181_FBSTAD2REG __preg16(KSEG1 + 0x0A00041A) /* Frame Buffer Start Address 2 Register (R/W) */
-#define VR4181_FBNDAD1REG __preg16(KSEG1 + 0x0A000420) /* Frame Buffer End Address 1 Register (R/W) */
-#define VR4181_FBNDAD2REG __preg16(KSEG1 + 0x0A000422) /* Frame Buffer End Address 2 register (R/W) */
-#define VR4181_FHSTARTREG __preg16(KSEG1 + 0x0A000424) /* FLM horizontal Start Register (R/W) */
-#define VR4181_FHENDREG __preg16(KSEG1 + 0x0A000426) /* FLM horizontal End Register (R/W) */
-#define VR4181_PWRCONREG1 __preg16(KSEG1 + 0x0A000430) /* Power Control register 1 (R/W) */
-#define VR4181_PWRCONREG2 __preg16(KSEG1 + 0x0A000432) /* Power Control register 2 (R/W) */
-#define VR4181_LCDIMSKREG __preg16(KSEG1 + 0x0A000434) /* LCD Interrupt Mask register (R/W) */
-#define VR4181_CPINDCTREG __preg16(KSEG1 + 0x0A00047E) /* Color palette Index and control Register (R/W) */
-#define VR4181_CPALDATREG __preg32(KSEG1 + 0x0A000480) /* Color palette data register (32bits Register) (R/W) */
-
-// physical address spaces
-#define VR4181_LCD 0x0a000000
-#define VR4181_INTERNAL_IO_2 0x0b000000
-#define VR4181_INTERNAL_IO_1 0x0c000000
-#define VR4181_ISA_MEM 0x10000000
-#define VR4181_ISA_IO 0x14000000
-#define VR4181_ROM 0x18000000
-
-// This is the base address for IO port decoding to which the 16 bit IO port address
-// is added. Defining it to 0 will usually cause a kernel oops any time port IO is
-// attempted, which can be handy for turning up parts of the kernel that make
-// incorrect architecture assumptions (by assuming that everything acts like a PC),
-// but we need it correctly defined to use the PCMCIA/CF controller:
-#define VR4181_PORT_BASE (KSEG1 + VR4181_ISA_IO)
-#define VR4181_ISAMEM_BASE (KSEG1 + VR4181_ISA_MEM)
-
-#endif /* __ASM_VR4181_VR4181_H */
diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h
index 7d41e44..bd2723c 100644
--- a/include/asm-mips/vr41xx/vr41xx.h
+++ b/include/asm-mips/vr41xx/vr41xx.h
@@ -7,7 +7,7 @@
* Copyright (C) 2001, 2002 Paul Mundt
* Copyright (C) 2002 MontaVista Software, Inc.
* Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -79,11 +79,11 @@
#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x))
#define MIPS_SOFTINT0_IRQ MIPS_CPU_IRQ(0)
#define MIPS_SOFTINT1_IRQ MIPS_CPU_IRQ(1)
-#define INT0_CASCADE_IRQ MIPS_CPU_IRQ(2)
-#define INT1_CASCADE_IRQ MIPS_CPU_IRQ(3)
-#define INT2_CASCADE_IRQ MIPS_CPU_IRQ(4)
-#define INT3_CASCADE_IRQ MIPS_CPU_IRQ(5)
-#define INT4_CASCADE_IRQ MIPS_CPU_IRQ(6)
+#define INT0_IRQ MIPS_CPU_IRQ(2)
+#define INT1_IRQ MIPS_CPU_IRQ(3)
+#define INT2_IRQ MIPS_CPU_IRQ(4)
+#define INT3_IRQ MIPS_CPU_IRQ(5)
+#define INT4_IRQ MIPS_CPU_IRQ(6)
#define TIMER_IRQ MIPS_CPU_IRQ(7)
/* SYINT1 Interrupt Numbers */
@@ -97,7 +97,7 @@
#define PIU_IRQ SYSINT1_IRQ(5)
#define AIU_IRQ SYSINT1_IRQ(6)
#define KIU_IRQ SYSINT1_IRQ(7)
-#define GIUINT_CASCADE_IRQ SYSINT1_IRQ(8)
+#define GIUINT_IRQ SYSINT1_IRQ(8)
#define SIU_IRQ SYSINT1_IRQ(9)
#define BUSERR_IRQ SYSINT1_IRQ(10)
#define SOFTINT_IRQ SYSINT1_IRQ(11)
@@ -128,7 +128,7 @@
#define GIU_IRQ_LAST GIU_IRQ(31)
extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign);
-extern int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq));
+extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *));
#define PIUINT_COMMAND 0x0040
#define PIUINT_DATA 0x0020
diff --git a/include/asm-mips/vr41xx/vrc4173.h b/include/asm-mips/vr41xx/vrc4173.h
index 58e193c..bb7a85c 100644
--- a/include/asm-mips/vr41xx/vrc4173.h
+++ b/include/asm-mips/vr41xx/vrc4173.h
@@ -21,8 +21,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __NEC_VRC4173_H
-#define __NEC_VRC4173_H
+#ifndef __NEC_VRC4173_H
+#define __NEC_VRC4173_H
#include <linux/config.h>
#include <asm/io.h>
diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h
index c4a7041..04ee53b 100644
--- a/include/asm-mips/war.h
+++ b/include/asm-mips/war.h
@@ -113,7 +113,7 @@
*/
#define BCM1250_M3_WAR 1
-/*
+/*
* This is a DUART workaround related to glitches around register accesses
*/
#define SIBYTE_1956_WAR 1
@@ -122,7 +122,7 @@
/*
* Fill buffers not flushed on CACHE instructions
- *
+ *
* Hit_Invalidate_I cacheops invalidate an icache line but the refill
* for that line can get stale data from the fill buffer instead of
* accessing memory if the previous icache miss was also to that line.
diff --git a/include/asm-mips/xxs1500.h b/include/asm-mips/xxs1500.h
index 75c0ddf..4d84a90 100644
--- a/include/asm-mips/xxs1500.h
+++ b/include/asm-mips/xxs1500.h
@@ -22,7 +22,7 @@
*
* ########################################################################
*
- *
+ *
*/
#ifndef __ASM_XXS1500_H
#define __ASM_XXS1500_H
diff --git a/include/asm-parisc/auxvec.h b/include/asm-parisc/auxvec.h
new file mode 100644
index 0000000..9c3ac4b
--- /dev/null
+++ b/include/asm-parisc/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMPARISC_AUXVEC_H
+#define __ASMPARISC_AUXVEC_H
+
+#endif
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 7630d1a..38b918f 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -13,8 +13,10 @@
typedef s32 compat_time_t;
typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
-typedef u32 compat_uid_t;
-typedef u32 compat_gid_t;
+typedef u32 __compat_uid_t;
+typedef u32 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u32 compat_dev_t;
@@ -67,8 +69,8 @@
compat_dev_t st_realdev;
u16 st_basemode;
u16 st_spareshort;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid32_t st_uid;
+ __compat_gid32_t st_gid;
u32 st_spare4[3];
};
diff --git a/include/asm-parisc/fcntl.h b/include/asm-parisc/fcntl.h
index def3523..317851f 100644
--- a/include/asm-parisc/fcntl.h
+++ b/include/asm-parisc/fcntl.h
@@ -3,38 +3,22 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_ACCMODE 00000003
-#define O_RDONLY 00000000
-#define O_WRONLY 00000001
-#define O_RDWR 00000002
#define O_APPEND 00000010
#define O_BLKSEEK 00000100 /* HPUX only */
#define O_CREAT 00000400 /* not fcntl */
-#define O_TRUNC 00001000 /* not fcntl */
#define O_EXCL 00002000 /* not fcntl */
#define O_LARGEFILE 00004000
#define O_SYNC 00100000
#define O_NONBLOCK 00200004 /* HPUX has separate NDELAY & NONBLOCK */
-#define O_NDELAY O_NONBLOCK
#define O_NOCTTY 00400000 /* not fcntl */
#define O_DSYNC 01000000 /* HPUX only */
#define O_RSYNC 02000000 /* HPUX only */
#define O_NOATIME 04000000
-#define FASYNC 00020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 00040000 /* direct disk access hint - currently ignored */
#define O_DIRECTORY 00010000 /* must be a directory */
#define O_NOFOLLOW 00000200 /* don't follow links */
#define O_INVISIBLE 04000000 /* invisible I/O, for DMAPI/XDSM */
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get f_flags */
-#define F_SETFD 2 /* set f_flags */
-#define F_GETFL 3 /* more flags (cloexec) */
-#define F_SETFL 4
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
#define F_GETLK64 8
#define F_SETLK64 9
#define F_SETLKW64 10
@@ -44,49 +28,11 @@
#define F_SETSIG 13 /* for sockets. */
#define F_GETSIG 14 /* for sockets. */
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
/* for posix fcntl() and lockf() */
#define F_RDLCK 01
#define F_WRLCK 02
#define F_UNLCK 03
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
+#include <asm-generic/fcntl.h>
#endif
diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-parisc/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-parisc/hdreg.h b/include/asm-parisc/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-parisc/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
index 75654ba..f876bdf 100644
--- a/include/asm-parisc/irq.h
+++ b/include/asm-parisc/irq.h
@@ -26,6 +26,11 @@
#define NR_IRQS (CPU_IRQ_MAX + 1)
+/*
+ * IRQ line status macro IRQ_PER_CPU is used
+ */
+#define ARCH_HAS_IRQ_PER_CPU
+
static __inline__ int irq_canonicalize(int irq)
{
return (irq == 2) ? 9 : irq;
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
index 4a12692..44eae9f 100644
--- a/include/asm-parisc/page.h
+++ b/include/asm-parisc/page.h
@@ -74,20 +74,6 @@
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
typedef struct __physmem_range {
unsigned long start_pfn;
unsigned long pages; /* PAGE_SIZE pages */
@@ -159,4 +145,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _PARISC_PAGE_H */
diff --git a/include/asm-parisc/types.h b/include/asm-parisc/types.h
index 8fe7a44..d21b9d0 100644
--- a/include/asm-parisc/types.h
+++ b/include/asm-parisc/types.h
@@ -56,8 +56,6 @@
typedef u32 dma_addr_t;
typedef u64 dma64_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h
index c1b5bde..f6c417c 100644
--- a/include/asm-parisc/uaccess.h
+++ b/include/asm-parisc/uaccess.h
@@ -40,10 +40,6 @@
return 1;
}
-#define verify_area(type,addr,size) (0) /* FIXME: all users should go away soon,
- * and use access_ok instead, then this
- * should be removed. */
-
#define put_user __put_user
#define get_user __get_user
diff --git a/include/asm-powerpc/bugs.h b/include/asm-powerpc/bugs.h
new file mode 100644
index 0000000..310187d
--- /dev/null
+++ b/include/asm-powerpc/bugs.h
@@ -0,0 +1,18 @@
+#ifndef _POWERPC_BUGS_H
+#define _POWERPC_BUGS_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * This file is included by 'init/main.c' to check for
+ * architecture-dependent bugs.
+ */
+
+extern void check_bugs(void);
+
+#endif /* _POWERPC_BUGS_H */
diff --git a/include/asm-powerpc/fcntl.h b/include/asm-powerpc/fcntl.h
new file mode 100644
index 0000000..ce5c451
--- /dev/null
+++ b/include/asm-powerpc/fcntl.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_FCNTL_H
+#define _ASM_FCNTL_H
+
+#define O_DIRECTORY 040000 /* must be a directory */
+#define O_NOFOLLOW 0100000 /* don't follow links */
+#define O_LARGEFILE 0200000
+#define O_DIRECT 0400000 /* direct disk access hint */
+
+#include <asm-generic/fcntl.h>
+
+#endif /* _ASM_FCNTL_H */
diff --git a/include/asm-ppc64/mc146818rtc.h b/include/asm-powerpc/mc146818rtc.h
similarity index 84%
rename from include/asm-ppc64/mc146818rtc.h
rename to include/asm-powerpc/mc146818rtc.h
index f713e1b..a5619a2 100644
--- a/include/asm-ppc64/mc146818rtc.h
+++ b/include/asm-powerpc/mc146818rtc.h
@@ -1,3 +1,6 @@
+#ifndef _POWERPC_MC146818RTC_H
+#define _POWERPC_MC146818RTC_H
+
/*
* Machine dependent access functions for RTC registers.
*
@@ -6,8 +9,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#ifndef __ASM_PPC64_MC146818RTC_H
-#define __ASM_PPC64_MC146818RTC_H
+
+#ifdef __KERNEL__
#include <asm/io.h>
@@ -29,4 +32,5 @@
outb_p((val),RTC_PORT(1)); \
})
-#endif /* __ASM_PPC64_MC146818RTC_H */
+#endif /* __KERNEL__ */
+#endif /* _POWERPC_MC146818RTC_H */
diff --git a/include/asm-ppc64/mman.h b/include/asm-powerpc/mman.h
similarity index 95%
rename from include/asm-ppc64/mman.h
rename to include/asm-powerpc/mman.h
index d4f9344..f2d5598 100644
--- a/include/asm-ppc64/mman.h
+++ b/include/asm-powerpc/mman.h
@@ -1,5 +1,5 @@
-#ifndef __PPC64_MMAN_H__
-#define __PPC64_MMAN_H__
+#ifndef _POWERPC_MMAN_H
+#define _POWERPC_MMAN_H
/*
* This program is free software; you can redistribute it and/or
@@ -49,4 +49,4 @@
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FILE 0
-#endif /* __PPC64_MMAN_H__ */
+#endif /* _POWERPC_MMAN_H */
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
new file mode 100644
index 0000000..4438f4f
--- /dev/null
+++ b/include/asm-powerpc/module.h
@@ -0,0 +1,77 @@
+#ifndef _POWERPC_MODULE_H
+#define _POWERPC_MODULE_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/list.h>
+#include <asm/bug.h>
+
+
+#ifndef __powerpc64__
+/*
+ * Thanks to Paul M for explaining this.
+ *
+ * PPC can only do rel jumps += 32MB, and often the kernel and other
+ * modules are furthur away than this. So, we jump to a table of
+ * trampolines attached to the module (the Procedure Linkage Table)
+ * whenever that happens.
+ */
+
+struct ppc_plt_entry {
+ /* 16 byte jump instruction sequence (4 instructions) */
+ unsigned int jump[4];
+};
+#endif /* __powerpc64__ */
+
+
+struct mod_arch_specific {
+#ifdef __powerpc64__
+ unsigned int stubs_section; /* Index of stubs section in module */
+ unsigned int toc_section; /* What section is the TOC? */
+#else
+ /* Indices of PLT sections within module. */
+ unsigned int core_plt_section;
+ unsigned int init_plt_section;
+#endif
+
+ /* List of BUG addresses, source line numbers and filenames */
+ struct list_head bug_list;
+ struct bug_entry *bug_table;
+ unsigned int num_bugs;
+};
+
+extern struct bug_entry *module_find_bug(unsigned long bugaddr);
+
+/*
+ * Select ELF headers.
+ * Make empty section for module_frob_arch_sections to expand.
+ */
+
+#ifdef __powerpc64__
+# define Elf_Shdr Elf64_Shdr
+# define Elf_Sym Elf64_Sym
+# define Elf_Ehdr Elf64_Ehdr
+# ifdef MODULE
+ asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
+# endif
+#else
+# define Elf_Shdr Elf32_Shdr
+# define Elf_Sym Elf32_Sym
+# define Elf_Ehdr Elf32_Ehdr
+# ifdef MODULE
+ asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
+ asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
+# endif /* MODULE */
+#endif
+
+
+struct exception_table_entry;
+void sort_ex_table(struct exception_table_entry *start,
+ struct exception_table_entry *finish);
+
+#endif /* _POWERPC_MODULE_H */
diff --git a/include/asm-ppc64/sembuf.h b/include/asm-powerpc/sembuf.h
similarity index 62%
rename from include/asm-ppc64/sembuf.h
rename to include/asm-powerpc/sembuf.h
index 172e590..c98fc18 100644
--- a/include/asm-ppc64/sembuf.h
+++ b/include/asm-powerpc/sembuf.h
@@ -1,27 +1,36 @@
-#ifndef _PPC64_SEMBUF_H
-#define _PPC64_SEMBUF_H
+#ifndef _POWERPC_SEMBUF_H
+#define _POWERPC_SEMBUF_H
-/*
- * The semid64_ds structure for PPC architecture.
- *
- *
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The semid64_ds structure for PPC architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
*
* Pad space is left for:
- * - 2 miscellaneous 64-bit values
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
*/
struct semid64_ds {
struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#ifndef __powerpc64__
+ unsigned long __unused1;
+#endif
__kernel_time_t sem_otime; /* last semop time */
+#ifndef __powerpc64__
+ unsigned long __unused2;
+#endif
__kernel_time_t sem_ctime; /* last change time */
unsigned long sem_nsems; /* no. of semaphores in array */
-
- unsigned long __unused1;
- unsigned long __unused2;
+ unsigned long __unused3;
+ unsigned long __unused4;
};
-#endif /* _PPC64_SEMBUF_H */
+#endif /* _POWERPC_SEMBUF_H */
diff --git a/include/asm-ppc64/shmbuf.h b/include/asm-powerpc/shmbuf.h
similarity index 72%
rename from include/asm-ppc64/shmbuf.h
rename to include/asm-powerpc/shmbuf.h
index 02e99d6..29632db 100644
--- a/include/asm-ppc64/shmbuf.h
+++ b/include/asm-powerpc/shmbuf.h
@@ -1,31 +1,47 @@
-#ifndef _PPC64_SHMBUF_H
-#define _PPC64_SHMBUF_H
+#ifndef _POWERPC_SHMBUF_H
+#define _POWERPC_SHMBUF_H
-/*
- * The shmid64_ds structure for PPC64 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 2 miscellaneous 64-bit values
- *
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+/*
+ * The shmid64_ds structure for PPC architecture.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
struct shmid64_ds {
struct ipc64_perm shm_perm; /* operation perms */
+#ifndef __power64__
+ unsigned long __unused1;
+#endif
__kernel_time_t shm_atime; /* last attach time */
+#ifndef __power64__
+ unsigned long __unused2;
+#endif
__kernel_time_t shm_dtime; /* last detach time */
+#ifndef __power64__
+ unsigned long __unused3;
+#endif
__kernel_time_t shm_ctime; /* last change time */
+#ifndef __power64__
+ unsigned long __unused4;
+#endif
size_t shm_segsz; /* size of segment (bytes) */
__kernel_pid_t shm_cpid; /* pid of creator */
__kernel_pid_t shm_lpid; /* pid of last operator */
unsigned long shm_nattch; /* no. of current attaches */
- unsigned long __unused1;
- unsigned long __unused2;
+ unsigned long __unused5;
+ unsigned long __unused6;
};
struct shminfo64 {
@@ -40,4 +56,4 @@
unsigned long __unused4;
};
-#endif /* _PPC64_SHMBUF_H */
+#endif /* _POWERPC_SHMBUF_H */
diff --git a/include/asm-powerpc/siginfo.h b/include/asm-powerpc/siginfo.h
new file mode 100644
index 0000000..ae70b80
--- /dev/null
+++ b/include/asm-powerpc/siginfo.h
@@ -0,0 +1,18 @@
+#ifndef _POWERPC_SIGINFO_H
+#define _POWERPC_SIGINFO_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifdef __powerpc64__
+# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+# define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
+#endif
+
+#include <asm-generic/siginfo.h>
+
+#endif /* _POWERPC_SIGINFO_H */
diff --git a/include/asm-ppc64/socket.h b/include/asm-powerpc/socket.h
similarity index 87%
rename from include/asm-ppc64/socket.h
rename to include/asm-powerpc/socket.h
index 9e1af8e..51a0cf5 100644
--- a/include/asm-ppc64/socket.h
+++ b/include/asm-powerpc/socket.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_SOCKET_H
-#define _ASM_SOCKET_H
+#ifndef _POWERPC_SOCKET_H
+#define _POWERPC_SOCKET_H
/*
* This program is free software; you can redistribute it and/or
@@ -10,7 +10,7 @@
#include <asm/sockios.h>
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
#define SOL_SOCKET 1
#define SO_DEBUG 1
@@ -52,8 +52,8 @@
#define SO_TIMESTAMP 29
#define SCM_TIMESTAMP SO_TIMESTAMP
-#define SO_ACCEPTCONN 30
+#define SO_ACCEPTCONN 30
-#define SO_PEERSEC 31
+#define SO_PEERSEC 31
-#endif /* _ASM_SOCKET_H */
+#endif /* _POWERPC_SOCKET_H */
diff --git a/include/asm-ppc64/sockios.h b/include/asm-powerpc/sockios.h
similarity index 83%
rename from include/asm-ppc64/sockios.h
rename to include/asm-powerpc/sockios.h
index 6bd1a22..ef7ff66 100644
--- a/include/asm-ppc64/sockios.h
+++ b/include/asm-powerpc/sockios.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_PPC64_SOCKIOS_H
-#define _ASM_PPC64_SOCKIOS_H
+#ifndef _POWERPC_SOCKIOS_H
+#define _POWERPC_SOCKIOS_H
/*
* This program is free software; you can redistribute it and/or
@@ -16,4 +16,4 @@
#define SIOCATMARK 0x8905
#define SIOCGSTAMP 0x8906 /* Get stamp */
-#endif /* _ASM_PPC64_SOCKIOS_H */
+#endif /* _POWERPC_SOCKIOS_H */
diff --git a/include/asm-ppc64/termbits.h b/include/asm-powerpc/termbits.h
similarity index 97%
rename from include/asm-ppc64/termbits.h
rename to include/asm-powerpc/termbits.h
index d1a2bee..2c5bf85 100644
--- a/include/asm-ppc64/termbits.h
+++ b/include/asm-powerpc/termbits.h
@@ -1,5 +1,5 @@
-#ifndef _PPC64_TERMBITS_H
-#define _PPC64_TERMBITS_H
+#ifndef _POWERPC_TERMBITS_H
+#define _POWERPC_TERMBITS_H
/*
* This program is free software; you can redistribute it and/or
@@ -8,8 +8,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/posix_types.h>
-
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
@@ -190,4 +188,4 @@
#define TCSADRAIN 1
#define TCSAFLUSH 2
-#endif /* _PPC64_TERMBITS_H */
+#endif /* _POWERPC_TERMBITS_H */
diff --git a/include/asm-ppc64/termios.h b/include/asm-powerpc/termios.h
similarity index 97%
rename from include/asm-ppc64/termios.h
rename to include/asm-powerpc/termios.h
index 02c3d28..237533b 100644
--- a/include/asm-ppc64/termios.h
+++ b/include/asm-powerpc/termios.h
@@ -1,5 +1,5 @@
-#ifndef _PPC64_TERMIOS_H
-#define _PPC64_TERMIOS_H
+#ifndef _POWERPC_TERMIOS_H
+#define _POWERPC_TERMIOS_H
/*
* Liberally adapted from alpha/termios.h. In particular, the c_cc[]
@@ -87,6 +87,7 @@
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
#define N_SYNC_PPP 14
+#define N_HCI 15 /* Bluetooth HCI UART */
#ifdef __KERNEL__
/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */
@@ -232,4 +233,4 @@
#endif /* __KERNEL__ */
-#endif /* _PPC64_TERMIOS_H */
+#endif /* _POWERPC_TERMIOS_H */
diff --git a/include/asm-ppc/auxvec.h b/include/asm-ppc/auxvec.h
new file mode 100644
index 0000000..172358d
--- /dev/null
+++ b/include/asm-ppc/auxvec.h
@@ -0,0 +1,14 @@
+#ifndef __PPC_AUXVEC_H
+#define __PPC_AUXVEC_H
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE 19
+#define AT_ICACHEBSIZE 20
+#define AT_UCACHEBSIZE 21
+/* A special ignored type value for PPC, for glibc compatibility. */
+#define AT_IGNOREPPC 22
+
+#endif
diff --git a/include/asm-ppc/bugs.h b/include/asm-ppc/bugs.h
deleted file mode 100644
index 8dce1e2..0000000
--- a/include/asm-ppc/bugs.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * This file is included by 'init/main.c'
- */
-
-extern void
-check_bugs(void);
diff --git a/include/asm-ppc/dma-mapping.h b/include/asm-ppc/dma-mapping.h
index 6f74f59..92b8ee7 100644
--- a/include/asm-ppc/dma-mapping.h
+++ b/include/asm-ppc/dma-mapping.h
@@ -60,7 +60,8 @@
}
static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle,
+ unsigned int __nocast gfp)
{
#ifdef CONFIG_NOT_COHERENT_CACHE
return __dma_alloc_coherent(size, dma_handle, gfp);
diff --git a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h
index 2c05696..c25cc35 100644
--- a/include/asm-ppc/elf.h
+++ b/include/asm-ppc/elf.h
@@ -7,6 +7,7 @@
#include <asm/types.h>
#include <asm/ptrace.h>
#include <asm/cputable.h>
+#include <asm/auxvec.h>
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE 0
@@ -122,16 +123,6 @@
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE 19
-#define AT_ICACHEBSIZE 20
-#define AT_UCACHEBSIZE 21
-/* A special ignored type value for PPC, for glibc compatibility. */
-#define AT_IGNOREPPC 22
-
extern int dcache_bsize;
extern int icache_bsize;
extern int ucache_bsize;
diff --git a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h
deleted file mode 100644
index 5e28e41..0000000
--- a/include/asm-ppc/fcntl.h
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef _PPC_FCNTL_H
-#define _PPC_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECTORY 040000 /* must be a directory */
-#define O_NOFOLLOW 0100000 /* don't follow links */
-#define O_LARGEFILE 0200000
-#define O_DIRECT 0400000 /* direct disk access hint */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-#ifdef __KERNEL__
-#define F_POSIX 1
-#define F_FLOCK 2
-#define F_BROKEN 4 /* broken flock() emulation */
-#endif /* __KERNEL__ */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-#endif
diff --git a/include/asm-ppc/futex.h b/include/asm-ppc/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-ppc/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
index e807be9..e992369 100644
--- a/include/asm-ppc/ibm4xx.h
+++ b/include/asm-ppc/ibm4xx.h
@@ -19,10 +19,6 @@
#ifdef CONFIG_40x
-#if defined(CONFIG_ASH)
-#include <platforms/4xx/ash.h>
-#endif
-
#if defined(CONFIG_BUBINGA)
#include <platforms/4xx/bubinga.h>
#endif
@@ -35,14 +31,6 @@
#include <platforms/4xx/ep405.h>
#endif
-#if defined(CONFIG_OAK)
-#include <platforms/4xx/oak.h>
-#endif
-
-#if defined(CONFIG_REDWOOD_4)
-#include <platforms/4xx/redwood.h>
-#endif
-
#if defined(CONFIG_REDWOOD_5)
#include <platforms/4xx/redwood5.h>
#endif
diff --git a/include/asm-ppc/ibm_ocp.h b/include/asm-ppc/ibm_ocp.h
index 3f7b566..6f10a25 100644
--- a/include/asm-ppc/ibm_ocp.h
+++ b/include/asm-ppc/ibm_ocp.h
@@ -67,6 +67,7 @@
int phy_mode; /* PHY type or configurable mode */
u8 mac_addr[6]; /* EMAC mac address */
u32 phy_map; /* EMAC phy map */
+ u32 phy_feat_exc; /* Excluded PHY features */
};
/* Sysfs support */
@@ -83,6 +84,7 @@
OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "%d\n", emac, tah_idx) \
OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "%d\n", emac, phy_mode) \
OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "0x%08x\n", emac, phy_map) \
+OCP_SYSFS_ADDTL(struct ocp_func_emac_data, "0x%08x\n", emac, phy_feat_exc)\
\
void ocp_show_emac_data(struct device *dev) \
{ \
@@ -98,8 +100,22 @@
device_create_file(dev, &dev_attr_emac_tah_idx); \
device_create_file(dev, &dev_attr_emac_phy_mode); \
device_create_file(dev, &dev_attr_emac_phy_map); \
+ device_create_file(dev, &dev_attr_emac_phy_feat_exc); \
}
+/*
+ * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
+ */
+#define PHY_MODE_NA 0
+#define PHY_MODE_MII 1
+#define PHY_MODE_RMII 2
+#define PHY_MODE_SMII 3
+#define PHY_MODE_RGMII 4
+#define PHY_MODE_TBI 5
+#define PHY_MODE_GMII 6
+#define PHY_MODE_RTBI 7
+#define PHY_MODE_SGMII 8
+
#ifdef CONFIG_40x
/*
* Helper function to copy MAC addresses from the bd_t to OCP EMAC
@@ -133,6 +149,7 @@
int txde_irq; /* TX Descriptor Error IRQ */
int rxde_irq; /* RX Descriptor Error IRQ */
int serr_irq; /* MAL System Error IRQ */
+ int dcr_base; /* MALx_CFG DCR number */
};
#define OCP_SYSFS_MAL_DATA() \
@@ -143,6 +160,7 @@
OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, txde_irq) \
OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, rxde_irq) \
OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, serr_irq) \
+OCP_SYSFS_ADDTL(struct ocp_func_mal_data, "%d\n", mal, dcr_base) \
\
void ocp_show_mal_data(struct device *dev) \
{ \
@@ -153,6 +171,7 @@
device_create_file(dev, &dev_attr_mal_txde_irq); \
device_create_file(dev, &dev_attr_mal_rxde_irq); \
device_create_file(dev, &dev_attr_mal_serr_irq); \
+ device_create_file(dev, &dev_attr_mal_dcr_base); \
}
/*
diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
index a9b3332..b4b2704 100644
--- a/include/asm-ppc/irq.h
+++ b/include/asm-ppc/irq.h
@@ -19,6 +19,11 @@
#define IRQ_POLARITY_POSITIVE 0x2 /* high level or low->high edge */
#define IRQ_POLARITY_NEGATIVE 0x0 /* low level or high->low edge */
+/*
+ * IRQ line status macro IRQ_PER_CPU is used
+ */
+#define ARCH_HAS_IRQ_PER_CPU
+
#if defined(CONFIG_40x)
#include <asm/ibm4xx.h>
@@ -337,6 +342,7 @@
#define SIU_INT_IDMA3 ((uint)0x08 + CPM_IRQ_OFFSET)
#define SIU_INT_IDMA4 ((uint)0x09 + CPM_IRQ_OFFSET)
#define SIU_INT_SDMA ((uint)0x0a + CPM_IRQ_OFFSET)
+#define SIU_INT_USB ((uint)0x0b + CPM_IRQ_OFFSET)
#define SIU_INT_TIMER1 ((uint)0x0c + CPM_IRQ_OFFSET)
#define SIU_INT_TIMER2 ((uint)0x0d + CPM_IRQ_OFFSET)
#define SIU_INT_TIMER3 ((uint)0x0e + CPM_IRQ_OFFSET)
diff --git a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h
index 2589f182..6d6fc78 100644
--- a/include/asm-ppc/kmap_types.h
+++ b/include/asm-ppc/kmap_types.h
@@ -17,6 +17,7 @@
KM_SOFTIRQ0,
KM_SOFTIRQ1,
KM_PPC_SYNC_PAGE,
+ KM_PPC_SYNC_ICACHE,
KM_TYPE_NR
};
diff --git a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h
deleted file mode 100644
index 227018b..0000000
--- a/include/asm-ppc/mc146818rtc.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifdef __KERNEL__
-#ifndef __ASM_PPC_MC146818RTC_H
-#define __ASM_PPC_MC146818RTC_H
-
-#include <asm/io.h>
-
-#ifndef RTC_PORT
-#define RTC_PORT(x) (0x70 + (x))
-#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */
-#endif
-
-/*
- * The yet supported machines all access the RTC index register via
- * an ISA port access but the way to access the date register differs ...
- */
-#define CMOS_READ(addr) ({ \
-outb_p((addr),RTC_PORT(0)); \
-inb_p(RTC_PORT(1)); \
-})
-#define CMOS_WRITE(val, addr) ({ \
-outb_p((addr),RTC_PORT(0)); \
-outb_p((val),RTC_PORT(1)); \
-})
-
-#define RTC_IRQ 8
-
-#endif /* __ASM_PPC_MC146818RTC_H */
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h
deleted file mode 100644
index 5fd19fd..0000000
--- a/include/asm-ppc/mman.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __PPC_MMAN_H__
-#define __PPC_MMAN_H__
-
-#define PROT_READ 0x1 /* page can be read */
-#define PROT_WRITE 0x2 /* page can be written */
-#define PROT_EXEC 0x4 /* page can be executed */
-#define PROT_SEM 0x8 /* page may be used for atomic ops */
-#define PROT_NONE 0x0 /* page can not be accessed */
-#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
-#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
-
-#define MAP_SHARED 0x01 /* Share changes */
-#define MAP_PRIVATE 0x02 /* Changes are private */
-#define MAP_TYPE 0x0f /* Mask for type of mapping */
-#define MAP_FIXED 0x10 /* Interpret addr exactly */
-#define MAP_ANONYMOUS 0x20 /* don't use a file */
-#define MAP_RENAME MAP_ANONYMOUS /* In SunOS terminology */
-#define MAP_NORESERVE 0x40 /* don't reserve swap pages */
-#define MAP_LOCKED 0x80
-
-#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
-#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
-#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
-#define MAP_NONBLOCK 0x10000 /* do not block on IO */
-
-#define MS_ASYNC 1 /* sync memory asynchronously */
-#define MS_INVALIDATE 2 /* invalidate the caches */
-#define MS_SYNC 4 /* synchronous memory sync */
-
-#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */
-#define MCL_FUTURE 0x4000 /* lock all additions to address space */
-
-#define MADV_NORMAL 0x0 /* default page-in behavior */
-#define MADV_RANDOM 0x1 /* page-in minimum required */
-#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */
-#define MADV_WILLNEED 0x3 /* pre-fault pages */
-#define MADV_DONTNEED 0x4 /* discard these pages */
-
-/* compatibility flags */
-#define MAP_ANON MAP_ANONYMOUS
-#define MAP_FILE 0
-
-#endif /* __PPC_MMAN_H__ */
diff --git a/include/asm-ppc/module.h b/include/asm-ppc/module.h
deleted file mode 100644
index fb63492..0000000
--- a/include/asm-ppc/module.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _ASM_PPC_MODULE_H
-#define _ASM_PPC_MODULE_H
-/* Module stuff for PPC. (C) 2001 Rusty Russell */
-
-#include <linux/list.h>
-#include <asm/bug.h>
-
-/* Thanks to Paul M for explaining this.
-
- PPC can only do rel jumps += 32MB, and often the kernel and other
- modules are furthur away than this. So, we jump to a table of
- trampolines attached to the module (the Procedure Linkage Table)
- whenever that happens.
-*/
-
-struct ppc_plt_entry
-{
- /* 16 byte jump instruction sequence (4 instructions) */
- unsigned int jump[4];
-};
-
-struct mod_arch_specific
-{
- /* Indices of PLT sections within module. */
- unsigned int core_plt_section, init_plt_section;
-
- /* List of BUG addresses, source line numbers and filenames */
- struct list_head bug_list;
- struct bug_entry *bug_table;
- unsigned int num_bugs;
-};
-
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-/* Make empty sections for module_frob_arch_sections to expand. */
-#ifdef MODULE
-asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
-asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
-#endif
-#endif /* _ASM_PPC_MODULE_H */
diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
index 89eb8a2..9694eca 100644
--- a/include/asm-ppc/mpc8260.h
+++ b/include/asm-ppc/mpc8260.h
@@ -67,6 +67,24 @@
#define IO_VIRT_ADDR IO_PHYS_ADDR
#endif
+enum ppc_sys_devices {
+ MPC82xx_CPM_FCC1,
+ MPC82xx_CPM_FCC2,
+ MPC82xx_CPM_FCC3,
+ MPC82xx_CPM_I2C,
+ MPC82xx_CPM_SCC1,
+ MPC82xx_CPM_SCC2,
+ MPC82xx_CPM_SCC3,
+ MPC82xx_CPM_SCC4,
+ MPC82xx_CPM_SPI,
+ MPC82xx_CPM_MCC1,
+ MPC82xx_CPM_MCC2,
+ MPC82xx_CPM_SMC1,
+ MPC82xx_CPM_SMC2,
+ MPC82xx_CPM_USB,
+ MPC82xx_SEC1,
+};
+
#ifndef __ASSEMBLY__
/* The "residual" data board information structure the boot loader
* hands to us.
diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
index 7c31f2d..dc8e598 100644
--- a/include/asm-ppc/mpc8xx.h
+++ b/include/asm-ppc/mpc8xx.h
@@ -36,10 +36,6 @@
#include <platforms/tqm8xx.h>
#endif
-#if defined(CONFIG_SPD823TS)
-#include <platforms/spd8xx.h>
-#endif
-
#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
#include <platforms/ivms8.h>
#endif
diff --git a/include/asm-ppc/mv64x60.h b/include/asm-ppc/mv64x60.h
index cc25b92..835930d 100644
--- a/include/asm-ppc/mv64x60.h
+++ b/include/asm-ppc/mv64x60.h
@@ -278,6 +278,13 @@
#define mv64x60_set_bits(bh, offs, bits) mv64x60_modify(bh, offs, ~0, bits)
#define mv64x60_clr_bits(bh, offs, bits) mv64x60_modify(bh, offs, 0, bits)
+#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
+#define MV64XXX_DEV_NAME "mv64xxx"
+
+struct mv64xxx_pdata {
+ u32 hs_reg_valid;
+};
+#endif
/* Externally visible function prototypes */
int mv64x60_init(struct mv64x60_handle *bh, struct mv64x60_setup_info *si);
diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h
index 2f42874..f8f7f16 100644
--- a/include/asm-ppc/mv64x60_defs.h
+++ b/include/asm-ppc/mv64x60_defs.h
@@ -333,7 +333,7 @@
/*
*****************************************************************************
*
- * SRAM Cotnroller Registers
+ * SRAM Controller Registers
*
*****************************************************************************
*/
@@ -352,7 +352,7 @@
/*
*****************************************************************************
*
- * SDRAM/MEM Cotnroller Registers
+ * SDRAM/MEM Controller Registers
*
*****************************************************************************
*/
@@ -375,6 +375,7 @@
/* SDRAM Control Registers */
#define MV64360_D_UNIT_CONTROL_LOW 0x1404
#define MV64360_D_UNIT_CONTROL_HIGH 0x1424
+#define MV64460_D_UNIT_MMASK 0x14b0
/* SDRAM Error Report Registers (64360) */
#define MV64360_SDRAM_ERR_DATA_LO 0x1444
@@ -388,7 +389,7 @@
/*
*****************************************************************************
*
- * Device/BOOT Cotnroller Registers
+ * Device/BOOT Controller Registers
*
*****************************************************************************
*/
@@ -680,6 +681,8 @@
#define MV64x60_PCI1_SLAVE_P2P_IO_REMAP 0x0dec
#define MV64x60_PCI1_SLAVE_CPU_REMAP 0x0df0
+#define MV64360_PCICFG_CPCI_HOTSWAP 0x68
+
/*
*****************************************************************************
*
diff --git a/include/asm-ppc/param.h b/include/asm-ppc/param.h
index b24a4e3..6198b16 100644
--- a/include/asm-ppc/param.h
+++ b/include/asm-ppc/param.h
@@ -1,8 +1,10 @@
#ifndef _ASM_PPC_PARAM_H
#define _ASM_PPC_PARAM_H
+#include <linux/config.h>
+
#ifdef __KERNEL__
-#define HZ 1000 /* internal timer frequency */
+#define HZ CONFIG_HZ /* internal timer frequency */
#define USER_HZ 100 /* for user interfaces in "ticks" */
#define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h
index 8beb162..e9683bc 100644
--- a/include/asm-ppc/pmac_feature.h
+++ b/include/asm-ppc/pmac_feature.h
@@ -32,6 +32,7 @@
#define __PPC_ASM_PMAC_FEATURE_H
#include <asm/macio.h>
+#include <asm/machdep.h>
/*
* Known Mac motherboard models
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
index 8ea6245..048f7c8 100644
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -21,7 +21,9 @@
#include <linux/device.h>
#include <linux/types.h>
-#if defined(CONFIG_83xx)
+#if defined(CONFIG_8260)
+#include <asm/mpc8260.h>
+#elif defined(CONFIG_83xx)
#include <asm/mpc83xx.h>
#elif defined(CONFIG_85xx)
#include <asm/mpc85xx.h>
@@ -50,6 +52,7 @@
/* determine which specific SOC we are */
extern void identify_ppc_sys_by_id(u32 id) __init;
extern void identify_ppc_sys_by_name(char *name) __init;
+extern void identify_ppc_sys_by_name_and_id(char *name, u32 id) __init;
/* describes all devices that may exist in a given family of processors */
extern struct platform_device ppc_sys_platform_devices[];
diff --git a/include/asm-ppc/sembuf.h b/include/asm-ppc/sembuf.h
deleted file mode 100644
index 883f682..0000000
--- a/include/asm-ppc/sembuf.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _PPC_SEMBUF_H
-#define _PPC_SEMBUF_H
-
-/*
- * The semid64_ds structure for PPC architecture.
- */
-
-struct semid64_ds {
- struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
- unsigned int __unused1;
- __kernel_time_t sem_otime; /* last semop time */
- unsigned int __unused2;
- __kernel_time_t sem_ctime; /* last change time */
- unsigned long sem_nsems; /* no. of semaphores in array */
- unsigned long __unused3;
- unsigned long __unused4;
-};
-
-#endif /* _PPC_SEMBUF_H */
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
index 6d47438..485a924 100644
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -18,8 +18,6 @@
#include <platforms/powerpmc250.h>
#elif defined(CONFIG_LOPEC)
#include <platforms/lopec.h>
-#elif defined(CONFIG_MCPN765)
-#include <platforms/mcpn765.h>
#elif defined(CONFIG_MVME5100)
#include <platforms/mvme5100.h>
#elif defined(CONFIG_PAL4)
diff --git a/include/asm-ppc/shmbuf.h b/include/asm-ppc/shmbuf.h
deleted file mode 100644
index 7ac0bd3..0000000
--- a/include/asm-ppc/shmbuf.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _PPC_SHMBUF_H
-#define _PPC_SHMBUF_H
-
-/*
- * The shmid64_ds structure for PPC architecture.
- */
-
-struct shmid64_ds {
- struct ipc64_perm shm_perm; /* operation perms */
- unsigned int __unused1;
- __kernel_time_t shm_atime; /* last attach time */
- unsigned int __unused2;
- __kernel_time_t shm_dtime; /* last detach time */
- unsigned int __unused3;
- __kernel_time_t shm_ctime; /* last change time */
- unsigned int __unused4;
- size_t shm_segsz; /* size of segment (bytes) */
- __kernel_pid_t shm_cpid; /* pid of creator */
- __kernel_pid_t shm_lpid; /* pid of last operator */
- unsigned long shm_nattch; /* no. of current attaches */
- unsigned long __unused5;
- unsigned long __unused6;
-};
-
-struct shminfo64 {
- unsigned long shmmax;
- unsigned long shmmin;
- unsigned long shmmni;
- unsigned long shmseg;
- unsigned long shmall;
- unsigned long __unused1;
- unsigned long __unused2;
- unsigned long __unused3;
- unsigned long __unused4;
-};
-
-#endif /* _PPC_SHMBUF_H */
diff --git a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h
deleted file mode 100644
index 4b9435b..0000000
--- a/include/asm-ppc/siginfo.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PPC_SIGINFO_H
-#define _PPC_SIGINFO_H
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/include/asm-ppc/socket.h b/include/asm-ppc/socket.h
deleted file mode 100644
index 296e1a3..0000000
--- a/include/asm-ppc/socket.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _ASM_SOCKET_H
-#define _ASM_SOCKET_H
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN 0x8901
-#define SIOCSPGRP 0x8902
-#define FIOGETOWN 0x8903
-#define SIOCGPGRP 0x8904
-#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
-
-/* For setsockopt(2) */
-#define SOL_SOCKET 1
-
-#define SO_DEBUG 1
-#define SO_REUSEADDR 2
-#define SO_TYPE 3
-#define SO_ERROR 4
-#define SO_DONTROUTE 5
-#define SO_BROADCAST 6
-#define SO_SNDBUF 7
-#define SO_RCVBUF 8
-#define SO_SNDBUFFORCE 32
-#define SO_RCVBUFFORCE 33
-#define SO_KEEPALIVE 9
-#define SO_OOBINLINE 10
-#define SO_NO_CHECK 11
-#define SO_PRIORITY 12
-#define SO_LINGER 13
-#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
-#define SO_RCVLOWAT 16
-#define SO_SNDLOWAT 17
-#define SO_RCVTIMEO 18
-#define SO_SNDTIMEO 19
-#define SO_PASSCRED 20
-#define SO_PEERCRED 21
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION 22
-#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
-#define SO_SECURITY_ENCRYPTION_NETWORK 24
-
-#define SO_BINDTODEVICE 25
-
-/* Socket filtering */
-#define SO_ATTACH_FILTER 26
-#define SO_DETACH_FILTER 27
-
-#define SO_PEERNAME 28
-#define SO_TIMESTAMP 29
-#define SCM_TIMESTAMP SO_TIMESTAMP
-
-#define SO_ACCEPTCONN 30
-
-#define SO_PEERSEC 31
-
-#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-ppc/sockios.h b/include/asm-ppc/sockios.h
deleted file mode 100644
index 385aedc..0000000
--- a/include/asm-ppc/sockios.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _ASM_PPC_SOCKIOS_H
-#define _ASM_PPC_SOCKIOS_H
-
-#if 0 /* These are defined this way on Alpha - maybe later. */
-/* Socket-level I/O control calls. */
-
-#define FIOGETOWN _IOR('f', 123, int)
-#define FIOSETOWN _IOW('f', 124, int)
-
-#define SIOCATMARK _IOR('s', 7, int)
-#define SIOCSPGRP _IOW('s', 8, pid_t)
-#define SIOCGPGRP _IOR('s', 9, pid_t)
-
-#define SIOCGSTAMP 0x8906 /* Get stamp - linux-specific */
-#endif
-
-#endif /* _ASM_PPC_SOCKIOS_H */
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 82395f3..513a334 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -84,9 +84,14 @@
extern void cvt_df(double *from, float *to, unsigned long *fpscr);
extern int call_rtas(const char *, int, int, unsigned long *, ...);
extern void cacheable_memzero(void *p, unsigned int nb);
+extern void *cacheable_memcpy(void *, const void *, unsigned int);
extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
extern void bad_page_fault(struct pt_regs *, unsigned long, int);
extern void die(const char *, struct pt_regs *, long);
+#ifdef CONFIG_BOOKE_WDT
+extern u32 booke_wdt_enabled;
+extern u32 booke_wdt_period;
+#endif /* CONFIG_BOOKE_WDT */
struct device_node;
extern void note_scsi_host(struct device_node *, void *);
diff --git a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h
deleted file mode 100644
index c343fb7..0000000
--- a/include/asm-ppc/termbits.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef _PPC_TERMBITS_H
-#define _PPC_TERMBITS_H
-
-typedef unsigned char cc_t;
-typedef unsigned int speed_t;
-typedef unsigned int tcflag_t;
-
-/*
- * termios type and macro definitions. Be careful about adding stuff
- * to this file since it's used in GNU libc and there are strict rules
- * concerning namespace pollution.
- */
-
-#define NCCS 19
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_cc[NCCS]; /* control characters */
- cc_t c_line; /* line discipline (== c_cc[19]) */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VMIN 5
-#define VEOL 6
-#define VTIME 7
-#define VEOL2 8
-#define VSWTC 9
-
-#define VWERASE 10
-#define VREPRINT 11
-#define VSUSP 12
-#define VSTART 13
-#define VSTOP 14
-#define VLNEXT 15
-#define VDISCARD 16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IXON 0001000
-#define IXOFF 0002000
-#define IXANY 0004000
-#define IUCLC 0010000
-#define IMAXBEL 0020000
-#define IUTF8 0040000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define ONLCR 0000002
-#define OLCUC 0000004
-
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-
-#define OFILL 00000100
-#define OFDEL 00000200
-#define NLDLY 00001400
-#define NL0 00000000
-#define NL1 00000400
-#define NL2 00001000
-#define NL3 00001400
-#define TABDLY 00006000
-#define TAB0 00000000
-#define TAB1 00002000
-#define TAB2 00004000
-#define TAB3 00006000
-#define XTABS 00006000 /* required by POSIX to == TAB3 */
-#define CRDLY 00030000
-#define CR0 00000000
-#define CR1 00010000
-#define CR2 00020000
-#define CR3 00030000
-#define FFDLY 00040000
-#define FF0 00000000
-#define FF1 00040000
-#define BSDLY 00100000
-#define BS0 00000000
-#define BS1 00100000
-#define VTDLY 00200000
-#define VT0 00000000
-#define VT1 00200000
-
-/* c_cflag bit meaning */
-#define CBAUD 0000377
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CBAUDEX 0000000
-#define B57600 00020
-#define B115200 00021
-#define B230400 00022
-#define B460800 00023
-#define B500000 00024
-#define B576000 00025
-#define B921600 00026
-#define B1000000 00027
-#define B1152000 00030
-#define B1500000 00031
-#define B2000000 00032
-#define B2500000 00033
-#define B3000000 00034
-#define B3500000 00035
-#define B4000000 00036
-
-#define CSIZE 00001400
-#define CS5 00000000
-#define CS6 00000400
-#define CS7 00001000
-#define CS8 00001400
-
-#define CSTOPB 00002000
-#define CREAD 00004000
-#define PARENB 00010000
-#define PARODD 00020000
-#define HUPCL 00040000
-
-#define CLOCAL 00100000
-#define CRTSCTS 020000000000 /* flow control */
-
-/* c_lflag bits */
-#define ISIG 0x00000080
-#define ICANON 0x00000100
-#define XCASE 0x00004000
-#define ECHO 0x00000008
-#define ECHOE 0x00000002
-#define ECHOK 0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL 0x00000040
-#define ECHOPRT 0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-
-/* Values for the ACTION argument to `tcflow'. */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
-
-#endif /* _PPC_TERMBITS_H */
diff --git a/include/asm-ppc/termios.h b/include/asm-ppc/termios.h
deleted file mode 100644
index 97c6287..0000000
--- a/include/asm-ppc/termios.h
+++ /dev/null
@@ -1,232 +0,0 @@
-#ifndef _PPC_TERMIOS_H
-#define _PPC_TERMIOS_H
-
-/*
- * Liberally adapted from alpha/termios.h. In particular, the c_cc[]
- * fields have been reordered so that termio & termios share the
- * common subset in the same order (for brain dead programs that don't
- * know or care about the differences).
- */
-
-#include <asm/ioctls.h>
-#include <asm/termbits.h>
-
-struct sgttyb {
- char sg_ispeed;
- char sg_ospeed;
- char sg_erase;
- char sg_kill;
- short sg_flags;
-};
-
-struct tchars {
- char t_intrc;
- char t_quitc;
- char t_startc;
- char t_stopc;
- char t_eofc;
- char t_brkc;
-};
-
-struct ltchars {
- char t_suspc;
- char t_dsuspc;
- char t_rprntc;
- char t_flushc;
- char t_werasc;
- char t_lnextc;
-};
-
-#define FIOCLEX _IO('f', 1)
-#define FIONCLEX _IO('f', 2)
-#define FIOASYNC _IOW('f', 125, int)
-#define FIONBIO _IOW('f', 126, int)
-#define FIONREAD _IOR('f', 127, int)
-#define TIOCINQ FIONREAD
-#define FIOQSIZE _IOR('f', 128, loff_t)
-
-#define TIOCGETP _IOR('t', 8, struct sgttyb)
-#define TIOCSETP _IOW('t', 9, struct sgttyb)
-#define TIOCSETN _IOW('t', 10, struct sgttyb) /* TIOCSETP wo flush */
-
-#define TIOCSETC _IOW('t', 17, struct tchars)
-#define TIOCGETC _IOR('t', 18, struct tchars)
-#define TCGETS _IOR('t', 19, struct termios)
-#define TCSETS _IOW('t', 20, struct termios)
-#define TCSETSW _IOW('t', 21, struct termios)
-#define TCSETSF _IOW('t', 22, struct termios)
-
-#define TCGETA _IOR('t', 23, struct termio)
-#define TCSETA _IOW('t', 24, struct termio)
-#define TCSETAW _IOW('t', 25, struct termio)
-#define TCSETAF _IOW('t', 28, struct termio)
-
-#define TCSBRK _IO('t', 29)
-#define TCXONC _IO('t', 30)
-#define TCFLSH _IO('t', 31)
-
-#define TIOCSWINSZ _IOW('t', 103, struct winsize)
-#define TIOCGWINSZ _IOR('t', 104, struct winsize)
-#define TIOCSTART _IO('t', 110) /* start output, like ^Q */
-#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */
-#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */
-
-#define TIOCGLTC _IOR('t', 116, struct ltchars)
-#define TIOCSLTC _IOW('t', 117, struct ltchars)
-#define TIOCSPGRP _IOW('t', 118, int)
-#define TIOCGPGRP _IOR('t', 119, int)
-
-#define TIOCEXCL 0x540C
-#define TIOCNXCL 0x540D
-#define TIOCSCTTY 0x540E
-
-#define TIOCSTI 0x5412
-#define TIOCMGET 0x5415
-#define TIOCMBIS 0x5416
-#define TIOCMBIC 0x5417
-#define TIOCMSET 0x5418
-#define TIOCGSOFTCAR 0x5419
-#define TIOCSSOFTCAR 0x541A
-#define TIOCLINUX 0x541C
-#define TIOCCONS 0x541D
-#define TIOCGSERIAL 0x541E
-#define TIOCSSERIAL 0x541F
-#define TIOCPKT 0x5420
-
-#define TIOCNOTTY 0x5422
-#define TIOCSETD 0x5423
-#define TIOCGETD 0x5424
-#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
-
-#define TIOCSERCONFIG 0x5453
-#define TIOCSERGWILD 0x5454
-#define TIOCSERSWILD 0x5455
-#define TIOCGLCKTRMIOS 0x5456
-#define TIOCSLCKTRMIOS 0x5457
-#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TIOCSERGETLSR 0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
-#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
-
-/* Used for packet mode */
-#define TIOCPKT_DATA 0
-#define TIOCPKT_FLUSHREAD 1
-#define TIOCPKT_FLUSHWRITE 2
-#define TIOCPKT_STOP 4
-#define TIOCPKT_START 8
-#define TIOCPKT_NOSTOP 16
-#define TIOCPKT_DOSTOP 32
-
-struct winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
-};
-
-#define NCC 10
-struct termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[NCC]; /* control characters */
-};
-
-/* c_cc characters */
-#define _VINTR 0
-#define _VQUIT 1
-#define _VERASE 2
-#define _VKILL 3
-#define _VEOF 4
-#define _VMIN 5
-#define _VEOL 6
-#define _VTIME 7
-#define _VEOL2 8
-#define _VSWTC 9
-
-#ifdef __KERNEL__
-/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */
-#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025"
-#endif /* __KERNEL__ */
-
-/* modem lines */
-#define TIOCM_LE 0x001
-#define TIOCM_DTR 0x002
-#define TIOCM_RTS 0x004
-#define TIOCM_ST 0x008
-#define TIOCM_SR 0x010
-#define TIOCM_CTS 0x020
-#define TIOCM_CAR 0x040
-#define TIOCM_RNG 0x080
-#define TIOCM_DSR 0x100
-#define TIOCM_CD TIOCM_CAR
-#define TIOCM_RI TIOCM_RNG
-#define TIOCM_OUT1 0x2000
-#define TIOCM_OUT2 0x4000
-#define TIOCM_LOOP 0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-
-/* line disciplines */
-#define N_TTY 0
-#define N_SLIP 1
-#define N_MOUSE 2
-#define N_PPP 3
-#define N_STRIP 4
-#define N_AX25 5
-#define N_X25 6 /* X.25 async */
-#define N_6PACK 7
-#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
-#define N_R3964 9 /* Reserved for Simatic R3964 module */
-#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
-#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */
-#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
-#define N_HDLC 13 /* synchronous HDLC */
-#define N_SYNC_PPP 14
-#define N_HCI 15 /* Bluetooth HCI UART */
-
-#ifdef __KERNEL__
-
-/*
- * Translate a "termio" structure into a "termios". Ugh.
- */
-#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
- unsigned short __tmp; \
- get_user(__tmp,&(termio)->x); \
- (termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
-}
-
-#define user_termio_to_kernel_termios(termios, termio) \
-({ \
- SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
- SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
- SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
- SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
- copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-})
-
-/*
- * Translate a "termios" structure into a "termio". Ugh.
- */
-#define kernel_termios_to_user_termio(termio, termios) \
-({ \
- put_user((termios)->c_iflag, &(termio)->c_iflag); \
- put_user((termios)->c_oflag, &(termio)->c_oflag); \
- put_user((termios)->c_cflag, &(termio)->c_cflag); \
- put_user((termios)->c_lflag, &(termio)->c_lflag); \
- put_user((termios)->c_line, &(termio)->c_line); \
- copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
-})
-
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
-
-#endif /* __KERNEL__ */
-
-#endif /* _PPC_TERMIOS_H */
diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h
index a787bc0..77dc24d 100644
--- a/include/asm-ppc/types.h
+++ b/include/asm-ppc/types.h
@@ -62,8 +62,6 @@
#define HAVE_SECTOR_T
#endif
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h
index b044ae0..63f5622 100644
--- a/include/asm-ppc/uaccess.h
+++ b/include/asm-ppc/uaccess.h
@@ -37,13 +37,6 @@
#define access_ok(type, addr, size) \
(__chk_user_ptr(addr),__access_ok((unsigned long)(addr),(size)))
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-ppc64/auxvec.h b/include/asm-ppc64/auxvec.h
new file mode 100644
index 0000000..ac6381a
--- /dev/null
+++ b/include/asm-ppc64/auxvec.h
@@ -0,0 +1,19 @@
+#ifndef __PPC64_AUXVEC_H
+#define __PPC64_AUXVEC_H
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE 19
+#define AT_ICACHEBSIZE 20
+#define AT_UCACHEBSIZE 21
+/* A special ignored type value for PPC, for glibc compatibility. */
+#define AT_IGNOREPPC 22
+
+/* The vDSO location. We have to use the same value as x86 for glibc's
+ * sake :-)
+ */
+#define AT_SYSINFO_EHDR 33
+
+#endif /* __PPC64_AUXVEC_H */
diff --git a/include/asm-ppc64/bugs.h b/include/asm-ppc64/bugs.h
deleted file mode 100644
index 861074b..0000000
--- a/include/asm-ppc64/bugs.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * This file is included by 'init/main.c' to check for architecture-dependent
- * bugs.
- *
- */
-#ifndef _ASM_PPC64_BUGS_H
-#define _ASM_PPC64_BUGS_H
-
-static void check_bugs(void) {
-}
-
-#endif /* _ASM_PPC64_BUGS_H */
diff --git a/include/asm-ppc64/compat.h b/include/asm-ppc64/compat.h
index 12414f5..6ec62cd 100644
--- a/include/asm-ppc64/compat.h
+++ b/include/asm-ppc64/compat.h
@@ -13,8 +13,10 @@
typedef s32 compat_time_t;
typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
-typedef u32 compat_uid_t;
-typedef u32 compat_gid_t;
+typedef u32 __compat_uid_t;
+typedef u32 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u32 compat_mode_t;
typedef u32 compat_ino_t;
typedef u32 compat_dev_t;
@@ -48,8 +50,8 @@
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid32_t st_uid;
+ __compat_gid32_t st_gid;
compat_dev_t st_rdev;
compat_off_t st_size;
compat_off_t st_blksize;
@@ -144,10 +146,10 @@
*/
struct compat_ipc64_perm {
compat_key_t key;
- compat_uid_t uid;
- compat_gid_t gid;
- compat_uid_t cuid;
- compat_gid_t cgid;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
+ __compat_uid_t cuid;
+ __compat_gid_t cgid;
compat_mode_t mode;
unsigned int seq;
unsigned int __pad2;
diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h
index ae6cf38..acc9b4d 100644
--- a/include/asm-ppc64/cputable.h
+++ b/include/asm-ppc64/cputable.h
@@ -36,6 +36,7 @@
* via the mkdefs mechanism.
*/
struct cpu_spec;
+struct op_ppc64_model;
typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
@@ -52,10 +53,19 @@
unsigned int icache_bsize;
unsigned int dcache_bsize;
+ /* number of performance monitor counters */
+ unsigned int num_pmcs;
+
/* this is called to initialize various CPU bits like L1 cache,
* BHT, SPD, etc... from head.S before branching to identify_machine
*/
cpu_setup_t cpu_setup;
+
+ /* Used by oprofile userspace to select the right counters */
+ char *oprofile_cpu_type;
+
+ /* Processor specific oprofile operations */
+ struct op_ppc64_model *oprofile_model;
};
extern struct cpu_spec cpu_specs[];
@@ -95,7 +105,7 @@
#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000001000000000)
#define CPU_FTR_IABR ASM_CONST(0x0000002000000000)
#define CPU_FTR_MMCRA ASM_CONST(0x0000004000000000)
-#define CPU_FTR_PMC8 ASM_CONST(0x0000008000000000)
+/* unused ASM_CONST(0x0000008000000000) */
#define CPU_FTR_SMT ASM_CONST(0x0000010000000000)
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000020000000000)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
diff --git a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h
index 085eedb..c919a89 100644
--- a/include/asm-ppc64/elf.h
+++ b/include/asm-ppc64/elf.h
@@ -4,6 +4,7 @@
#include <asm/types.h>
#include <asm/ptrace.h>
#include <asm/cputable.h>
+#include <asm/auxvec.h>
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE 0
@@ -237,21 +238,6 @@
#endif
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE 19
-#define AT_ICACHEBSIZE 20
-#define AT_UCACHEBSIZE 21
-/* A special ignored type value for PPC, for glibc compatibility. */
-#define AT_IGNOREPPC 22
-
-/* The vDSO location. We have to use the same value as x86 for glibc's
- * sake :-)
- */
-#define AT_SYSINFO_EHDR 33
-
extern int dcache_bsize;
extern int icache_bsize;
extern int ucache_bsize;
diff --git a/include/asm-ppc64/fcntl.h b/include/asm-ppc64/fcntl.h
deleted file mode 100644
index 842560d..0000000
--- a/include/asm-ppc64/fcntl.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef _PPC64_FCNTL_H
-#define _PPC64_FCNTL_H
-
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECTORY 040000 /* must be a directory */
-#define O_NOFOLLOW 0100000 /* don't follow links */
-#define O_LARGEFILE 0200000
-#define O_DIRECT 0400000 /* direct disk access hint */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-#ifdef __KERNEL__
-#define F_POSIX 1
-#define F_FLOCK 2
-#define F_BROKEN 4 /* broken flock() emulation */
-#endif /* __KERNEL__ */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-
-#endif /* _PPC64_FCNTL_H */
diff --git a/include/asm-ppc64/futex.h b/include/asm-ppc64/futex.h
new file mode 100644
index 0000000..cb2640b
--- /dev/null
+++ b/include/asm-ppc64/futex.h
@@ -0,0 +1,83 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/memory.h>
+#include <asm/uaccess.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+ __asm__ __volatile (SYNC_ON_SMP \
+"1: lwarx %0,0,%2\n" \
+ insn \
+"2: stwcx. %1,0,%2\n\
+ bne- 1b\n\
+ li %1,0\n\
+3: .section .fixup,\"ax\"\n\
+4: li %1,%3\n\
+ b 3b\n\
+ .previous\n\
+ .section __ex_table,\"a\"\n\
+ .align 3\n\
+ .llong 1b,4b,2b,4b\n\
+ .previous" \
+ : "=&r" (oldval), "=&r" (ret) \
+ : "b" (uaddr), "i" (-EFAULT), "1" (oparg) \
+ : "cr0", "memory")
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op("", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op("add %1,%0,%1\n", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op("or %1,%0,%1\n", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op("andc %1,%0,%1\n", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op("xor %1,%0,%1\n", ret, oldval, uaddr, oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-ppc64/irq.h b/include/asm-ppc64/irq.h
index 570678b..99782af 100644
--- a/include/asm-ppc64/irq.h
+++ b/include/asm-ppc64/irq.h
@@ -33,6 +33,11 @@
#define IRQ_POLARITY_POSITIVE 0x2 /* high level or low->high edge */
#define IRQ_POLARITY_NEGATIVE 0x0 /* low level or high->low edge */
+/*
+ * IRQ line status macro IRQ_PER_CPU is used
+ */
+#define ARCH_HAS_IRQ_PER_CPU
+
#define get_irq_desc(irq) (&irq_desc[(irq)])
/* Define a way to iterate across irqs. */
diff --git a/include/asm-ppc64/kprobes.h b/include/asm-ppc64/kprobes.h
index 0802919..d9129d2 100644
--- a/include/asm-ppc64/kprobes.h
+++ b/include/asm-ppc64/kprobes.h
@@ -42,6 +42,9 @@
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
+#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
+ IS_TWI(instr) || IS_TDI(instr))
+
#define ARCH_SUPPORTS_KRETPROBES
void kretprobe_trampoline(void);
diff --git a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h
index cb368bf..de91e03 100644
--- a/include/asm-ppc64/lmb.h
+++ b/include/asm-ppc64/lmb.h
@@ -56,4 +56,26 @@
extern unsigned long io_hole_start;
+static inline unsigned long
+lmb_size_bytes(struct lmb_region *type, unsigned long region_nr)
+{
+ return type->region[region_nr].size;
+}
+static inline unsigned long
+lmb_size_pages(struct lmb_region *type, unsigned long region_nr)
+{
+ return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT;
+}
+static inline unsigned long
+lmb_start_pfn(struct lmb_region *type, unsigned long region_nr)
+{
+ return type->region[region_nr].base >> PAGE_SHIFT;
+}
+static inline unsigned long
+lmb_end_pfn(struct lmb_region *type, unsigned long region_nr)
+{
+ return lmb_start_pfn(type, region_nr) +
+ lmb_size_pages(type, region_nr);
+}
+
#endif /* _PPC64_LMB_H */
diff --git a/include/asm-ppc64/lppaca.h b/include/asm-ppc64/lppaca.h
index 70766b5..9e2a6c0 100644
--- a/include/asm-ppc64/lppaca.h
+++ b/include/asm-ppc64/lppaca.h
@@ -108,7 +108,7 @@
volatile u32 virtual_decr; // Virtual DECR for shared procsx78-x7B
u16 slb_count; // # of SLBs to maintain x7C-x7D
u8 idle; // Indicate OS is idle x7E
- u8 reserved5; // Reserved x7F
+ u8 vmxregs_in_use; // VMX registers in use x7F
//=============================================================================
diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
index ff2c928..9a1ef44 100644
--- a/include/asm-ppc64/machdep.h
+++ b/include/asm-ppc64/machdep.h
@@ -103,11 +103,6 @@
void (*progress)(char *, unsigned short);
- /* Debug interface. Low level I/O to some terminal device */
- void (*udbg_putc)(unsigned char c);
- unsigned char (*udbg_getc)(void);
- int (*udbg_getc_poll)(void);
-
/* Interface for platform error logging */
void (*log_error)(char *buf, unsigned int err_type, int fatal);
diff --git a/include/asm-ppc64/memory.h b/include/asm-ppc64/memory.h
index 56e09fa..af53ffb 100644
--- a/include/asm-ppc64/memory.h
+++ b/include/asm-ppc64/memory.h
@@ -18,9 +18,11 @@
#ifdef CONFIG_SMP
#define EIEIO_ON_SMP "eieio\n"
#define ISYNC_ON_SMP "\n\tisync"
+#define SYNC_ON_SMP "lwsync\n\t"
#else
#define EIEIO_ON_SMP
#define ISYNC_ON_SMP
+#define SYNC_ON_SMP
#endif
static inline void eieio(void)
diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
index ad36bb2..7bc42eb 100644
--- a/include/asm-ppc64/mmu.h
+++ b/include/asm-ppc64/mmu.h
@@ -54,8 +54,10 @@
#define SLB_VSID_C ASM_CONST(0x0000000000000080) /* class */
#define SLB_VSID_LS ASM_CONST(0x0000000000000070) /* size of largepage */
-#define SLB_VSID_KERNEL (SLB_VSID_KP|SLB_VSID_C)
-#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS)
+#define SLB_VSID_KERNEL (SLB_VSID_KP)
+#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
+
+#define SLBIE_C (0x08000000)
/*
* Hash table
diff --git a/include/asm-ppc64/module.h b/include/asm-ppc64/module.h
deleted file mode 100644
index 0581607..0000000
--- a/include/asm-ppc64/module.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _ASM_PPC64_MODULE_H
-#define _ASM_PPC64_MODULE_H
-
-#include <linux/list.h>
-#include <asm/bug.h>
-
-struct mod_arch_specific
-{
- /* Index of stubs section within module. */
- unsigned int stubs_section;
-
- /* What section is the TOC? */
- unsigned int toc_section;
-
- /* List of BUG addresses, source line numbers and filenames */
- struct list_head bug_list;
- struct bug_entry *bug_table;
- unsigned int num_bugs;
-};
-
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-
-/* Make empty section for module_frob_arch_sections to expand. */
-#ifdef MODULE
-asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
-#endif
-
-struct exception_table_entry;
-void sort_ex_table(struct exception_table_entry *start,
- struct exception_table_entry *finish);
-
-#endif /* _ASM_PPC64_MODULE_H */
diff --git a/arch/ppc64/oprofile/op_impl.h b/include/asm-ppc64/oprofile_impl.h
similarity index 95%
rename from arch/ppc64/oprofile/op_impl.h
rename to include/asm-ppc64/oprofile_impl.h
index 7fa7eaa..b04f1df 100644
--- a/arch/ppc64/oprofile/op_impl.h
+++ b/include/asm-ppc64/oprofile_impl.h
@@ -49,6 +49,9 @@
int num_counters;
};
+extern struct op_ppc64_model op_model_rs64;
+extern struct op_ppc64_model op_model_power4;
+
static inline unsigned int ctr_read(unsigned int i)
{
switch(i) {
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
index a79a08d..a15422b 100644
--- a/include/asm-ppc64/page.h
+++ b/include/asm-ppc64/page.h
@@ -172,20 +172,6 @@
#endif
-/* Pure 2^n version of get_order */
-static inline int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
extern int page_is_ram(unsigned long pfn);
@@ -270,4 +256,7 @@
VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
#endif /* __KERNEL__ */
+
+#include <asm-generic/page.h>
+
#endif /* _PPC64_PAGE_H */
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
index 7bd4796..8bd7aa9 100644
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -311,6 +311,20 @@
.type GLUE(.,name),@function; \
GLUE(.,name):
+#define _KPROBE(name) \
+ .section ".kprobes.text","a"; \
+ .align 2 ; \
+ .globl name; \
+ .globl GLUE(.,name); \
+ .section ".opd","aw"; \
+name: \
+ .quad GLUE(.,name); \
+ .quad .TOC.@tocbase; \
+ .quad 0; \
+ .previous; \
+ .type GLUE(.,name),@function; \
+GLUE(.,name):
+
#define _STATIC(name) \
.section ".text"; \
.align 2 ; \
diff --git a/include/asm-ppc64/siginfo.h b/include/asm-ppc64/siginfo.h
deleted file mode 100644
index 3a7c23d..0000000
--- a/include/asm-ppc64/siginfo.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _PPC64_SIGINFO_H
-#define _PPC64_SIGINFO_H
-
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
-
-#include <asm-generic/siginfo.h>
-
-#endif /* _PPC64_SIGINFO_H */
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
index b9e1835..c039642 100644
--- a/include/asm-ppc64/system.h
+++ b/include/asm-ppc64/system.h
@@ -158,7 +158,7 @@
* is more like most of the other architectures.
*/
static __inline__ unsigned long
-__xchg_u32(volatile int *m, unsigned long val)
+__xchg_u32(volatile unsigned int *m, unsigned long val)
{
unsigned long dummy;
@@ -200,7 +200,7 @@
extern void __xchg_called_with_bad_pointer(void);
static __inline__ unsigned long
-__xchg(volatile void *ptr, unsigned long x, int size)
+__xchg(volatile void *ptr, unsigned long x, unsigned int size)
{
switch (size) {
case 4:
@@ -223,7 +223,7 @@
#define __HAVE_ARCH_CMPXCHG 1
static __inline__ unsigned long
-__cmpxchg_u32(volatile int *p, int old, int new)
+__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
{
unsigned int prev;
@@ -271,7 +271,8 @@
extern void __cmpxchg_called_with_bad_pointer(void);
static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
+ unsigned int size)
{
switch (size) {
case 4:
@@ -283,13 +284,9 @@
return old;
}
-#define cmpxchg(ptr,o,n) \
- ({ \
- __typeof__(*(ptr)) _o_ = (o); \
- __typeof__(*(ptr)) _n_ = (n); \
- (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
- (unsigned long)_n_, sizeof(*(ptr))); \
- })
+#define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
/*
* We handle most unaligned accesses in hardware. On the other hand
diff --git a/include/asm-ppc64/types.h b/include/asm-ppc64/types.h
index 5b8c2cf..bf294c1 100644
--- a/include/asm-ppc64/types.h
+++ b/include/asm-ppc64/types.h
@@ -72,7 +72,6 @@
unsigned long env;
} func_descr_t;
-typedef unsigned int kmem_bufctl_t;
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc64/uaccess.h b/include/asm-ppc64/uaccess.h
index 05b5943..c181a60d 100644
--- a/include/asm-ppc64/uaccess.h
+++ b/include/asm-ppc64/uaccess.h
@@ -56,13 +56,6 @@
#define access_ok(type,addr,size) \
__access_ok(((__force unsigned long)(addr)),(size),get_fs())
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-ppc64/udbg.h b/include/asm-ppc64/udbg.h
index a6e04d0..c786604 100644
--- a/include/asm-ppc64/udbg.h
+++ b/include/asm-ppc64/udbg.h
@@ -2,6 +2,7 @@
#define __UDBG_HDR
#include <linux/compiler.h>
+#include <linux/init.h>
/*
* c 2001 PPC 64 Team, IBM Corp
@@ -12,17 +13,19 @@
* 2 of the License, or (at your option) any later version.
*/
-void udbg_init_uart(void __iomem *comport, unsigned int speed);
-void udbg_putc(unsigned char c);
-unsigned char udbg_getc(void);
-int udbg_getc_poll(void);
-void udbg_puts(const char *s);
-int udbg_write(const char *s, int n);
-int udbg_read(char *buf, int buflen);
-struct console;
-void udbg_console_write(struct console *con, const char *s, unsigned int n);
-void udbg_printf(const char *fmt, ...);
-void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
-unsigned long udbg_ifdebug(unsigned long flags);
+extern void (*udbg_putc)(unsigned char c);
+extern unsigned char (*udbg_getc)(void);
+extern int (*udbg_getc_poll)(void);
+extern void udbg_puts(const char *s);
+extern int udbg_write(const char *s, int n);
+extern int udbg_read(char *buf, int buflen);
+
+extern void register_early_udbg_console(void);
+extern void udbg_printf(const char *fmt, ...);
+extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
+extern unsigned long udbg_ifdebug(unsigned long flags);
+extern void __init ppcdbg_initialize(void);
+
+extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
#endif
diff --git a/include/asm-s390/auxvec.h b/include/asm-s390/auxvec.h
new file mode 100644
index 0000000..0d34072
--- /dev/null
+++ b/include/asm-s390/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMS390_AUXVEC_H
+#define __ASMS390_AUXVEC_H
+
+#endif
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h
index 7f8f544..a007715 100644
--- a/include/asm-s390/compat.h
+++ b/include/asm-s390/compat.h
@@ -13,10 +13,10 @@
typedef s32 compat_time_t;
typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
-typedef u16 compat_uid_t;
-typedef u16 compat_gid_t;
-typedef u32 compat_uid32_t;
-typedef u32 compat_gid32_t;
+typedef u16 __compat_uid_t;
+typedef u16 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u16 compat_dev_t;
@@ -51,8 +51,8 @@
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid_t st_uid;
+ __compat_gid_t st_gid;
compat_dev_t st_rdev;
u16 __pad2;
u32 st_size;
@@ -140,10 +140,10 @@
struct compat_ipc64_perm {
compat_key_t key;
- compat_uid32_t uid;
- compat_gid32_t gid;
- compat_uid32_t cuid;
- compat_gid32_t cgid;
+ __compat_uid32_t uid;
+ __compat_gid32_t gid;
+ __compat_uid32_t cuid;
+ __compat_gid32_t cgid;
compat_mode_t mode;
unsigned short __pad1;
unsigned short seq;
diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h
index 92360d9..7127030 100644
--- a/include/asm-s390/debug.h
+++ b/include/asm-s390/debug.h
@@ -52,8 +52,6 @@
#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
/* the entry information */
-#define STCK(x) asm volatile ("STCK 0(%1)" : "=m" (x) : "a" (&(x)) : "cc")
-
typedef struct __debug_entry debug_entry_t;
struct debug_view;
diff --git a/include/asm-s390/fcntl.h b/include/asm-s390/fcntl.h
index 48f692b..46ab12d 100644
--- a/include/asm-s390/fcntl.h
+++ b/include/asm-s390/fcntl.h
@@ -1,97 +1 @@
-/*
- * include/asm-s390/fcntl.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/fcntl.h"
- */
-#ifndef _S390_FCNTL_H
-#define _S390_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#ifndef __s390x__
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-#endif /* ! __s390x__ */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-#ifndef __s390x__
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-#endif
-#define F_LINUX_SPECIFIC_BASE 1024
-#endif
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-s390/futex.h b/include/asm-s390/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-s390/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index afe6a9f..c6f51c9 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -68,6 +68,7 @@
#define __LC_SYSTEM_TIMER 0x270
#define __LC_LAST_UPDATE_CLOCK 0x278
#define __LC_STEAL_CLOCK 0x280
+#define __LC_RETURN_MCCK_PSW 0x288
#define __LC_KERNEL_STACK 0xC40
#define __LC_THREAD_INFO 0xC44
#define __LC_ASYNC_STACK 0xC48
@@ -90,6 +91,7 @@
#define __LC_SYSTEM_TIMER 0x278
#define __LC_LAST_UPDATE_CLOCK 0x280
#define __LC_STEAL_CLOCK 0x288
+#define __LC_RETURN_MCCK_PSW 0x290
#define __LC_KERNEL_STACK 0xD40
#define __LC_THREAD_INFO 0xD48
#define __LC_ASYNC_STACK 0xD50
@@ -196,7 +198,8 @@
__u64 system_timer; /* 0x270 */
__u64 last_update_clock; /* 0x278 */
__u64 steal_clock; /* 0x280 */
- __u8 pad8[0xc00-0x288]; /* 0x288 */
+ psw_t return_mcck_psw; /* 0x288 */
+ __u8 pad8[0xc00-0x290]; /* 0x290 */
/* System info area */
__u32 save_area[16]; /* 0xc00 */
@@ -285,7 +288,8 @@
__u64 system_timer; /* 0x278 */
__u64 last_update_clock; /* 0x280 */
__u64 steal_clock; /* 0x288 */
- __u8 pad8[0xc00-0x290]; /* 0x290 */
+ psw_t return_mcck_psw; /* 0x290 */
+ __u8 pad8[0xc00-0x2a0]; /* 0x2a0 */
/* System info area */
__u64 save_area[16]; /* 0xc00 */
__u8 pad9[0xd40-0xc80]; /* 0xc80 */
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index 2be287b..2430c56 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -111,20 +111,6 @@
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
/*
* These are used to make use of C type-checking..
*/
@@ -207,4 +193,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _S390_PAGE_H */
diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
index 8ff1030..321b23b 100644
--- a/include/asm-s390/spinlock.h
+++ b/include/asm-s390/spinlock.h
@@ -47,7 +47,7 @@
static inline void _raw_spin_lock(spinlock_t *lp)
{
- unsigned long pc = (unsigned long) __builtin_return_address(0);
+ unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
if (unlikely(_raw_compare_and_swap(&lp->lock, 0, pc) != 0))
_raw_spin_lock_wait(lp, pc);
@@ -55,7 +55,7 @@
static inline int _raw_spin_trylock(spinlock_t *lp)
{
- unsigned long pc = (unsigned long) __builtin_return_address(0);
+ unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
if (likely(_raw_compare_and_swap(&lp->lock, 0, pc) == 0))
return 1;
diff --git a/include/asm-s390/types.h b/include/asm-s390/types.h
index 3fefd61..d0be3e4 100644
--- a/include/asm-s390/types.h
+++ b/include/asm-s390/types.h
@@ -79,8 +79,6 @@
typedef u32 dma_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#ifndef __s390x__
typedef union {
unsigned long long pair;
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
index 3e3bfe6..38a5cf8 100644
--- a/include/asm-s390/uaccess.h
+++ b/include/asm-s390/uaccess.h
@@ -65,13 +65,6 @@
#define access_ok(type,addr,size) __access_ok(addr,size)
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user *addr,
- unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-sh/auxvec.h b/include/asm-sh/auxvec.h
new file mode 100644
index 0000000..fc21e4d
--- /dev/null
+++ b/include/asm-sh/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASM_SH_AUXVEC_H
+#define __ASM_SH_AUXVEC_H
+
+#endif /* __ASM_SH_AUXVEC_H */
diff --git a/include/asm-sh/fcntl.h b/include/asm-sh/fcntl.h
index 0b3ae52..46ab12d 100644
--- a/include/asm-sh/fcntl.h
+++ b/include/asm-sh/fcntl.h
@@ -1,88 +1 @@
-#ifndef __ASM_SH_FCNTL_H
-#define __ASM_SH_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint - currently ignored */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-#endif /* __ASM_SH_FCNTL_H */
-
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-sh/futex.h b/include/asm-sh/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-sh/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sh/hdreg.h b/include/asm-sh/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-sh/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index 180467b..324e6cc 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -122,24 +122,8 @@
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
-#endif
-
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* __ASM_SH_PAGE_H */
diff --git a/include/asm-sh/types.h b/include/asm-sh/types.h
index c4dc126..cb7e183 100644
--- a/include/asm-sh/types.h
+++ b/include/asm-sh/types.h
@@ -58,8 +58,6 @@
#define HAVE_SECTOR_T
#endif
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
index fb9e334..2cb01861e 100644
--- a/include/asm-sh/uaccess.h
+++ b/include/asm-sh/uaccess.h
@@ -146,12 +146,6 @@
return __access_ok(addr, size);
}
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
/*
* Uh, these should become the main single-value transfer routines ...
* They automatically use the right size if we just have the right
diff --git a/include/asm-sh64/auxvec.h b/include/asm-sh64/auxvec.h
new file mode 100644
index 0000000..1ad5a44
--- /dev/null
+++ b/include/asm-sh64/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASM_SH64_AUXVEC_H
+#define __ASM_SH64_AUXVEC_H
+
+#endif /* __ASM_SH64_AUXVEC_H */
diff --git a/include/asm-sh64/fcntl.h b/include/asm-sh64/fcntl.h
index ffcc36c..744dd79 100644
--- a/include/asm-sh64/fcntl.h
+++ b/include/asm-sh64/fcntl.h
@@ -1,7 +1 @@
-#ifndef __ASM_SH64_FCNTL_H
-#define __ASM_SH64_FCNTL_H
-
#include <asm-sh/fcntl.h>
-
-#endif /* __ASM_SH64_FCNTL_H */
-
diff --git a/include/asm-sh64/futex.h b/include/asm-sh64/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-sh64/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sh64/hdreg.h b/include/asm-sh64/hdreg.h
deleted file mode 100644
index 52d9836..0000000
--- a/include/asm-sh64/hdreg.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SH64_HDREG_H
-#define __ASM_SH64_HDREG_H
-
-#include <asm-generic/hdreg.h>
-
-#endif /* __ASM_SH64_HDREG_H */
diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h
index d6167f1..c86df90 100644
--- a/include/asm-sh64/page.h
+++ b/include/asm-sh64/page.h
@@ -115,24 +115,8 @@
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
-#endif
-
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* __ASM_SH64_PAGE_H */
diff --git a/include/asm-sh64/types.h b/include/asm-sh64/types.h
index 41d4d2f..8d41db2 100644
--- a/include/asm-sh64/types.h
+++ b/include/asm-sh64/types.h
@@ -65,8 +65,6 @@
#endif
typedef u64 dma64_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#define BITS_PER_LONG 32
diff --git a/include/asm-sh64/uaccess.h b/include/asm-sh64/uaccess.h
index a33654d..56aa3cf 100644
--- a/include/asm-sh64/uaccess.h
+++ b/include/asm-sh64/uaccess.h
@@ -60,12 +60,6 @@
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
#define __access_ok(addr,size) (__range_ok(addr,size) == 0)
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
/*
* Uh, these should become the main single-value transfer routines ...
* They automatically use the right size if we just have the right
diff --git a/include/asm-sparc/auxvec.h b/include/asm-sparc/auxvec.h
new file mode 100644
index 0000000..ad6f360
--- /dev/null
+++ b/include/asm-sparc/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMSPARC_AUXVEC_H
+#define __ASMSPARC_AUXVEC_H
+
+#endif /* !(__ASMSPARC_AUXVEC_H) */
diff --git a/include/asm-sparc/fcntl.h b/include/asm-sparc/fcntl.h
index df9c75d..5db60b5 100644
--- a/include/asm-sparc/fcntl.h
+++ b/include/asm-sparc/fcntl.h
@@ -4,10 +4,6 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_RDONLY 0x0000
-#define O_WRONLY 0x0001
-#define O_RDWR 0x0002
-#define O_ACCMODE 0x0003
#define O_APPEND 0x0008
#define FASYNC 0x0040 /* fcntl, for BSD compatibility */
#define O_CREAT 0x0200 /* not fcntl */
@@ -17,73 +13,24 @@
#define O_NONBLOCK 0x4000
#define O_NDELAY (0x0004 | O_NONBLOCK)
#define O_NOCTTY 0x8000 /* not fcntl */
-#define O_DIRECTORY 0x10000 /* must be a directory */
-#define O_NOFOLLOW 0x20000 /* don't follow links */
#define O_LARGEFILE 0x40000
#define O_DIRECT 0x100000 /* direct disk access hint */
#define O_NOATIME 0x200000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */
#define F_GETLK 7
#define F_SETLK 8
#define F_SETLKW 9
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
/* for posix fcntl() and lockf() */
#define F_RDLCK 1
#define F_WRLCK 2
#define F_UNLCK 3
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
+#define __ARCH_FLOCK_PAD short __unused;
+#define __ARCH_FLOCK64_PAD short __unused;
-/* for leases */
-#define F_INPROGRESS 16
+#include <asm-generic/fcntl.h>
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
- short __unused;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
- short __unused;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
#endif
diff --git a/include/asm-sparc/futex.h b/include/asm-sparc/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-sparc/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sparc/hdreg.h b/include/asm-sparc/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-sparc/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h
index 383060e..9122684 100644
--- a/include/asm-sparc/page.h
+++ b/include/asm-sparc/page.h
@@ -132,20 +132,6 @@
#define TASK_UNMAPPED_BASE BTFIXUP_SETHI(sparc_unmapped_base)
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#else /* !(__ASSEMBLY__) */
#define __pgprot(x) (x)
@@ -178,4 +164,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _SPARC_PAGE_H */
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index 40ed30a..8f4f6a9 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -435,9 +435,6 @@
#define kern_addr_valid(addr) \
(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
-extern int io_remap_page_range(struct vm_area_struct *vma,
- unsigned long from, unsigned long to,
- unsigned long size, pgprot_t prot, int space);
extern int io_remap_pfn_range(struct vm_area_struct *vma,
unsigned long from, unsigned long pfn,
unsigned long size, pgprot_t prot);
diff --git a/include/asm-sparc/types.h b/include/asm-sparc/types.h
index 9eabf6e..42fc6ed 100644
--- a/include/asm-sparc/types.h
+++ b/include/asm-sparc/types.h
@@ -54,8 +54,6 @@
typedef u32 dma_addr_t;
typedef u32 dma64_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc/uaccess.h b/include/asm-sparc/uaccess.h
index 0a780e8..f8f1ec1 100644
--- a/include/asm-sparc/uaccess.h
+++ b/include/asm-sparc/uaccess.h
@@ -47,12 +47,6 @@
#define access_ok(type, addr, size) \
({ (void)(type); __access_ok((unsigned long)(addr), size); })
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-sparc64/auxvec.h b/include/asm-sparc64/auxvec.h
new file mode 100644
index 0000000..436a291
--- /dev/null
+++ b/include/asm-sparc64/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASM_SPARC64_AUXVEC_H
+#define __ASM_SPARC64_AUXVEC_H
+
+#endif /* !(__ASM_SPARC64_AUXVEC_H) */
diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h
index b59122d..c73935d 100644
--- a/include/asm-sparc64/compat.h
+++ b/include/asm-sparc64/compat.h
@@ -12,8 +12,10 @@
typedef s32 compat_time_t;
typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
-typedef u16 compat_uid_t;
-typedef u16 compat_gid_t;
+typedef u16 __compat_uid_t;
+typedef u16 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u16 compat_dev_t;
@@ -47,8 +49,8 @@
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid_t st_uid;
+ __compat_gid_t st_gid;
compat_dev_t st_rdev;
compat_off_t st_size;
compat_time_t st_atime;
@@ -177,10 +179,10 @@
struct compat_ipc64_perm {
compat_key_t key;
- __kernel_uid_t uid;
- __kernel_gid_t gid;
- __kernel_uid_t cuid;
- __kernel_gid_t cgid;
+ __compat_uid32_t uid;
+ __compat_gid32_t gid;
+ __compat_uid32_t cuid;
+ __compat_gid32_t cgid;
unsigned short __pad1;
compat_mode_t mode;
unsigned short __pad2;
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index cc7198a..9a3a81f 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -1,6 +1,6 @@
/* cpudata.h: Per-cpu parameters.
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2005 David S. Miller (davem@redhat.com)
*/
#ifndef _SPARC64_CPUDATA_H
@@ -10,7 +10,7 @@
typedef struct {
/* Dcache line 1 */
- unsigned int __pad0; /* bh_count moved to irq_stat for consistency. KAO */
+ unsigned int __softirq_pending; /* must be 1st, see rtrap.S */
unsigned int multiplier;
unsigned int counter;
unsigned int idle_volume;
diff --git a/include/asm-sparc64/fcntl.h b/include/asm-sparc64/fcntl.h
index e36def0..b2aecf0 100644
--- a/include/asm-sparc64/fcntl.h
+++ b/include/asm-sparc64/fcntl.h
@@ -4,10 +4,6 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_RDONLY 0x0000
-#define O_WRONLY 0x0001
-#define O_RDWR 0x0002
-#define O_ACCMODE 0x0003
#define O_NDELAY 0x0004
#define O_APPEND 0x0008
#define FASYNC 0x0040 /* fcntl, for BSD compatibility */
@@ -17,62 +13,24 @@
#define O_SYNC 0x2000
#define O_NONBLOCK 0x4000
#define O_NOCTTY 0x8000 /* not fcntl */
-#define O_DIRECTORY 0x10000 /* must be a directory */
-#define O_NOFOLLOW 0x20000 /* don't follow links */
#define O_LARGEFILE 0x40000
#define O_DIRECT 0x100000 /* direct disk access hint */
#define O_NOATIME 0x200000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */
#define F_GETLK 7
#define F_SETLK 8
#define F_SETLKW 9
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
/* for posix fcntl() and lockf() */
#define F_RDLCK 1
#define F_WRLCK 2
#define F_UNLCK 3
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
+#define __ARCH_FLOCK_PAD short __unused;
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
- short __unused;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
+#include <asm-generic/fcntl.h>
#endif /* !(_SPARC64_FCNTL_H) */
diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-sparc64/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h
index d6db1ae..f0cf713 100644
--- a/include/asm-sparc64/hardirq.h
+++ b/include/asm-sparc64/hardirq.h
@@ -1,22 +1,16 @@
/* hardirq.h: 64-bit Sparc hard IRQ support.
*
- * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998, 2005 David S. Miller (davem@davemloft.net)
*/
#ifndef __SPARC64_HARDIRQ_H
#define __SPARC64_HARDIRQ_H
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
+#include <asm/cpudata.h>
-/* rtrap.S is sensitive to the offsets of these fields */
-typedef struct {
- unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#define __ARCH_IRQ_STAT
+#define local_softirq_pending() \
+ (local_cpu_data().__softirq_pending)
#define HARDIRQ_BITS 8
diff --git a/include/asm-sparc64/hdreg.h b/include/asm-sparc64/hdreg.h
deleted file mode 100644
index 7f7fd1a..0000000
--- a/include/asm-sparc64/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/hdreg.h>
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index afdcea9..0056770 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -100,18 +100,41 @@
#define inl_p(__addr) inl(__addr)
#define outl_p(__l, __addr) outl(__l, __addr)
-extern void outsb(void __iomem *addr, const void *src, unsigned long count);
-extern void outsw(void __iomem *addr, const void *src, unsigned long count);
-extern void outsl(void __iomem *addr, const void *src, unsigned long count);
-extern void insb(void __iomem *addr, void *dst, unsigned long count);
-extern void insw(void __iomem *addr, void *dst, unsigned long count);
-extern void insl(void __iomem *addr, void *dst, unsigned long count);
-#define ioread8_rep(a,d,c) insb(a,d,c)
-#define ioread16_rep(a,d,c) insw(a,d,c)
-#define ioread32_rep(a,d,c) insl(a,d,c)
-#define iowrite8_rep(a,s,c) outsb(a,s,c)
-#define iowrite16_rep(a,s,c) outsw(a,s,c)
-#define iowrite32_rep(a,s,c) outsl(a,s,c)
+extern void outsb(unsigned long, const void *, unsigned long);
+extern void outsw(unsigned long, const void *, unsigned long);
+extern void outsl(unsigned long, const void *, unsigned long);
+extern void insb(unsigned long, void *, unsigned long);
+extern void insw(unsigned long, void *, unsigned long);
+extern void insl(unsigned long, void *, unsigned long);
+
+static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
+{
+ insb((unsigned long __force)port, buf, count);
+}
+static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
+{
+ insw((unsigned long __force)port, buf, count);
+}
+
+static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
+{
+ insl((unsigned long __force)port, buf, count);
+}
+
+static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+ outsb((unsigned long __force)port, buf, count);
+}
+
+static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+ outsw((unsigned long __force)port, buf, count);
+}
+
+static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+ outsl((unsigned long __force)port, buf, count);
+}
/* Memory functions, same as I/O accesses on Ultra. */
static inline u8 _readb(const volatile void __iomem *addr)
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index b87dbbd..c9f8ef2 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -150,20 +150,6 @@
extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#endif /* !(__ASSEMBLY__) */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
@@ -171,4 +157,6 @@
#endif /* !(__KERNEL__) */
+#include <asm-generic/page.h>
+
#endif /* !(_SPARC64_PAGE_H) */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 1ae00c5..a2b4f5e 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -410,9 +410,6 @@
#define kern_addr_valid(addr) \
(test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
-extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
- unsigned long offset,
- unsigned long size, pgprot_t prot, int space);
extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn,
unsigned long size, pgprot_t prot);
diff --git a/include/asm-sparc64/types.h b/include/asm-sparc64/types.h
index 6248ed1..d0ee7f1 100644
--- a/include/asm-sparc64/types.h
+++ b/include/asm-sparc64/types.h
@@ -56,8 +56,6 @@
typedef u32 dma_addr_t;
typedef u64 dma64_addr_t;
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h
index 5690142..80a65d7 100644
--- a/include/asm-sparc64/uaccess.h
+++ b/include/asm-sparc64/uaccess.h
@@ -59,12 +59,6 @@
return 1;
}
-/* this function will go away soon - use access_ok() instead */
-static inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return 0;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-um/auxvec.h b/include/asm-um/auxvec.h
new file mode 100644
index 0000000..1e5e1c2
--- /dev/null
+++ b/include/asm-um/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __UM_AUXVEC_H
+#define __UM_AUXVEC_H
+
+#endif
diff --git a/include/asm-um/futex.h b/include/asm-um/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-um/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-um/hdreg.h b/include/asm-um/hdreg.h
deleted file mode 100644
index cf6363a..0000000
--- a/include/asm-um/hdreg.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UM_HDREG_H
-#define __UM_HDREG_H
-
-#include "asm/arch/hdreg.h"
-
-#endif
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 095bb62..2edb4f1 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -20,7 +20,15 @@
static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
{
- if (old != new)
+ /*
+ * This is called by fs/exec.c and fs/aio.c. In the first case, for an
+ * exec, we don't need to do anything as we're called from userspace
+ * and thus going to use a new host PID. In the second, we're called
+ * from a kernel thread, and thus need to go doing the mmap's on the
+ * host. Since they're very expensive, we want to avoid that as far as
+ * possible.
+ */
+ if (old != new && (current->flags & PF_BORROWED_MM))
force_flush_all();
}
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index f58aeda..bd850a2 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -116,24 +116,12 @@
#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
extern struct page *arch_validate(struct page *page, int mask, int order);
#define HAVE_ARCH_VALIDATE
extern void arch_free_page(struct page *page, int order);
#define HAVE_ARCH_FREE_PAGE
+#include <asm-generic/page.h>
+
#endif
diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h
index 8fcb2fc..ea49411 100644
--- a/include/asm-um/pgalloc.h
+++ b/include/asm-um/pgalloc.h
@@ -42,11 +42,13 @@
#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
#ifdef CONFIG_3_LEVEL_PGTABLES
-/*
- * In the 3-level case we free the pmds as part of the pgd.
- */
-#define pmd_free(x) do { } while (0)
-#define __pmd_free_tlb(tlb,x) do { } while (0)
+
+extern __inline__ void pmd_free(pmd_t *pmd)
+{
+ free_page((unsigned long)pmd);
+}
+
+#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
#endif
#define check_pgt_cache() do { } while (0)
diff --git a/include/asm-um/pgtable-2level.h b/include/asm-um/pgtable-2level.h
index 9b3abc0..ffe017f 100644
--- a/include/asm-um/pgtable-2level.h
+++ b/include/asm-um/pgtable-2level.h
@@ -35,35 +35,8 @@
static inline int pgd_newpage(pgd_t pgd) { return 0; }
static inline void pgd_mkuptodate(pgd_t pgd) { }
-#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
-
-static inline pte_t pte_mknewprot(pte_t pte)
-{
- pte_val(pte) |= _PAGE_NEWPROT;
- return(pte);
-}
-
-static inline pte_t pte_mknewpage(pte_t pte)
-{
- pte_val(pte) |= _PAGE_NEWPAGE;
- return(pte);
-}
-
-static inline void set_pte(pte_t *pteptr, pte_t pteval)
-{
- /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
- * fix_range knows to unmap it. _PAGE_NEWPROT is specific to
- * mapped pages.
- */
- *pteptr = pte_mknewpage(pteval);
- if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
-}
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
-#define pte_page(x) pfn_to_page(pte_pfn(x))
-#define pte_none(x) !(pte_val(x) & ~_PAGE_NEWPAGE)
#define pte_pfn(x) phys_to_pfn(pte_val(x))
#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h
index 65e8bfc..786c257 100644
--- a/include/asm-um/pgtable-3level.h
+++ b/include/asm-um/pgtable-3level.h
@@ -57,35 +57,6 @@
static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
-
-#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE))
-
-static inline pte_t pte_mknewprot(pte_t pte)
-{
- pte_set_bits(pte, _PAGE_NEWPROT);
- return(pte);
-}
-
-static inline pte_t pte_mknewpage(pte_t pte)
-{
- pte_set_bits(pte, _PAGE_NEWPAGE);
- return(pte);
-}
-
-static inline void set_pte(pte_t *pteptr, pte_t pteval)
-{
- pte_copy(*pteptr, pteval);
-
- /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
- * fix_range knows to unmap it. _PAGE_NEWPROT is specific to
- * mapped pages.
- */
-
- *pteptr = pte_mknewpage(*pteptr);
- if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
-}
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-
#define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
@@ -98,14 +69,11 @@
return pmd;
}
-static inline void pmd_free(pmd_t *pmd){
- free_page((unsigned long) pmd);
+extern inline void pud_clear (pud_t *pud)
+{
+ set_pud(pud, __pud(0));
}
-#define __pmd_free_tlb(tlb,x) do { } while (0)
-
-static inline void pud_clear (pud_t * pud) { }
-
#define pud_page(pud) \
((struct page *) __va(pud_val(pud) & PAGE_MASK))
@@ -113,13 +81,6 @@
#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
pmd_index(address))
-#define pte_page(x) pfn_to_page(pte_pfn(x))
-
-static inline int pte_none(pte_t pte)
-{
- return pte_is_zero(pte);
-}
-
static inline unsigned long pte_pfn(pte_t pte)
{
return phys_to_pfn(pte_val(pte));
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index a880409..b48e096 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -16,13 +16,15 @@
#define _PAGE_PRESENT 0x001
#define _PAGE_NEWPAGE 0x002
-#define _PAGE_NEWPROT 0x004
-#define _PAGE_FILE 0x008 /* set:pagecache unset:swap */
-#define _PAGE_PROTNONE 0x010 /* If not present */
+#define _PAGE_NEWPROT 0x004
#define _PAGE_RW 0x020
#define _PAGE_USER 0x040
#define _PAGE_ACCESSED 0x080
#define _PAGE_DIRTY 0x100
+/* If _PAGE_PRESENT is clear, we use these: */
+#define _PAGE_FILE 0x008 /* nonlinear file mapping, saved PTE; unset:swap */
+#define _PAGE_PROTNONE 0x010 /* if the user mapped it with PROT_NONE;
+ pte_present gives true */
#ifdef CONFIG_3_LEVEL_PGTABLES
#include "asm/pgtable-3level.h"
@@ -151,10 +153,24 @@
#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
+#define pte_page(x) pfn_to_page(pte_pfn(x))
#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
#define mk_phys(a, r) ((a) + (((unsigned long) r) << REGION_SHIFT))
#define phys_addr(p) ((p) & ~REGION_MASK)
+#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE))
+
+/*
+ * =================================
+ * Flags checking section.
+ * =================================
+ */
+
+static inline int pte_none(pte_t pte)
+{
+ return pte_is_zero(pte);
+}
+
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
@@ -210,6 +226,18 @@
return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT)));
}
+/*
+ * =================================
+ * Flags setting section.
+ * =================================
+ */
+
+static inline pte_t pte_mknewprot(pte_t pte)
+{
+ pte_set_bits(pte, _PAGE_NEWPROT);
+ return(pte);
+}
+
static inline pte_t pte_rdprotect(pte_t pte)
{
pte_clear_bits(pte, _PAGE_USER);
@@ -278,6 +306,26 @@
return(pte);
}
+static inline pte_t pte_mknewpage(pte_t pte)
+{
+ pte_set_bits(pte, _PAGE_NEWPAGE);
+ return(pte);
+}
+
+static inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+ pte_copy(*pteptr, pteval);
+
+ /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
+ * fix_range knows to unmap it. _PAGE_NEWPROT is specific to
+ * mapped pages.
+ */
+
+ *pteptr = pte_mknewpage(*pteptr);
+ if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
+}
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
extern phys_t page_to_phys(struct page *page);
/*
diff --git a/include/asm-v850/auxvec.h b/include/asm-v850/auxvec.h
new file mode 100644
index 0000000..f493232
--- /dev/null
+++ b/include/asm-v850/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __V850_AUXVEC_H__
+#define __V850_AUXVEC_H__
+
+#endif /* __V850_AUXVEC_H__ */
diff --git a/include/asm-v850/fcntl.h b/include/asm-v850/fcntl.h
index 31d4b59..3af4d56 100644
--- a/include/asm-v850/fcntl.h
+++ b/include/asm-v850/fcntl.h
@@ -1,87 +1,11 @@
#ifndef __V850_FCNTL_H__
#define __V850_FCNTL_H__
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0400000
-#define O_NOATIME 01000000
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
+#include <asm-generic/fcntl.h>
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-#define F_GETLK64 12 /* using 'struct flock64' */
-#define F_SETLK64 13
-#define F_SETLKW64 14
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-struct flock64 {
- short l_type;
- short l_whence;
- loff_t l_start;
- loff_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
#endif /* __V850_FCNTL_H__ */
diff --git a/include/asm-v850/futex.h b/include/asm-v850/futex.h
new file mode 100644
index 0000000..2cac5ec
--- /dev/null
+++ b/include/asm-v850/futex.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-v850/page.h b/include/asm-v850/page.h
index d609162..b4bc85e 100644
--- a/include/asm-v850/page.h
+++ b/include/asm-v850/page.h
@@ -98,25 +98,6 @@
#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
-#ifndef __ASSEMBLY__
-
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order (unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
-#endif /* !__ASSEMBLY__ */
-
-
/* No current v850 processor has virtual memory. */
#define __virt_to_phys(addr) (addr)
#define __phys_to_virt(addr) (addr)
@@ -144,4 +125,6 @@
#endif /* KERNEL */
+#include <asm-generic/page.h>
+
#endif /* __V850_PAGE_H__ */
diff --git a/include/asm-v850/types.h b/include/asm-v850/types.h
index e7cfe5b..dcef571 100644
--- a/include/asm-v850/types.h
+++ b/include/asm-v850/types.h
@@ -59,8 +59,6 @@
typedef u32 dma_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-v850/uaccess.h b/include/asm-v850/uaccess.h
index 4386cfc..188b285 100644
--- a/include/asm-v850/uaccess.h
+++ b/include/asm-v850/uaccess.h
@@ -27,12 +27,6 @@
return val >= (0x80 + NUM_CPU_IRQS*16) && val < 0xFFFFF000;
}
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area (int type, const void *addr, unsigned long size)
-{
- return access_ok (type, addr, size) ? 0 : -EFAULT;
-}
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-x86_64/auxvec.h b/include/asm-x86_64/auxvec.h
new file mode 100644
index 0000000..2403c4c
--- /dev/null
+++ b/include/asm-x86_64/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASM_X86_64_AUXVEC_H
+#define __ASM_X86_64_AUXVEC_H
+
+#endif
diff --git a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h
index d0f453c..f0155c3 100644
--- a/include/asm-x86_64/compat.h
+++ b/include/asm-x86_64/compat.h
@@ -14,10 +14,10 @@
typedef s32 compat_time_t;
typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
-typedef u16 compat_uid_t;
-typedef u16 compat_gid_t;
-typedef u32 compat_uid32_t;
-typedef u32 compat_gid32_t;
+typedef u16 __compat_uid_t;
+typedef u16 __compat_gid_t;
+typedef u32 __compat_uid32_t;
+typedef u32 __compat_gid32_t;
typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u16 compat_dev_t;
@@ -52,8 +52,8 @@
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
- compat_uid_t st_uid;
- compat_gid_t st_gid;
+ __compat_uid_t st_uid;
+ __compat_gid_t st_gid;
compat_dev_t st_rdev;
u16 __pad2;
u32 st_size;
@@ -122,10 +122,10 @@
struct compat_ipc64_perm {
compat_key_t key;
- compat_uid32_t uid;
- compat_gid32_t gid;
- compat_uid32_t cuid;
- compat_gid32_t cgid;
+ __compat_uid32_t uid;
+ __compat_gid32_t gid;
+ __compat_uid32_t cuid;
+ __compat_gid32_t cgid;
unsigned short mode;
unsigned short __pad1;
unsigned short seq;
diff --git a/include/asm-x86_64/fcntl.h b/include/asm-x86_64/fcntl.h
index 4411f22..46ab12d 100644
--- a/include/asm-x86_64/fcntl.h
+++ b/include/asm-x86_64/fcntl.h
@@ -1,76 +1 @@
-#ifndef _X86_64_FCNTL_H
-#define _X86_64_FCNTL_H
-
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
-#define O_ACCMODE 0003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100 /* not fcntl */
-#define O_EXCL 0200 /* not fcntl */
-#define O_NOCTTY 0400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-#define O_SYNC 010000
-#define FASYNC 020000 /* fcntl, for BSD compatibility */
-#define O_DIRECT 040000 /* direct disk access hint */
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000 /* must be a directory */
-#define O_NOFOLLOW 0400000 /* don't follow links */
-#define O_NOATIME 01000000
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
-#define F_GETLK 5
-#define F_SETLK 6
-#define F_SETLKW 7
-
-#define F_SETOWN 8 /* for sockets. */
-#define F_GETOWN 9 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock */
-#define LOCK_READ 64 /* ... Which allows concurrent read operations */
-#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
-#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
-
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-#define F_LINUX_SPECIFIC_BASE 1024
-
-#endif /* !_X86_64_FCNTL_H */
+#include <asm-generic/fcntl.h>
diff --git a/include/asm-x86_64/futex.h b/include/asm-x86_64/futex.h
new file mode 100644
index 0000000..8602c09
--- /dev/null
+++ b/include/asm-x86_64/futex.h
@@ -0,0 +1,98 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
+ __asm__ __volatile ( \
+"1: " insn "\n" \
+"2: .section .fixup,\"ax\"\n\
+3: mov %3, %1\n\
+ jmp 2b\n\
+ .previous\n\
+ .section __ex_table,\"a\"\n\
+ .align 8\n\
+ .quad 1b,3b\n\
+ .previous" \
+ : "=r" (oldval), "=r" (ret), "=m" (*uaddr) \
+ : "i" (-EFAULT), "m" (*uaddr), "0" (oparg), "1" (0))
+
+#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
+ __asm__ __volatile ( \
+"1: movl %2, %0\n\
+ movl %0, %3\n" \
+ insn "\n" \
+"2: " LOCK_PREFIX "cmpxchgl %3, %2\n\
+ jnz 1b\n\
+3: .section .fixup,\"ax\"\n\
+4: mov %5, %1\n\
+ jmp 3b\n\
+ .previous\n\
+ .section __ex_table,\"a\"\n\
+ .align 8\n\
+ .quad 1b,4b,2b,4b\n\
+ .previous" \
+ : "=&a" (oldval), "=&r" (ret), "=m" (*uaddr), \
+ "=&r" (tem) \
+ : "r" (oparg), "i" (-EFAULT), "m" (*uaddr), "1" (0))
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret, tem;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
+ uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op2("andl %4, %3", ret, oldval, uaddr, ~oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr, oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+#endif
+#endif
diff --git a/include/asm-x86_64/hdreg.h b/include/asm-x86_64/hdreg.h
deleted file mode 100644
index 5989bbc..0000000
--- a/include/asm-x86_64/hdreg.h
+++ /dev/null
@@ -1 +0,0 @@
-#warning this file is obsolete, please do not use it
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 4313187..135ffaa 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -28,7 +28,6 @@
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
-#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
@@ -92,20 +91,6 @@
#include <asm/bug.h>
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#endif /* __ASSEMBLY__ */
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
@@ -141,4 +126,6 @@
#endif /* __KERNEL__ */
+#include <asm-generic/page.h>
+
#endif /* _X86_64_PAGE_H */
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 4e167b5..5e0f2fd 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -104,6 +104,19 @@
((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
#define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte, 0))
+
+static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
+{
+ pte_t pte;
+ if (full) {
+ pte = *ptep;
+ *ptep = __pte(0);
+ } else {
+ pte = ptep_get_and_clear(mm, addr, ptep);
+ }
+ return pte;
+}
+
#define pte_same(a, b) ((a).pte == (b).pte)
#define PMD_SIZE (1UL << PMD_SHIFT)
@@ -143,7 +156,7 @@
#define _PAGE_ACCESSED 0x020
#define _PAGE_DIRTY 0x040
#define _PAGE_PSE 0x080 /* 2MB page */
-#define _PAGE_FILE 0x040 /* set:pagecache, unset:swap */
+#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */
#define _PAGE_GLOBAL 0x100 /* Global TLB entry */
#define _PAGE_PROTNONE 0x080 /* If not present */
@@ -247,6 +260,7 @@
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
+#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
static inline int pte_user(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
@@ -254,8 +268,8 @@
extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_huge(pte_t pte) { return (pte_val(pte) & __LARGE_PTE) == __LARGE_PTE; }
-#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
extern inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
extern inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
extern inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -433,6 +447,7 @@
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
#include <asm-generic/pgtable.h>
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 85549e6..a832199 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -398,7 +398,7 @@
#define ARCH_HAS_PREFETCHW 1
static inline void prefetchw(void *x)
{
- alternative_input(ASM_NOP5,
+ alternative_input("prefetcht0 (%1)",
"prefetchw (%1)",
X86_FEATURE_3DNOW,
"r" (x));
@@ -437,6 +437,11 @@
outb((data), 0x23); \
} while (0)
+static inline void serialize_cpu(void)
+{
+ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+}
+
static inline void __monitor(const void *eax, unsigned long ecx,
unsigned long edx)
{
diff --git a/include/asm-x86_64/types.h b/include/asm-x86_64/types.h
index 32bd142..c86c2e6 100644
--- a/include/asm-x86_64/types.h
+++ b/include/asm-x86_64/types.h
@@ -51,8 +51,6 @@
typedef u64 sector_t;
#define HAVE_SECTOR_T
-typedef unsigned short kmem_bufctl_t;
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
index 48f2927..1bb8b8a 100644
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -49,13 +49,6 @@
#define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
-/* this function will go away soon - use access_ok() instead */
-extern inline int __deprecated verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
-
/*
* The exception table consists of pairs of addresses: the first is the
* address of an instruction that is allowed to fault, and the second is
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
index d72bcb3..24f86f0 100644
--- a/include/asm-xtensa/atomic.h
+++ b/include/asm-xtensa/atomic.h
@@ -66,7 +66,7 @@
*
* Atomically adds @i to @v.
*/
-extern __inline__ void atomic_add(int i, atomic_t * v)
+static inline void atomic_add(int i, atomic_t * v)
{
unsigned int vval;
@@ -90,7 +90,7 @@
*
* Atomically subtracts @i from @v.
*/
-extern __inline__ void atomic_sub(int i, atomic_t *v)
+static inline void atomic_sub(int i, atomic_t *v)
{
unsigned int vval;
@@ -111,7 +111,7 @@
* We use atomic_{add|sub}_return to define other functions.
*/
-extern __inline__ int atomic_add_return(int i, atomic_t * v)
+static inline int atomic_add_return(int i, atomic_t * v)
{
unsigned int vval;
@@ -130,7 +130,7 @@
return vval;
}
-extern __inline__ int atomic_sub_return(int i, atomic_t * v)
+static inline int atomic_sub_return(int i, atomic_t * v)
{
unsigned int vval;
@@ -224,7 +224,7 @@
#define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0)
-extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
unsigned int all_f = -1;
unsigned int vval;
@@ -243,7 +243,7 @@
);
}
-extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
{
unsigned int vval;
diff --git a/include/asm-xtensa/auxvec.h b/include/asm-xtensa/auxvec.h
new file mode 100644
index 0000000..257dec7
--- /dev/null
+++ b/include/asm-xtensa/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __XTENSA_AUXVEC_H
+#define __XTENSA_AUXVEC_H
+
+#endif
diff --git a/include/asm-xtensa/checksum.h b/include/asm-xtensa/checksum.h
index 1a00fad..81a797a 100644
--- a/include/asm-xtensa/checksum.h
+++ b/include/asm-xtensa/checksum.h
@@ -47,14 +47,14 @@
* If you use these functions directly please don't forget the
* verify_area().
*/
-extern __inline__
+static inline
unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
int len, int sum)
{
return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
}
-extern __inline__
+static inline
unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
int len, int sum, int *err_ptr)
{
diff --git a/include/asm-xtensa/delay.h b/include/asm-xtensa/delay.h
index 0a123d5..1bc601e 100644
--- a/include/asm-xtensa/delay.h
+++ b/include/asm-xtensa/delay.h
@@ -18,7 +18,7 @@
extern unsigned long loops_per_jiffy;
-extern __inline__ void __delay(unsigned long loops)
+static inline void __delay(unsigned long loops)
{
/* 2 cycles per loop. */
__asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
diff --git a/include/asm-xtensa/fcntl.h b/include/asm-xtensa/fcntl.h
index 48876bb..ec066ae 100644
--- a/include/asm-xtensa/fcntl.h
+++ b/include/asm-xtensa/fcntl.h
@@ -14,31 +14,17 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_ACCMODE 0x0003
-#define O_RDONLY 0x0000
-#define O_WRONLY 0x0001
-#define O_RDWR 0x0002
#define O_APPEND 0x0008
#define O_SYNC 0x0010
#define O_NONBLOCK 0x0080
#define O_CREAT 0x0100 /* not fcntl */
-#define O_TRUNC 0x0200 /* not fcntl */
#define O_EXCL 0x0400 /* not fcntl */
#define O_NOCTTY 0x0800 /* not fcntl */
#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
#define O_LARGEFILE 0x2000 /* allow large file opens - currently ignored */
#define O_DIRECT 0x8000 /* direct disk access hint - currently ignored*/
-#define O_DIRECTORY 0x10000 /* must be a directory */
-#define O_NOFOLLOW 0x20000 /* don't follow links */
#define O_NOATIME 0x100000
-#define O_NDELAY O_NONBLOCK
-
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get close_on_exec */
-#define F_SETFD 2 /* set/clear close_on_exec */
-#define F_GETFL 3 /* get file->f_flags */
-#define F_SETFL 4 /* set file->f_flags */
#define F_GETLK 14
#define F_GETLK64 15
#define F_SETLK 6
@@ -48,35 +34,6 @@
#define F_SETOWN 24 /* for sockets. */
#define F_GETOWN 23 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* for posix fcntl() and lockf() */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* for old implementation of bsd flock () */
-#define F_EXLCK 4 /* or 3 */
-#define F_SHLCK 8 /* or 4 */
-
-/* for leases */
-#define F_INPROGRESS 16
-
-/* operations for bsd flock(), also used by the kernel implementation */
-#define LOCK_SH 1 /* shared lock */
-#define LOCK_EX 2 /* exclusive lock */
-#define LOCK_NB 4 /* or'd with one of the above to prevent
- blocking */
-#define LOCK_UN 8 /* remove lock */
-
-#define LOCK_MAND 32 /* This is a mandatory flock ... */
-#define LOCK_READ 64 /* which allows concurrent read operations */
-#define LOCK_WRITE 128 /* which allows concurrent write operations */
-#define LOCK_RW 192 /* which allows concurrent read & write ops */
typedef struct flock {
short l_type;
@@ -96,6 +53,9 @@
pid_t l_pid;
};
-#define F_LINUX_SPECIFIC_BASE 1024
+#define HAVE_ARCH_STRUCT_FLOCK
+#define HAVE_ARCH_STRUCT_FLOCK64
+
+#include <asm-generic/fcntl.h>
#endif /* _XTENSA_FCNTL_H */
diff --git a/include/asm-xtensa/hdreg.h b/include/asm-xtensa/hdreg.h
deleted file mode 100644
index 64b8060..0000000
--- a/include/asm-xtensa/hdreg.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * include/asm-xtensa/hdreg.h
- *
- * 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) 2002 - 2005 Tensilica Inc.
- * Copyright (C) 1994-1996 Linus Torvalds & authors
- */
-
-#ifndef _XTENSA_HDREG_H
-#define _XTENSA_HDREG_H
-
-typedef unsigned int ide_ioreg_t;
-
-#endif
diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h
index 2c471c4..c5c1398 100644
--- a/include/asm-xtensa/io.h
+++ b/include/asm-xtensa/io.h
@@ -41,12 +41,12 @@
* These are trivial on the 1:1 Linux/Xtensa mapping
*/
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
{
return PHYSADDR((unsigned long)address);
}
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
{
return (void*) CACHED_ADDR(address);
}
@@ -55,12 +55,12 @@
* IO bus memory addresses are also 1:1 with the physical address
*/
-extern inline unsigned long virt_to_bus(volatile void * address)
+static inline unsigned long virt_to_bus(volatile void * address)
{
return PHYSADDR((unsigned long)address);
}
-extern inline void * bus_to_virt (unsigned long address)
+static inline void * bus_to_virt (unsigned long address)
{
return (void *) CACHED_ADDR(address);
}
@@ -69,17 +69,17 @@
* Change "struct page" to physical address.
*/
-extern inline void *ioremap(unsigned long offset, unsigned long size)
+static inline void *ioremap(unsigned long offset, unsigned long size)
{
return (void *) CACHED_ADDR_IO(offset);
}
-extern inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
{
return (void *) BYPASS_ADDR_IO(offset);
}
-extern inline void iounmap(void *addr)
+static inline void iounmap(void *addr)
{
}
diff --git a/include/asm-xtensa/mmu_context.h b/include/asm-xtensa/mmu_context.h
index 1b08015..364a7b0 100644
--- a/include/asm-xtensa/mmu_context.h
+++ b/include/asm-xtensa/mmu_context.h
@@ -199,13 +199,13 @@
#define ASID_FIRST_VERSION \
((unsigned long)(~ASID_VERSION_MASK) + 1 + ASID_FIRST_NONRESERVED)
-extern inline void set_rasid_register (unsigned long val)
+static inline void set_rasid_register (unsigned long val)
{
__asm__ __volatile__ (" wsr %0, "__stringify(RASID)"\n\t"
" isync\n" : : "a" (val));
}
-extern inline unsigned long get_rasid_register (void)
+static inline unsigned long get_rasid_register (void)
{
unsigned long tmp;
__asm__ __volatile__ (" rsr %0, "__stringify(RASID)"\n\t" : "=a" (tmp));
@@ -215,7 +215,7 @@
#if ((XCHAL_MMU_ASID_INVALID == 0) && (XCHAL_MMU_ASID_KERNEL == 1))
-extern inline void
+static inline void
get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
{
extern void flush_tlb_all(void);
@@ -234,7 +234,7 @@
/* XCHAL_MMU_ASID_INVALID == 0 and XCHAL_MMU_ASID_KERNEL ==1 are
really the best, but if you insist... */
-extern inline int validate_asid (unsigned long asid)
+static inline int validate_asid (unsigned long asid)
{
switch (asid) {
case XCHAL_MMU_ASID_INVALID:
@@ -247,7 +247,7 @@
return 1; /* valid */
}
-extern inline void
+static inline void
get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
{
extern void flush_tlb_all(void);
@@ -274,14 +274,14 @@
* instance.
*/
-extern inline int
+static inline int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context = NO_CONTEXT;
return 0;
}
-extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
unsigned long asid = asid_cache;
@@ -301,7 +301,7 @@
* Destroy context related info for an mm_struct that is about
* to be put to rest.
*/
-extern inline void destroy_context(struct mm_struct *mm)
+static inline void destroy_context(struct mm_struct *mm)
{
/* Nothing to do. */
}
@@ -310,7 +310,7 @@
* After we have set current->mm to a new value, this activates
* the context for the new mm so we see the new mappings.
*/
-extern inline void
+static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
/* Unconditionally get a new ASID. */
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
index b495e5b..8ded36f 100644
--- a/include/asm-xtensa/page.h
+++ b/include/asm-xtensa/page.h
@@ -55,7 +55,7 @@
* Pure 2^n version of get_order
*/
-extern __inline__ int get_order(unsigned long size)
+static inline int get_order(unsigned long size)
{
int order;
#ifndef XCHAL_HAVE_NSU
diff --git a/include/asm-xtensa/page.h.n b/include/asm-xtensa/page.h.n
deleted file mode 100644
index 546cc66..0000000
--- a/include/asm-xtensa/page.h.n
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * linux/include/asm-xtensa/page.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version2 as
- * published by the Free Software Foundation.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_PAGE_H
-#define _XTENSA_PAGE_H
-
-#ifdef __KERNEL__
-
-#include <asm/processor.h>
-#include <linux/config.h>
-
-/*
- * PAGE_SHIFT determines the page size
- * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
- */
-#define PAGE_SHIFT XCHAL_MMU_MIN_PTE_PAGE_SIZE
-#define PAGE_SIZE (1 << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
-
-#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
-#define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR
-
-#ifdef __ASSEMBLY__
-
-#define __pgprot(x) (x)
-
-#else
-
-
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t; /* page table entry */
-typedef struct { unsigned long pmd; } pmd_t; /* PMD table entry */
-typedef struct { unsigned long pgd; } pgd_t; /* PGD table entry */
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-#define pte_val(x) ((x).pte)
-#define pmd_val(x) ((x).pmd)
-#define pgd_val(x) ((x).pgd)
-#define pgprot_val(x) ((x).pgprot)
-
-#define __pte(x) ((pte_t) { (x) } )
-#define __pmd(x) ((pmd_t) { (x) } )
-#define __pgd(x) ((pgd_t) { (x) } )
-#define __pgprot(x) ((pgprot_t) { (x) } )
-
-/*
- * Pure 2^n version of get_order
- */
-extern __inline__ int get_order(unsigned long size)
-{
- int order;
-#ifndef XCHAL_HAVE_NSU
- unsigned long x1, x2, x4, x8, x16;
-
- size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- x1 = size & 0xAAAAAAAA;
- x2 = size & 0xCCCCCCCC;
- x4 = size & 0xF0F0F0F0;
- x8 = size & 0xFF00FF00;
- x16 = size & 0xFFFF0000;
- order = x2 ? 2 : 0;
- order += (x16 != 0) * 16;
- order += (x8 != 0) * 8;
- order += (x4 != 0) * 4;
- order += (x1 != 0);
-
- return order;
-#else
- size = (size - 1) >> PAGE_SHIFT;
- asm ("nsau %0, %1" : "=r" (order) : "r" (size));
- return 32 - order;
-#endif
-}
-
-
-struct page;
-extern void clear_page(void *page);
-extern void copy_page(void *to, void *from);
-
-/*
- * If we have cache aliasing and writeback caches, we might have to do
- * some extra work
- */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
-void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
-void copy_user_page(void *to, void* from, unsigned long vaddr, struct page* page);
-#else
-# define clear_user_page(page,vaddr,pg) clear_page(page)
-# define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#endif
-
-
-/*
- * This handles the memory map. We handle pages at
- * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
- * These macros are for conversion of kernel address, not user
- * addresses.
- */
-
-#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
-#define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define pfn_valid(pfn) ((unsigned long)pfn < max_mapnr)
-#ifndef CONFIG_DISCONTIGMEM
-# define pfn_to_page(pfn) (mem_map + (pfn))
-# define page_to_pfn(page) ((unsigned long)((page) - mem_map))
-#else
-# error CONFIG_DISCONTIGMEM not supported
-#endif
-
-#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT)
-#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
-
-#define WANT_PAGE_VIRTUAL
-
-
-#endif /* __ASSEMBLY__ */
-
-#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#endif /* __KERNEL__ */
-#endif /* _XTENSA_PAGE_H */
diff --git a/include/asm-xtensa/pci.h b/include/asm-xtensa/pci.h
index 6817742..24eb7fc 100644
--- a/include/asm-xtensa/pci.h
+++ b/include/asm-xtensa/pci.h
@@ -22,12 +22,12 @@
extern struct pci_controller* pcibios_alloc_controller(void);
-extern inline void pcibios_set_master(struct pci_dev *dev)
+static inline void pcibios_set_master(struct pci_dev *dev)
{
/* No special bus mastering setup handling */
}
-extern inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq)
{
/* We don't do dynamic PCI IRQ allocation */
}
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index 0bb6416..883ebc2d 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -260,7 +260,7 @@
#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
}
@@ -278,14 +278,14 @@
#endif
}
-extern inline void
+static inline void
set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval)
{
update_pte(ptep, pteval);
}
-extern inline void
+static inline void
set_pmd(pmd_t *pmdp, pmd_t pmdval)
{
*pmdp = pmdval;
diff --git a/include/asm-xtensa/semaphore.h b/include/asm-xtensa/semaphore.h
index c8a7574..db740b8 100644
--- a/include/asm-xtensa/semaphore.h
+++ b/include/asm-xtensa/semaphore.h
@@ -47,7 +47,7 @@
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
-extern inline void sema_init (struct semaphore *sem, int val)
+static inline void sema_init (struct semaphore *sem, int val)
{
/*
* *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
@@ -79,7 +79,7 @@
extern spinlock_t semaphore_wake_lock;
-extern __inline__ void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
{
#if WAITQUEUE_DEBUG
CHECK_MAGIC(sem->__magic);
@@ -89,7 +89,7 @@
__down(sem);
}
-extern __inline__ int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
{
int ret = 0;
#if WAITQUEUE_DEBUG
@@ -101,7 +101,7 @@
return ret;
}
-extern __inline__ int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
{
int ret = 0;
#if WAITQUEUE_DEBUG
@@ -117,7 +117,7 @@
* Note! This is subtle. We jump to wake people up only if
* the semaphore was negative (== somebody was waiting on it).
*/
-extern __inline__ void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
{
#if WAITQUEUE_DEBUG
CHECK_MAGIC(sem->__magic);
diff --git a/include/asm-xtensa/string.h b/include/asm-xtensa/string.h
index 3f81b27..5fb8c27 100644
--- a/include/asm-xtensa/string.h
+++ b/include/asm-xtensa/string.h
@@ -16,7 +16,7 @@
#define _XTENSA_STRING_H
#define __HAVE_ARCH_STRCPY
-extern __inline__ char *strcpy(char *__dest, const char *__src)
+static inline char *strcpy(char *__dest, const char *__src)
{
register char *__xdest = __dest;
unsigned long __dummy;
@@ -35,7 +35,7 @@
}
#define __HAVE_ARCH_STRNCPY
-extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+static inline char *strncpy(char *__dest, const char *__src, size_t __n)
{
register char *__xdest = __dest;
unsigned long __dummy;
@@ -60,7 +60,7 @@
}
#define __HAVE_ARCH_STRCMP
-extern __inline__ int strcmp(const char *__cs, const char *__ct)
+static inline int strcmp(const char *__cs, const char *__ct)
{
register int __res;
unsigned long __dummy;
@@ -82,7 +82,7 @@
}
#define __HAVE_ARCH_STRNCMP
-extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+static inline int strncmp(const char *__cs, const char *__ct, size_t __n)
{
register int __res;
unsigned long __dummy;
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
index 690fe32..f093932 100644
--- a/include/asm-xtensa/system.h
+++ b/include/asm-xtensa/system.h
@@ -56,7 +56,7 @@
#define clear_cpenable() __clear_cpenable()
-extern __inline__ void __clear_cpenable(void)
+static inline void __clear_cpenable(void)
{
#if XCHAL_HAVE_CP
unsigned long i = 0;
@@ -64,7 +64,7 @@
#endif
}
-extern __inline__ void enable_coprocessor(int i)
+static inline void enable_coprocessor(int i)
{
#if XCHAL_HAVE_CP
int cp;
@@ -74,7 +74,7 @@
#endif
}
-extern __inline__ void disable_coprocessor(int i)
+static inline void disable_coprocessor(int i)
{
#if XCHAL_HAVE_CP
int cp;
@@ -123,7 +123,7 @@
* cmpxchg
*/
-extern __inline__ unsigned long
+static inline unsigned long
__cmpxchg_u32(volatile int *p, int old, int new)
{
__asm__ __volatile__("rsil a15, "__stringify(LOCKLEVEL)"\n\t"
@@ -173,7 +173,7 @@
* where no register reference will cause an overflow.
*/
-extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
{
unsigned long tmp;
__asm__ __volatile__("rsil a15, "__stringify(LOCKLEVEL)"\n\t"
diff --git a/include/asm-xtensa/tlbflush.h b/include/asm-xtensa/tlbflush.h
index 23bfe9d..43f6ec8 100644
--- a/include/asm-xtensa/tlbflush.h
+++ b/include/asm-xtensa/tlbflush.h
@@ -39,7 +39,7 @@
* page-table pages.
*/
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
unsigned long start, unsigned long end)
{
}
@@ -51,26 +51,26 @@
#define ITLB_PROBE_SUCCESS (1 << ITLB_WAYS_LOG2)
#define DTLB_PROBE_SUCCESS (1 << DTLB_WAYS_LOG2)
-extern inline unsigned long itlb_probe(unsigned long addr)
+static inline unsigned long itlb_probe(unsigned long addr)
{
unsigned long tmp;
__asm__ __volatile__("pitlb %0, %1\n\t" : "=a" (tmp) : "a" (addr));
return tmp;
}
-extern inline unsigned long dtlb_probe(unsigned long addr)
+static inline unsigned long dtlb_probe(unsigned long addr)
{
unsigned long tmp;
__asm__ __volatile__("pdtlb %0, %1\n\t" : "=a" (tmp) : "a" (addr));
return tmp;
}
-extern inline void invalidate_itlb_entry (unsigned long probe)
+static inline void invalidate_itlb_entry (unsigned long probe)
{
__asm__ __volatile__("iitlb %0; isync\n\t" : : "a" (probe));
}
-extern inline void invalidate_dtlb_entry (unsigned long probe)
+static inline void invalidate_dtlb_entry (unsigned long probe)
{
__asm__ __volatile__("idtlb %0; dsync\n\t" : : "a" (probe));
}
@@ -80,68 +80,68 @@
* caller must follow up with an 'isync', which can be relatively
* expensive on some Xtensa implementations.
*/
-extern inline void invalidate_itlb_entry_no_isync (unsigned entry)
+static inline void invalidate_itlb_entry_no_isync (unsigned entry)
{
/* Caller must follow up with 'isync'. */
__asm__ __volatile__ ("iitlb %0\n" : : "a" (entry) );
}
-extern inline void invalidate_dtlb_entry_no_isync (unsigned entry)
+static inline void invalidate_dtlb_entry_no_isync (unsigned entry)
{
/* Caller must follow up with 'isync'. */
__asm__ __volatile__ ("idtlb %0\n" : : "a" (entry) );
}
-extern inline void set_itlbcfg_register (unsigned long val)
+static inline void set_itlbcfg_register (unsigned long val)
{
__asm__ __volatile__("wsr %0, "__stringify(ITLBCFG)"\n\t" "isync\n\t"
: : "a" (val));
}
-extern inline void set_dtlbcfg_register (unsigned long val)
+static inline void set_dtlbcfg_register (unsigned long val)
{
__asm__ __volatile__("wsr %0, "__stringify(DTLBCFG)"; dsync\n\t"
: : "a" (val));
}
-extern inline void set_ptevaddr_register (unsigned long val)
+static inline void set_ptevaddr_register (unsigned long val)
{
__asm__ __volatile__(" wsr %0, "__stringify(PTEVADDR)"; isync\n"
: : "a" (val));
}
-extern inline unsigned long read_ptevaddr_register (void)
+static inline unsigned long read_ptevaddr_register (void)
{
unsigned long tmp;
__asm__ __volatile__("rsr %0, "__stringify(PTEVADDR)"\n\t" : "=a" (tmp));
return tmp;
}
-extern inline void write_dtlb_entry (pte_t entry, int way)
+static inline void write_dtlb_entry (pte_t entry, int way)
{
__asm__ __volatile__("wdtlb %1, %0; dsync\n\t"
: : "r" (way), "r" (entry) );
}
-extern inline void write_itlb_entry (pte_t entry, int way)
+static inline void write_itlb_entry (pte_t entry, int way)
{
__asm__ __volatile__("witlb %1, %0; isync\n\t"
: : "r" (way), "r" (entry) );
}
-extern inline void invalidate_page_directory (void)
+static inline void invalidate_page_directory (void)
{
invalidate_dtlb_entry (DTLB_WAY_PGTABLE);
}
-extern inline void invalidate_itlb_mapping (unsigned address)
+static inline void invalidate_itlb_mapping (unsigned address)
{
unsigned long tlb_entry;
while ((tlb_entry = itlb_probe (address)) & ITLB_PROBE_SUCCESS)
invalidate_itlb_entry (tlb_entry);
}
-extern inline void invalidate_dtlb_mapping (unsigned address)
+static inline void invalidate_dtlb_mapping (unsigned address)
{
unsigned long tlb_entry;
while ((tlb_entry = dtlb_probe (address)) & DTLB_PROBE_SUCCESS)
@@ -165,28 +165,28 @@
* as[07..00] contain the asid
*/
-extern inline unsigned long read_dtlb_virtual (int way)
+static inline unsigned long read_dtlb_virtual (int way)
{
unsigned long tmp;
__asm__ __volatile__("rdtlb0 %0, %1\n\t" : "=a" (tmp), "+a" (way));
return tmp;
}
-extern inline unsigned long read_dtlb_translation (int way)
+static inline unsigned long read_dtlb_translation (int way)
{
unsigned long tmp;
__asm__ __volatile__("rdtlb1 %0, %1\n\t" : "=a" (tmp), "+a" (way));
return tmp;
}
-extern inline unsigned long read_itlb_virtual (int way)
+static inline unsigned long read_itlb_virtual (int way)
{
unsigned long tmp;
__asm__ __volatile__("ritlb0 %0, %1\n\t" : "=a" (tmp), "+a" (way));
return tmp;
}
-extern inline unsigned long read_itlb_translation (int way)
+static inline unsigned long read_itlb_translation (int way)
{
unsigned long tmp;
__asm__ __volatile__("ritlb1 %0, %1\n\t" : "=a" (tmp), "+a" (way));
diff --git a/include/asm-xtensa/types.h b/include/asm-xtensa/types.h
index ebac004..9d99a8e 100644
--- a/include/asm-xtensa/types.h
+++ b/include/asm-xtensa/types.h
@@ -58,8 +58,6 @@
typedef u32 dma_addr_t;
-typedef unsigned int kmem_bufctl_t;
-
#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h
index 35576b2..fc268ac 100644
--- a/include/asm-xtensa/uaccess.h
+++ b/include/asm-xtensa/uaccess.h
@@ -211,7 +211,7 @@
#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
{
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
@@ -464,7 +464,7 @@
* success.
*/
-extern inline unsigned long
+static inline unsigned long
__xtensa_clear_user(void *addr, unsigned long size)
{
if ( ! memset(addr, 0, size) )
@@ -472,7 +472,7 @@
return 0;
}
-extern inline unsigned long
+static inline unsigned long
clear_user(void *addr, unsigned long size)
{
if (access_ok(VERIFY_WRITE, addr, size))
@@ -486,7 +486,7 @@
extern long __strncpy_user(char *, const char *, long);
#define __strncpy_from_user __strncpy_user
-extern inline long
+static inline long
strncpy_from_user(char *dst, const char *src, long count)
{
if (access_ok(VERIFY_READ, src, 1))
@@ -502,7 +502,7 @@
*/
extern long __strnlen_user(const char *, long);
-extern inline long strnlen_user(const char *str, long len)
+static inline long strnlen_user(const char *str, long len)
{
unsigned long top = __kernel_ok ? ~0UL : TASK_SIZE - 1;
diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h
index af1010b..93bfb0b 100644
--- a/include/linux/attribute_container.h
+++ b/include/linux/attribute_container.h
@@ -11,10 +11,12 @@
#include <linux/device.h>
#include <linux/list.h>
+#include <linux/klist.h>
+#include <linux/spinlock.h>
struct attribute_container {
struct list_head node;
- struct list_head containers;
+ struct klist containers;
struct class *class;
struct class_device_attribute **attrs;
int (*match)(struct attribute_container *, struct device *);
@@ -62,12 +64,8 @@
struct class_device *classdev);
void attribute_container_remove_attrs(struct class_device *classdev);
void attribute_container_class_device_del(struct class_device *classdev);
-
-
-
-
-
-
+struct attribute_container *attribute_container_classdev_to_container(struct class_device *);
+struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *);
struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev);
#endif
diff --git a/include/linux/auxvec.h b/include/linux/auxvec.h
new file mode 100644
index 0000000..9a7b374
--- /dev/null
+++ b/include/linux/auxvec.h
@@ -0,0 +1,31 @@
+#ifndef _LINUX_AUXVEC_H
+#define _LINUX_AUXVEC_H
+
+#include <asm/auxvec.h>
+
+/* Symbolic values for the entries in the auxiliary table
+ put on the initial stack */
+#define AT_NULL 0 /* end of vector */
+#define AT_IGNORE 1 /* entry should be ignored */
+#define AT_EXECFD 2 /* file descriptor of program */
+#define AT_PHDR 3 /* program headers for program */
+#define AT_PHENT 4 /* size of program header entry */
+#define AT_PHNUM 5 /* number of program headers */
+#define AT_PAGESZ 6 /* system page size */
+#define AT_BASE 7 /* base address of interpreter */
+#define AT_FLAGS 8 /* flags */
+#define AT_ENTRY 9 /* entry point of program */
+#define AT_NOTELF 10 /* program is not ELF */
+#define AT_UID 11 /* real uid */
+#define AT_EUID 12 /* effective uid */
+#define AT_GID 13 /* real gid */
+#define AT_EGID 14 /* effective gid */
+#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
+#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17 /* frequency at which times() increments */
+
+#define AT_SECURE 23 /* secure mode boolean */
+
+#define AT_VECTOR_SIZE 42 /* Size of auxiliary table. */
+
+#endif /* _LINUX_AUXVEC_H */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 36ef29f..cdaf03a 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -111,7 +111,6 @@
void *bi_private;
bio_destructor_t *bi_destructor; /* destructor */
- struct bio_set *bi_set; /* memory pools set */
};
/*
@@ -280,6 +279,7 @@
extern struct bio *bio_alloc(unsigned int __nocast, int);
extern struct bio *bio_alloc_bioset(unsigned int __nocast, int, struct bio_set *);
extern void bio_put(struct bio *);
+extern void bio_free(struct bio *, struct bio_set *);
extern void bio_endio(struct bio *, unsigned int, int);
struct request_queue;
@@ -295,7 +295,13 @@
extern int bio_get_nr_vecs(struct block_device *);
extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
unsigned long, unsigned int, int);
+struct sg_iovec;
+extern struct bio *bio_map_user_iov(struct request_queue *,
+ struct block_device *,
+ struct sg_iovec *, int, int);
extern void bio_unmap_user(struct bio *);
+extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
+ unsigned int);
extern void bio_set_pages_dirty(struct bio *bio);
extern void bio_check_pages_dirty(struct bio *bio);
extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 19bd8e7..aefa26f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -563,10 +563,12 @@
extern void __blk_stop_queue(request_queue_t *q);
extern void blk_run_queue(request_queue_t *);
extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
-extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int);
-extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int);
-extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
-
+extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int);
+extern int blk_rq_unmap_user(struct bio *, unsigned int);
+extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, unsigned int);
+extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int);
+extern int blk_execute_rq(request_queue_t *, struct gendisk *,
+ struct request *, int);
static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
{
return bdev->bd_disk->queue;
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 8d139f4..6b46189 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -233,6 +233,7 @@
/* Allow enabling/disabling tagged queuing on SCSI controllers and sending
arbitrary SCSI commands */
/* Allow setting encryption key on loopback filesystem */
+/* Allow setting zone reclaim policy */
#define CAP_SYS_ADMIN 21
diff --git a/include/linux/compat.h b/include/linux/compat.h
index b58b7d6..f9ca534 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -18,6 +18,9 @@
#define compat_jiffies_to_clock_t(x) \
(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
+typedef __compat_uid32_t compat_uid_t;
+typedef __compat_gid32_t compat_gid_t;
+
struct rusage;
struct compat_itimerspec {
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index e8904c0..86980c6 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -8,7 +8,7 @@
* Basic handling of the devices is done in drivers/base/cpu.c
* and system devices are handled in drivers/base/sys.c.
*
- * CPUs are exported via driverfs in the class/cpu/devices/
+ * CPUs are exported via sysfs in the class/cpu/devices/
* directory.
*
* Per-cpu interfaces can be implemented using a struct device_interface.
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 3438233..24062a1 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -23,7 +23,8 @@
void cpuset_update_current_mems_allowed(void);
void cpuset_restrict_to_mems_allowed(unsigned long *nodes);
int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
-int cpuset_zone_allowed(struct zone *z);
+extern int cpuset_zone_allowed(struct zone *z, unsigned int __nocast gfp_mask);
+extern int cpuset_excl_nodes_overlap(const struct task_struct *p);
extern struct file_operations proc_cpuset_operations;
extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
@@ -48,7 +49,13 @@
return 1;
}
-static inline int cpuset_zone_allowed(struct zone *z)
+static inline int cpuset_zone_allowed(struct zone *z,
+ unsigned int __nocast gfp_mask)
+{
+ return 1;
+}
+
+static inline int cpuset_excl_nodes_overlap(const struct task_struct *p)
{
return 1;
}
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 5e2bcc6..3c89df6 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -45,6 +45,7 @@
#define CRYPTO_TFM_MODE_CTR 0x00000008
#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100
+#define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200
#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000
#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000
#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 50be290..ab04b4f 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -88,8 +88,9 @@
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
- * so they all fit in a 16-byte range, with 16-byte alignment.
+ * so they all fit in a cache line.
*/
+ struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
@@ -103,7 +104,6 @@
void *d_fsdata; /* fs-specific data */
struct rcu_head d_rcu;
struct dcookie_struct *d_cookie; /* cookie, if any */
- struct hlist_node d_hash; /* lookup hash list */
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 5e93e6d..c30175e 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -1,6 +1,8 @@
#ifndef __DMI_H__
#define __DMI_H__
+#include <linux/list.h>
+
enum dmi_field {
DMI_NONE,
DMI_BIOS_VENDOR,
@@ -16,6 +18,24 @@
DMI_STRING_MAX,
};
+enum dmi_device_type {
+ DMI_DEV_TYPE_ANY = 0,
+ DMI_DEV_TYPE_OTHER,
+ DMI_DEV_TYPE_UNKNOWN,
+ DMI_DEV_TYPE_VIDEO,
+ DMI_DEV_TYPE_SCSI,
+ DMI_DEV_TYPE_ETHERNET,
+ DMI_DEV_TYPE_TOKENRING,
+ DMI_DEV_TYPE_SOUND,
+ DMI_DEV_TYPE_IPMI = -1
+};
+
+struct dmi_header {
+ u8 type;
+ u8 length;
+ u16 handle;
+};
+
/*
* DMI callbacks for problem boards
*/
@@ -26,22 +46,32 @@
struct dmi_system_id {
int (*callback)(struct dmi_system_id *);
- char *ident;
+ const char *ident;
struct dmi_strmatch matches[4];
void *driver_data;
};
-#define DMI_MATCH(a,b) { a, b }
+#define DMI_MATCH(a, b) { a, b }
+
+struct dmi_device {
+ struct list_head list;
+ int type;
+ const char *name;
+ void *device_data; /* Type specific data */
+};
#if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
extern int dmi_check_system(struct dmi_system_id *list);
extern char * dmi_get_system_info(int field);
-
+extern struct dmi_device * dmi_find_device(int type, const char *name,
+ struct dmi_device *from);
#else
static inline int dmi_check_system(struct dmi_system_id *list) { return 0; }
static inline char * dmi_get_system_info(int field) { return NULL; }
+static struct dmi_device * dmi_find_device(int type, const char *name,
+ struct dmi_device *from) { return NULL; }
#endif
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 73781ec..c7c5dd3 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -91,11 +91,6 @@
#define EFI_PAGE_SHIFT 12
-/*
- * For current x86 implementations of EFI, there is
- * additional padding in the mem descriptors. This is not
- * the case in ia64. Need to have this fixed in the f/w.
- */
typedef struct {
u32 type;
u32 pad;
@@ -103,9 +98,6 @@
u64 virt_addr;
u64 num_pages;
u64 attribute;
-#if defined (__i386__)
- u64 pad1;
-#endif
} efi_memory_desc_t;
typedef int (*efi_freemem_callback_t) (unsigned long start, unsigned long end, void *arg);
@@ -240,10 +232,12 @@
} efi_system_table_t;
struct efi_memory_map {
- efi_memory_desc_t *phys_map;
- efi_memory_desc_t *map;
+ void *phys_map;
+ void *map;
+ void *map_end;
int nr_map;
unsigned long desc_version;
+ unsigned long desc_size;
};
/*
diff --git a/include/linux/elf.h b/include/linux/elf.h
index f5b3ba5..ff955db 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -2,6 +2,7 @@
#define _LINUX_ELF_H
#include <linux/types.h>
+#include <linux/auxvec.h>
#include <asm/elf.h>
#ifndef elf_read_implies_exec
@@ -158,29 +159,6 @@
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
-/* Symbolic values for the entries in the auxiliary table
- put on the initial stack */
-#define AT_NULL 0 /* end of vector */
-#define AT_IGNORE 1 /* entry should be ignored */
-#define AT_EXECFD 2 /* file descriptor of program */
-#define AT_PHDR 3 /* program headers for program */
-#define AT_PHENT 4 /* size of program header entry */
-#define AT_PHNUM 5 /* number of program headers */
-#define AT_PAGESZ 6 /* system page size */
-#define AT_BASE 7 /* base address of interpreter */
-#define AT_FLAGS 8 /* flags */
-#define AT_ENTRY 9 /* entry point of program */
-#define AT_NOTELF 10 /* program is not ELF */
-#define AT_UID 11 /* real uid */
-#define AT_EUID 12 /* effective uid */
-#define AT_GID 13 /* real gid */
-#define AT_EGID 14 /* effective gid */
-#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
-#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
-#define AT_CLKTCK 17 /* frequency at which times() increments */
-
-#define AT_SECURE 23 /* secure mode boolean */
-
typedef struct dynamic{
Elf32_Sword d_tag;
union{
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index ce8518e..4522c71 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -69,6 +69,12 @@
return ((addr[0] != 0xff) && (0x01 & addr[0]));
}
+static inline int is_broadcast_ether_addr(const u8 *addr)
+{
+ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) &&
+ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
+}
+
/**
* is_valid_ether_addr - Determine if the given Ethernet address is valid
* @addr: Pointer to a six-byte array containing the Ethernet address
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index a657130b..f7bd1c7 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -313,6 +313,9 @@
#define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */
#define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */
#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */
+#define EXT2_MOUNT_USRQUOTA 0x020000 /* user quota */
+#define EXT2_MOUNT_GRPQUOTA 0x040000 /* group quota */
+
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index c166628..c0272d7 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -373,6 +373,8 @@
#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */
#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */
#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */
+#define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
+#define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 886255b..2063c08 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -3,6 +3,9 @@
#include <linux/module.h>
#include <linux/types.h>
#define FIRMWARE_NAME_MAX 30
+#define FW_ACTION_NOHOTPLUG 0
+#define FW_ACTION_HOTPLUG 1
+
struct firmware {
size_t size;
u8 *data;
@@ -11,7 +14,7 @@
int request_firmware(const struct firmware **fw, const char *name,
struct device *device);
int request_firmware_nowait(
- struct module *module,
+ struct module *module, int hotplug,
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context));
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 67e6732..fd93ab7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -69,6 +69,7 @@
#define READ 0
#define WRITE 1
#define READA 2 /* read-ahead - don't block if no resources */
+#define SWRITE 3 /* for ll_rw_block() - wait for buffer lock */
#define SPECIAL 4 /* For non-blockdevice requests in request queue */
#define READ_SYNC (READ | (1 << BIO_RW_SYNC))
#define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC))
@@ -281,19 +282,9 @@
struct timespec ia_atime;
struct timespec ia_mtime;
struct timespec ia_ctime;
- unsigned int ia_attr_flags;
};
/*
- * This is the inode attributes flag definitions
- */
-#define ATTR_FLAG_SYNCRONOUS 1 /* Syncronous write */
-#define ATTR_FLAG_NOATIME 2 /* Don't update atime */
-#define ATTR_FLAG_APPEND 4 /* Append-only file */
-#define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */
-#define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */
-
-/*
* Includes for diskquotas.
*/
#include <linux/quota.h>
@@ -594,7 +585,6 @@
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;
- size_t f_maxcount;
unsigned long f_version;
void *f_security;
@@ -1291,6 +1281,7 @@
/* fs/open.c */
extern int do_truncate(struct dentry *, loff_t start);
+extern long do_sys_open(const char __user *filename, int flags, int mode);
extern struct file *filp_open(const char *, int, int);
extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
extern int filp_close(struct file *, fl_owner_t id);
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 65d6cfd..10f96c3 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -4,14 +4,40 @@
/* Second argument to futex syscall */
-#define FUTEX_WAIT (0)
-#define FUTEX_WAKE (1)
-#define FUTEX_FD (2)
-#define FUTEX_REQUEUE (3)
-#define FUTEX_CMP_REQUEUE (4)
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_FD 2
+#define FUTEX_REQUEUE 3
+#define FUTEX_CMP_REQUEUE 4
+#define FUTEX_WAKE_OP 5
long do_futex(unsigned long uaddr, int op, int val,
unsigned long timeout, unsigned long uaddr2, int val2,
int val3);
+#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */
+#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */
+#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */
+#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */
+#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */
+
+#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */
+
+#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */
+#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */
+#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */
+#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */
+#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */
+#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */
+
+/* FUTEX_WAKE_OP will perform atomically
+ int oldval = *(int *)UADDR2;
+ *(int *)UADDR2 = oldval OP OPARG;
+ if (oldval CMP CMPARG)
+ wake UADDR2; */
+
+#define FUTEX_OP(op, oparg, cmp, cmparg) \
+ (((op & 0xf) << 28) | ((cmp & 0xf) << 24) \
+ | ((oparg & 0xfff) << 12) | (cmparg & 0xfff))
+
#endif
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 7c74001..4dc990f 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -40,6 +40,7 @@
#define __GFP_ZERO 0x8000u /* Return zeroed page on success */
#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */
#define __GFP_NORECLAIM 0x20000u /* No realy zone reclaim during allocation */
+#define __GFP_HARDWALL 0x40000u /* Enforce hardwall cpuset memory allocs */
#define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */
#define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
@@ -48,14 +49,15 @@
#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
- __GFP_NOMEMALLOC|__GFP_NORECLAIM)
+ __GFP_NOMEMALLOC|__GFP_NORECLAIM|__GFP_HARDWALL)
#define GFP_ATOMIC (__GFP_HIGH)
#define GFP_NOIO (__GFP_WAIT)
#define GFP_NOFS (__GFP_WAIT | __GFP_IO)
#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HIGHMEM)
+#define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
+#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \
+ __GFP_HIGHMEM)
/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
platforms, used as appropriate on others */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index f529d14..e670b0d 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -70,12 +70,6 @@
void hugetlb_prefault_arch_hook(struct mm_struct *mm);
#endif
-#ifndef ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
-#define hugetlb_clean_stale_pgtable(pte) BUG()
-#else
-void hugetlb_clean_stale_pgtable(pte_t *pte);
-#endif
-
#else /* !CONFIG_HUGETLB_PAGE */
static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
diff --git a/include/linux/hwmon-sysfs.h b/include/linux/hwmon-sysfs.h
index 1b5018a..7eb4004 100644
--- a/include/linux/hwmon-sysfs.h
+++ b/include/linux/hwmon-sysfs.h
@@ -33,4 +33,19 @@
.index = _index, \
}
+struct sensor_device_attribute_2 {
+ struct device_attribute dev_attr;
+ u8 index;
+ u8 nr;
+};
+#define to_sensor_dev_attr_2(_dev_attr) \
+ container_of(_dev_attr, struct sensor_device_attribute_2, dev_attr)
+
+#define SENSOR_DEVICE_ATTR_2(_name,_mode,_show,_store,_nr,_index) \
+struct sensor_device_attribute_2 sensor_dev_attr_##_name = { \
+ .dev_attr = __ATTR(_name,_mode,_show,_store), \
+ .index = _index, \
+ .nr = _nr, \
+}
+
#endif /* _LINUX_HWMON_SYSFS_H */
diff --git a/include/linux/hwmon-vid.h b/include/linux/hwmon-vid.h
new file mode 100644
index 0000000..cd4b7a0
--- /dev/null
+++ b/include/linux/hwmon-vid.h
@@ -0,0 +1,45 @@
+/*
+ hwmon-vid.h - VID/VRM/VRD voltage conversions
+
+ Originally part of lm_sensors
+ Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ With assistance from Trent Piepho <xyzzy@speakeasy.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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LINUX_HWMON_VID_H
+#define _LINUX_HWMON_VID_H
+
+int vid_from_reg(int val, int vrm);
+int vid_which_vrm(void);
+
+/* vrm is the VRM/VRD document version multiplied by 10.
+ val is in mV to avoid floating point in the kernel.
+ Returned value is the 4-, 5- or 6-bit VID code.
+ Note that only VRM 9.x is supported for now. */
+static inline int vid_to_reg(int val, int vrm)
+{
+ switch (vrm) {
+ case 91: /* VRM 9.1 */
+ case 90: /* VRM 9.0 */
+ return ((val >= 1100) && (val <= 1850) ?
+ ((18499 - val * 10) / 25 + 5) / 10 : -1);
+ default:
+ return -1;
+ }
+}
+
+#endif /* _LINUX_HWMON_VID_H */
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
new file mode 100644
index 0000000..0efd994
--- /dev/null
+++ b/include/linux/hwmon.h
@@ -0,0 +1,35 @@
+/*
+ hwmon.h - part of lm_sensors, Linux kernel modules for hardware monitoring
+
+ This file declares helper functions for the sysfs class "hwmon",
+ for use by sensors drivers.
+
+ Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.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.
+*/
+
+#ifndef _HWMON_H_
+#define _HWMON_H_
+
+#include <linux/device.h>
+
+struct class_device *hwmon_device_register(struct device *dev);
+
+void hwmon_device_unregister(struct class_device *cdev);
+
+/* Scale user input to sensible values */
+static inline int SENSORS_LIMIT(long value, long low, long high)
+{
+ if (value < low)
+ return low;
+ else if (value > high)
+ return high;
+ else
+ return value;
+}
+
+#endif
+
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 33f0825..44f3087 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -1,6 +1,6 @@
/* ------------------------------------------------------------------------- */
/* */
-/* i2c.h - definitions for the i2c-bus interface */
+/* i2c-id.h - identifier values for i2c drivers and adapters */
/* */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 1995-1999 Simon G. Vogl
@@ -24,16 +24,6 @@
#define LINUX_I2C_ID_H
/*
- * This file is part of the i2c-bus package and contains the identifier
- * values for drivers, adapters and other folk populating these serial
- * worlds.
- *
- * These will change often (i.e. additions) , therefore this has been
- * separated from the functional interface definitions of the i2c api.
- *
- */
-
-/*
* ---- Driver types -----------------------------------------------------
* device id name + number function description, i2c address(es)
*
@@ -170,151 +160,113 @@
/*
* ---- Adapter types ----------------------------------------------------
- *
- * First, we distinguish between several algorithms to access the hardware
- * interface types, as a PCF 8584 needs other care than a bit adapter.
- */
-
-#define I2C_ALGO_NONE 0x000000
-#define I2C_ALGO_BIT 0x010000 /* bit style adapters */
-#define I2C_ALGO_PCF 0x020000 /* PCF 8584 style adapters */
-#define I2C_ALGO_ATI 0x030000 /* ATI video card */
-#define I2C_ALGO_SMBUS 0x040000
-#define I2C_ALGO_ISA 0x050000 /* lm_sensors ISA pseudo-adapter */
-#define I2C_ALGO_SAA7146 0x060000 /* SAA 7146 video decoder bus */
-#define I2C_ALGO_ACB 0x070000 /* ACCESS.bus algorithm */
-#define I2C_ALGO_IIC 0x080000 /* ITE IIC bus */
-#define I2C_ALGO_SAA7134 0x090000
-#define I2C_ALGO_MPC824X 0x0a0000 /* Motorola 8240 / 8245 */
-#define I2C_ALGO_IPMI 0x0b0000 /* IPMI dummy adapter */
-#define I2C_ALGO_IPMB 0x0c0000 /* IPMB adapter */
-#define I2C_ALGO_MPC107 0x0d0000
-#define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */
-
-#define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */
-#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */
-#define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */
-#define I2C_ALGO_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */
-#define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */
-#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */
-
-#define I2C_ALGO_USB 0x170000 /* USB algorithm */
-#define I2C_ALGO_VIRT 0x180000 /* Virtual bus adapter */
-
-#define I2C_ALGO_MV64XXX 0x190000 /* Marvell mv64xxx i2c ctlr */
-#define I2C_ALGO_PCA 0x1a0000 /* PCA 9564 style adapters */
-#define I2C_ALGO_AU1550 0x1b0000 /* Au1550 PSC algorithm */
-
-#define I2C_ALGO_EXP 0x800000 /* experimental */
-
-#define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */
-#define I2C_ALGO_SHIFT 0x10 /* right shift to get index values */
-
-#define I2C_HW_ADAPS 0x10000 /* # adapter types */
-#define I2C_HW_MASK 0xffff
-
-
-/* hw specific modules that are defined per algorithm layer
*/
/* --- Bit algorithm adapters */
-#define I2C_HW_B_LP 0x00 /* Parallel port Philips style adapter */
-#define I2C_HW_B_LPC 0x01 /* Parallel port, over control reg. */
-#define I2C_HW_B_SER 0x02 /* Serial line interface */
-#define I2C_HW_B_ELV 0x03 /* ELV Card */
-#define I2C_HW_B_VELLE 0x04 /* Vellemann K8000 */
-#define I2C_HW_B_BT848 0x05 /* BT848 video boards */
-#define I2C_HW_B_WNV 0x06 /* Winnov Videums */
-#define I2C_HW_B_VIA 0x07 /* Via vt82c586b */
-#define I2C_HW_B_HYDRA 0x08 /* Apple Hydra Mac I/O */
-#define I2C_HW_B_G400 0x09 /* Matrox G400 */
-#define I2C_HW_B_I810 0x0a /* Intel I810 */
-#define I2C_HW_B_VOO 0x0b /* 3dfx Voodoo 3 / Banshee */
-#define I2C_HW_B_PPORT 0x0c /* Primitive parallel port adapter */
-#define I2C_HW_B_SAVG 0x0d /* Savage 4 */
-#define I2C_HW_B_SCX200 0x0e /* Nat'l Semi SCx200 I2C */
-#define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */
-#define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */
-#define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */
-#define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */
-#define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface (ARM) */
-#define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */
-#define I2C_HW_B_IXP2000 0x16 /* GPIO on IXP2000 systems */
-#define I2C_HW_B_IXP4XX 0x17 /* GPIO on IXP4XX systems */
-#define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */
-#define I2C_HW_B_ZR36067 0x19 /* Zoran-36057/36067 based boards */
-#define I2C_HW_B_PCILYNX 0x1a /* TI PCILynx I2C adapter */
-#define I2C_HW_B_CX2388x 0x1b /* connexant 2388x based tv cards */
+#define I2C_HW_B_LP 0x010000 /* Parallel port Philips style */
+#define I2C_HW_B_LPC 0x010001 /* Parallel port control reg. */
+#define I2C_HW_B_SER 0x010002 /* Serial line interface */
+#define I2C_HW_B_ELV 0x010003 /* ELV Card */
+#define I2C_HW_B_VELLE 0x010004 /* Vellemann K8000 */
+#define I2C_HW_B_BT848 0x010005 /* BT848 video boards */
+#define I2C_HW_B_WNV 0x010006 /* Winnov Videums */
+#define I2C_HW_B_VIA 0x010007 /* Via vt82c586b */
+#define I2C_HW_B_HYDRA 0x010008 /* Apple Hydra Mac I/O */
+#define I2C_HW_B_G400 0x010009 /* Matrox G400 */
+#define I2C_HW_B_I810 0x01000a /* Intel I810 */
+#define I2C_HW_B_VOO 0x01000b /* 3dfx Voodoo 3 / Banshee */
+#define I2C_HW_B_PPORT 0x01000c /* Primitive parallel port adapter */
+#define I2C_HW_B_SAVG 0x01000d /* Savage 4 */
+#define I2C_HW_B_SCX200 0x01000e /* Nat'l Semi SCx200 I2C */
+#define I2C_HW_B_RIVA 0x010010 /* Riva based graphics cards */
+#define I2C_HW_B_IOC 0x010011 /* IOC bit-wiggling */
+#define I2C_HW_B_TSUNA 0x010012 /* DEC Tsunami chipset */
+#define I2C_HW_B_FRODO 0x010013 /* 2d3D SA-1110 Development Board */
+#define I2C_HW_B_OMAHA 0x010014 /* Omaha I2C interface (ARM) */
+#define I2C_HW_B_GUIDE 0x010015 /* Guide bit-basher */
+#define I2C_HW_B_IXP2000 0x010016 /* GPIO on IXP2000 systems */
+#define I2C_HW_B_IXP4XX 0x010017 /* GPIO on IXP4XX systems */
+#define I2C_HW_B_S3VIA 0x010018 /* S3Via ProSavage adapter */
+#define I2C_HW_B_ZR36067 0x010019 /* Zoran-36057/36067 based boards */
+#define I2C_HW_B_PCILYNX 0x01001a /* TI PCILynx I2C adapter */
+#define I2C_HW_B_CX2388x 0x01001b /* connexant 2388x based tv cards */
+#define I2C_HW_B_NVIDIA 0x01001c /* nvidia framebuffer driver */
+#define I2C_HW_B_SAVAGE 0x01001d /* savage framebuffer driver */
+#define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */
/* --- PCF 8584 based algorithms */
-#define I2C_HW_P_LP 0x00 /* Parallel port interface */
-#define I2C_HW_P_ISA 0x01 /* generic ISA Bus inteface card */
-#define I2C_HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */
+#define I2C_HW_P_LP 0x020000 /* Parallel port interface */
+#define I2C_HW_P_ISA 0x020001 /* generic ISA Bus inteface card */
+#define I2C_HW_P_ELEK 0x020002 /* Elektor ISA Bus inteface card */
/* --- PCA 9564 based algorithms */
-#define I2C_HW_A_ISA 0x00 /* generic ISA Bus interface card */
+#define I2C_HW_A_ISA 0x1a0000 /* generic ISA Bus interface card */
/* --- ACPI Embedded controller algorithms */
-#define I2C_HW_ACPI_EC 0x00
+#define I2C_HW_ACPI_EC 0x1f0000
/* --- MPC824x PowerPC adapters */
-#define I2C_HW_MPC824X 0x00 /* Motorola 8240 / 8245 */
+#define I2C_HW_MPC824X 0x100001 /* Motorola 8240 / 8245 */
/* --- MPC8xx PowerPC adapters */
-#define I2C_HW_MPC8XX_EPON 0x00 /* Eponymous MPC8xx I2C adapter */
+#define I2C_HW_MPC8XX_EPON 0x110000 /* Eponymous MPC8xx I2C adapter */
/* --- ITE based algorithms */
-#define I2C_HW_I_IIC 0x00 /* controller on the ITE */
+#define I2C_HW_I_IIC 0x080000 /* controller on the ITE */
/* --- PowerPC on-chip adapters */
-#define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */
+#define I2C_HW_OCP 0x120000 /* IBM on-chip I2C adapter */
/* --- Broadcom SiByte adapters */
-#define I2C_HW_SIBYTE 0x00
+#define I2C_HW_SIBYTE 0x150000
/* --- SGI adapters */
-#define I2C_HW_SGI_VINO 0x00
-#define I2C_HW_SGI_MACE 0x01
+#define I2C_HW_SGI_VINO 0x160000
+#define I2C_HW_SGI_MACE 0x160001
/* --- XSCALE on-chip adapters */
-#define I2C_HW_IOP3XX 0x00
+#define I2C_HW_IOP3XX 0x140000
/* --- Au1550 PSC adapters adapters */
-#define I2C_HW_AU1550_PSC 0x00
+#define I2C_HW_AU1550_PSC 0x1b0000
/* --- SMBus only adapters */
-#define I2C_HW_SMBUS_PIIX4 0x00
-#define I2C_HW_SMBUS_ALI15X3 0x01
-#define I2C_HW_SMBUS_VIA2 0x02
-#define I2C_HW_SMBUS_VOODOO3 0x03
-#define I2C_HW_SMBUS_I801 0x04
-#define I2C_HW_SMBUS_AMD756 0x05
-#define I2C_HW_SMBUS_SIS5595 0x06
-#define I2C_HW_SMBUS_ALI1535 0x07
-#define I2C_HW_SMBUS_SIS630 0x08
-#define I2C_HW_SMBUS_SIS96X 0x09
-#define I2C_HW_SMBUS_AMD8111 0x0a
-#define I2C_HW_SMBUS_SCX200 0x0b
-#define I2C_HW_SMBUS_NFORCE2 0x0c
-#define I2C_HW_SMBUS_W9968CF 0x0d
-#define I2C_HW_SMBUS_OV511 0x0e /* OV511(+) USB 1.1 webcam ICs */
-#define I2C_HW_SMBUS_OV518 0x0f /* OV518(+) USB 1.1 webcam ICs */
-#define I2C_HW_SMBUS_OV519 0x10 /* OV519 USB 1.1 webcam IC */
-#define I2C_HW_SMBUS_OVFX2 0x11 /* Cypress/OmniVision FX2 webcam */
+#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
+#define I2C_HW_SMBUS_ALI1535 0x040007
+#define I2C_HW_SMBUS_SIS630 0x040008
+#define I2C_HW_SMBUS_SIS96X 0x040009
+#define I2C_HW_SMBUS_AMD8111 0x04000a
+#define I2C_HW_SMBUS_SCX200 0x04000b
+#define I2C_HW_SMBUS_NFORCE2 0x04000c
+#define I2C_HW_SMBUS_W9968CF 0x04000d
+#define I2C_HW_SMBUS_OV511 0x04000e /* OV511(+) USB 1.1 webcam ICs */
+#define I2C_HW_SMBUS_OV518 0x04000f /* OV518(+) USB 1.1 webcam ICs */
+#define I2C_HW_SMBUS_OV519 0x040010 /* OV519 USB 1.1 webcam IC */
+#define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */
/* --- ISA pseudo-adapter */
-#define I2C_HW_ISA 0x00
+#define I2C_HW_ISA 0x050000
/* --- IPMI pseudo-adapter */
-#define I2C_HW_IPMI 0x00
+#define I2C_HW_IPMI 0x0b0000
/* --- IPMB adapter */
-#define I2C_HW_IPMB 0x00
+#define I2C_HW_IPMB 0x0c0000
/* --- MCP107 adapter */
-#define I2C_HW_MPC107 0x00
+#define I2C_HW_MPC107 0x0d0000
/* --- Marvell mv64xxx i2c adapter */
-#define I2C_HW_MV64XXX 0x00
+#define I2C_HW_MV64XXX 0x190000
+
+/* --- Miscellaneous adapters */
+#define I2C_HW_SAA7146 0x060000 /* SAA7146 video decoder bus */
+#define I2C_HW_SAA7134 0x090000 /* SAA7134 video decoder bus */
#endif /* LINUX_I2C_ID_H */
diff --git a/include/linux/i2c-isa.h b/include/linux/i2c-isa.h
new file mode 100644
index 0000000..67e3598
--- /dev/null
+++ b/include/linux/i2c-isa.h
@@ -0,0 +1,36 @@
+/*
+ * i2c-isa.h - definitions for the i2c-isa pseudo-i2c-adapter interface
+ *
+ * Copyright (C) 2005 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_I2C_ISA_H
+#define _LINUX_I2C_ISA_H
+
+#include <linux/i2c.h>
+
+extern int i2c_isa_add_driver(struct i2c_driver *driver);
+extern int i2c_isa_del_driver(struct i2c_driver *driver);
+
+/* Detect whether we are on the isa bus. This is only useful to hybrid
+ (i2c+isa) drivers. */
+#define i2c_is_isa_adapter(adapptr) \
+ ((adapptr)->id == I2C_HW_ISA)
+#define i2c_is_isa_client(clientptr) \
+ i2c_is_isa_adapter((clientptr)->adapter)
+
+#endif /* _LINUX_I2C_ISA_H */
diff --git a/include/linux/i2c-sensor.h b/include/linux/i2c-sensor.h
deleted file mode 100644
index 21b6252..0000000
--- a/include/linux/i2c-sensor.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- i2c-sensor.h - Part of the i2c package
- was originally sensors.h - Part of lm_sensors, Linux kernel modules
- for hardware monitoring
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _LINUX_I2C_SENSOR_H
-#define _LINUX_I2C_SENSOR_H
-
-/* A structure containing detect information.
- Force variables overrule all other variables; they force a detection on
- that place. If a specific chip is given, the module blindly assumes this
- chip type is present; if a general force (kind == 0) is given, the module
- will still try to figure out what type of chip is present. This is useful
- if for some reasons the detect for SMBus or ISA address space filled
- fails.
- probe: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
- A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the address.
- kind: The kind of chip. 0 equals any chip.
-*/
-struct i2c_force_data {
- unsigned short *force;
- unsigned short kind;
-};
-
-/* A structure containing the detect information.
- normal_i2c: filled in by the module writer. Terminated by I2C_CLIENT_ISA_END.
- A list of I2C addresses which should normally be examined.
- normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
- A list of ISA addresses which should normally be examined.
- probe: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
- A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the address. These
- addresses are also probed, as if they were in the 'normal' list.
- ignore: insmod parameter. Initialize this list with I2C_CLIENT_ISA_END values.
- A list of pairs. The first value is a bus number (ANY_I2C_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the I2C address. These
- addresses are never probed. This parameter overrules 'normal' and
- 'probe', but not the 'force' lists.
- force_data: insmod parameters. A list, ending with an element of which
- the force field is NULL.
-*/
-struct i2c_address_data {
- unsigned short *normal_i2c;
- unsigned int *normal_isa;
- unsigned short *probe;
- unsigned short *ignore;
- struct i2c_force_data *forces;
-};
-
-#define SENSORS_MODULE_PARM_FORCE(name) \
- I2C_CLIENT_MODULE_PARM(force_ ## name, \
- "List of adapter,address pairs which are unquestionably" \
- " assumed to contain a `" # name "' chip")
-
-
-/* This defines several insmod variables, and the addr_data structure */
-#define SENSORS_INSMOD \
- I2C_CLIENT_MODULE_PARM(probe, \
- "List of adapter,address pairs to scan additionally"); \
- I2C_CLIENT_MODULE_PARM(ignore, \
- "List of adapter,address pairs not to scan"); \
- static struct i2c_address_data addr_data = { \
- .normal_i2c = normal_i2c, \
- .normal_isa = normal_isa, \
- .probe = probe, \
- .ignore = ignore, \
- .forces = forces, \
- }
-
-/* The following functions create an enum with the chip names as elements.
- The first element of the enum is any_chip. These are the only macros
- a module will want to use. */
-
-#define SENSORS_INSMOD_0 \
- enum chips { any_chip }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- static struct i2c_force_data forces[] = {{force,any_chip},{NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_1(chip1) \
- enum chips { any_chip, chip1 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- static struct i2c_force_data forces[] = {{force,any_chip},\
- {force_ ## chip1,chip1}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_2(chip1,chip2) \
- enum chips { any_chip, chip1, chip2 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_3(chip1,chip2,chip3) \
- enum chips { any_chip, chip1, chip2, chip3 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- SENSORS_MODULE_PARM_FORCE(chip3); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {force_ ## chip3,chip3}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_4(chip1,chip2,chip3,chip4) \
- enum chips { any_chip, chip1, chip2, chip3, chip4 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- SENSORS_MODULE_PARM_FORCE(chip3); \
- SENSORS_MODULE_PARM_FORCE(chip4); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {force_ ## chip3,chip3}, \
- {force_ ## chip4,chip4}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_5(chip1,chip2,chip3,chip4,chip5) \
- enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- SENSORS_MODULE_PARM_FORCE(chip3); \
- SENSORS_MODULE_PARM_FORCE(chip4); \
- SENSORS_MODULE_PARM_FORCE(chip5); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {force_ ## chip3,chip3}, \
- {force_ ## chip4,chip4}, \
- {force_ ## chip5,chip5}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_6(chip1,chip2,chip3,chip4,chip5,chip6) \
- enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- SENSORS_MODULE_PARM_FORCE(chip3); \
- SENSORS_MODULE_PARM_FORCE(chip4); \
- SENSORS_MODULE_PARM_FORCE(chip5); \
- SENSORS_MODULE_PARM_FORCE(chip6); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {force_ ## chip3,chip3}, \
- {force_ ## chip4,chip4}, \
- {force_ ## chip5,chip5}, \
- {force_ ## chip6,chip6}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_7(chip1,chip2,chip3,chip4,chip5,chip6,chip7) \
- enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- SENSORS_MODULE_PARM_FORCE(chip3); \
- SENSORS_MODULE_PARM_FORCE(chip4); \
- SENSORS_MODULE_PARM_FORCE(chip5); \
- SENSORS_MODULE_PARM_FORCE(chip6); \
- SENSORS_MODULE_PARM_FORCE(chip7); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {force_ ## chip3,chip3}, \
- {force_ ## chip4,chip4}, \
- {force_ ## chip5,chip5}, \
- {force_ ## chip6,chip6}, \
- {force_ ## chip7,chip7}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \
- enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \
- I2C_CLIENT_MODULE_PARM(force, \
- "List of adapter,address pairs to boldly assume " \
- "to be present"); \
- SENSORS_MODULE_PARM_FORCE(chip1); \
- SENSORS_MODULE_PARM_FORCE(chip2); \
- SENSORS_MODULE_PARM_FORCE(chip3); \
- SENSORS_MODULE_PARM_FORCE(chip4); \
- SENSORS_MODULE_PARM_FORCE(chip5); \
- SENSORS_MODULE_PARM_FORCE(chip6); \
- SENSORS_MODULE_PARM_FORCE(chip7); \
- SENSORS_MODULE_PARM_FORCE(chip8); \
- static struct i2c_force_data forces[] = {{force,any_chip}, \
- {force_ ## chip1,chip1}, \
- {force_ ## chip2,chip2}, \
- {force_ ## chip3,chip3}, \
- {force_ ## chip4,chip4}, \
- {force_ ## chip5,chip5}, \
- {force_ ## chip6,chip6}, \
- {force_ ## chip7,chip7}, \
- {force_ ## chip8,chip8}, \
- {NULL}}; \
- SENSORS_INSMOD
-
-/* Detect function. It iterates over all possible addresses itself. For
- SMBus addresses, it will only call found_proc if some client is connected
- to the SMBus (unless a 'force' matched); for ISA detections, this is not
- done. */
-extern int i2c_detect(struct i2c_adapter *adapter,
- struct i2c_address_data *address_data,
- int (*found_proc) (struct i2c_adapter *, int, int));
-
-
-/* This macro is used to scale user-input to sensible values in almost all
- chip drivers. */
-static inline int SENSORS_LIMIT(long value, long low, long high)
-{
- if (value < low)
- return low;
- else if (value > high)
- return high;
- else
- return value;
-}
-#endif /* def _LINUX_I2C_SENSOR_H */
diff --git a/include/linux/i2c-vid.h b/include/linux/i2c-vid.h
deleted file mode 100644
index 41d0635..0000000
--- a/include/linux/i2c-vid.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- i2c-vid.h - Part of lm_sensors, Linux kernel modules for hardware
- monitoring
- Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
- With assistance from Trent Piepho <xyzzy@speakeasy.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.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
- This file contains common code for decoding VID pins.
- This file is #included in various chip drivers in this directory.
- As the user is unlikely to load more than one driver which
- includes this code we don't worry about the wasted space.
- Reference: VRM x.y DC-DC Converter Design Guidelines,
- available at http://developer.intel.com
-*/
-
-/*
- AMD Opteron processors don't follow the Intel VRM spec.
- I'm going to "make up" 2.4 as the VRM spec for the Opterons.
- No good reason just a mnemonic for the 24x Opteron processor
- series
-
- Opteron VID encoding is:
-
- 00000 = 1.550 V
- 00001 = 1.525 V
- . . . .
- 11110 = 0.800 V
- 11111 = 0.000 V (off)
- */
-
-/*
- Legal val values 0x00 - 0x1f; except for VRD 10.0, 0x00 - 0x3f.
- vrm is the Intel VRM document version.
- Note: vrm version is scaled by 10 and the return value is scaled by 1000
- to avoid floating point in the kernel.
-*/
-
-int i2c_which_vrm(void);
-
-#define DEFAULT_VRM 82
-
-static inline int vid_from_reg(int val, int vrm)
-{
- int vid;
-
- switch(vrm) {
-
- case 0:
- return 0;
-
- case 100: /* VRD 10.0 */
- if((val & 0x1f) == 0x1f)
- return 0;
- if((val & 0x1f) <= 0x09 || val == 0x0a)
- vid = 10875 - (val & 0x1f) * 250;
- else
- vid = 18625 - (val & 0x1f) * 250;
- if(val & 0x20)
- vid -= 125;
- vid /= 10; /* only return 3 dec. places for now */
- return vid;
-
- case 24: /* Opteron processor */
- return(val == 0x1f ? 0 : 1550 - val * 25);
-
- case 91: /* VRM 9.1 */
- case 90: /* VRM 9.0 */
- return(val == 0x1f ? 0 :
- 1850 - val * 25);
-
- case 85: /* VRM 8.5 */
- return((val & 0x10 ? 25 : 0) +
- ((val & 0x0f) > 0x04 ? 2050 : 1250) -
- ((val & 0x0f) * 50));
-
- case 84: /* VRM 8.4 */
- val &= 0x0f;
- /* fall through */
- default: /* VRM 8.2 */
- return(val == 0x1f ? 0 :
- val & 0x10 ? 5100 - (val) * 100 :
- 2050 - (val) * 50);
- }
-}
-
-static inline int vid_to_reg(int val, int vrm)
-{
- switch (vrm) {
- case 91: /* VRM 9.1 */
- case 90: /* VRM 9.0 */
- return ((val >= 1100) && (val <= 1850) ?
- ((18499 - val * 10) / 25 + 5) / 10 : -1);
- default:
- return -1;
- }
-}
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index be837b1..be35332 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -34,6 +34,13 @@
#include <linux/device.h> /* for struct device */
#include <asm/semaphore.h>
+/* --- For i2c-isa ---------------------------------------------------- */
+
+extern void i2c_adapter_dev_release(struct device *dev);
+extern struct device_driver i2c_adapter_driver;
+extern struct class i2c_adapter_class;
+extern struct bus_type i2c_bus_type;
+
/* --- General options ------------------------------------------------ */
struct i2c_msg;
@@ -41,7 +48,6 @@
struct i2c_adapter;
struct i2c_client;
struct i2c_driver;
-struct i2c_client_address_data;
union i2c_smbus_data;
/*
@@ -143,12 +149,9 @@
*/
struct i2c_client {
unsigned int flags; /* div., see below */
- unsigned int addr; /* chip address - NOTE: 7bit */
+ unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
- /* _LOWER_ 7 bits of this char */
- /* addr: unsigned int to make lm_sensors i2c-isa adapter work
- more cleanly. It does not take any more memory space, due to
- alignment considerations */
+ /* _LOWER_ 7 bits */
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
int usage_count; /* How many accesses currently */
@@ -160,6 +163,11 @@
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
+static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
+{
+ return to_i2c_client(container_of(kobj, struct device, kobj));
+}
+
static inline void *i2c_get_clientdata (struct i2c_client *dev)
{
return dev_get_drvdata (&dev->dev);
@@ -170,13 +178,6 @@
dev_set_drvdata (&dev->dev, data);
}
-#define I2C_DEVNAME(str) .name = str
-
-static inline char *i2c_clientname(struct i2c_client *c)
-{
- return &c->name[0];
-}
-
/*
* The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can
@@ -184,9 +185,6 @@
* to name two of the most common.
*/
struct i2c_algorithm {
- char name[32]; /* textual description */
- unsigned int id;
-
/* If an adapter algorithm can't do I2C-level access, set master_xfer
to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
@@ -214,8 +212,7 @@
*/
struct i2c_adapter {
struct module *owner;
- unsigned int id;/* == is algo->id | hwdep.struct->id, */
- /* for registered values see below */
+ unsigned int id;
unsigned int class;
struct i2c_algorithm *algo;/* the algorithm to access the bus */
void *algo_data;
@@ -292,12 +289,11 @@
unsigned short *normal_i2c;
unsigned short *probe;
unsigned short *ignore;
- unsigned short *force;
+ unsigned short **forces;
};
/* Internal numbers to terminate lists */
#define I2C_CLIENT_END 0xfffeU
-#define I2C_CLIENT_ISA_END 0xfffefffeU
/* The numbers to use to set I2C bus address */
#define ANY_I2C_BUS 0xffff
@@ -356,10 +352,6 @@
*/
extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
-/* This call returns a unique low identifier for each registered adapter,
- * or -1 if the adapter was not registered.
- */
-extern int i2c_adapter_id(struct i2c_adapter *adap);
extern struct i2c_adapter* i2c_get_adapter(int id);
extern void i2c_put_adapter(struct i2c_adapter *adap);
@@ -376,6 +368,12 @@
return (func & i2c_get_functionality(adap)) == func;
}
+/* Return id number for a specific adapter */
+static inline int i2c_adapter_id(struct i2c_adapter *adap)
+{
+ return adap->nr;
+}
+
/*
* I2C Message - used for pure i2c transaction, also from /dev interface
*/
@@ -510,9 +508,6 @@
#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
-#if 0
-#define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */
-#endif
#define I2C_SMBUS 0x0720 /* SMBus-level access */
@@ -556,27 +551,148 @@
module_param_array(var, short, &var##_num, 0); \
MODULE_PARM_DESC(var,desc)
-/* This is the one you want to use in your own modules */
+#define I2C_CLIENT_MODULE_PARM_FORCE(name) \
+I2C_CLIENT_MODULE_PARM(force_##name, \
+ "List of adapter,address pairs which are " \
+ "unquestionably assumed to contain a `" \
+ # name "' chip")
+
+
+#define I2C_CLIENT_INSMOD_COMMON \
+I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \
+ "additionally"); \
+I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \
+ "scan"); \
+static struct i2c_client_address_data addr_data = { \
+ .normal_i2c = normal_i2c, \
+ .probe = probe, \
+ .ignore = ignore, \
+ .forces = forces, \
+}
+
+/* These are the ones you want to use in your own drivers. Pick the one
+ which matches the number of devices the driver differenciates between. */
#define I2C_CLIENT_INSMOD \
- I2C_CLIENT_MODULE_PARM(probe, \
- "List of adapter,address pairs to scan additionally"); \
- I2C_CLIENT_MODULE_PARM(ignore, \
- "List of adapter,address pairs not to scan"); \
I2C_CLIENT_MODULE_PARM(force, \
"List of adapter,address pairs to boldly assume " \
"to be present"); \
- static struct i2c_client_address_data addr_data = { \
- .normal_i2c = normal_i2c, \
- .probe = probe, \
- .ignore = ignore, \
- .force = force, \
- }
+ static unsigned short *forces[] = { \
+ force, \
+ NULL \
+ }; \
+I2C_CLIENT_INSMOD_COMMON
-/* Detect whether we are on the isa bus. If this returns true, all i2c
- access will fail! */
-#define i2c_is_isa_client(clientptr) \
- ((clientptr)->adapter->algo->id == I2C_ALGO_ISA)
-#define i2c_is_isa_adapter(adapptr) \
- ((adapptr)->algo->id == I2C_ALGO_ISA)
+#define I2C_CLIENT_INSMOD_1(chip1) \
+enum chips { any_chip, chip1 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+static unsigned short *forces[] = { force, force_##chip1, NULL }; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_2(chip1, chip2) \
+enum chips { any_chip, chip1, chip2 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, NULL }; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3) \
+enum chips { any_chip, chip1, chip2, chip3 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, force_##chip3, \
+ NULL }; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4) \
+enum chips { any_chip, chip1, chip2, chip3, chip4 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, force_##chip3, \
+ force_##chip4, NULL}; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5) \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, force_##chip3, \
+ force_##chip4, force_##chip5, \
+ NULL }; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6) \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, force_##chip3, \
+ force_##chip4, force_##chip5, \
+ force_##chip6, NULL }; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \
+ chip7 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip7); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, force_##chip3, \
+ force_##chip4, force_##chip5, \
+ force_##chip6, force_##chip7, \
+ NULL }; \
+I2C_CLIENT_INSMOD_COMMON
+
+#define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \
+enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \
+ chip7, chip8 }; \
+I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to " \
+ "boldly assume to be present"); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip7); \
+I2C_CLIENT_MODULE_PARM_FORCE(chip8); \
+static unsigned short *forces[] = { force, force_##chip1, \
+ force_##chip2, force_##chip3, \
+ force_##chip4, force_##chip5, \
+ force_##chip6, force_##chip7, \
+ force_##chip8, NULL }; \
+I2C_CLIENT_INSMOD_COMMON
#endif /* _LINUX_I2C_H */
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 096a85a..88aef7b 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -77,6 +77,7 @@
#define TUNSETIFF _IOW('T', 202, int)
#define TUNSETPERSIST _IOW('T', 203, int)
#define TUNSETOWNER _IOW('T', 204, int)
+#define TUNSETLINK _IOW('T', 205, int)
/* TUNSETIFF ifr flags */
#define IFF_TUN 0x0001
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index 93bb3af..ee5b239 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -47,6 +47,7 @@
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
/* special flags */
+#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
#define IN_ISDIR 0x40000000 /* event occurred against dir */
#define IN_ONESHOT 0x80000000 /* only send event once */
diff --git a/include/linux/input.h b/include/linux/input.h
index bdc53c6..4767e54 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -66,6 +66,7 @@
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
+#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
@@ -86,6 +87,7 @@
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
+#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
@@ -551,6 +553,20 @@
#define ABS_MAX 0x3f
/*
+ * Switch events
+ */
+
+#define SW_0 0x00
+#define SW_1 0x01
+#define SW_2 0x02
+#define SW_3 0x03
+#define SW_4 0x04
+#define SW_5 0x05
+#define SW_6 0x06
+#define SW_7 0x07
+#define SW_MAX 0x0f
+
+/*
* Misc events
*/
@@ -824,6 +840,7 @@
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
+ unsigned long swbit[NBITS(SW_MAX)];
int ff_effects_max;
unsigned int keycodemax;
@@ -844,6 +861,7 @@
unsigned long key[NBITS(KEY_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)];
+ unsigned long sw[NBITS(SW_MAX)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
@@ -886,6 +904,7 @@
#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200
#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400
#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800
+#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000
#define INPUT_DEVICE_ID_MATCH_DEVICE\
(INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
@@ -906,6 +925,7 @@
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
+ unsigned long swbit[NBITS(SW_MAX)];
unsigned long driver_info;
};
@@ -998,6 +1018,11 @@
input_event(dev, EV_FF_STATUS, code, value);
}
+static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
+{
+ input_event(dev, EV_SW, code, !!value);
+}
+
static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
{
dev->regs = regs;
diff --git a/include/linux/ioctl32.h b/include/linux/ioctl32.h
index e8c4af3..948809d 100644
--- a/include/linux/ioctl32.h
+++ b/include/linux/ioctl32.h
@@ -14,26 +14,4 @@
struct ioctl_trans *next;
};
-/*
- * Register an 32bit ioctl translation handler for ioctl cmd.
- *
- * handler == NULL: use 64bit ioctl handler.
- * arguments to handler: fd: file descriptor
- * cmd: ioctl command.
- * arg: ioctl argument
- * struct file *file: file descriptor pointer.
- */
-
-#ifdef CONFIG_COMPAT
-extern int __deprecated register_ioctl32_conversion(unsigned int cmd,
- ioctl_trans_handler_t handler);
-extern int __deprecated unregister_ioctl32_conversion(unsigned int cmd);
-
-#else
-
-#define register_ioctl32_conversion(cmd, handler) ({ 0; })
-#define unregister_ioctl32_conversion(cmd) ({ 0; })
-
-#endif
-
#endif
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 596ca61..938d55b 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -35,6 +35,7 @@
#define __LINUX_IPMI_H
#include <linux/ipmi_msgdefs.h>
+#include <linux/compiler.h>
/*
* This file describes an interface to an IPMI driver. You have to
@@ -241,7 +242,8 @@
/* The user_msg_data is the data supplied when a message was
sent, if this is a response to a sent message. If this is
not a response to a sent message, then user_msg_data will
- be NULL. */
+ be NULL. If the user above is NULL, then this will be the
+ intf. */
void *user_msg_data;
/* Call this when done with the message. It will presumably free
@@ -298,13 +300,19 @@
this user, so it will affect all users of this interface. This is
so some initialization code can come in and do the OEM-specific
things it takes to determine your address (if not the BMC) and set
- it for everyone else. */
-void ipmi_set_my_address(ipmi_user_t user,
- unsigned char address);
-unsigned char ipmi_get_my_address(ipmi_user_t user);
-void ipmi_set_my_LUN(ipmi_user_t user,
- unsigned char LUN);
-unsigned char ipmi_get_my_LUN(ipmi_user_t user);
+ it for everyone else. Note that each channel can have its own address. */
+int ipmi_set_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char address);
+int ipmi_get_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address);
+int ipmi_set_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char LUN);
+int ipmi_get_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *LUN);
/*
* Like ipmi_request, but lets you specify the number of retries and
@@ -585,6 +593,16 @@
* things it takes to determine your address (if not the BMC) and set
* it for everyone else. You should probably leave the LUN alone.
*/
+struct ipmi_channel_lun_address_set
+{
+ unsigned short channel;
+ unsigned char value;
+};
+#define IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 24, struct ipmi_channel_lun_address_set)
+#define IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 25, struct ipmi_channel_lun_address_set)
+#define IPMICTL_SET_MY_CHANNEL_LUN_CMD _IOR(IPMI_IOC_MAGIC, 26, struct ipmi_channel_lun_address_set)
+#define IPMICTL_GET_MY_CHANNEL_LUN_CMD _IOR(IPMI_IOC_MAGIC, 27, struct ipmi_channel_lun_address_set)
+/* Legacy interfaces, these only set IPMB 0. */
#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int)
#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int)
#define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 069d3b8..69681c3 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -32,7 +32,12 @@
#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */
#define IRQ_LEVEL 64 /* IRQ level triggered */
#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */
-#define IRQ_PER_CPU 256 /* IRQ is per CPU */
+#if defined(ARCH_HAS_IRQ_PER_CPU)
+# define IRQ_PER_CPU 256 /* IRQ is per CPU */
+# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
+#else
+# define CHECK_IRQ_PER_CPU(var) 0
+#endif
/*
* Interrupt controller descriptor. This is all we need
@@ -71,16 +76,139 @@
unsigned int irq_count; /* For detecting broken interrupts */
unsigned int irqs_unhandled;
spinlock_t lock;
+#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
+ unsigned int move_irq; /* Flag need to re-target intr dest*/
+#endif
} ____cacheline_aligned irq_desc_t;
extern irq_desc_t irq_desc [NR_IRQS];
+/* Return a pointer to the irq descriptor for IRQ. */
+static inline irq_desc_t *
+irq_descp (int irq)
+{
+ return irq_desc + irq;
+}
+
#include <asm/hw_irq.h> /* the arch dependent stuff */
extern int setup_irq(unsigned int irq, struct irqaction * new);
#ifdef CONFIG_GENERIC_HARDIRQS
extern cpumask_t irq_affinity[NR_IRQS];
+
+#ifdef CONFIG_SMP
+static inline void set_native_irq_info(int irq, cpumask_t mask)
+{
+ irq_affinity[irq] = mask;
+}
+#else
+static inline void set_native_irq_info(int irq, cpumask_t mask)
+{
+}
+#endif
+
+#ifdef CONFIG_SMP
+
+#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
+extern cpumask_t pending_irq_cpumask[NR_IRQS];
+
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ desc->move_irq = 1;
+ pending_irq_cpumask[irq] = mask;
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+static inline void
+move_native_irq(int irq)
+{
+ cpumask_t tmp;
+ irq_desc_t *desc = irq_descp(irq);
+
+ if (likely (!desc->move_irq))
+ return;
+
+ desc->move_irq = 0;
+
+ if (likely(cpus_empty(pending_irq_cpumask[irq])))
+ return;
+
+ if (!desc->handler->set_affinity)
+ return;
+
+ /* note - we hold the desc->lock */
+ cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
+
+ /*
+ * If there was a valid mask to work with, please
+ * do the disable, re-program, enable sequence.
+ * This is *not* particularly important for level triggered
+ * but in a edge trigger case, we might be setting rte
+ * when an active trigger is comming in. This could
+ * cause some ioapics to mal-function.
+ * Being paranoid i guess!
+ */
+ if (unlikely(!cpus_empty(tmp))) {
+ desc->handler->disable(irq);
+ desc->handler->set_affinity(irq,tmp);
+ desc->handler->enable(irq);
+ }
+ cpus_clear(pending_irq_cpumask[irq]);
+}
+
+#ifdef CONFIG_PCI_MSI
+/*
+ * Wonder why these are dummies?
+ * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq()
+ * counter part after translating the vector to irq info. We need to perform
+ * this operation on the real irq, when we dont use vector, i.e when
+ * pci_use_vector() is false.
+ */
+static inline void move_irq(int irq)
+{
+}
+
+static inline void set_irq_info(int irq, cpumask_t mask)
+{
+}
+
+#else // CONFIG_PCI_MSI
+
+static inline void move_irq(int irq)
+{
+ move_native_irq(irq);
+}
+
+static inline void set_irq_info(int irq, cpumask_t mask)
+{
+ set_native_irq_info(irq, mask);
+}
+#endif // CONFIG_PCI_MSI
+
+#else // CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE
+
+#define move_irq(x)
+#define move_native_irq(x)
+#define set_pending_irq(x,y)
+static inline void set_irq_info(int irq, cpumask_t mask)
+{
+ set_native_irq_info(irq, mask);
+}
+
+#endif // CONFIG_GENERIC_PENDING_IRQ
+
+#else // CONFIG_SMP
+
+#define move_irq(x)
+#define move_native_irq(x)
+
+#endif // CONFIG_SMP
+
extern int no_irq_affinity;
extern int noirqdebug_setup(char *str);
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 862083e..53eaee9 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -150,7 +150,6 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/signal.h>
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 593407e..84321a4 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -914,7 +914,6 @@
extern int journal_skip_recovery (journal_t *);
extern void journal_update_superblock (journal_t *, int);
extern void __journal_abort_hard (journal_t *);
-extern void __journal_abort_soft (journal_t *, int);
extern void journal_abort (journal_t *, int);
extern int journal_errno (journal_t *);
extern void journal_ack_err (journal_t *);
diff --git a/include/linux/klist.h b/include/linux/klist.h
index eebf5e5..7407125 100644
--- a/include/linux/klist.h
+++ b/include/linux/klist.h
@@ -9,20 +9,25 @@
* This file is rleased under the GPL v2.
*/
+#ifndef _LINUX_KLIST_H
+#define _LINUX_KLIST_H
+
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/kref.h>
#include <linux/list.h>
-
+struct klist_node;
struct klist {
spinlock_t k_lock;
struct list_head k_list;
+ void (*get)(struct klist_node *);
+ void (*put)(struct klist_node *);
};
-extern void klist_init(struct klist * k);
-
+extern void klist_init(struct klist * k, void (*get)(struct klist_node *),
+ void (*put)(struct klist_node *));
struct klist_node {
struct klist * n_klist;
@@ -31,8 +36,8 @@
struct completion n_removed;
};
-extern void klist_add_tail(struct klist * k, struct klist_node * n);
-extern void klist_add_head(struct klist * k, struct klist_node * n);
+extern void klist_add_tail(struct klist_node * n, struct klist * k);
+extern void klist_add_head(struct klist_node * n, struct klist * k);
extern void klist_del(struct klist_node * n);
extern void klist_remove(struct klist_node * n);
@@ -53,3 +58,4 @@
extern void klist_iter_exit(struct klist_iter * i);
extern struct klist_node * klist_next(struct klist_iter * i);
+#endif
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index e050fc2..e30afdc 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -42,6 +42,9 @@
#define KPROBE_REENTER 0x00000004
#define KPROBE_HIT_SSDONE 0x00000008
+/* Attach to insert probes on any functions which should be ignored*/
+#define __kprobes __attribute__((__section__(".kprobes.text")))
+
struct kprobe;
struct pt_regs;
struct kretprobe;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7b2116d..f76f54a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -40,7 +40,6 @@
#undef ATA_VERBOSE_DEBUG /* yet more debugging output */
#undef ATA_IRQ_TRAP /* define to ack screaming irqs */
#undef ATA_NDEBUG /* define to disable quick runtime checks */
-#undef ATA_ENABLE_ATAPI /* define to enable ATAPI support */
#undef ATA_ENABLE_PATA /* define to enable PATA support in some
* low-level drivers */
#undef ATAPI_ENABLE_DMADIR /* enables ATAPI DMADIR bridge support */
@@ -456,6 +455,7 @@
unsigned long val;
};
+extern void ata_pci_host_stop (struct ata_host_set *host_set);
extern struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port);
extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 338f779..147eb01 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -33,6 +33,13 @@
ALIGN; \
name:
+#define KPROBE_ENTRY(name) \
+ .section .kprobes.text, "ax"; \
+ .globl name; \
+ ALIGN; \
+ name:
+
+
#endif
#define NORET_TYPE /**/
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 8480aef..94a46f3 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -150,6 +150,9 @@
struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
unsigned long idx);
+struct mempolicy *get_vma_policy(struct task_struct *task,
+ struct vm_area_struct *vma, unsigned long addr);
+
extern void numa_default_policy(void);
extern void numa_policy_init(void);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aefedf0..18fc77f 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -33,6 +33,13 @@
unsigned int capacity;
};
+struct sd_scr {
+ unsigned char sda_vsn;
+ unsigned char bus_widths;
+#define SD_SCR_BUS_WIDTH_1 (1<<0)
+#define SD_SCR_BUS_WIDTH_4 (1<<2)
+};
+
struct mmc_host;
/*
@@ -47,19 +54,27 @@
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
#define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
+#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
+#define MMC_STATE_READONLY (1<<4) /* card is read-only */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
+ u32 raw_scr[2]; /* raw card SCR */
struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */
+ struct sd_scr scr; /* extra SD information */
};
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
+#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
+#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
#define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD)
+#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
+#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9a0893f..6014160 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -46,16 +46,28 @@
#define MMC_BUSMODE_OPENDRAIN 1
#define MMC_BUSMODE_PUSHPULL 2
+ unsigned char chip_select; /* SPI chip select */
+
+#define MMC_CS_DONTCARE 0
+#define MMC_CS_HIGH 1
+#define MMC_CS_LOW 2
+
unsigned char power_mode; /* power supply mode */
#define MMC_POWER_OFF 0
#define MMC_POWER_UP 1
#define MMC_POWER_ON 2
+
+ unsigned char bus_width; /* data bus width */
+
+#define MMC_BUS_WIDTH_1 0
+#define MMC_BUS_WIDTH_4 2
};
struct mmc_host_ops {
void (*request)(struct mmc_host *host, struct mmc_request *req);
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
+ int (*get_ro)(struct mmc_host *host);
};
struct mmc_card;
@@ -70,6 +82,10 @@
unsigned int f_max;
u32 ocr_avail;
+ unsigned long caps; /* Host capabilities */
+
+#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
+
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
@@ -81,6 +97,10 @@
struct mmc_ios ios; /* current io bus settings */
u32 ocr; /* the current OCR setting */
+ unsigned int mode; /* current card mode of host */
+#define MMC_MODE_MMC 0
+#define MMC_MODE_SD 1
+
struct list_head cards; /* devices attached to this host */
wait_queue_head_t wq;
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 0d35d4f..1ab78e8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -88,6 +88,8 @@
extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
+ struct mmc_command *, int);
extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
index 8963428..f819cae 100644
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -236,5 +236,12 @@
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1 0
+#define SD_BUS_WIDTH_4 2
+
#endif /* MMC_MMC_PROTOCOL_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 6c90461..5ed471b 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -487,11 +487,27 @@
unsigned long section_mem_map;
};
-extern struct mem_section mem_section[NR_MEM_SECTIONS];
+#ifdef CONFIG_SPARSEMEM_EXTREME
+#define SECTIONS_PER_ROOT (PAGE_SIZE / sizeof (struct mem_section))
+#else
+#define SECTIONS_PER_ROOT 1
+#endif
+
+#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT)
+#define NR_SECTION_ROOTS (NR_MEM_SECTIONS / SECTIONS_PER_ROOT)
+#define SECTION_ROOT_MASK (SECTIONS_PER_ROOT - 1)
+
+#ifdef CONFIG_SPARSEMEM_EXTREME
+extern struct mem_section *mem_section[NR_SECTION_ROOTS];
+#else
+extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT];
+#endif
static inline struct mem_section *__nr_to_section(unsigned long nr)
{
- return &mem_section[nr];
+ if (!mem_section[SECTION_NR_TO_ROOT(nr)])
+ return NULL;
+ return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
}
/*
@@ -513,12 +529,12 @@
static inline int valid_section(struct mem_section *section)
{
- return (section->section_mem_map & SECTION_MARKED_PRESENT);
+ return (section && (section->section_mem_map & SECTION_MARKED_PRESENT));
}
static inline int section_has_mem_map(struct mem_section *section)
{
- return (section->section_mem_map & SECTION_HAS_MEM_MAP);
+ return (section && (section->section_mem_map & SECTION_HAS_MEM_MAP));
}
static inline int valid_section_nr(unsigned long nr)
@@ -572,6 +588,7 @@
void sparse_init(void);
#else
#define sparse_init() do {} while (0)
+#define sparse_index_init(_sec, _nid) do {} while (0)
#endif /* CONFIG_SPARSEMEM */
#ifdef CONFIG_NODES_SPAN_OTHER_NODES
diff --git a/include/linux/msg.h b/include/linux/msg.h
index 2c4c6aa..903e0ab 100644
--- a/include/linux/msg.h
+++ b/include/linux/msg.h
@@ -77,6 +77,7 @@
/* one msq_queue structure for each present queue on the system */
struct msg_queue {
struct kern_ipc_perm q_perm;
+ int q_id;
time_t q_stime; /* last msgsnd time */
time_t q_rtime; /* last msgrcv time */
time_t q_ctime; /* last change time */
diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h
index 5773ea4..0b08cd6 100644
--- a/include/linux/mv643xx.h
+++ b/include/linux/mv643xx.h
@@ -980,7 +980,7 @@
/* I2C Registers */
/****************************************/
-#define MV64XXX_I2C_CTLR_NAME "mv64xxx i2c"
+#define MV64XXX_I2C_CTLR_NAME "mv64xxx_i2c"
#define MV64XXX_I2C_OFFSET 0xc000
#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 088742b..7e033e9 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -263,6 +263,9 @@
/* Unique ID */
unsigned int id;
+ /* Flags */
+ unsigned int flags;
+
#ifdef CONFIG_IP_NF_NAT_NEEDED
/* This is the original per-proto part, used to map the
* expected connection the way the recipient expects. */
@@ -272,6 +275,8 @@
#endif
};
+#define IP_CT_EXPECT_PERMANENT 0x1
+
static inline struct ip_conntrack *
tuplehash_to_ctrack(const struct ip_conntrack_tuple_hash *hash)
{
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
index dc4d2a0..907d4f5 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h
@@ -52,7 +52,7 @@
return ret;
}
-extern void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp);
+extern void ip_ct_unlink_expect(struct ip_conntrack_expect *exp);
extern struct list_head *ip_conntrack_hash;
extern struct list_head ip_conntrack_expect_list;
diff --git a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h
index fecd2a0..73b9552 100644
--- a/include/linux/netfilter_ipv4/ip_nat_rule.h
+++ b/include/linux/netfilter_ipv4/ip_nat_rule.h
@@ -19,5 +19,10 @@
alloc_null_binding(struct ip_conntrack *conntrack,
struct ip_nat_info *info,
unsigned int hooknum);
+
+extern unsigned int
+alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
+ struct ip_nat_info *info,
+ unsigned int hooknum);
#endif
#endif /* _IP_NAT_RULE_H */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index f5a6695..f34767c 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -134,6 +134,7 @@
};
extern void get_page_state(struct page_state *ret);
+extern void get_page_state_node(struct page_state *ret, int node);
extern void get_full_page_state(struct page_state *ret);
extern unsigned long __read_page_state(unsigned long offset);
extern void __mod_page_state(unsigned long offset, unsigned long delta);
@@ -194,6 +195,7 @@
#define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags)
#define TestSetPageDirty(page) test_and_set_bit(PG_dirty, &(page)->flags)
#define ClearPageDirty(page) clear_bit(PG_dirty, &(page)->flags)
+#define __ClearPageDirty(page) __clear_bit(PG_dirty, &(page)->flags)
#define TestClearPageDirty(page) test_and_clear_bit(PG_dirty, &(page)->flags)
#define SetPageLRU(page) set_bit(PG_lru, &(page)->flags)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d513c16..ee0ab7a 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1612,6 +1612,7 @@
#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
#define PCI_DEVICE_ID_TOSHIBA_TX4927 0x0180
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
+#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
#define PCI_VENDOR_ID_RICOH 0x1180
#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
@@ -2147,6 +2148,9 @@
#define PCI_DEVICE_ID_ENE_1420 0x1420
#define PCI_VENDOR_ID_CHELSIO 0x1425
+#define PCI_VENDOR_ID_MIPS 0x153f
+#define PCI_DEVICE_ID_SOC_IT 0x0001
+
#define PCI_VENDOR_ID_SYBA 0x1592
#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782
#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 36725e7..1767073 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -39,9 +39,6 @@
#define PIPE_SEM(inode) (&(inode).i_sem)
#define PIPE_WAIT(inode) (&(inode).i_pipe->wait)
-#define PIPE_BASE(inode) ((inode).i_pipe->base)
-#define PIPE_START(inode) ((inode).i_pipe->start)
-#define PIPE_LEN(inode) ((inode).i_pipe->len)
#define PIPE_READERS(inode) ((inode).i_pipe->readers)
#define PIPE_WRITERS(inode) ((inode).i_pipe->writers)
#define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers)
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 7aeb208..5cfb076 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -186,7 +186,9 @@
struct device;
-typedef u32 __bitwise pm_message_t;
+typedef struct pm_message {
+ int event;
+} pm_message_t;
/*
* There are 4 important states driver can be in:
@@ -207,9 +209,13 @@
* or something similar soon.
*/
-#define PMSG_FREEZE ((__force pm_message_t) 3)
-#define PMSG_SUSPEND ((__force pm_message_t) 3)
-#define PMSG_ON ((__force pm_message_t) 0)
+#define PM_EVENT_ON 0
+#define PM_EVENT_FREEZE 1
+#define PM_EVENT_SUSPEND 2
+
+#define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, })
+#define PMSG_SUSPEND ((struct pm_message){ .event = PM_EVENT_SUSPEND, })
+#define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, })
struct dev_pm_info {
pm_message_t power_state;
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 5ec2bd0..aadbac2 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -443,7 +443,7 @@
#define pnp_info(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
#define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)
-#ifdef DEBUG
+#ifdef CONFIG_PNP_DEBUG
#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
#else
#define pnp_dbg(format, arg...) do {} while (0)
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index a373fc2..dc6f364 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -20,6 +20,8 @@
#define PTRACE_DETACH 0x11
#define PTRACE_SYSCALL 24
+#define PTRACE_SYSEMU 31
+#define PTRACE_SYSEMU_SINGLESTEP 32
/* 0x4200-0x4300 are reserved for architecture-independent additions. */
#define PTRACE_SETOPTIONS 0x4200
@@ -88,6 +90,7 @@
struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child);
extern void ptrace_untrace(struct task_struct *child);
+extern int ptrace_may_attach(struct task_struct *task);
static inline void ptrace_link(struct task_struct *child,
struct task_struct *new_parent)
diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h
new file mode 100644
index 0000000..a71123c
--- /dev/null
+++ b/include/linux/raid_class.h
@@ -0,0 +1,59 @@
+/*
+ */
+#include <linux/transport_class.h>
+
+struct raid_template {
+ struct transport_container raid_attrs;
+};
+
+struct raid_function_template {
+ void *cookie;
+ int (*is_raid)(struct device *);
+ void (*get_resync)(struct device *);
+ void (*get_state)(struct device *);
+};
+
+enum raid_state {
+ RAID_ACTIVE = 1,
+ RAID_DEGRADED,
+ RAID_RESYNCING,
+ RAID_OFFLINE,
+};
+
+struct raid_data {
+ struct list_head component_list;
+ int component_count;
+ int level;
+ enum raid_state state;
+ int resync;
+};
+
+#define DEFINE_RAID_ATTRIBUTE(type, attr) \
+static inline void \
+raid_set_##attr(struct raid_template *r, struct device *dev, type value) { \
+ struct class_device *cdev = \
+ attribute_container_find_class_device(&r->raid_attrs.ac, dev);\
+ struct raid_data *rd; \
+ BUG_ON(!cdev); \
+ rd = class_get_devdata(cdev); \
+ rd->attr = value; \
+} \
+static inline type \
+raid_get_##attr(struct raid_template *r, struct device *dev) { \
+ struct class_device *cdev = \
+ attribute_container_find_class_device(&r->raid_attrs.ac, dev);\
+ struct raid_data *rd; \
+ BUG_ON(!cdev); \
+ rd = class_get_devdata(cdev); \
+ return rd->attr; \
+}
+
+DEFINE_RAID_ATTRIBUTE(int, level)
+DEFINE_RAID_ATTRIBUTE(int, resync)
+DEFINE_RAID_ATTRIBUTE(enum raid_state, state)
+
+struct raid_template *raid_class_attach(struct raid_function_template *);
+void raid_class_release(struct raid_template *);
+
+void raid_component_add(struct raid_template *, struct device *,
+ struct device *);
diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h
new file mode 100644
index 0000000..cfafc3e
--- /dev/null
+++ b/include/linux/relayfs_fs.h
@@ -0,0 +1,255 @@
+/*
+ * linux/include/linux/relayfs_fs.h
+ *
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * RelayFS definitions and declarations
+ */
+
+#ifndef _LINUX_RELAYFS_FS_H
+#define _LINUX_RELAYFS_FS_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/kref.h>
+
+/*
+ * Tracks changes to rchan_buf struct
+ */
+#define RELAYFS_CHANNEL_VERSION 5
+
+/*
+ * Per-cpu relay channel buffer
+ */
+struct rchan_buf
+{
+ void *start; /* start of channel buffer */
+ void *data; /* start of current sub-buffer */
+ size_t offset; /* current offset into sub-buffer */
+ size_t subbufs_produced; /* count of sub-buffers produced */
+ size_t subbufs_consumed; /* count of sub-buffers consumed */
+ struct rchan *chan; /* associated channel */
+ wait_queue_head_t read_wait; /* reader wait queue */
+ struct work_struct wake_readers; /* reader wake-up work struct */
+ struct dentry *dentry; /* channel file dentry */
+ struct kref kref; /* channel buffer refcount */
+ struct page **page_array; /* array of current buffer pages */
+ unsigned int page_count; /* number of current buffer pages */
+ unsigned int finalized; /* buffer has been finalized */
+ size_t *padding; /* padding counts per sub-buffer */
+ size_t prev_padding; /* temporary variable */
+ size_t bytes_consumed; /* bytes consumed in cur read subbuf */
+ unsigned int cpu; /* this buf's cpu */
+} ____cacheline_aligned;
+
+/*
+ * Relay channel data structure
+ */
+struct rchan
+{
+ u32 version; /* the version of this struct */
+ size_t subbuf_size; /* sub-buffer size */
+ size_t n_subbufs; /* number of sub-buffers per buffer */
+ size_t alloc_size; /* total buffer size allocated */
+ struct rchan_callbacks *cb; /* client callbacks */
+ struct kref kref; /* channel refcount */
+ void *private_data; /* for user-defined data */
+ struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
+};
+
+/*
+ * Relayfs inode
+ */
+struct relayfs_inode_info
+{
+ struct inode vfs_inode;
+ struct rchan_buf *buf;
+};
+
+static inline struct relayfs_inode_info *RELAYFS_I(struct inode *inode)
+{
+ return container_of(inode, struct relayfs_inode_info, vfs_inode);
+}
+
+/*
+ * Relay channel client callbacks
+ */
+struct rchan_callbacks
+{
+ /*
+ * subbuf_start - called on buffer-switch to a new sub-buffer
+ * @buf: the channel buffer containing the new sub-buffer
+ * @subbuf: the start of the new sub-buffer
+ * @prev_subbuf: the start of the previous sub-buffer
+ * @prev_padding: unused space at the end of previous sub-buffer
+ *
+ * The client should return 1 to continue logging, 0 to stop
+ * logging.
+ *
+ * NOTE: subbuf_start will also be invoked when the buffer is
+ * created, so that the first sub-buffer can be initialized
+ * if necessary. In this case, prev_subbuf will be NULL.
+ *
+ * NOTE: the client can reserve bytes at the beginning of the new
+ * sub-buffer by calling subbuf_start_reserve() in this callback.
+ */
+ int (*subbuf_start) (struct rchan_buf *buf,
+ void *subbuf,
+ void *prev_subbuf,
+ size_t prev_padding);
+
+ /*
+ * buf_mapped - relayfs buffer mmap notification
+ * @buf: the channel buffer
+ * @filp: relayfs file pointer
+ *
+ * Called when a relayfs file is successfully mmapped
+ */
+ void (*buf_mapped)(struct rchan_buf *buf,
+ struct file *filp);
+
+ /*
+ * buf_unmapped - relayfs buffer unmap notification
+ * @buf: the channel buffer
+ * @filp: relayfs file pointer
+ *
+ * Called when a relayfs file is successfully unmapped
+ */
+ void (*buf_unmapped)(struct rchan_buf *buf,
+ struct file *filp);
+};
+
+/*
+ * relayfs kernel API, fs/relayfs/relay.c
+ */
+
+struct rchan *relay_open(const char *base_filename,
+ struct dentry *parent,
+ size_t subbuf_size,
+ size_t n_subbufs,
+ struct rchan_callbacks *cb);
+extern void relay_close(struct rchan *chan);
+extern void relay_flush(struct rchan *chan);
+extern void relay_subbufs_consumed(struct rchan *chan,
+ unsigned int cpu,
+ size_t consumed);
+extern void relay_reset(struct rchan *chan);
+extern int relay_buf_full(struct rchan_buf *buf);
+
+extern size_t relay_switch_subbuf(struct rchan_buf *buf,
+ size_t length);
+extern struct dentry *relayfs_create_dir(const char *name,
+ struct dentry *parent);
+extern int relayfs_remove_dir(struct dentry *dentry);
+
+/**
+ * relay_write - write data into the channel
+ * @chan: relay channel
+ * @data: data to be written
+ * @length: number of bytes to write
+ *
+ * Writes data into the current cpu's channel buffer.
+ *
+ * Protects the buffer by disabling interrupts. Use this
+ * if you might be logging from interrupt context. Try
+ * __relay_write() if you know you won't be logging from
+ * interrupt context.
+ */
+static inline void relay_write(struct rchan *chan,
+ const void *data,
+ size_t length)
+{
+ unsigned long flags;
+ struct rchan_buf *buf;
+
+ local_irq_save(flags);
+ buf = chan->buf[smp_processor_id()];
+ if (unlikely(buf->offset + length > chan->subbuf_size))
+ length = relay_switch_subbuf(buf, length);
+ memcpy(buf->data + buf->offset, data, length);
+ buf->offset += length;
+ local_irq_restore(flags);
+}
+
+/**
+ * __relay_write - write data into the channel
+ * @chan: relay channel
+ * @data: data to be written
+ * @length: number of bytes to write
+ *
+ * Writes data into the current cpu's channel buffer.
+ *
+ * Protects the buffer by disabling preemption. Use
+ * relay_write() if you might be logging from interrupt
+ * context.
+ */
+static inline void __relay_write(struct rchan *chan,
+ const void *data,
+ size_t length)
+{
+ struct rchan_buf *buf;
+
+ buf = chan->buf[get_cpu()];
+ if (unlikely(buf->offset + length > buf->chan->subbuf_size))
+ length = relay_switch_subbuf(buf, length);
+ memcpy(buf->data + buf->offset, data, length);
+ buf->offset += length;
+ put_cpu();
+}
+
+/**
+ * relay_reserve - reserve slot in channel buffer
+ * @chan: relay channel
+ * @length: number of bytes to reserve
+ *
+ * Returns pointer to reserved slot, NULL if full.
+ *
+ * Reserves a slot in the current cpu's channel buffer.
+ * Does not protect the buffer at all - caller must provide
+ * appropriate synchronization.
+ */
+static inline void *relay_reserve(struct rchan *chan, size_t length)
+{
+ void *reserved;
+ struct rchan_buf *buf = chan->buf[smp_processor_id()];
+
+ if (unlikely(buf->offset + length > buf->chan->subbuf_size)) {
+ length = relay_switch_subbuf(buf, length);
+ if (!length)
+ return NULL;
+ }
+ reserved = buf->data + buf->offset;
+ buf->offset += length;
+
+ return reserved;
+}
+
+/**
+ * subbuf_start_reserve - reserve bytes at the start of a sub-buffer
+ * @buf: relay channel buffer
+ * @length: number of bytes to reserve
+ *
+ * Helper function used to reserve bytes at the beginning of
+ * a sub-buffer in the subbuf_start() callback.
+ */
+static inline void subbuf_start_reserve(struct rchan_buf *buf,
+ size_t length)
+{
+ BUG_ON(length >= buf->chan->subbuf_size - 1);
+ buf->offset = length;
+}
+
+/*
+ * exported relayfs file operations, fs/relayfs/inode.c
+ */
+
+extern struct file_operations relayfs_file_operations;
+
+#endif /* _LINUX_RELAYFS_FS_H */
+
diff --git a/include/linux/sched.h b/include/linux/sched.h
index dec5827..ea1b5f3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -35,6 +35,8 @@
#include <linux/topology.h>
#include <linux/seccomp.h>
+#include <linux/auxvec.h> /* For AT_VECTOR_SIZE */
+
struct exec_domain;
/*
@@ -176,6 +178,23 @@
extern void update_process_times(int user);
extern void scheduler_tick(void);
+#ifdef CONFIG_DETECT_SOFTLOCKUP
+extern void softlockup_tick(struct pt_regs *regs);
+extern void spawn_softlockup_task(void);
+extern void touch_softlockup_watchdog(void);
+#else
+static inline void softlockup_tick(struct pt_regs *regs)
+{
+}
+static inline void spawn_softlockup_task(void)
+{
+}
+static inline void touch_softlockup_watchdog(void)
+{
+}
+#endif
+
+
/* Attach to any functions which should be ignored in wchan output. */
#define __sched __attribute__((__section__(".sched.text")))
/* Is this address in the __sched functions? */
@@ -244,7 +263,7 @@
mm_counter_t _rss;
mm_counter_t _anon_rss;
- unsigned long saved_auxv[42]; /* for /proc/PID/auxv */
+ unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
unsigned dumpable:2;
cpumask_t cpu_vm_mask;
@@ -545,13 +564,6 @@
extern void partition_sched_domains(cpumask_t *partition1,
cpumask_t *partition2);
-#ifdef ARCH_HAS_SCHED_DOMAIN
-/* Useful helpers that arch setup code may use. Defined in kernel/sched.c */
-extern cpumask_t cpu_isolated_map;
-extern void init_sched_build_groups(struct sched_group groups[],
- cpumask_t span, int (*group_fn)(int cpu));
-extern void cpu_attach_domain(struct sched_domain *sd, int cpu);
-#endif /* ARCH_HAS_SCHED_DOMAIN */
#endif /* CONFIG_SMP */
diff --git a/include/linux/sem.h b/include/linux/sem.h
index 2d8516b..106f975 100644
--- a/include/linux/sem.h
+++ b/include/linux/sem.h
@@ -88,6 +88,7 @@
/* One sem_array data structure for each set of semaphores in the system. */
struct sem_array {
struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */
+ int sem_id;
time_t sem_otime; /* last semop time */
time_t sem_ctime; /* last change time */
struct sem *sem_base; /* ptr to first semaphore in array */
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 9f2d852..12cd9cf6 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -176,10 +176,6 @@
#ifdef __KERNEL__
#include <linux/compiler.h>
-/* Export to allow PCMCIA to use this - Dave Hinds */
-extern int __deprecated register_serial(struct serial_struct *req);
-extern void __deprecated unregister_serial(int line);
-
/* Allow architectures to override entries in serial8250_ports[] at run time: */
struct uart_port; /* forward declaration */
extern int early_serial_setup(struct uart_port *port);
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 3e3c1fa..d8a023d 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -14,6 +14,9 @@
#include <linux/serial_core.h>
#include <linux/device.h>
+/*
+ * This is the platform device platform_data structure
+ */
struct plat_serial8250_port {
unsigned long iobase; /* io base address */
void __iomem *membase; /* ioremap cookie or NULL */
@@ -26,4 +29,17 @@
unsigned int flags; /* UPF_* flags */
};
+/*
+ * This should be used by drivers which want to register
+ * their own 8250 ports without registering their own
+ * platform device. Using these will make your driver
+ * dependent on the 8250 driver.
+ */
+struct uart_port;
+
+int serial8250_register_port(struct uart_port *);
+void serial8250_unregister_port(int line);
+void serial8250_suspend_port(int line);
+void serial8250_resume_port(int line);
+
#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index f6fca8f..9b12fe7 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -142,8 +142,8 @@
unsigned int (*tx_empty)(struct uart_port *);
void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
unsigned int (*get_mctrl)(struct uart_port *);
- void (*stop_tx)(struct uart_port *, unsigned int tty_stop);
- void (*start_tx)(struct uart_port *, unsigned int tty_start);
+ void (*stop_tx)(struct uart_port *);
+ void (*start_tx)(struct uart_port *);
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
@@ -360,8 +360,6 @@
*/
int uart_register_driver(struct uart_driver *uart);
void uart_unregister_driver(struct uart_driver *uart);
-void __deprecated uart_unregister_port(struct uart_driver *reg, int line);
-int __deprecated uart_register_port(struct uart_driver *reg, struct uart_port *port);
int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_match_port(struct uart_port *port1, struct uart_port *port2);
@@ -387,11 +385,11 @@
/*
* The following are helper functions for the low level drivers.
*/
-#ifdef SUPPORT_SYSRQ
static inline int
uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
struct pt_regs *regs)
{
+#ifdef SUPPORT_SYSRQ
if (port->sysrq) {
if (ch && time_before(jiffies, port->sysrq)) {
handle_sysrq(ch, regs, NULL);
@@ -400,11 +398,9 @@
}
port->sysrq = 0;
}
+#endif
return 0;
}
-#else
-#define uart_handle_sysrq_char(port,ch,regs) (0)
-#endif
/*
* We do the SysRQ and SAK checking like this...
@@ -468,13 +464,13 @@
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
- port->ops->start_tx(port, 0);
+ port->ops->start_tx(port);
uart_write_wakeup(port);
}
} else {
if (!status) {
tty->hw_stopped = 1;
- port->ops->stop_tx(port, 0);
+ port->ops->stop_tx(port);
}
}
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 42edce6..da7da9c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1251,7 +1251,7 @@
* This function converts the offset back to a struct timeval and stores
* it in stamp.
*/
-static inline void skb_get_timestamp(struct sk_buff *skb, struct timeval *stamp)
+static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
{
stamp->tv_sec = skb->tstamp.off_sec;
stamp->tv_usec = skb->tstamp.off_usec;
@@ -1270,7 +1270,7 @@
* This function converts a struct timeval to an offset and stores
* it in the skb.
*/
-static inline void skb_set_timestamp(struct sk_buff *skb, struct timeval *stamp)
+static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
{
skb->tstamp.off_sec = stamp->tv_sec - skb_tv_base.tv_sec;
skb->tstamp.off_usec = stamp->tv_usec - skb_tv_base.tv_usec;
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 80b2dfd..42a6bea 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -99,7 +99,21 @@
return __kmalloc(size, flags);
}
-extern void *kcalloc(size_t, size_t, unsigned int __nocast);
+extern void *kzalloc(size_t, unsigned int __nocast);
+
+/**
+ * kcalloc - allocate memory for an array. The memory is set to zero.
+ * @n: number of elements.
+ * @size: element size.
+ * @flags: the type of memory to allocate.
+ */
+static inline void *kcalloc(size_t n, size_t size, unsigned int __nocast flags)
+{
+ if (n != 0 && size > INT_MAX / n)
+ return NULL;
+ return kzalloc(n * size, flags);
+}
+
extern void kfree(const void *);
extern unsigned int ksize(const void *);
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index 768cbba..f56d247 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -99,6 +99,8 @@
#define SONYPI_EVENT_BATTERY_INSERT 57
#define SONYPI_EVENT_BATTERY_REMOVE 58
#define SONYPI_EVENT_FNKEY_RELEASED 59
+#define SONYPI_EVENT_WIRELESS_ON 60
+#define SONYPI_EVENT_WIRELESS_OFF 61
/* get/set brightness */
#define SONYPI_IOCGBRT _IOR('v', 0, __u8)
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 6864063..c4e3ea7 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -60,6 +60,7 @@
#define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */
struct cache_detail {
+ struct module * owner;
int hash_size;
struct cache_head ** hash_table;
rwlock_t hash_lock;
diff --git a/include/linux/swap.h b/include/linux/swap.h
index bfe3e76..3c9ff00 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -107,6 +107,8 @@
SWP_USED = (1 << 0), /* is slot in swap_info[] used? */
SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */
SWP_ACTIVE = (SWP_USED | SWP_WRITEOK),
+ /* add others here before... */
+ SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */
};
#define SWAP_CLUSTER_MAX 32
@@ -116,16 +118,13 @@
/*
* The in-memory structure used to track swap areas.
- * extent_list.prev points at the lowest-index extent. That list is
- * sorted.
*/
struct swap_info_struct {
unsigned int flags;
- spinlock_t sdev_lock;
+ int prio; /* swap priority */
struct file *swap_file;
struct block_device *bdev;
struct list_head extent_list;
- int nr_extents;
struct swap_extent *curr_swap_extent;
unsigned old_block_size;
unsigned short * swap_map;
@@ -133,10 +132,9 @@
unsigned int highest_bit;
unsigned int cluster_next;
unsigned int cluster_nr;
- int prio; /* swap priority */
- int pages;
- unsigned long max;
- unsigned long inuse_pages;
+ unsigned int pages;
+ unsigned int max;
+ unsigned int inuse_pages;
int next; /* next entry on swap list */
};
@@ -222,13 +220,7 @@
extern int remove_exclusive_swap_page(struct page *);
struct backing_dev_info;
-extern struct swap_list_t swap_list;
-extern spinlock_t swaplock;
-
-#define swap_list_lock() spin_lock(&swaplock)
-#define swap_list_unlock() spin_unlock(&swaplock)
-#define swap_device_lock(p) spin_lock(&p->sdev_lock)
-#define swap_device_unlock(p) spin_unlock(&p->sdev_lock)
+extern spinlock_t swap_lock;
/* linux/mm/thrash.c */
extern struct mm_struct * swap_token_mm;
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index d4c7db3..87b9d14 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -4,7 +4,7 @@
* the low-order bits.
*
* We arrange the `type' and `offset' fields so that `type' is at the five
- * high-order bits of the smp_entry_t and `offset' is right-aligned in the
+ * high-order bits of the swp_entry_t and `offset' is right-aligned in the
* remaining bits.
*
* swp_entry_t's are *never* stored anywhere in their arch-dependent format.
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e82be96..532a6c5 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -711,6 +711,7 @@
DEV_RAID=4,
DEV_MAC_HID=5,
DEV_SCSI=6,
+ DEV_IPMI=7,
};
/* /proc/sys/dev/cdrom */
@@ -776,6 +777,11 @@
DEV_SCSI_LOGGING_LEVEL=1,
};
+/* /proc/sys/dev/ipmi */
+enum {
+ DEV_IPMI_POWEROFF_POWERCYCLE=1,
+};
+
/* /proc/sys/abi */
enum
{
diff --git a/include/linux/time.h b/include/linux/time.h
index 5634497..c10d4c2 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -97,7 +97,6 @@
extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
extern void clock_was_set(void); // call when ever the clock is set
extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
-extern long do_nanosleep(struct timespec *t);
extern long do_utimes(char __user * filename, struct timeval * times);
struct itimerval;
extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 74fdd07..7e050a2 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -260,6 +260,29 @@
extern long pps_errcnt; /* calibration errors */
extern long pps_stbcnt; /* stability limit exceeded */
+/**
+ * ntp_clear - Clears the NTP state variables
+ *
+ * Must be called while holding a write on the xtime_lock
+ */
+static inline void ntp_clear(void)
+{
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+}
+
+/**
+ * ntp_synced - Returns 1 if the NTP status is not UNSYNC
+ *
+ */
+static inline int ntp_synced(void)
+{
+ return !(time_status & STA_UNSYNC);
+}
+
+
#ifdef CONFIG_TIME_INTERPOLATION
#define TIME_SOURCE_CPU 0
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 0320225..3df1d47 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -135,6 +135,29 @@
}
#endif
+/* sched_domains SD_ALLNODES_INIT for NUMA machines */
+#define SD_ALLNODES_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .groups = NULL, \
+ .min_interval = 64, \
+ .max_interval = 64*num_online_cpus(), \
+ .busy_factor = 128, \
+ .imbalance_pct = 133, \
+ .cache_hot_time = (10*1000000), \
+ .cache_nice_tries = 1, \
+ .busy_idx = 3, \
+ .idle_idx = 3, \
+ .newidle_idx = 0, /* unused */ \
+ .wake_idx = 0, /* unused */ \
+ .forkexec_idx = 0, /* unused */ \
+ .per_cpu_gain = 100, \
+ .flags = SD_LOAD_BALANCE, \
+ .last_balance = jiffies, \
+ .balance_interval = 64, \
+ .nr_balance_failed = 0, \
+}
+
#ifdef CONFIG_NUMA
#ifndef SD_NODE_INIT
#error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h
index 87d98d1..1d6cc22 100644
--- a/include/linux/transport_class.h
+++ b/include/linux/transport_class.h
@@ -12,11 +12,16 @@
#include <linux/device.h>
#include <linux/attribute_container.h>
+struct transport_container;
+
struct transport_class {
struct class class;
- int (*setup)(struct device *);
- int (*configure)(struct device *);
- int (*remove)(struct device *);
+ int (*setup)(struct transport_container *, struct device *,
+ struct class_device *);
+ int (*configure)(struct transport_container *, struct device *,
+ struct class_device *);
+ int (*remove)(struct transport_container *, struct device *,
+ struct class_device *);
};
#define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 6409d9c..b244f69 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -10,6 +10,14 @@
#define VM_MAP 0x00000004 /* vmap()ed pages */
/* bits [20..32] reserved for arch specific ioremap internals */
+/*
+ * Maximum alignment for ioremap() regions.
+ * Can be overriden by arch-specific value.
+ */
+#ifndef IOREMAP_MAX_ORDER
+#define IOREMAP_MAX_ORDER (7 + PAGE_SHIFT) /* 128 pages */
+#endif
+
struct vm_struct {
void *addr;
unsigned long size;
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index ae485f9..a555a0f 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -1,7 +1,7 @@
/*
* This file define a set of standard wireless extensions
*
- * Version : 18 12.3.05
+ * Version : 19 18.3.05
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
@@ -69,8 +69,6 @@
/***************************** INCLUDES *****************************/
-/* To minimise problems in user space, I might remove those headers
- * at some point. Jean II */
#include <linux/types.h> /* for "caddr_t" et al */
#include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/if.h> /* for IFNAMSIZ and co... */
@@ -82,7 +80,7 @@
* (there is some stuff that will be added in the future...)
* I just plan to increment with each new version.
*/
-#define WIRELESS_EXT 18
+#define WIRELESS_EXT 19
/*
* Changes :
@@ -197,6 +195,15 @@
* related parameters (extensible up to 4096 parameter values)
* - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
* IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
+ *
+ * V18 to V19
+ * ----------
+ * - Remove (struct iw_point *)->pointer from events and streams
+ * - Remove header includes to help user space
+ * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64
+ * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
+ * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
+ * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
*/
/**************************** CONSTANTS ****************************/
@@ -322,6 +329,7 @@
/* The first and the last (range) */
#define SIOCIWFIRST 0x8B00
#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */
+#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
/* Even : get (world access), odd : set (root access) */
#define IW_IS_SET(cmd) (!((cmd) & 0x1))
@@ -366,6 +374,7 @@
* (struct iw_pmkid_cand) */
#define IWEVFIRST 0x8C00
+#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
/* ------------------------- PRIVATE INFO ------------------------- */
/*
@@ -427,12 +436,15 @@
#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
/* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED 0x2
-#define IW_QUAL_NOISE_UPDATED 0x4
+#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */
+#define IW_QUAL_LEVEL_UPDATED 0x02
+#define IW_QUAL_NOISE_UPDATED 0x04
+#define IW_QUAL_ALL_UPDATED 0x07
+#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */
#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
#define IW_QUAL_LEVEL_INVALID 0x20
#define IW_QUAL_NOISE_INVALID 0x40
+#define IW_QUAL_ALL_INVALID 0x70
/* Frequency flags */
#define IW_FREQ_AUTO 0x00 /* Let the driver decides */
@@ -443,7 +455,7 @@
#define IW_MAX_ENCODING_SIZES 8
/* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX 32 /* 256 bits (for now) */
+#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */
/* Flags for encoding (along with the token) */
#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */
@@ -1039,12 +1051,16 @@
#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point))
#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param))
#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
-/* Note : in the case of iw_point, the extra data will come at the
- * end of the event */
+/* iw_point events are special. First, the payload (extra data) come at
+ * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
+ * we omit the pointer, so start at an offset. */
+#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
+ (char *) NULL)
+#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
+ IW_EV_POINT_OFF)
#endif /* _LINUX_WIRELESS_H */
diff --git a/include/media/id.h b/include/media/id.h
index a39a642..801ddef 100644
--- a/include/media/id.h
+++ b/include/media/id.h
@@ -34,8 +34,3 @@
#ifndef I2C_DRIVERID_SAA6752HS
# define I2C_DRIVERID_SAA6752HS I2C_DRIVERID_EXP0+8
#endif
-
-/* algorithms */
-#ifndef I2C_ALGO_SAA7134
-# define I2C_ALGO_SAA7134 0x090000
-#endif
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 926eed5..364b046 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -257,7 +257,7 @@
/* ax25_addr.c */
extern ax25_address null_ax25_address;
-extern char *ax2asc(ax25_address *);
+extern char *ax2asc(char *buf, ax25_address *);
extern ax25_address *asc2ax(char *);
extern int ax25cmp(ax25_address *, ax25_address *);
extern int ax25digicmp(ax25_digi *, ax25_digi *);
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index db09580..dc36b1b 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -20,18 +20,9 @@
*/
#ifndef IEEE80211_H
#define IEEE80211_H
-
#include <linux/if_ether.h> /* ETH_ALEN */
#include <linux/kernel.h> /* ARRAY_SIZE */
-
-#if WIRELESS_EXT < 17
-#define IW_QUAL_QUAL_INVALID 0x10
-#define IW_QUAL_LEVEL_INVALID 0x20
-#define IW_QUAL_NOISE_INVALID 0x40
-#define IW_QUAL_QUAL_UPDATED 0x1
-#define IW_QUAL_LEVEL_UPDATED 0x2
-#define IW_QUAL_NOISE_UPDATED 0x4
-#endif
+#include <linux/wireless.h>
#define IEEE80211_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
@@ -47,51 +38,22 @@
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
struct ieee80211_hdr {
- u16 frame_ctl;
- u16 duration_id;
+ __le16 frame_ctl;
+ __le16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
- u16 seq_ctl;
+ __le16 seq_ctl;
u8 addr4[ETH_ALEN];
} __attribute__ ((packed));
struct ieee80211_hdr_3addr {
- u16 frame_ctl;
- u16 duration_id;
+ __le16 frame_ctl;
+ __le16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
- u16 seq_ctl;
-} __attribute__ ((packed));
-
-enum eap_type {
- EAP_PACKET = 0,
- EAPOL_START,
- EAPOL_LOGOFF,
- EAPOL_KEY,
- EAPOL_ENCAP_ASF_ALERT
-};
-
-static const char *eap_types[] = {
- [EAP_PACKET] = "EAP-Packet",
- [EAPOL_START] = "EAPOL-Start",
- [EAPOL_LOGOFF] = "EAPOL-Logoff",
- [EAPOL_KEY] = "EAPOL-Key",
- [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
-};
-
-static inline const char *eap_get_type(int type)
-{
- return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
-}
-
-struct eapol {
- u8 snap[6];
- u16 ethertype;
- u8 version;
- u8 type;
- u16 length;
+ __le16 seq_ctl;
} __attribute__ ((packed));
#define IEEE80211_1ADDR_LEN 10
@@ -104,7 +66,7 @@
#define MAX_FRAG_THRESHOLD 2346U
/* Frame control field constants */
-#define IEEE80211_FCTL_VERS 0x0002
+#define IEEE80211_FCTL_VERS 0x0003
#define IEEE80211_FCTL_FTYPE 0x000c
#define IEEE80211_FCTL_STYPE 0x00f0
#define IEEE80211_FCTL_TODS 0x0100
@@ -112,8 +74,8 @@
#define IEEE80211_FCTL_MOREFRAGS 0x0400
#define IEEE80211_FCTL_RETRY 0x0800
#define IEEE80211_FCTL_PM 0x1000
-#define IEEE80211_FCTL_MOREDATA 0x2000
-#define IEEE80211_FCTL_WEP 0x4000
+#define IEEE80211_FCTL_MOREDATA 0x2000
+#define IEEE80211_FCTL_PROTECTED 0x4000
#define IEEE80211_FCTL_ORDER 0x8000
#define IEEE80211_FTYPE_MGMT 0x0000
@@ -132,6 +94,7 @@
#define IEEE80211_STYPE_DISASSOC 0x00A0
#define IEEE80211_STYPE_AUTH 0x00B0
#define IEEE80211_STYPE_DEAUTH 0x00C0
+#define IEEE80211_STYPE_ACTION 0x00D0
/* control */
#define IEEE80211_STYPE_PSPOLL 0x00A0
@@ -167,8 +130,19 @@
#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IEEE80211_DEBUG */
+
+/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+/* escape_essid() is intended to be used in debug (and possibly error)
+ * messages. It should never be used for passing essid to user space. */
+const char *escape_essid(const char *essid, u8 essid_len);
+
+
/*
- * To use the debug system;
+ * To use the debug system:
*
* If you are defining a new debug classification, simply add it to the #define
* list here in the form of:
@@ -184,11 +158,11 @@
*
* To add your debug level to the list of levels seen when you perform
*
- * % cat /proc/net/ipw/debug_level
+ * % cat /proc/net/ieee80211/debug_level
*
- * you simply need to add your entry to the ipw_debug_levels array.
+ * you simply need to add your entry to the ieee80211_debug_level array.
*
- * If you do not see debug_level in /proc/net/ipw then you do not have
+ * If you do not see debug_level in /proc/net/ieee80211 then you do not have
* CONFIG_IEEE80211_DEBUG defined in your kernel configuration
*
*/
@@ -199,7 +173,6 @@
#define IEEE80211_DL_STATE (1<<3)
#define IEEE80211_DL_MGMT (1<<4)
#define IEEE80211_DL_FRAG (1<<5)
-#define IEEE80211_DL_EAP (1<<6)
#define IEEE80211_DL_DROP (1<<7)
#define IEEE80211_DL_TX (1<<8)
@@ -214,7 +187,6 @@
#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
-#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
@@ -223,9 +195,9 @@
#include <linux/if_arp.h> /* ARPHRD_ETHER */
#ifndef WIRELESS_SPY
-#define WIRELESS_SPY // enable iwspy support
+#define WIRELESS_SPY /* enable iwspy support */
#endif
-#include <net/iw_handler.h> // new driver API
+#include <net/iw_handler.h> /* new driver API */
#ifndef ETH_P_PAE
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
@@ -252,6 +224,7 @@
#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
@@ -264,7 +237,7 @@
#define WLAN_AUTH_CHALLENGE_LEN 128
-#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_ESS (1<<0)
#define WLAN_CAPABILITY_IBSS (1<<1)
#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
@@ -272,34 +245,72 @@
#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
#define WLAN_CAPABILITY_PBCC (1<<6)
#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
+#define WLAN_CAPABILITY_OSSS_OFDM (1<<13)
/* Status codes */
-#define WLAN_STATUS_SUCCESS 0
-#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
-#define WLAN_STATUS_CAPS_UNSUPPORTED 10
-#define WLAN_STATUS_REASSOC_NO_ASSOC 11
-#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
-#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
-#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
-#define WLAN_STATUS_CHALLENGE_FAIL 15
-#define WLAN_STATUS_AUTH_TIMEOUT 16
-#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
-#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* 802.11b */
-#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+enum ieee80211_statuscode {
+ WLAN_STATUS_SUCCESS = 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
+ WLAN_STATUS_CAPS_UNSUPPORTED = 10,
+ WLAN_STATUS_REASSOC_NO_ASSOC = 11,
+ WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
+ WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
+ WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
+ WLAN_STATUS_CHALLENGE_FAIL = 15,
+ WLAN_STATUS_AUTH_TIMEOUT = 16,
+ WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+ WLAN_STATUS_ASSOC_DENIED_RATES = 18,
+ /* 802.11b */
+ WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
+ WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
+ WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
+ /* 802.11h */
+ WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
+ WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
+ WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
+ /* 802.11g */
+ WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
+ WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+ /* 802.11i */
+ WLAN_STATUS_INVALID_IE = 40,
+ WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
+ WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
+ WLAN_STATUS_INVALID_AKMP = 43,
+ WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
+ WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
+ WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+};
/* Reason codes */
-#define WLAN_REASON_UNSPECIFIED 1
-#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
-#define WLAN_REASON_DEAUTH_LEAVING 3
-#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
-#define WLAN_REASON_DISASSOC_AP_BUSY 5
-#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
-#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
-#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
-#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+enum ieee80211_reasoncode {
+ WLAN_REASON_UNSPECIFIED = 1,
+ WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+ WLAN_REASON_DEAUTH_LEAVING = 3,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
+ WLAN_REASON_DISASSOC_AP_BUSY = 5,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+ WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
+ WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+ /* 802.11h */
+ WLAN_REASON_DISASSOC_BAD_POWER = 10,
+ WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
+ /* 802.11i */
+ WLAN_REASON_INVALID_IE = 13,
+ WLAN_REASON_MIC_FAILURE = 14,
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
+ WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
+ WLAN_REASON_IE_DIFFERENT = 17,
+ WLAN_REASON_INVALID_GROUP_CIPHER = 18,
+ WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
+ WLAN_REASON_INVALID_AKMP = 20,
+ WLAN_REASON_UNSUPP_RSN_VERSION = 21,
+ WLAN_REASON_INVALID_RSN_IE_CAP = 22,
+ WLAN_REASON_IEEE8021X_FAILED = 23,
+ WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+};
#define IEEE80211_STATMASK_SIGNAL (1<<0)
@@ -426,9 +437,7 @@
struct ieee80211_device;
-#if 0 /* for later */
#include "ieee80211_crypt.h"
-#endif
#define SEC_KEY_1 (1<<0)
#define SEC_KEY_2 (1<<1)
@@ -480,17 +489,34 @@
#define BEACON_PROBE_SSID_ID_POSITION 12
/* Management Frame Information Element Types */
-#define MFIE_TYPE_SSID 0
-#define MFIE_TYPE_RATES 1
-#define MFIE_TYPE_FH_SET 2
-#define MFIE_TYPE_DS_SET 3
-#define MFIE_TYPE_CF_SET 4
-#define MFIE_TYPE_TIM 5
-#define MFIE_TYPE_IBSS_SET 6
-#define MFIE_TYPE_CHALLENGE 16
-#define MFIE_TYPE_RSN 48
-#define MFIE_TYPE_RATES_EX 50
-#define MFIE_TYPE_GENERIC 221
+enum ieee80211_mfie {
+ MFIE_TYPE_SSID = 0,
+ MFIE_TYPE_RATES = 1,
+ MFIE_TYPE_FH_SET = 2,
+ MFIE_TYPE_DS_SET = 3,
+ MFIE_TYPE_CF_SET = 4,
+ MFIE_TYPE_TIM = 5,
+ MFIE_TYPE_IBSS_SET = 6,
+ MFIE_TYPE_COUNTRY = 7,
+ MFIE_TYPE_HOP_PARAMS = 8,
+ MFIE_TYPE_HOP_TABLE = 9,
+ MFIE_TYPE_REQUEST = 10,
+ MFIE_TYPE_CHALLENGE = 16,
+ MFIE_TYPE_POWER_CONSTRAINT = 32,
+ MFIE_TYPE_POWER_CAPABILITY = 33,
+ MFIE_TYPE_TPC_REQUEST = 34,
+ MFIE_TYPE_TPC_REPORT = 35,
+ MFIE_TYPE_SUPP_CHANNELS = 36,
+ MFIE_TYPE_CSA = 37,
+ MFIE_TYPE_MEASURE_REQUEST = 38,
+ MFIE_TYPE_MEASURE_REPORT = 39,
+ MFIE_TYPE_QUIET = 40,
+ MFIE_TYPE_IBSS_DFS = 41,
+ MFIE_TYPE_ERP_INFO = 42,
+ MFIE_TYPE_RSN = 48,
+ MFIE_TYPE_RATES_EX = 50,
+ MFIE_TYPE_GENERIC = 221,
+};
struct ieee80211_info_element_hdr {
u8 id;
@@ -522,9 +548,9 @@
struct ieee80211_authentication {
struct ieee80211_hdr_3addr header;
- u16 algorithm;
- u16 transaction;
- u16 status;
+ __le16 algorithm;
+ __le16 transaction;
+ __le16 status;
struct ieee80211_info_element info_element;
} __attribute__ ((packed));
@@ -532,23 +558,23 @@
struct ieee80211_probe_response {
struct ieee80211_hdr_3addr header;
u32 time_stamp[2];
- u16 beacon_interval;
- u16 capability;
+ __le16 beacon_interval;
+ __le16 capability;
struct ieee80211_info_element info_element;
} __attribute__ ((packed));
struct ieee80211_assoc_request_frame {
- u16 capability;
- u16 listen_interval;
+ __le16 capability;
+ __le16 listen_interval;
u8 current_ap[ETH_ALEN];
struct ieee80211_info_element info_element;
} __attribute__ ((packed));
struct ieee80211_assoc_response_frame {
struct ieee80211_hdr_3addr header;
- u16 capability;
- u16 status;
- u16 aid;
+ __le16 capability;
+ __le16 status;
+ __le16 aid;
struct ieee80211_info_element info_element; /* supported rates */
} __attribute__ ((packed));
@@ -563,7 +589,7 @@
};
-/* SWEEP TABLE ENTRIES NUMBER*/
+/* SWEEP TABLE ENTRIES NUMBER */
#define MAX_SWEEP_TAB_ENTRIES 42
#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
@@ -624,8 +650,6 @@
#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
#define DEFAULT_FTS 2346
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
#define CFG_IEEE80211_RESERVE_FCS (1<<0)
@@ -793,8 +817,6 @@
extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
/* ieee80211_tx.c */
-
-
extern int ieee80211_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
@@ -807,7 +829,7 @@
struct ieee80211_hdr *header,
struct ieee80211_rx_stats *stats);
-/* iee80211_wx.c */
+/* ieee80211_wx.c */
extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key);
@@ -829,28 +851,5 @@
return ieee->scans;
}
-static inline const char *escape_essid(const char *essid, u8 essid_len) {
- static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- const char *s = essid;
- char *d = escaped;
-
- if (ieee80211_is_empty_essid(essid, essid_len)) {
- memcpy(escaped, "<hidden>", sizeof("<hidden>"));
- return escaped;
- }
-
- essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
- while (essid_len--) {
- if (*s == '\0') {
- *d++ = '\\';
- *d++ = '0';
- s++;
- } else {
- *d++ = *s++;
- }
- }
- *d = '\0';
- return escaped;
-}
#endif /* IEEE80211_H */
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
new file mode 100644
index 0000000..b58a3bc
--- /dev/null
+++ b/include/net/ieee80211_crypt.h
@@ -0,0 +1,86 @@
+/*
+ * Original code based on Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ *
+ * Copyright (c) 2004, Intel 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. See README and COPYING for
+ * more details.
+ */
+
+/*
+ * This file defines the interface to the ieee80211 crypto module.
+ */
+#ifndef IEEE80211_CRYPT_H
+#define IEEE80211_CRYPT_H
+
+#include <linux/skbuff.h>
+
+struct ieee80211_crypto_ops {
+ const char *name;
+
+ /* init new crypto context (e.g., allocate private data space,
+ * select IV, etc.); returns NULL on failure or pointer to allocated
+ * private data on success */
+ void * (*init)(int keyidx);
+
+ /* deinitialize crypto context and free allocated private data */
+ void (*deinit)(void *priv);
+
+ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
+ * value from decrypt_mpdu is passed as the keyidx value for
+ * decrypt_msdu. skb must have enough head and tail room for the
+ * encryption; if not, error will be returned; these functions are
+ * called for all MPDUs (i.e., fragments).
+ */
+ int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv);
+ int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv);
+
+ /* These functions are called for full MSDUs, i.e. full frames.
+ * These can be NULL if full MSDU operations are not needed. */
+ int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv);
+ int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len,
+ void *priv);
+
+ int (*set_key)(void *key, int len, u8 *seq, void *priv);
+ int (*get_key)(void *key, int len, u8 *seq, void *priv);
+
+ /* procfs handler for printing out key information and possible
+ * statistics */
+ char * (*print_stats)(char *p, void *priv);
+
+ /* maximum number of bytes added by encryption; encrypt buf is
+ * allocated with extra_prefix_len bytes, copy of in_buf, and
+ * extra_postfix_len; encrypt need not use all this space, but
+ * the result must start at the beginning of the buffer and correct
+ * length must be returned */
+ int extra_prefix_len, extra_postfix_len;
+
+ struct module *owner;
+};
+
+struct ieee80211_crypt_data {
+ struct list_head list; /* delayed deletion list */
+ struct ieee80211_crypto_ops *ops;
+ void *priv;
+ atomic_t refcnt;
+};
+
+int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops);
+int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops);
+struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name);
+void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int);
+void ieee80211_crypt_deinit_handler(unsigned long);
+void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
+ struct ieee80211_crypt_data **crypt);
+
+#endif
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 7a3c437..e426641 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -958,7 +958,7 @@
*/
#define IP_VS_FWD_METHOD(cp) (cp->flags & IP_VS_CONN_F_FWD_MASK)
-extern __inline__ char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
{
char fwd;
diff --git a/include/net/irda/irlan_filter.h b/include/net/irda/irlan_filter.h
index 3afeb6c..492deda 100644
--- a/include/net/irda/irlan_filter.h
+++ b/include/net/irda/irlan_filter.h
@@ -28,6 +28,6 @@
void irlan_check_command_param(struct irlan_cb *self, char *param,
char *value);
void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb);
-int irlan_print_filter(struct seq_file *seq, int filter_type);
+void irlan_print_filter(struct seq_file *seq, int filter_type);
#endif /* IRLAN_FILTER_H */
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index 44edd48..d67c839 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -1,10 +1,10 @@
/*
* This file define the new driver API for Wireless Extensions
*
- * Version : 6 21.6.04
+ * Version : 7 18.3.05
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2005 Jean Tourrilhes, All Rights Reserved.
*/
#ifndef _IW_HANDLER_H
@@ -207,7 +207,7 @@
* will be needed...
* I just plan to increment with each new version.
*/
-#define IW_HANDLER_VERSION 6
+#define IW_HANDLER_VERSION 7
/*
* Changes :
@@ -232,6 +232,13 @@
* - Remove spy #ifdef, they are always on -> cleaner code
* - Add IW_DESCR_FLAG_NOMAX flag for very large requests
* - Start migrating get_wireless_stats to struct iw_handler_def
+ *
+ * V6 to V7
+ * --------
+ * - Add struct ieee80211_device pointer in struct iw_public_data
+ * - Remove (struct iw_point *)->pointer from events and streams
+ * - Remove spy_offset from struct iw_handler_def
+ * - Add "check" version of event macros for ieee802.11 stack
*/
/**************************** CONSTANTS ****************************/
@@ -334,9 +341,6 @@
* We will automatically export that to user space... */
const struct iw_priv_args * private_args;
- /* This field will be *removed* in the next version of WE */
- long spy_offset; /* DO NOT USE */
-
/* New location of get_wireless_stats, to de-bloat struct net_device.
* The old pointer in struct net_device will be gradually phased
* out, and drivers are encouraged to use this one... */
@@ -400,16 +404,21 @@
/* --------------------- DEVICE WIRELESS DATA --------------------- */
/*
* This is all the wireless data specific to a device instance that
- * is managed by the core of Wireless Extensions.
+ * is managed by the core of Wireless Extensions or the 802.11 layer.
* We only keep pointer to those structures, so that a driver is free
* to share them between instances.
* This structure should be initialised before registering the device.
* Access to this data follow the same rules as any other struct net_device
* data (i.e. valid as long as struct net_device exist, same locking rules).
*/
+/* Forward declaration */
+struct ieee80211_device;
+/* The struct */
struct iw_public_data {
/* Driver enhanced spy support */
- struct iw_spy_data * spy_data;
+ struct iw_spy_data * spy_data;
+ /* Structure managed by the in-kernel IEEE 802.11 layer */
+ struct ieee80211_device * ieee80211;
};
/**************************** PROTOTYPES ****************************/
@@ -424,7 +433,7 @@
extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
int length);
-/* Handle IOCTLs, called in net/code/dev.c */
+/* Handle IOCTLs, called in net/core/dev.c */
extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
/* Second : functions that may be called by driver modules */
@@ -479,7 +488,7 @@
int event_len) /* Real size of payload */
{
/* Check if it's possible */
- if((stream + event_len) < ends) {
+ if(likely((stream + event_len) < ends)) {
iwe->len = event_len;
memcpy(stream, (char *) iwe, event_len);
stream += event_len;
@@ -495,14 +504,17 @@
static inline char *
iwe_stream_add_point(char * stream, /* Stream of events */
char * ends, /* End of stream */
- struct iw_event *iwe, /* Payload */
- char * extra)
+ struct iw_event *iwe, /* Payload length + flags */
+ char * extra) /* More payload */
{
int event_len = IW_EV_POINT_LEN + iwe->u.data.length;
/* Check if it's possible */
- if((stream + event_len) < ends) {
+ if(likely((stream + event_len) < ends)) {
iwe->len = event_len;
- memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
+ memcpy(stream, (char *) iwe, IW_EV_LCP_LEN);
+ memcpy(stream + IW_EV_LCP_LEN,
+ ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+ IW_EV_POINT_LEN - IW_EV_LCP_LEN);
memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
stream += event_len;
}
@@ -526,7 +538,7 @@
event_len -= IW_EV_LCP_LEN;
/* Check if it's possible */
- if((value + event_len) < ends) {
+ if(likely((value + event_len) < ends)) {
/* Add new value */
memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
value += event_len;
@@ -537,4 +549,85 @@
return value;
}
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an Wireless Event to a stream of events.
+ * Same as above, with explicit error check...
+ */
+static inline char *
+iwe_stream_check_add_event(char * stream, /* Stream of events */
+ char * ends, /* End of stream */
+ struct iw_event *iwe, /* Payload */
+ int event_len, /* Size of payload */
+ int * perr) /* Error report */
+{
+ /* Check if it's possible, set error if not */
+ if(likely((stream + event_len) < ends)) {
+ iwe->len = event_len;
+ memcpy(stream, (char *) iwe, event_len);
+ stream += event_len;
+ } else
+ *perr = -E2BIG;
+ return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an short Wireless Event containing a pointer to a
+ * stream of events.
+ * Same as above, with explicit error check...
+ */
+static inline char *
+iwe_stream_check_add_point(char * stream, /* Stream of events */
+ char * ends, /* End of stream */
+ struct iw_event *iwe, /* Payload length + flags */
+ char * extra, /* More payload */
+ int * perr) /* Error report */
+{
+ int event_len = IW_EV_POINT_LEN + iwe->u.data.length;
+ /* Check if it's possible */
+ if(likely((stream + event_len) < ends)) {
+ iwe->len = event_len;
+ memcpy(stream, (char *) iwe, IW_EV_LCP_LEN);
+ memcpy(stream + IW_EV_LCP_LEN,
+ ((char *) iwe) + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+ IW_EV_POINT_LEN - IW_EV_LCP_LEN);
+ memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
+ stream += event_len;
+ } else
+ *perr = -E2BIG;
+ return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add a value to a Wireless Event in a stream of events.
+ * Be careful, this one is tricky to use properly :
+ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
+ * Same as above, with explicit error check...
+ */
+static inline char *
+iwe_stream_check_add_value(char * event, /* Event in the stream */
+ char * value, /* Value in event */
+ char * ends, /* End of stream */
+ struct iw_event *iwe, /* Payload */
+ int event_len, /* Size of payload */
+ int * perr) /* Error report */
+{
+ /* Don't duplicate LCP */
+ event_len -= IW_EV_LCP_LEN;
+
+ /* Check if it's possible */
+ if(likely((value + event_len) < ends)) {
+ /* Add new value */
+ memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+ value += event_len;
+ /* Patch LCP */
+ iwe->len = value - event;
+ memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
+ } else
+ *perr = -E2BIG;
+ return value;
+}
+
#endif /* _IW_HANDLER_H */
diff --git a/include/net/sock.h b/include/net/sock.h
index 312cb25..8c48fbe 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -709,6 +709,12 @@
sk_stream_mem_schedule(sk, skb->truesize, 1);
}
+static inline int sk_stream_wmem_schedule(struct sock *sk, int size)
+{
+ return size <= sk->sk_forward_alloc ||
+ sk_stream_mem_schedule(sk, size, 0);
+}
+
/* Used by processes to "lock" a socket state, so that
* interrupts and bottom half handlers won't change it
* from under us. It essentially blocks any incoming
@@ -1203,8 +1209,7 @@
skb = alloc_skb_fclone(size + hdr_len, gfp);
if (skb) {
skb->truesize += mem;
- if (sk->sk_forward_alloc >= (int)skb->truesize ||
- sk_stream_mem_schedule(sk, skb->truesize, 0)) {
+ if (sk_stream_wmem_schedule(sk, skb->truesize)) {
skb_reserve(skb, hdr_len);
return skb;
}
@@ -1227,10 +1232,8 @@
{
struct page *page = NULL;
- if (sk->sk_forward_alloc >= (int)PAGE_SIZE ||
- sk_stream_mem_schedule(sk, PAGE_SIZE, 0))
- page = alloc_pages(sk->sk_allocation, 0);
- else {
+ page = alloc_pages(sk->sk_allocation, 0);
+ if (!page) {
sk->sk_prot->enter_memory_pressure();
sk_stream_moderate_sndbuf(sk);
}
@@ -1374,9 +1377,10 @@
#ifdef CONFIG_SYSCTL
extern struct ctl_table core_table[];
-extern int sysctl_optmem_max;
#endif
+extern int sysctl_optmem_max;
+
extern __u32 sysctl_wmem_default;
extern __u32 sysctl_rmem_default;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index d6bcf13..97af77c 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -454,6 +454,7 @@
extern void tcp_xmit_retransmit_queue(struct sock *);
extern void tcp_simple_retransmit(struct sock *);
extern int tcp_trim_head(struct sock *, struct sk_buff *, u32);
+extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int);
extern void tcp_send_probe0(struct sock *);
extern void tcp_send_partial(struct sock *);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 9957f16..bed4b7c 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -51,12 +51,16 @@
* printk's to use ->pid, so that we can kill this field.
*/
unsigned long serial_number;
+ /*
+ * This is set to jiffies as it was when the command was first
+ * allocated. It is used to time how long the command has
+ * been outstanding
+ */
+ unsigned long jiffies_at_alloc;
int retries;
int allowed;
int timeout_per_command;
- int timeout_total;
- int timeout;
unsigned char cmd_len;
unsigned char old_cmd_len;
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index 12e9093..b090a11 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -3,8 +3,10 @@
struct scsi_cmnd;
struct scsi_request;
+struct scsi_sense_hdr;
extern void scsi_print_command(struct scsi_cmnd *);
+extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
extern void __scsi_print_command(unsigned char *);
extern void scsi_print_sense(const char *, struct scsi_cmnd *);
extern void scsi_print_req_sense(const char *, struct scsi_request *);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 835af8e..da63722 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -8,8 +8,17 @@
struct request_queue;
struct scsi_cmnd;
-struct scsi_mode_data;
struct scsi_lun;
+struct scsi_sense_hdr;
+
+struct scsi_mode_data {
+ __u32 length;
+ __u16 block_descriptor_length;
+ __u8 medium_type;
+ __u8 device_specific;
+ __u8 header_length;
+ __u8 longlba:1;
+};
/*
* sdev state: If you alter this, you also need to alter scsi_sysfs.c
@@ -228,7 +237,8 @@
extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
unsigned char *buffer, int len, int timeout,
- int retries, struct scsi_mode_data *data);
+ int retries, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *);
extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
int retries);
extern int scsi_device_set_state(struct scsi_device *sdev,
@@ -247,6 +257,14 @@
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
+extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ unsigned char *sense, int timeout, int retries,
+ int flag);
+extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ struct scsi_sense_hdr *, int timeout, int retries);
+
static inline int scsi_device_online(struct scsi_device *sdev)
{
return sdev->sdev_state != SDEV_OFFLINE;
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 80557f8..fabd879 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -26,10 +26,15 @@
u8 additional_length; /* always 0 for fixed sense format */
};
+static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
+{
+ if (!sshdr)
+ return 0;
-extern void scsi_add_timer(struct scsi_cmnd *, int,
- void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
+ return (sshdr->response_code & 0x70) == 0x70;
+}
+
+
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
extern int scsi_block_when_processing_errors(struct scsi_device *);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 81d5234..916144b 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -429,12 +429,15 @@
};
/*
- * shost states
+ * shost state: If you alter this, you also need to alter scsi_sysfs.c
+ * (for the ascii descriptions) and the state model enforcer:
+ * scsi_host_set_state()
*/
-enum {
- SHOST_ADD,
- SHOST_DEL,
+enum scsi_host_state {
+ SHOST_CREATED = 1,
+ SHOST_RUNNING,
SHOST_CANCEL,
+ SHOST_DEL,
SHOST_RECOVERY,
};
@@ -464,12 +467,10 @@
struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits
on this. */
- struct completion * eh_notify; /* wait for eh to begin or end */
struct semaphore * eh_action; /* Wait for specific actions on the
host. */
unsigned int eh_active:1; /* Indicates the eh thread is awake and active if
this is true. */
- unsigned int eh_kill:1; /* set when killing the eh thread */
wait_queue_head_t host_wait;
struct scsi_host_template *hostt;
struct scsi_transport_template *transportt;
@@ -575,7 +576,7 @@
unsigned int irq;
- unsigned long shost_state;
+ enum scsi_host_state shost_state;
/* ldm bits */
struct device shost_gendev;
@@ -633,6 +634,7 @@
extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
extern void scsi_host_put(struct Scsi_Host *t);
extern struct Scsi_Host *scsi_host_lookup(unsigned short);
+extern const char *scsi_host_state_name(enum scsi_host_state);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
@@ -646,6 +648,15 @@
return shost->shost_gendev.parent;
}
+/**
+ * scsi_host_scan_allowed - Is scanning of this host allowed
+ * @shost: Pointer to Scsi_Host.
+ **/
+static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)
+{
+ return shost->shost_state == SHOST_RUNNING;
+}
+
extern void scsi_unblock_requests(struct Scsi_Host *);
extern void scsi_block_requests(struct Scsi_Host *);
@@ -663,5 +674,6 @@
/* legacy interfaces */
extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
extern void scsi_unregister(struct Scsi_Host *);
+extern int scsi_host_set_state(struct Scsi_Host *, enum scsi_host_state);
#endif /* _SCSI_SCSI_HOST_H */
diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h
index 9871940..6a14002 100644
--- a/include/scsi/scsi_request.h
+++ b/include/scsi/scsi_request.h
@@ -54,20 +54,4 @@
void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
-
-struct scsi_mode_data {
- __u32 length;
- __u16 block_descriptor_length;
- __u8 medium_type;
- __u8 device_specific;
- __u8 header_length;
- __u8 longlba:1;
-};
-
-extern int __scsi_mode_sense(struct scsi_request *SRpnt, int dbd,
- int modepage, unsigned char *buffer, int len,
- int timeout, int retries,
- struct scsi_mode_data *data);
-
-
#endif /* _SCSI_SCSI_REQUEST_H */
diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
index a30d6cd..6bdc4af 100644
--- a/include/scsi/scsi_transport_spi.h
+++ b/include/scsi/scsi_transport_spi.h
@@ -39,6 +39,7 @@
unsigned int rd_strm:1; /* Read streaming enabled */
unsigned int rti:1; /* Retain Training Information */
unsigned int pcomp_en:1;/* Precompensation enabled */
+ unsigned int hold_mcs:1;/* Hold Margin Control Settings */
unsigned int initial_dv:1; /* DV done to this target yet */
unsigned long flags; /* flags field for drivers to use */
/* Device Properties fields */
@@ -78,6 +79,7 @@
#define spi_rd_strm(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rd_strm)
#define spi_rti(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rti)
#define spi_pcomp_en(x) (((struct spi_transport_attrs *)&(x)->starget_data)->pcomp_en)
+#define spi_hold_mcs(x) (((struct spi_transport_attrs *)&(x)->starget_data)->hold_mcs)
#define spi_initial_dv(x) (((struct spi_transport_attrs *)&(x)->starget_data)->initial_dv)
#define spi_support_sync(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_sync)
@@ -114,8 +116,11 @@
void (*set_rti)(struct scsi_target *, int);
void (*get_pcomp_en)(struct scsi_target *);
void (*set_pcomp_en)(struct scsi_target *, int);
+ void (*get_hold_mcs)(struct scsi_target *);
+ void (*set_hold_mcs)(struct scsi_target *, int);
void (*get_signalling)(struct Scsi_Host *);
void (*set_signalling)(struct Scsi_Host *, enum spi_signal_type);
+ int (*deny_binding)(struct scsi_target *);
/* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
@@ -130,6 +135,7 @@
unsigned long show_rd_strm:1;
unsigned long show_rti:1;
unsigned long show_pcomp_en:1;
+ unsigned long show_hold_mcs:1;
};
struct scsi_transport_template *spi_attach_transport(struct spi_function_template *);
diff --git a/include/sound/core.h b/include/sound/core.h
index f72b3ef..3dc41fd 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -291,12 +291,14 @@
int snd_memory_info_init(void);
int snd_memory_info_done(void);
void *snd_hidden_kmalloc(size_t size, unsigned int __nocast flags);
+void *snd_hidden_kzalloc(size_t size, unsigned int __nocast flags);
void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags);
void snd_hidden_kfree(const void *obj);
void *snd_hidden_vmalloc(unsigned long size);
void snd_hidden_vfree(void *obj);
char *snd_hidden_kstrdup(const char *s, unsigned int __nocast flags);
#define kmalloc(size, flags) snd_hidden_kmalloc(size, flags)
+#define kzalloc(size, flags) snd_hidden_kzalloc(size, flags)
#define kcalloc(n, size, flags) snd_hidden_kcalloc(n, size, flags)
#define kfree(obj) snd_hidden_kfree(obj)
#define vmalloc(size) snd_hidden_vmalloc(size)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index fa23ebf..389e8eb 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -903,7 +903,7 @@
int snd_pcm_format_linear(snd_pcm_format_t format);
int snd_pcm_format_little_endian(snd_pcm_format_t format);
int snd_pcm_format_big_endian(snd_pcm_format_t format);
-/**
+/*
* snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
* @format: the format to check
*
diff --git a/include/video/pmag-ba-fb.h b/include/video/pmag-ba-fb.h
index cebef07..fceb6c0 100644
--- a/include/video/pmag-ba-fb.h
+++ b/include/video/pmag-ba-fb.h
@@ -1,24 +1,27 @@
/*
- * linux/drivers/video/pmag-ba-fb.h
+ * linux/include/video/pmag-ba-fb.h
*
- * TurboChannel PMAG-BA framebuffer card support,
- * Copyright (C) 1999,2000,2001 by
- * Michael Engel <engel@unix-ag.org>,
- * Karsten Merker <merker@linuxtag.org>
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
+ * TURBOchannel PMAG-BA Color Frame Buffer (CFB) card support,
+ * Copyright (C) 1999, 2000, 2001 by
+ * Michael Engel <engel@unix-ag.org>,
+ * Karsten Merker <merker@linuxtag.org>
+ * Copyright (c) 2005 Maciej W. Rozycki
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
*/
-/*
- * Bt459 RAM DAC register base offset (rel. to TC slot base address)
- */
+/* IOmem resource offsets. */
+#define PMAG_BA_FBMEM 0x000000 /* frame buffer */
+#define PMAG_BA_BT459 0x200000 /* Bt459 RAMDAC */
+#define PMAG_BA_IRQ 0x300000 /* IRQ acknowledge */
+#define PMAG_BA_ROM 0x380000 /* REX option ROM */
+#define PMAG_BA_BT438 0x380000 /* Bt438 clock chip reset */
+#define PMAG_BA_SIZE 0x400000 /* address space size */
-#define PMAG_BA_BT459_OFFSET 0x00200000
-
-/*
- * Begin of PMAG-BA framebuffer memory relative to TC slot address,
- * resolution is 1024x864x8
- */
-
-#define PMAG_BA_ONBOARD_FBMEM_OFFSET 0x00000000
+/* Bt459 register offsets, byte-wide registers. */
+#define BT459_ADDR_LO 0x0 /* address low */
+#define BT459_ADDR_HI 0x4 /* address high */
+#define BT459_DATA 0x8 /* data window register */
+#define BT459_CMAP 0xc /* color map window register */
diff --git a/include/video/pmagb-b-fb.h b/include/video/pmagb-b-fb.h
index 87b81a5..7539b90 100644
--- a/include/video/pmagb-b-fb.h
+++ b/include/video/pmagb-b-fb.h
@@ -1,32 +1,58 @@
/*
- * linux/drivers/video/pmagb-b-fb.h
+ * linux/include/video/pmagb-b-fb.h
*
- * TurboChannel PMAGB-B framebuffer card support,
- * Copyright (C) 1999, 2000, 2001 by
- * Michael Engel <engel@unix-ag.org> and
- * Karsten Merker <merker@linuxtag.org>
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
+ * TURBOchannel PMAGB-B Smart Frame Buffer (SFB) card support,
+ * Copyright (C) 1999, 2000, 2001 by
+ * Michael Engel <engel@unix-ag.org> and
+ * Karsten Merker <merker@linuxtag.org>
+ * Copyright (c) 2005 Maciej W. Rozycki
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
*/
+/* IOmem resource offsets. */
+#define PMAGB_B_ROM 0x000000 /* REX option ROM */
+#define PMAGB_B_SFB 0x100000 /* SFB ASIC */
+#define PMAGB_B_GP0 0x140000 /* general purpose output 0 */
+#define PMAGB_B_GP1 0x180000 /* general purpose output 1 */
+#define PMAGB_B_BT459 0x1c0000 /* Bt459 RAMDAC */
+#define PMAGB_B_FBMEM 0x200000 /* frame buffer */
+#define PMAGB_B_SIZE 0x400000 /* address space size */
-/*
- * Bt459 RAM DAC register base offset (rel. to TC slot base address)
- */
-#define PMAGB_B_BT459_OFFSET 0x001C0000
+/* IOmem register offsets. */
+#define SFB_REG_VID_HOR 0x64 /* video horizontal setup */
+#define SFB_REG_VID_VER 0x68 /* video vertical setup */
+#define SFB_REG_VID_BASE 0x6c /* video base address */
+#define SFB_REG_TCCLK_COUNT 0x78 /* TURBOchannel clock count */
+#define SFB_REG_VIDCLK_COUNT 0x7c /* video clock count */
-/*
- * Begin of PMAGB-B framebuffer memory, resolution is configurable:
- * 1024x864x8 or 1280x1024x8, settable by jumper on the card
- */
-#define PMAGB_B_ONBOARD_FBMEM_OFFSET 0x00201000
+/* Video horizontal setup register constants. All bits are r/w. */
+#define SFB_VID_HOR_BP_SHIFT 0x15 /* back porch */
+#define SFB_VID_HOR_BP_MASK 0x7f
+#define SFB_VID_HOR_SYN_SHIFT 0x0e /* sync pulse */
+#define SFB_VID_HOR_SYN_MASK 0x7f
+#define SFB_VID_HOR_FP_SHIFT 0x09 /* front porch */
+#define SFB_VID_HOR_FP_MASK 0x1f
+#define SFB_VID_HOR_PIX_SHIFT 0x00 /* active video */
+#define SFB_VID_HOR_PIX_MASK 0x1ff
-/*
- * Bt459 register offsets, byte-wide registers
- */
+/* Video vertical setup register constants. All bits are r/w. */
+#define SFB_VID_VER_BP_SHIFT 0x16 /* back porch */
+#define SFB_VID_VER_BP_MASK 0x3f
+#define SFB_VID_VER_SYN_SHIFT 0x10 /* sync pulse */
+#define SFB_VID_VER_SYN_MASK 0x3f
+#define SFB_VID_VER_FP_SHIFT 0x0b /* front porch */
+#define SFB_VID_VER_FP_MASK 0x1f
+#define SFB_VID_VER_SL_SHIFT 0x00 /* active scan lines */
+#define SFB_VID_VER_SL_MASK 0x7ff
-#define BT459_ADR_LOW BT459_OFFSET + 0x00 /* addr. low */
-#define BT459_ADR_HIGH BT459_OFFSET + 0x04 /* addr. high */
-#define BT459_DATA BT459_OFFSET + 0x08 /* r/w data */
-#define BT459_CMAP BT459_OFFSET + 0x0C /* color map */
+/* Video base address register constants. All bits are r/w. */
+#define SFB_VID_BASE_MASK 0x1ff /* video base row address */
+
+/* Bt459 register offsets, byte-wide registers. */
+#define BT459_ADDR_LO 0x0 /* address low */
+#define BT459_ADDR_HI 0x4 /* address high */
+#define BT459_DATA 0x8 /* data window register */
+#define BT459_CMAP 0xc /* color map window register */
diff --git a/include/video/w100fb.h b/include/video/w100fb.h
index bd548c2..e6da2d7 100644
--- a/include/video/w100fb.h
+++ b/include/video/w100fb.h
@@ -1,21 +1,149 @@
/*
* Support for the w100 frame buffer.
*
- * Copyright (c) 2004 Richard Purdie
+ * Copyright (c) 2004-2005 Richard Purdie
+ * Copyright (c) 2005 Ian Molton
*
* 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.
*/
+#define W100_GPIO_PORT_A 0
+#define W100_GPIO_PORT_B 1
+
+#define CLK_SRC_XTAL 0
+#define CLK_SRC_PLL 1
+
+struct w100fb_par;
+
+unsigned long w100fb_gpio_read(int port);
+void w100fb_gpio_write(int port, unsigned long value);
+
+/* LCD Specific Routines and Config */
+struct w100_tg_info {
+ void (*change)(struct w100fb_par*);
+ void (*suspend)(struct w100fb_par*);
+ void (*resume)(struct w100fb_par*);
+};
+
+/* General Platform Specific w100 Register Values */
+struct w100_gen_regs {
+ unsigned long lcd_format;
+ unsigned long lcdd_cntl1;
+ unsigned long lcdd_cntl2;
+ unsigned long genlcd_cntl1;
+ unsigned long genlcd_cntl2;
+ unsigned long genlcd_cntl3;
+};
+
+struct w100_gpio_regs {
+ unsigned long init_data1;
+ unsigned long init_data2;
+ unsigned long gpio_dir1;
+ unsigned long gpio_oe1;
+ unsigned long gpio_dir2;
+ unsigned long gpio_oe2;
+};
+
+/* Optional External Memory Configuration */
+struct w100_mem_info {
+ unsigned long ext_cntl;
+ unsigned long sdram_mode_reg;
+ unsigned long ext_timing_cntl;
+ unsigned long io_cntl;
+ unsigned int size;
+};
+
+struct w100_bm_mem_info {
+ unsigned long ext_mem_bw;
+ unsigned long offset;
+ unsigned long ext_timing_ctl;
+ unsigned long ext_cntl;
+ unsigned long mode_reg;
+ unsigned long io_cntl;
+ unsigned long config;
+};
+
+/* LCD Mode definition */
+struct w100_mode {
+ unsigned int xres;
+ unsigned int yres;
+ unsigned short left_margin;
+ unsigned short right_margin;
+ unsigned short upper_margin;
+ unsigned short lower_margin;
+ unsigned long crtc_ss;
+ unsigned long crtc_ls;
+ unsigned long crtc_gs;
+ unsigned long crtc_vpos_gs;
+ unsigned long crtc_rev;
+ unsigned long crtc_dclk;
+ unsigned long crtc_gclk;
+ unsigned long crtc_goe;
+ unsigned long crtc_ps1_active;
+ char pll_freq;
+ char fast_pll_freq;
+ int sysclk_src;
+ int sysclk_divider;
+ int pixclk_src;
+ int pixclk_divider;
+ int pixclk_divider_rotated;
+};
+
+struct w100_pll_info {
+ uint16_t freq; /* desired Fout for PLL (Mhz) */
+ uint8_t M; /* input divider */
+ uint8_t N_int; /* VCO multiplier */
+ uint8_t N_fac; /* VCO multiplier fractional part */
+ uint8_t tfgoal;
+ uint8_t lock_time;
+};
+
+/* Initial Video mode orientation flags */
+#define INIT_MODE_ROTATED 0x1
+#define INIT_MODE_FLIPPED 0x2
+
/*
* This structure describes the machine which we are running on.
* It is set by machine specific code and used in the probe routine
* of drivers/video/w100fb.c
*/
-
struct w100fb_mach_info {
- void (*w100fb_ssp_send)(u8 adrs, u8 data);
- int comadj;
- int phadadj;
+ /* General Platform Specific Registers */
+ struct w100_gen_regs *regs;
+ /* Table of modes the LCD is capable of */
+ struct w100_mode *modelist;
+ unsigned int num_modes;
+ /* Hooks for any platform specific tg/lcd code (optional) */
+ struct w100_tg_info *tg;
+ /* External memory definition (if present) */
+ struct w100_mem_info *mem;
+ /* Additional External memory definition (if present) */
+ struct w100_bm_mem_info *bm_mem;
+ /* GPIO definitions (optional) */
+ struct w100_gpio_regs *gpio;
+ /* Initial Mode flags */
+ unsigned int init_mode;
+ /* Xtal Frequency */
+ unsigned int xtal_freq;
+ /* Enable Xtal input doubler (1 == enable) */
+ unsigned int xtal_dbl;
+};
+
+/* General frame buffer data structure */
+struct w100fb_par {
+ unsigned int chip_id;
+ unsigned int xres;
+ unsigned int yres;
+ unsigned int extmem_active;
+ unsigned int flip;
+ unsigned int blanked;
+ unsigned int fastpll_mode;
+ unsigned long hsync_len;
+ struct w100_mode *mode;
+ struct w100_pll_info *pll_table;
+ struct w100fb_mach_info *mach;
+ uint32_t *saved_intmem;
+ uint32_t *saved_extmem;
};
diff --git a/init/Kconfig b/init/Kconfig
index 05a75c4..d5a1a12 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -77,6 +77,22 @@
object and source tree, in that order. Your total string can
be a maximum of 64 characters.
+config LOCALVERSION_AUTO
+ bool "Automatically append version information to the version string"
+ default y
+ help
+ This will try to automatically determine if the current tree is a
+ release tree by looking for git tags that
+ belong to the current top of tree revision.
+
+ A string of the format -gxxxxxxxx will be added to the localversion
+ if a git based tree is found. The string generated by this will be
+ appended after any matching localversion* files, and after the value
+ set in CONFIG_LOCALVERSION
+
+ Note: This requires Perl, and a git repository, but not necessarily
+ the git or cogito tools to be installed.
+
config SWAP
bool "Support for paging of anonymous memory (swap)"
depends on MMU
@@ -238,6 +254,8 @@
Say N if unsure.
+source "usr/Kconfig"
+
menuconfig EMBEDDED
bool "Configure standard kernel features (for small systems)"
help
@@ -260,8 +278,8 @@
help
Normally kallsyms only contains the symbols of functions, for nicer
OOPS messages. Some debuggers can use kallsyms for other
- symbols too: say Y here to include all symbols, and you
- don't care about adding 300k to the size of your kernel.
+ symbols too: say Y here to include all symbols, if you need them
+ and you don't care about adding 300k to the size of your kernel.
Say N.
diff --git a/init/Makefile b/init/Makefile
index 93a53fb..a230007 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -25,4 +25,5 @@
include/linux/compile.h: FORCE
@echo ' CHK $@'
- @$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
+ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(CFLAGS)"
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 4e11a9a..b27c110 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -127,10 +127,10 @@
* used when disk name of partitioned disk ends on a digit.
*
* If name doesn't have fall into the categories above, we return 0.
- * Driverfs is used to check if something is a disk name - it has
+ * Sysfs is used to check if something is a disk name - it has
* all known disks under bus/block/devices. If the disk name
- * contains slashes, name of driverfs node has them replaced with
- * bangs. try_name() does the actual checks, assuming that driverfs
+ * contains slashes, name of sysfs node has them replaced with
+ * bangs. try_name() does the actual checks, assuming that sysfs
* is mounted on rootfs /sys.
*/
diff --git a/init/main.c b/init/main.c
index ff41006..f142d40 100644
--- a/init/main.c
+++ b/init/main.c
@@ -123,6 +123,7 @@
char saved_command_line[COMMAND_LINE_SIZE];
static char *execute_command;
+static char *ramdisk_execute_command;
/* Setup configured maximum number of CPUs to activate */
static unsigned int max_cpus = NR_CPUS;
@@ -297,6 +298,18 @@
}
__setup("init=", init_setup);
+static int __init rdinit_setup(char *str)
+{
+ unsigned int i;
+
+ ramdisk_execute_command = str;
+ /* See "auto" comment in init_setup */
+ for (i = 1; i < MAX_INIT_ARGS; i++)
+ argv_init[i] = NULL;
+ return 1;
+}
+__setup("rdinit=", rdinit_setup);
+
extern void setup_arch(char **);
#ifndef CONFIG_SMP
@@ -614,6 +627,7 @@
migration_init();
#endif
spawn_ksoftirqd();
+ spawn_softlockup_task();
}
static void run_init_process(char *init_filename)
@@ -680,10 +694,14 @@
* check if there is an early userspace init. If yes, let it do all
* the work
*/
- if (sys_access((const char __user *) "/init", 0) == 0)
- execute_command = "/init";
- else
+
+ if (!ramdisk_execute_command)
+ ramdisk_execute_command = "/init";
+
+ if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
+ ramdisk_execute_command = NULL;
prepare_namespace();
+ }
/*
* Ok, we have completed the initial bootup, and
@@ -700,17 +718,24 @@
(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)
+ 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");
diff --git a/ipc/compat.c b/ipc/compat.c
index 3881d56..1fe95f6 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -42,10 +42,10 @@
struct compat_ipc_perm {
key_t key;
- compat_uid_t uid;
- compat_gid_t gid;
- compat_uid_t cuid;
- compat_gid_t cgid;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
+ __compat_uid_t cuid;
+ __compat_gid_t cgid;
compat_mode_t mode;
unsigned short seq;
};
@@ -174,8 +174,8 @@
struct compat_ipc_perm __user *up)
{
int err;
- compat_uid_t u;
- compat_gid_t g;
+ __compat_uid_t u;
+ __compat_gid_t g;
err = __put_user(p->key, &up->key);
SET_UID(u, p->uid);
diff --git a/ipc/msg.c b/ipc/msg.c
index 27e516f..d035bd2a 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -26,6 +26,7 @@
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
+#include <linux/seq_file.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -74,16 +75,16 @@
static void freeque (struct msg_queue *msq, int id);
static int newque (key_t key, int msgflg);
#ifdef CONFIG_PROC_FS
-static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif
void __init msg_init (void)
{
ipc_init_ids(&msg_ids,msg_ctlmni);
-
-#ifdef CONFIG_PROC_FS
- create_proc_read_entry("sysvipc/msg", 0, NULL, sysvipc_msg_read_proc, NULL);
-#endif
+ ipc_init_proc_interface("sysvipc/msg",
+ " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
+ &msg_ids,
+ sysvipc_msg_proc_show);
}
static int newque (key_t key, int msgflg)
@@ -113,6 +114,7 @@
return -ENOSPC;
}
+ msq->q_id = msg_buildid(id,msq->q_perm.seq);
msq->q_stime = msq->q_rtime = 0;
msq->q_ctime = get_seconds();
msq->q_cbytes = msq->q_qnum = 0;
@@ -123,7 +125,7 @@
INIT_LIST_HEAD(&msq->q_senders);
msg_unlock(msq);
- return msg_buildid(id,msq->q_perm.seq);
+ return msq->q_id;
}
static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)
@@ -808,55 +810,25 @@
}
#ifdef CONFIG_PROC_FS
-static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
{
- off_t pos = 0;
- off_t begin = 0;
- int i, len = 0;
+ struct msg_queue *msq = it;
- down(&msg_ids.sem);
- len += sprintf(buffer, " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n");
-
- for(i = 0; i <= msg_ids.max_id; i++) {
- struct msg_queue * msq;
- msq = msg_lock(i);
- if(msq != NULL) {
- len += sprintf(buffer + len, "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
- msq->q_perm.key,
- msg_buildid(i,msq->q_perm.seq),
- msq->q_perm.mode,
- msq->q_cbytes,
- msq->q_qnum,
- msq->q_lspid,
- msq->q_lrpid,
- msq->q_perm.uid,
- msq->q_perm.gid,
- msq->q_perm.cuid,
- msq->q_perm.cgid,
- msq->q_stime,
- msq->q_rtime,
- msq->q_ctime);
- msg_unlock(msq);
-
- pos += len;
- if(pos < offset) {
- len = 0;
- begin = pos;
- }
- if(pos > offset + length)
- goto done;
- }
-
- }
- *eof = 1;
-done:
- up(&msg_ids.sem);
- *start = buffer + (offset - begin);
- len -= (offset - begin);
- if(len > length)
- len = length;
- if(len < 0)
- len = 0;
- return len;
+ return seq_printf(s,
+ "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
+ msq->q_perm.key,
+ msq->q_id,
+ msq->q_perm.mode,
+ msq->q_cbytes,
+ msq->q_qnum,
+ msq->q_lspid,
+ msq->q_lrpid,
+ msq->q_perm.uid,
+ msq->q_perm.gid,
+ msq->q_perm.cuid,
+ msq->q_perm.cgid,
+ msq->q_stime,
+ msq->q_rtime,
+ msq->q_ctime);
}
#endif
diff --git a/ipc/sem.c b/ipc/sem.c
index 70975ce..19af028 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -73,6 +73,7 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -89,7 +90,7 @@
static int newary (key_t, int, int);
static void freeary (struct sem_array *sma, int id);
#ifdef CONFIG_PROC_FS
-static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
#endif
#define SEMMSL_FAST 256 /* 512 bytes on stack */
@@ -116,10 +117,10 @@
{
used_sems = 0;
ipc_init_ids(&sem_ids,sc_semmni);
-
-#ifdef CONFIG_PROC_FS
- create_proc_read_entry("sysvipc/sem", 0, NULL, sysvipc_sem_read_proc, NULL);
-#endif
+ ipc_init_proc_interface("sysvipc/sem",
+ " key semid perms nsems uid gid cuid cgid otime ctime\n",
+ &sem_ids,
+ sysvipc_sem_proc_show);
}
/*
@@ -193,6 +194,7 @@
}
used_sems += nsems;
+ sma->sem_id = sem_buildid(id, sma->sem_perm.seq);
sma->sem_base = (struct sem *) &sma[1];
/* sma->sem_pending = NULL; */
sma->sem_pending_last = &sma->sem_pending;
@@ -201,7 +203,7 @@
sma->sem_ctime = get_seconds();
sem_unlock(sma);
- return sem_buildid(id, sma->sem_perm.seq);
+ return sma->sem_id;
}
asmlinkage long sys_semget (key_t key, int nsems, int semflg)
@@ -1328,50 +1330,21 @@
}
#ifdef CONFIG_PROC_FS
-static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
{
- off_t pos = 0;
- off_t begin = 0;
- int i, len = 0;
+ struct sem_array *sma = it;
- len += sprintf(buffer, " key semid perms nsems uid gid cuid cgid otime ctime\n");
- down(&sem_ids.sem);
-
- for(i = 0; i <= sem_ids.max_id; i++) {
- struct sem_array *sma;
- sma = sem_lock(i);
- if(sma) {
- len += sprintf(buffer + len, "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
- sma->sem_perm.key,
- sem_buildid(i,sma->sem_perm.seq),
- sma->sem_perm.mode,
- sma->sem_nsems,
- sma->sem_perm.uid,
- sma->sem_perm.gid,
- sma->sem_perm.cuid,
- sma->sem_perm.cgid,
- sma->sem_otime,
- sma->sem_ctime);
- sem_unlock(sma);
-
- pos += len;
- if(pos < offset) {
- len = 0;
- begin = pos;
- }
- if(pos > offset + length)
- goto done;
- }
- }
- *eof = 1;
-done:
- up(&sem_ids.sem);
- *start = buffer + (offset - begin);
- len -= (offset - begin);
- if(len > length)
- len = length;
- if(len < 0)
- len = 0;
- return len;
+ return seq_printf(s,
+ "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
+ sma->sem_perm.key,
+ sma->sem_id,
+ sma->sem_perm.mode,
+ sma->sem_nsems,
+ sma->sem_perm.uid,
+ sma->sem_perm.gid,
+ sma->sem_perm.cuid,
+ sma->sem_perm.cgid,
+ sma->sem_otime,
+ sma->sem_ctime);
}
#endif
diff --git a/ipc/shm.c b/ipc/shm.c
index 1d6cf08..dca9048 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -23,12 +23,12 @@
#include <linux/init.h>
#include <linux/file.h>
#include <linux/mman.h>
-#include <linux/proc_fs.h>
#include <linux/shmem_fs.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
#include <linux/ptrace.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
@@ -51,7 +51,7 @@
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
#ifdef CONFIG_PROC_FS
-static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
#endif
size_t shm_ctlmax = SHMMAX;
@@ -63,9 +63,10 @@
void __init shm_init (void)
{
ipc_init_ids(&shm_ids, 1);
-#ifdef CONFIG_PROC_FS
- create_proc_read_entry("sysvipc/shm", 0, NULL, sysvipc_shm_read_proc, NULL);
-#endif
+ ipc_init_proc_interface("sysvipc/shm",
+ " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n",
+ &shm_ids,
+ sysvipc_shm_proc_show);
}
static inline int shm_checkid(struct shmid_kernel *s, int id)
@@ -869,63 +870,32 @@
}
#ifdef CONFIG_PROC_FS
-static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
{
- off_t pos = 0;
- off_t begin = 0;
- int i, len = 0;
+ struct shmid_kernel *shp = it;
+ char *format;
- down(&shm_ids.sem);
- len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n");
-
- for(i = 0; i <= shm_ids.max_id; i++) {
- struct shmid_kernel* shp;
-
- shp = shm_lock(i);
- if(shp!=NULL) {
#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
- char *format;
- if (sizeof(size_t) <= sizeof(int))
- format = SMALL_STRING;
- else
- format = BIG_STRING;
- len += sprintf(buffer + len, format,
- shp->shm_perm.key,
- shm_buildid(i, shp->shm_perm.seq),
- shp->shm_flags,
- shp->shm_segsz,
- shp->shm_cprid,
- shp->shm_lprid,
- is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
- shp->shm_perm.uid,
- shp->shm_perm.gid,
- shp->shm_perm.cuid,
- shp->shm_perm.cgid,
- shp->shm_atim,
- shp->shm_dtim,
- shp->shm_ctim);
- shm_unlock(shp);
-
- pos += len;
- if(pos < offset) {
- len = 0;
- begin = pos;
- }
- if(pos > offset + length)
- goto done;
- }
- }
- *eof = 1;
-done:
- up(&shm_ids.sem);
- *start = buffer + (offset - begin);
- len -= (offset - begin);
- if(len > length)
- len = length;
- if(len < 0)
- len = 0;
- return len;
+ if (sizeof(size_t) <= sizeof(int))
+ format = SMALL_STRING;
+ else
+ format = BIG_STRING;
+ return seq_printf(s, format,
+ shp->shm_perm.key,
+ shp->id,
+ shp->shm_flags,
+ shp->shm_segsz,
+ shp->shm_cprid,
+ shp->shm_lprid,
+ is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
+ shp->shm_perm.uid,
+ shp->shm_perm.gid,
+ shp->shm_perm.cuid,
+ shp->shm_perm.cgid,
+ shp->shm_atim,
+ shp->shm_dtim,
+ shp->shm_ctim);
}
#endif
diff --git a/ipc/util.c b/ipc/util.c
index e00c35f..10e836d 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -24,11 +24,20 @@
#include <linux/security.h>
#include <linux/rcupdate.h>
#include <linux/workqueue.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
#include <asm/unistd.h>
#include "util.h"
+struct ipc_proc_iface {
+ const char *path;
+ const char *header;
+ struct ipc_ids *ids;
+ int (*show)(struct seq_file *, void *);
+};
+
/**
* ipc_init - initialise IPC subsystem
*
@@ -86,6 +95,43 @@
ids->entries->p[i] = NULL;
}
+#ifdef CONFIG_PROC_FS
+static struct file_operations sysvipc_proc_fops;
+/**
+ * ipc_init_proc_interface - Create a proc interface for sysipc types
+ * using a seq_file interface.
+ * @path: Path in procfs
+ * @header: Banner to be printed at the beginning of the file.
+ * @ids: ipc id table to iterate.
+ * @show: show routine.
+ */
+void __init ipc_init_proc_interface(const char *path, const char *header,
+ struct ipc_ids *ids,
+ int (*show)(struct seq_file *, void *))
+{
+ struct proc_dir_entry *pde;
+ struct ipc_proc_iface *iface;
+
+ iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ if (!iface)
+ return;
+ iface->path = path;
+ iface->header = header;
+ iface->ids = ids;
+ iface->show = show;
+
+ pde = create_proc_entry(path,
+ S_IRUGO, /* world readable */
+ NULL /* parent dir */);
+ if (pde) {
+ pde->data = iface;
+ pde->proc_fops = &sysvipc_proc_fops;
+ } else {
+ kfree(iface);
+ }
+}
+#endif
+
/**
* ipc_findkey - find a key in an ipc identifier set
* @ids: Identifier set
@@ -578,3 +624,113 @@
}
#endif /* __ARCH_WANT_IPC_PARSE_VERSION */
+
+#ifdef CONFIG_PROC_FS
+static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
+{
+ struct ipc_proc_iface *iface = s->private;
+ struct kern_ipc_perm *ipc = it;
+ loff_t p;
+
+ /* If we had an ipc id locked before, unlock it */
+ if (ipc && ipc != SEQ_START_TOKEN)
+ ipc_unlock(ipc);
+
+ /*
+ * p = *pos - 1 (because id 0 starts at position 1)
+ * + 1 (because we increment the position by one)
+ */
+ for (p = *pos; p <= iface->ids->max_id; p++) {
+ if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
+ *pos = p + 1;
+ return ipc;
+ }
+ }
+
+ /* Out of range - return NULL to terminate iteration */
+ return NULL;
+}
+
+/*
+ * File positions: pos 0 -> header, pos n -> ipc id + 1.
+ * SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START.
+ */
+static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
+{
+ struct ipc_proc_iface *iface = s->private;
+ struct kern_ipc_perm *ipc;
+ loff_t p;
+
+ /*
+ * Take the lock - this will be released by the corresponding
+ * call to stop().
+ */
+ down(&iface->ids->sem);
+
+ /* pos < 0 is invalid */
+ if (*pos < 0)
+ return NULL;
+
+ /* pos == 0 means header */
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
+
+ /* Find the (pos-1)th ipc */
+ for (p = *pos - 1; p <= iface->ids->max_id; p++) {
+ if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
+ *pos = p + 1;
+ return ipc;
+ }
+ }
+ return NULL;
+}
+
+static void sysvipc_proc_stop(struct seq_file *s, void *it)
+{
+ struct kern_ipc_perm *ipc = it;
+ struct ipc_proc_iface *iface = s->private;
+
+ /* If we had a locked segment, release it */
+ if (ipc && ipc != SEQ_START_TOKEN)
+ ipc_unlock(ipc);
+
+ /* Release the lock we took in start() */
+ up(&iface->ids->sem);
+}
+
+static int sysvipc_proc_show(struct seq_file *s, void *it)
+{
+ struct ipc_proc_iface *iface = s->private;
+
+ if (it == SEQ_START_TOKEN)
+ return seq_puts(s, iface->header);
+
+ return iface->show(s, it);
+}
+
+static struct seq_operations sysvipc_proc_seqops = {
+ .start = sysvipc_proc_start,
+ .stop = sysvipc_proc_stop,
+ .next = sysvipc_proc_next,
+ .show = sysvipc_proc_show,
+};
+
+static int sysvipc_proc_open(struct inode *inode, struct file *file) {
+ int ret;
+ struct seq_file *seq;
+
+ ret = seq_open(file, &sysvipc_proc_seqops);
+ if (!ret) {
+ seq = file->private_data;
+ seq->private = PDE(inode)->data;
+ }
+ return ret;
+}
+
+static struct file_operations sysvipc_proc_fops = {
+ .open = sysvipc_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif /* CONFIG_PROC_FS */
diff --git a/ipc/util.h b/ipc/util.h
index 44348ca..fc9a28b 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -30,7 +30,15 @@
struct ipc_id_ary* entries;
};
+struct seq_file;
void __init ipc_init_ids(struct ipc_ids* ids, int size);
+#ifdef CONFIG_PROC_FS
+void __init ipc_init_proc_interface(const char *path, const char *header,
+ struct ipc_ids *ids,
+ int (*show)(struct seq_file *, void *));
+#else
+#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
+#endif
/* must be called with ids->sem acquired.*/
int ipc_findkey(struct ipc_ids* ids, key_t key);
diff --git a/kernel/Makefile b/kernel/Makefile
index cb05cd0..8d57a2f 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -27,6 +27,7 @@
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_SYSFS) += ksysfs.o
+obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_SECCOMP) += seccomp.o
diff --git a/kernel/acct.c b/kernel/acct.c
index 4168f63..f70e602 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -220,7 +220,7 @@
return (PTR_ERR(tmp));
}
/* Difference from BSD - they don't do O_APPEND */
- file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
+ file = filp_open(tmp, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
putname(tmp);
if (IS_ERR(file)) {
return (PTR_ERR(file));
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 8ab1b4e..1f06e76 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -628,13 +628,6 @@
* lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
*/
-/*
- * Hack to avoid 2.6.13 partial node dynamic sched domain bug.
- * Disable letting 'cpu_exclusive' cpusets define dynamic sched
- * domains, until the sched domain can handle partial nodes.
- * Remove this #if hackery when sched domains fixed.
- */
-#if 0
static void update_cpu_domains(struct cpuset *cur)
{
struct cpuset *c, *par = cur->parent;
@@ -675,11 +668,6 @@
partition_sched_domains(&pspan, &cspan);
unlock_cpu_hotplug();
}
-#else
-static void update_cpu_domains(struct cpuset *cur)
-{
-}
-#endif
static int update_cpumask(struct cpuset *cs, char *buf)
{
@@ -1611,17 +1599,114 @@
return 0;
}
-/**
- * cpuset_zone_allowed - is zone z allowed in current->mems_allowed
- * @z: zone in question
- *
- * Is zone z allowed in current->mems_allowed, or is
- * the CPU in interrupt context? (zone is always allowed in this case)
+/*
+ * nearest_exclusive_ancestor() - Returns the nearest mem_exclusive
+ * ancestor to the specified cpuset. Call while holding cpuset_sem.
+ * If no ancestor is mem_exclusive (an unusual configuration), then
+ * returns the root cpuset.
*/
-int cpuset_zone_allowed(struct zone *z)
+static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
{
- return in_interrupt() ||
- node_isset(z->zone_pgdat->node_id, current->mems_allowed);
+ while (!is_mem_exclusive(cs) && cs->parent)
+ cs = cs->parent;
+ return cs;
+}
+
+/**
+ * cpuset_zone_allowed - Can we allocate memory on zone z's memory node?
+ * @z: is this zone on an allowed node?
+ * @gfp_mask: memory allocation flags (we use __GFP_HARDWALL)
+ *
+ * If we're in interrupt, yes, we can always allocate. If zone
+ * z's node is in our tasks mems_allowed, yes. If it's not a
+ * __GFP_HARDWALL request and this zone's nodes is in the nearest
+ * mem_exclusive cpuset ancestor to this tasks cpuset, yes.
+ * Otherwise, no.
+ *
+ * GFP_USER allocations are marked with the __GFP_HARDWALL bit,
+ * and do not allow allocations outside the current tasks cpuset.
+ * GFP_KERNEL allocations are not so marked, so can escape to the
+ * nearest mem_exclusive ancestor cpuset.
+ *
+ * Scanning up parent cpusets requires cpuset_sem. The __alloc_pages()
+ * routine only calls here with __GFP_HARDWALL bit _not_ set if
+ * it's a GFP_KERNEL allocation, and all nodes in the current tasks
+ * mems_allowed came up empty on the first pass over the zonelist.
+ * So only GFP_KERNEL allocations, if all nodes in the cpuset are
+ * short of memory, might require taking the cpuset_sem semaphore.
+ *
+ * The first loop over the zonelist in mm/page_alloc.c:__alloc_pages()
+ * calls here with __GFP_HARDWALL always set in gfp_mask, enforcing
+ * hardwall cpusets - no allocation on a node outside the cpuset is
+ * allowed (unless in interrupt, of course).
+ *
+ * The second loop doesn't even call here for GFP_ATOMIC requests
+ * (if the __alloc_pages() local variable 'wait' is set). That check
+ * and the checks below have the combined affect in the second loop of
+ * the __alloc_pages() routine that:
+ * in_interrupt - any node ok (current task context irrelevant)
+ * GFP_ATOMIC - any node ok
+ * GFP_KERNEL - any node in enclosing mem_exclusive cpuset ok
+ * GFP_USER - only nodes in current tasks mems allowed ok.
+ **/
+
+int cpuset_zone_allowed(struct zone *z, unsigned int __nocast gfp_mask)
+{
+ int node; /* node that zone z is on */
+ const struct cpuset *cs; /* current cpuset ancestors */
+ int allowed = 1; /* is allocation in zone z allowed? */
+
+ if (in_interrupt())
+ return 1;
+ node = z->zone_pgdat->node_id;
+ if (node_isset(node, current->mems_allowed))
+ return 1;
+ if (gfp_mask & __GFP_HARDWALL) /* If hardwall request, stop here */
+ return 0;
+
+ /* Not hardwall and node outside mems_allowed: scan up cpusets */
+ down(&cpuset_sem);
+ cs = current->cpuset;
+ if (!cs)
+ goto done; /* current task exiting */
+ cs = nearest_exclusive_ancestor(cs);
+ allowed = node_isset(node, cs->mems_allowed);
+done:
+ up(&cpuset_sem);
+ return allowed;
+}
+
+/**
+ * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors?
+ * @p: pointer to task_struct of some other task.
+ *
+ * Description: Return true if the nearest mem_exclusive ancestor
+ * cpusets of tasks @p and current overlap. Used by oom killer to
+ * determine if task @p's memory usage might impact the memory
+ * available to the current task.
+ *
+ * Acquires cpuset_sem - not suitable for calling from a fast path.
+ **/
+
+int cpuset_excl_nodes_overlap(const struct task_struct *p)
+{
+ const struct cpuset *cs1, *cs2; /* my and p's cpuset ancestors */
+ int overlap = 0; /* do cpusets overlap? */
+
+ down(&cpuset_sem);
+ cs1 = current->cpuset;
+ if (!cs1)
+ goto done; /* current task exiting */
+ cs2 = p->cpuset;
+ if (!cs2)
+ goto done; /* task p is exiting */
+ cs1 = nearest_exclusive_ancestor(cs1);
+ cs2 = nearest_exclusive_ancestor(cs2);
+ overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed);
+done:
+ up(&cpuset_sem);
+
+ return overlap;
}
/*
diff --git a/kernel/fork.c b/kernel/fork.c
index b65187f..7e1ead9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -994,6 +994,9 @@
* of CLONE_PTRACE.
*/
clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
+#ifdef TIF_SYSCALL_EMU
+ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
+#endif
/* Our parent execution domain becomes current domain
These must match for thread signalling to apply */
diff --git a/kernel/futex.c b/kernel/futex.c
index c7130f8..ca05fe6 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -40,6 +40,7 @@
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/signal.h>
+#include <asm/futex.h>
#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
@@ -327,6 +328,118 @@
}
/*
+ * Wake up all waiters hashed on the physical page that is mapped
+ * to this virtual address:
+ */
+static int futex_wake_op(unsigned long uaddr1, unsigned long uaddr2, int nr_wake, int nr_wake2, int op)
+{
+ union futex_key key1, key2;
+ struct futex_hash_bucket *bh1, *bh2;
+ struct list_head *head;
+ struct futex_q *this, *next;
+ int ret, op_ret, attempt = 0;
+
+retryfull:
+ down_read(¤t->mm->mmap_sem);
+
+ ret = get_futex_key(uaddr1, &key1);
+ if (unlikely(ret != 0))
+ goto out;
+ ret = get_futex_key(uaddr2, &key2);
+ if (unlikely(ret != 0))
+ goto out;
+
+ bh1 = hash_futex(&key1);
+ bh2 = hash_futex(&key2);
+
+retry:
+ if (bh1 < bh2)
+ spin_lock(&bh1->lock);
+ spin_lock(&bh2->lock);
+ if (bh1 > bh2)
+ spin_lock(&bh1->lock);
+
+ op_ret = futex_atomic_op_inuser(op, (int __user *)uaddr2);
+ if (unlikely(op_ret < 0)) {
+ int dummy;
+
+ spin_unlock(&bh1->lock);
+ if (bh1 != bh2)
+ spin_unlock(&bh2->lock);
+
+ /* futex_atomic_op_inuser needs to both read and write
+ * *(int __user *)uaddr2, but we can't modify it
+ * non-atomically. Therefore, if get_user below is not
+ * enough, we need to handle the fault ourselves, while
+ * still holding the mmap_sem. */
+ if (attempt++) {
+ struct vm_area_struct * vma;
+ struct mm_struct *mm = current->mm;
+
+ ret = -EFAULT;
+ if (attempt >= 2 ||
+ !(vma = find_vma(mm, uaddr2)) ||
+ vma->vm_start > uaddr2 ||
+ !(vma->vm_flags & VM_WRITE))
+ goto out;
+
+ switch (handle_mm_fault(mm, vma, uaddr2, 1)) {
+ case VM_FAULT_MINOR:
+ current->min_flt++;
+ break;
+ case VM_FAULT_MAJOR:
+ current->maj_flt++;
+ break;
+ default:
+ goto out;
+ }
+ goto retry;
+ }
+
+ /* If we would have faulted, release mmap_sem,
+ * fault it in and start all over again. */
+ up_read(¤t->mm->mmap_sem);
+
+ ret = get_user(dummy, (int __user *)uaddr2);
+ if (ret)
+ return ret;
+
+ goto retryfull;
+ }
+
+ head = &bh1->chain;
+
+ list_for_each_entry_safe(this, next, head, list) {
+ if (match_futex (&this->key, &key1)) {
+ wake_futex(this);
+ if (++ret >= nr_wake)
+ break;
+ }
+ }
+
+ if (op_ret > 0) {
+ head = &bh2->chain;
+
+ op_ret = 0;
+ list_for_each_entry_safe(this, next, head, list) {
+ if (match_futex (&this->key, &key2)) {
+ wake_futex(this);
+ if (++op_ret >= nr_wake2)
+ break;
+ }
+ }
+ ret += op_ret;
+ }
+
+ spin_unlock(&bh1->lock);
+ if (bh1 != bh2)
+ spin_unlock(&bh2->lock);
+out:
+ up_read(¤t->mm->mmap_sem);
+ return ret;
+}
+
+/*
* Requeue all waiters hashed on one physical page to another
* physical page.
*/
@@ -673,23 +786,17 @@
filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
if (signal) {
- int err;
err = f_setown(filp, current->pid, 1);
if (err < 0) {
- put_unused_fd(ret);
- put_filp(filp);
- ret = err;
- goto out;
+ goto error;
}
filp->f_owner.signum = signal;
}
q = kmalloc(sizeof(*q), GFP_KERNEL);
if (!q) {
- put_unused_fd(ret);
- put_filp(filp);
- ret = -ENOMEM;
- goto out;
+ err = -ENOMEM;
+ goto error;
}
down_read(¤t->mm->mmap_sem);
@@ -697,10 +804,8 @@
if (unlikely(err != 0)) {
up_read(¤t->mm->mmap_sem);
- put_unused_fd(ret);
- put_filp(filp);
kfree(q);
- return err;
+ goto error;
}
/*
@@ -716,6 +821,11 @@
fd_install(ret, filp);
out:
return ret;
+error:
+ put_unused_fd(ret);
+ put_filp(filp);
+ ret = err;
+ goto out;
}
long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
@@ -740,6 +850,9 @@
case FUTEX_CMP_REQUEUE:
ret = futex_requeue(uaddr, uaddr2, val, val2, &val3);
break;
+ case FUTEX_WAKE_OP:
+ ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
+ break;
default:
ret = -ENOSYS;
}
diff --git a/kernel/intermodule.c b/kernel/intermodule.c
index 388977f..0cbe633 100644
--- a/kernel/intermodule.c
+++ b/kernel/intermodule.c
@@ -39,7 +39,7 @@
struct list_head *tmp;
struct inter_module_entry *ime, *ime_new;
- if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+ if (!(ime_new = kzalloc(sizeof(*ime), GFP_KERNEL))) {
/* Overloaded kernel, not fatal */
printk(KERN_ERR
"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
@@ -47,7 +47,6 @@
kmalloc_failed = 1;
return;
}
- memset(ime_new, 0, sizeof(*ime_new));
ime_new->im_name = im_name;
ime_new->owner = owner;
ime_new->userdata = userdata;
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index c29f83c..3ff7b92 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -111,7 +111,7 @@
unsigned int status;
kstat_this_cpu.irqs[irq]++;
- if (desc->status & IRQ_PER_CPU) {
+ if (CHECK_IRQ_PER_CPU(desc->status)) {
irqreturn_t action_ret;
/*
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index ac67009..1cfdb08 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -18,6 +18,10 @@
cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
+cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
+#endif
+
/**
* synchronize_irq - wait for pending IRQ handlers (on other CPUs)
*
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 85d08da..f26e534 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -19,12 +19,22 @@
*/
static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-void __attribute__((weak))
-proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+void proc_set_irq_affinity(unsigned int irq, cpumask_t 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)
{
irq_affinity[irq] = mask_val;
irq_desc[irq].handler->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)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index b023712..f3ea492 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -37,6 +37,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleloader.h>
+#include <asm-generic/sections.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
#include <asm/kdebug.h>
@@ -72,7 +73,7 @@
* get_insn_slot() - Find a slot on an executable page for an instruction.
* We allocate an executable page if there's no room on existing ones.
*/
-kprobe_opcode_t *get_insn_slot(void)
+kprobe_opcode_t __kprobes *get_insn_slot(void)
{
struct kprobe_insn_page *kip;
struct hlist_node *pos;
@@ -117,7 +118,7 @@
return kip->insns;
}
-void free_insn_slot(kprobe_opcode_t *slot)
+void __kprobes free_insn_slot(kprobe_opcode_t *slot)
{
struct kprobe_insn_page *kip;
struct hlist_node *pos;
@@ -152,20 +153,42 @@
}
/* Locks kprobe: irqs must be disabled */
-void lock_kprobes(void)
+void __kprobes lock_kprobes(void)
{
+ unsigned long flags = 0;
+
+ /* Avoiding local interrupts to happen right after we take the kprobe_lock
+ * and before we get a chance to update kprobe_cpu, this to prevent
+ * deadlock when we have a kprobe on ISR routine and a kprobe on task
+ * routine
+ */
+ local_irq_save(flags);
+
spin_lock(&kprobe_lock);
kprobe_cpu = smp_processor_id();
+
+ local_irq_restore(flags);
}
-void unlock_kprobes(void)
+void __kprobes unlock_kprobes(void)
{
+ unsigned long flags = 0;
+
+ /* Avoiding local interrupts to happen right after we update
+ * kprobe_cpu and before we get a a chance to release kprobe_lock,
+ * this to prevent deadlock when we have a kprobe on ISR routine and
+ * a kprobe on task routine
+ */
+ local_irq_save(flags);
+
kprobe_cpu = NR_CPUS;
spin_unlock(&kprobe_lock);
+
+ local_irq_restore(flags);
}
/* You have to be holding the kprobe_lock */
-struct kprobe *get_kprobe(void *addr)
+struct kprobe __kprobes *get_kprobe(void *addr)
{
struct hlist_head *head;
struct hlist_node *node;
@@ -183,7 +206,7 @@
* Aggregate handlers for multiple kprobes support - these handlers
* take care of invoking the individual kprobe handlers on p->list
*/
-static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kprobe *kp;
@@ -198,8 +221,8 @@
return 0;
}
-static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
- unsigned long flags)
+static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
+ unsigned long flags)
{
struct kprobe *kp;
@@ -213,8 +236,8 @@
return;
}
-static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
- int trapnr)
+static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
+ int trapnr)
{
/*
* if we faulted "during" the execution of a user specified
@@ -227,7 +250,7 @@
return 0;
}
-static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kprobe *kp = curr_kprobe;
if (curr_kprobe && kp->break_handler) {
@@ -240,7 +263,7 @@
return 0;
}
-struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
+struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp)
{
struct hlist_node *node;
struct kretprobe_instance *ri;
@@ -249,7 +272,8 @@
return NULL;
}
-static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
+static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe
+ *rp)
{
struct hlist_node *node;
struct kretprobe_instance *ri;
@@ -258,7 +282,7 @@
return NULL;
}
-void add_rp_inst(struct kretprobe_instance *ri)
+void __kprobes add_rp_inst(struct kretprobe_instance *ri)
{
/*
* Remove rp inst off the free list -
@@ -276,7 +300,7 @@
hlist_add_head(&ri->uflist, &ri->rp->used_instances);
}
-void recycle_rp_inst(struct kretprobe_instance *ri)
+void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
{
/* remove rp inst off the rprobe_inst_table */
hlist_del(&ri->hlist);
@@ -291,7 +315,7 @@
kfree(ri);
}
-struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk)
+struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
{
return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
}
@@ -302,7 +326,7 @@
* instances associated with this task. These left over instances represent
* probed functions that have been called but will never return.
*/
-void kprobe_flush_task(struct task_struct *tk)
+void __kprobes kprobe_flush_task(struct task_struct *tk)
{
struct kretprobe_instance *ri;
struct hlist_head *head;
@@ -322,7 +346,8 @@
* This kprobe pre_handler is registered with every kretprobe. When probe
* hits it will set up the return probe.
*/
-static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+ struct pt_regs *regs)
{
struct kretprobe *rp = container_of(p, struct kretprobe, kp);
@@ -353,7 +378,7 @@
* Add the new probe to old_p->list. Fail if this is the
* second jprobe at the address - two jprobes can't coexist
*/
-static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
+static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
{
struct kprobe *kp;
@@ -395,7 +420,8 @@
* the intricacies
* TODO: Move kcalloc outside the spinlock
*/
-static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
+static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
+ struct kprobe *p)
{
int ret = 0;
struct kprobe *ap;
@@ -434,15 +460,25 @@
spin_unlock_irqrestore(&kprobe_lock, flags);
}
-int register_kprobe(struct kprobe *p)
+static int __kprobes in_kprobes_functions(unsigned long addr)
+{
+ if (addr >= (unsigned long)__kprobes_text_start
+ && addr < (unsigned long)__kprobes_text_end)
+ return -EINVAL;
+ return 0;
+}
+
+int __kprobes register_kprobe(struct kprobe *p)
{
int ret = 0;
unsigned long flags = 0;
struct kprobe *old_p;
- if ((ret = arch_prepare_kprobe(p)) != 0) {
+ if ((ret = in_kprobes_functions((unsigned long) p->addr)) != 0)
+ return ret;
+ if ((ret = arch_prepare_kprobe(p)) != 0)
goto rm_kprobe;
- }
+
spin_lock_irqsave(&kprobe_lock, flags);
old_p = get_kprobe(p->addr);
p->nmissed = 0;
@@ -466,7 +502,7 @@
return ret;
}
-void unregister_kprobe(struct kprobe *p)
+void __kprobes unregister_kprobe(struct kprobe *p)
{
unsigned long flags;
struct kprobe *old_p;
@@ -487,7 +523,7 @@
.priority = 0x7fffffff /* we need to notified first */
};
-int register_jprobe(struct jprobe *jp)
+int __kprobes register_jprobe(struct jprobe *jp)
{
/* Todo: Verify probepoint is a function entry point */
jp->kp.pre_handler = setjmp_pre_handler;
@@ -496,14 +532,14 @@
return register_kprobe(&jp->kp);
}
-void unregister_jprobe(struct jprobe *jp)
+void __kprobes unregister_jprobe(struct jprobe *jp)
{
unregister_kprobe(&jp->kp);
}
#ifdef ARCH_SUPPORTS_KRETPROBES
-int register_kretprobe(struct kretprobe *rp)
+int __kprobes register_kretprobe(struct kretprobe *rp)
{
int ret = 0;
struct kretprobe_instance *inst;
@@ -540,14 +576,14 @@
#else /* ARCH_SUPPORTS_KRETPROBES */
-int register_kretprobe(struct kretprobe *rp)
+int __kprobes register_kretprobe(struct kretprobe *rp)
{
return -ENOSYS;
}
#endif /* ARCH_SUPPORTS_KRETPROBES */
-void unregister_kretprobe(struct kretprobe *rp)
+void __kprobes unregister_kretprobe(struct kretprobe *rp)
{
unsigned long flags;
struct kretprobe_instance *ri;
diff --git a/kernel/module.c b/kernel/module.c
index c32995f..4b39d37 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1509,6 +1509,7 @@
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
struct exception_table_entry *extable;
+ mm_segment_t old_fs;
DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
umod, len, uargs);
@@ -1779,6 +1780,24 @@
if (err < 0)
goto cleanup;
+ /* flush the icache in correct context */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /*
+ * Flush the instruction cache, since we've played with text.
+ * Do it before processing of module parameters, so the module
+ * can provide parameter accessor functions of its own.
+ */
+ if (mod->module_init)
+ flush_icache_range((unsigned long)mod->module_init,
+ (unsigned long)mod->module_init
+ + mod->init_size);
+ flush_icache_range((unsigned long)mod->module_core,
+ (unsigned long)mod->module_core + mod->core_size);
+
+ set_fs(old_fs);
+
mod->args = args;
if (obsparmindex) {
err = obsolete_params(mod->name, mod->args,
@@ -1860,7 +1879,6 @@
const char __user *uargs)
{
struct module *mod;
- mm_segment_t old_fs = get_fs();
int ret = 0;
/* Must have permission */
@@ -1878,19 +1896,6 @@
return PTR_ERR(mod);
}
- /* flush the icache in correct context */
- set_fs(KERNEL_DS);
-
- /* Flush the instruction cache, since we've played with text */
- if (mod->module_init)
- flush_icache_range((unsigned long)mod->module_init,
- (unsigned long)mod->module_init
- + mod->init_size);
- flush_icache_range((unsigned long)mod->module_core,
- (unsigned long)mod->module_core + mod->core_size);
-
- set_fs(old_fs);
-
/* Now sew it into the lists. They won't access us, since
strong_try_module_get() will fail. */
stop_machine_run(__link_module, mod, NR_CPUS);
diff --git a/kernel/params.c b/kernel/params.c
index d586c35ef..fbf1732 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -542,8 +542,8 @@
{
struct module_kobject *mk;
- mk = kmalloc(sizeof(struct module_kobject), GFP_KERNEL);
- memset(mk, 0, sizeof(struct module_kobject));
+ mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
+ BUG_ON(!mk);
mk->mod = THIS_MODULE;
kobj_set_kset_s(mk, module_subsys);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 38798a2..b7b532a 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -427,21 +427,23 @@
timr->sigq->info.si_code = SI_TIMER;
timr->sigq->info.si_tid = timr->it_id;
timr->sigq->info.si_value = timr->it_sigev_value;
+
if (timr->it_sigev_notify & SIGEV_THREAD_ID) {
- if (unlikely(timr->it_process->flags & PF_EXITING)) {
- timr->it_sigev_notify = SIGEV_SIGNAL;
- put_task_struct(timr->it_process);
- timr->it_process = timr->it_process->group_leader;
- goto group;
- }
- return send_sigqueue(timr->it_sigev_signo, timr->sigq,
- timr->it_process);
+ struct task_struct *leader;
+ int ret = send_sigqueue(timr->it_sigev_signo, timr->sigq,
+ timr->it_process);
+
+ if (likely(ret >= 0))
+ return ret;
+
+ timr->it_sigev_notify = SIGEV_SIGNAL;
+ leader = timr->it_process->group_leader;
+ put_task_struct(timr->it_process);
+ timr->it_process = leader;
}
- else {
- group:
- return send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
- timr->it_process);
- }
+
+ return send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
+ timr->it_process);
}
EXPORT_SYMBOL_GPL(posix_timer_event);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 2c7121d..c14cd99 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -28,7 +28,7 @@
config SOFTWARE_SUSPEND
bool "Software Suspend"
- depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP))
+ depends on PM && SWAP && (X86 || ((FVR || PPC32) && !SMP))
---help---
Enable the possibility of suspending the machine.
It doesn't need APM.
@@ -72,6 +72,18 @@
suspended image to. It will simply pick the first available swap
device.
+config SWSUSP_ENCRYPT
+ bool "Encrypt suspend image"
+ depends on SOFTWARE_SUSPEND && CRYPTO=y && (CRYPTO_AES=y || CRYPTO_AES_586=y || CRYPTO_AES_X86_64=y)
+ default ""
+ ---help---
+ To prevent data gathering from swap after resume you can encrypt
+ the suspend image with a temporary key that is deleted on
+ resume.
+
+ Note that the temporary key is stored unencrypted on disk while the
+ system is suspended.
+
config SUSPEND_SMP
bool
depends on HOTPLUG_CPU && X86 && PM
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 664eb04..2d8bf05 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -112,24 +112,12 @@
}
}
-static void finish(void)
-{
- device_resume();
- platform_finish();
- thaw_processes();
- enable_nonboot_cpus();
- pm_restore_console();
-}
-
-
static int prepare_processes(void)
{
int error;
pm_prepare_console();
-
sys_sync();
-
disable_nonboot_cpus();
if (freeze_processes()) {
@@ -162,15 +150,6 @@
pm_restore_console();
}
-static int prepare_devices(void)
-{
- int error;
-
- if ((error = device_suspend(PMSG_FREEZE)))
- printk("Some devices failed to suspend\n");
- return error;
-}
-
/**
* pm_suspend_disk - The granpappy of power management.
*
@@ -187,17 +166,14 @@
error = prepare_processes();
if (error)
return error;
- error = prepare_devices();
+ error = device_suspend(PMSG_FREEZE);
if (error) {
+ printk("Some devices failed to suspend\n");
unprepare_processes();
return error;
}
- pr_debug("PM: Attempting to suspend to disk.\n");
- if (pm_disk_mode == PM_DISK_FIRMWARE)
- return pm_ops->enter(PM_SUSPEND_DISK);
-
pr_debug("PM: snapshotting memory.\n");
in_suspend = 1;
if ((error = swsusp_suspend()))
@@ -208,11 +184,20 @@
error = swsusp_write();
if (!error)
power_down(pm_disk_mode);
+ else {
+ /* swsusp_write can not fail in device_resume,
+ no need to do second device_resume */
+ swsusp_free();
+ unprepare_processes();
+ return error;
+ }
} else
pr_debug("PM: Image restored successfully.\n");
+
swsusp_free();
Done:
- finish();
+ device_resume();
+ unprepare_processes();
return error;
}
@@ -233,9 +218,12 @@
{
int error;
+ down(&pm_sem);
if (!swsusp_resume_device) {
- if (!strlen(resume_file))
+ if (!strlen(resume_file)) {
+ up(&pm_sem);
return -ENOENT;
+ }
swsusp_resume_device = name_to_dev_t(resume_file);
pr_debug("swsusp: Resume From Partition %s\n", resume_file);
} else {
@@ -248,6 +236,7 @@
* FIXME: If noresume is specified, we need to find the partition
* and reset it back to normal swap space.
*/
+ up(&pm_sem);
return 0;
}
@@ -270,20 +259,24 @@
pr_debug("PM: Preparing devices for restore.\n");
- if ((error = prepare_devices()))
+ if ((error = device_suspend(PMSG_FREEZE))) {
+ printk("Some devices failed to suspend\n");
goto Free;
+ }
mb();
pr_debug("PM: Restoring saved image.\n");
swsusp_resume();
pr_debug("PM: Restore failed, recovering.n");
- finish();
+ device_resume();
Free:
swsusp_free();
Cleanup:
unprepare_processes();
Done:
+ /* For success case, the suspend path will release the lock */
+ up(&pm_sem);
pr_debug("PM: Resume from disk failed.\n");
return 0;
}
@@ -390,7 +383,9 @@
if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
res = MKDEV(maj,min);
if (maj == MAJOR(res) && min == MINOR(res)) {
+ down(&pm_sem);
swsusp_resume_device = res;
+ up(&pm_sem);
printk("Attempting manual resume\n");
noresume = 0;
software_resume();
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 71aa0fd..22bdc93 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -143,11 +143,12 @@
-static char * pm_states[] = {
+static char *pm_states[PM_SUSPEND_MAX] = {
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
+#ifdef CONFIG_SOFTWARE_SUSPEND
[PM_SUSPEND_DISK] = "disk",
- NULL,
+#endif
};
diff --git a/kernel/power/pm.c b/kernel/power/pm.c
index 61deda0..1591493 100644
--- a/kernel/power/pm.c
+++ b/kernel/power/pm.c
@@ -60,9 +60,8 @@
unsigned long id,
pm_callback callback)
{
- struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+ struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL);
if (dev) {
- memset(dev, 0, sizeof(*dev));
dev->type = type;
dev->id = id;
dev->callback = callback;
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 3bd0d26..28de118 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -38,7 +38,6 @@
processes around? */
long save;
save = current->state;
- current->state = TASK_UNINTERRUPTIBLE;
pr_debug("%s entered refrigerator\n", current->comm);
printk("=");
@@ -47,8 +46,10 @@
recalc_sigpending(); /* We sent fake signal, clean it up */
spin_unlock_irq(¤t->sighand->siglock);
- while (frozen(current))
+ while (frozen(current)) {
+ current->state = TASK_UNINTERRUPTIBLE;
schedule();
+ }
pr_debug("%s left refrigerator\n", current->comm);
current->state = save;
}
@@ -80,13 +81,33 @@
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
yield(); /* Yield is okay here */
- if (time_after(jiffies, start_time + TIMEOUT)) {
+ if (todo && time_after(jiffies, start_time + TIMEOUT)) {
printk( "\n" );
printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo );
- return todo;
+ break;
}
} while(todo);
+ /* This does not unfreeze processes that are already frozen
+ * (we have slightly ugly calling convention in that respect,
+ * and caller must call thaw_processes() if something fails),
+ * but it cleans up leftover PF_FREEZE requests.
+ */
+ if (todo) {
+ read_lock(&tasklist_lock);
+ do_each_thread(g, p)
+ if (freezing(p)) {
+ pr_debug(" clean up: %s\n", p->comm);
+ p->flags &= ~PF_FREEZE;
+ spin_lock_irqsave(&p->sighand->siglock, flags);
+ recalc_sigpending_tsk(p);
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
+ }
+ while_each_thread(g, p);
+ read_unlock(&tasklist_lock);
+ return todo;
+ }
+
printk( "|\n" );
BUG_ON(in_atomic());
return 0;
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index f2bc71b..d967e87 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -31,6 +31,9 @@
* Alex Badea <vampire@go.ro>:
* Fixed runaway init
*
+ * Andreas Steinmetz <ast@domdv.de>:
+ * Added encrypted suspend option
+ *
* More state savers are welcome. Especially for the scsi layer...
*
* For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
@@ -71,8 +74,16 @@
#include <asm/tlbflush.h>
#include <asm/io.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+
#include "power.h"
+#define CIPHER "aes"
+#define MAXKEY 32
+#define MAXIV 32
+
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
@@ -103,7 +114,8 @@
#define SWSUSP_SIG "S1SUSPEND"
static struct swsusp_header {
- char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
+ char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)];
+ u8 key_iv[MAXKEY+MAXIV];
swp_entry_t swsusp_info;
char orig_sig[10];
char sig[10];
@@ -129,6 +141,131 @@
static unsigned short swapfile_used[MAX_SWAPFILES];
static unsigned short root_swap;
+static int write_page(unsigned long addr, swp_entry_t * loc);
+static int bio_read_page(pgoff_t page_off, void * page);
+
+static u8 key_iv[MAXKEY+MAXIV];
+
+#ifdef CONFIG_SWSUSP_ENCRYPT
+
+static int crypto_init(int mode, void **mem)
+{
+ int error = 0;
+ int len;
+ char *modemsg;
+ struct crypto_tfm *tfm;
+
+ modemsg = mode ? "suspend not possible" : "resume not possible";
+
+ tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC);
+ if(!tfm) {
+ printk(KERN_ERR "swsusp: no tfm, %s\n", modemsg);
+ error = -EINVAL;
+ goto out;
+ }
+
+ if(MAXKEY < crypto_tfm_alg_min_keysize(tfm)) {
+ printk(KERN_ERR "swsusp: key buffer too small, %s\n", modemsg);
+ error = -ENOKEY;
+ goto fail;
+ }
+
+ if (mode)
+ get_random_bytes(key_iv, MAXKEY+MAXIV);
+
+ len = crypto_tfm_alg_max_keysize(tfm);
+ if (len > MAXKEY)
+ len = MAXKEY;
+
+ if (crypto_cipher_setkey(tfm, key_iv, len)) {
+ printk(KERN_ERR "swsusp: key setup failure, %s\n", modemsg);
+ error = -EKEYREJECTED;
+ goto fail;
+ }
+
+ len = crypto_tfm_alg_ivsize(tfm);
+
+ if (MAXIV < len) {
+ printk(KERN_ERR "swsusp: iv buffer too small, %s\n", modemsg);
+ error = -EOVERFLOW;
+ goto fail;
+ }
+
+ crypto_cipher_set_iv(tfm, key_iv+MAXKEY, len);
+
+ *mem=(void *)tfm;
+
+ goto out;
+
+fail: crypto_free_tfm(tfm);
+out: return error;
+}
+
+static __inline__ void crypto_exit(void *mem)
+{
+ crypto_free_tfm((struct crypto_tfm *)mem);
+}
+
+static __inline__ int crypto_write(struct pbe *p, void *mem)
+{
+ int error = 0;
+ struct scatterlist src, dst;
+
+ src.page = virt_to_page(p->address);
+ src.offset = 0;
+ src.length = PAGE_SIZE;
+ dst.page = virt_to_page((void *)&swsusp_header);
+ dst.offset = 0;
+ dst.length = PAGE_SIZE;
+
+ error = crypto_cipher_encrypt((struct crypto_tfm *)mem, &dst, &src,
+ PAGE_SIZE);
+
+ if (!error)
+ error = write_page((unsigned long)&swsusp_header,
+ &(p->swap_address));
+ return error;
+}
+
+static __inline__ int crypto_read(struct pbe *p, void *mem)
+{
+ int error = 0;
+ struct scatterlist src, dst;
+
+ error = bio_read_page(swp_offset(p->swap_address), (void *)p->address);
+ if (!error) {
+ src.offset = 0;
+ src.length = PAGE_SIZE;
+ dst.offset = 0;
+ dst.length = PAGE_SIZE;
+ src.page = dst.page = virt_to_page((void *)p->address);
+
+ error = crypto_cipher_decrypt((struct crypto_tfm *)mem, &dst,
+ &src, PAGE_SIZE);
+ }
+ return error;
+}
+#else
+static __inline__ int crypto_init(int mode, void *mem)
+{
+ return 0;
+}
+
+static __inline__ void crypto_exit(void *mem)
+{
+}
+
+static __inline__ int crypto_write(struct pbe *p, void *mem)
+{
+ return write_page(p->address, &(p->swap_address));
+}
+
+static __inline__ int crypto_read(struct pbe *p, void *mem)
+{
+ return bio_read_page(swp_offset(p->swap_address), (void *)p->address);
+}
+#endif
+
static int mark_swapfiles(swp_entry_t prev)
{
int error;
@@ -140,6 +277,7 @@
!memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
+ memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV);
swsusp_header.swsusp_info = prev;
error = rw_swap_page_sync(WRITE,
swp_entry(root_swap, 0),
@@ -179,9 +317,9 @@
len=strlen(resume_file);
root_swap = 0xFFFF;
- swap_list_lock();
+ spin_lock(&swap_lock);
for (i=0; i<MAX_SWAPFILES; i++) {
- if (swap_info[i].flags == 0) {
+ if (!(swap_info[i].flags & SWP_WRITEOK)) {
swapfile_used[i]=SWAPFILE_UNUSED;
} else {
if (!len) {
@@ -202,7 +340,7 @@
}
}
}
- swap_list_unlock();
+ spin_unlock(&swap_lock);
return (root_swap != 0xffff) ? 0 : -ENODEV;
}
@@ -216,12 +354,12 @@
{
int i;
- swap_list_lock();
+ spin_lock(&swap_lock);
for (i = 0; i< MAX_SWAPFILES; i++)
if (swapfile_used[i] == SWAPFILE_IGNORED) {
- swap_info[i].flags ^= 0xFF;
+ swap_info[i].flags ^= SWP_WRITEOK;
}
- swap_list_unlock();
+ spin_unlock(&swap_lock);
}
/**
@@ -286,6 +424,10 @@
int error = 0, i = 0;
unsigned int mod = nr_copy_pages / 100;
struct pbe *p;
+ void *tfm;
+
+ if ((error = crypto_init(1, &tfm)))
+ return error;
if (!mod)
mod = 1;
@@ -294,11 +436,14 @@
for_each_pbe (p, pagedir_nosave) {
if (!(i%mod))
printk( "\b\b\b\b%3d%%", i / mod );
- if ((error = write_page(p->address, &(p->swap_address))))
+ if ((error = crypto_write(p, tfm))) {
+ crypto_exit(tfm);
return error;
+ }
i++;
}
printk("\b\b\b\bdone\n");
+ crypto_exit(tfm);
return error;
}
@@ -385,7 +530,6 @@
* write_suspend_image - Write entire image and metadata.
*
*/
-
static int write_suspend_image(void)
{
int error;
@@ -400,6 +544,7 @@
if ((error = close_swap()))
goto FreePagedir;
Done:
+ memset(key_iv, 0, MAXKEY+MAXIV);
return error;
FreePagedir:
free_pagedir_entries();
@@ -591,18 +736,7 @@
static int calc_nr(int nr_copy)
{
- int extra = 0;
- int mod = !!(nr_copy % PBES_PER_PAGE);
- int diff = (nr_copy / PBES_PER_PAGE) + mod;
-
- do {
- extra += diff;
- nr_copy += diff;
- mod = !!(nr_copy % PBES_PER_PAGE);
- diff = (nr_copy / PBES_PER_PAGE) + mod - extra;
- } while (diff > 0);
-
- return nr_copy;
+ return nr_copy + (nr_copy+PBES_PER_PAGE-2)/(PBES_PER_PAGE-1);
}
/**
@@ -886,20 +1020,21 @@
* at resume time, and evil weirdness ensues.
*/
if ((error = device_power_down(PMSG_FREEZE))) {
+ printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
local_irq_enable();
return error;
}
if ((error = swsusp_swap_check())) {
- printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
- "swapon -a!\n");
+ printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
+ device_power_up();
local_irq_enable();
return error;
}
save_processor_state();
if ((error = swsusp_arch_suspend()))
- printk("Error %d suspending\n", error);
+ printk(KERN_ERR "Error %d suspending\n", error);
/* Restore control flow magically appears here */
restore_processor_state();
BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -924,6 +1059,7 @@
BUG_ON(!error);
restore_processor_state();
restore_highmem();
+ touch_softlockup_watchdog();
device_power_up();
local_irq_enable();
return error;
@@ -1179,7 +1315,8 @@
if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
return "machine";
#if 0
- if(swsusp_info.cpus != num_online_cpus())
+ /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */
+ if (swsusp_info.cpus != num_possible_cpus())
return "number of cpus";
#endif
return NULL;
@@ -1212,13 +1349,14 @@
return error;
if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
+ memcpy(key_iv, swsusp_header.key_iv, MAXKEY+MAXIV);
+ memset(swsusp_header.key_iv, 0, MAXKEY+MAXIV);
/*
* Reset swap signature now.
*/
error = bio_write_page(0, &swsusp_header);
} else {
- printk(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
return -EINVAL;
}
if (!error)
@@ -1239,6 +1377,10 @@
int error = 0;
int i = 0;
int mod = swsusp_info.image_pages / 100;
+ void *tfm;
+
+ if ((error = crypto_init(0, &tfm)))
+ return error;
if (!mod)
mod = 1;
@@ -1250,14 +1392,15 @@
if (!(i % mod))
printk("\b\b\b\b%3d%%", i / mod);
- error = bio_read_page(swp_offset(p->swap_address),
- (void *)p->address);
- if (error)
+ if ((error = crypto_read(p, tfm))) {
+ crypto_exit(tfm);
return error;
+ }
i++;
}
printk("\b\b\b\bdone\n");
+ crypto_exit(tfm);
return error;
}
@@ -1385,6 +1528,7 @@
error = read_suspend_image();
blkdev_put(resume_bdev);
+ memset(key_iv, 0, MAXKEY+MAXIV);
if (!error)
pr_debug("swsusp: Reading resume file was successful\n");
diff --git a/kernel/printk.c b/kernel/printk.c
index 5092397..a967605 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -514,6 +514,9 @@
return r;
}
+/* cpu currently holding logbuf_lock */
+static volatile unsigned int printk_cpu = UINT_MAX;
+
asmlinkage int vprintk(const char *fmt, va_list args)
{
unsigned long flags;
@@ -522,11 +525,15 @@
static char printk_buf[1024];
static int log_level_unknown = 1;
- if (unlikely(oops_in_progress))
+ preempt_disable();
+ if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
+ /* If a crash is occurring during printk() on this CPU,
+ * make sure we can't deadlock */
zap_locks();
/* This stops the holder of console_sem just where we want him */
spin_lock_irqsave(&logbuf_lock, flags);
+ printk_cpu = smp_processor_id();
/* Emit the output into the temporary buffer */
printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
@@ -595,6 +602,7 @@
* CPU until it is officially up. We shouldn't be calling into
* random console drivers on a CPU which doesn't exist yet..
*/
+ printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
goto out;
}
@@ -604,6 +612,7 @@
* We own the drivers. We can drop the spinlock and let
* release_console_sem() print the text
*/
+ printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
console_may_schedule = 0;
release_console_sem();
@@ -613,9 +622,11 @@
* allows the semaphore holder to proceed and to call the
* console drivers with the output which we just produced.
*/
+ printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
}
out:
+ preempt_enable();
return printed_len;
}
EXPORT_SYMBOL(printk);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 8dcb8f6..019e04e 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -118,6 +118,33 @@
return ret;
}
+static int may_attach(struct task_struct *task)
+{
+ if (!task->mm)
+ return -EPERM;
+ if (((current->uid != task->euid) ||
+ (current->uid != task->suid) ||
+ (current->uid != task->uid) ||
+ (current->gid != task->egid) ||
+ (current->gid != task->sgid) ||
+ (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+ return -EPERM;
+ smp_rmb();
+ if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+ return -EPERM;
+
+ return security_ptrace(current, task);
+}
+
+int ptrace_may_attach(struct task_struct *task)
+{
+ int err;
+ task_lock(task);
+ err = may_attach(task);
+ task_unlock(task);
+ return !err;
+}
+
int ptrace_attach(struct task_struct *task)
{
int retval;
@@ -127,22 +154,10 @@
goto bad;
if (task == current)
goto bad;
- if (!task->mm)
- goto bad;
- if(((current->uid != task->euid) ||
- (current->uid != task->suid) ||
- (current->uid != task->uid) ||
- (current->gid != task->egid) ||
- (current->gid != task->sgid) ||
- (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
- goto bad;
- smp_rmb();
- if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
- goto bad;
/* the same process cannot be attached many times */
if (task->ptrace & PT_PTRACED)
goto bad;
- retval = security_ptrace(current, task);
+ retval = may_attach(task);
if (retval)
goto bad;
diff --git a/kernel/resource.c b/kernel/resource.c
index 26967e0..92285d8 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -430,10 +430,9 @@
*/
struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
{
- struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+ struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
if (res) {
- memset(res, 0, sizeof(*res));
res->name = name;
res->start = start;
res->end = start + n - 1;
diff --git a/kernel/sched.c b/kernel/sched.c
index 5f889d0..18b9552 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1478,6 +1478,7 @@
/**
* finish_task_switch - clean up after a task-switch
+ * @rq: runqueue associated with task-switch
* @prev: the thread we just switched away from.
*
* finish_task_switch must be called after the context switch, paired
@@ -4779,7 +4780,7 @@
* Attach the domain 'sd' to 'cpu' as its base domain. Callers must
* hold the hotplug lock.
*/
-void cpu_attach_domain(struct sched_domain *sd, int cpu)
+static void cpu_attach_domain(struct sched_domain *sd, int cpu)
{
runqueue_t *rq = cpu_rq(cpu);
struct sched_domain *tmp;
@@ -4802,7 +4803,7 @@
}
/* cpus with isolated domains */
-cpumask_t __devinitdata cpu_isolated_map = CPU_MASK_NONE;
+static cpumask_t __devinitdata cpu_isolated_map = CPU_MASK_NONE;
/* Setup the mask of cpus configured for isolated domains */
static int __init isolated_cpu_setup(char *str)
@@ -4830,8 +4831,8 @@
* covered by the given span, and will set each group's ->cpumask correctly,
* and ->cpu_power to 0.
*/
-void init_sched_build_groups(struct sched_group groups[],
- cpumask_t span, int (*group_fn)(int cpu))
+static void init_sched_build_groups(struct sched_group groups[], cpumask_t span,
+ int (*group_fn)(int cpu))
{
struct sched_group *first = NULL, *last = NULL;
cpumask_t covered = CPU_MASK_NONE;
@@ -4864,12 +4865,85 @@
last->next = first;
}
+#define SD_NODES_PER_DOMAIN 16
-#ifdef ARCH_HAS_SCHED_DOMAIN
-extern void build_sched_domains(const cpumask_t *cpu_map);
-extern void arch_init_sched_domains(const cpumask_t *cpu_map);
-extern void arch_destroy_sched_domains(const cpumask_t *cpu_map);
-#else
+#ifdef CONFIG_NUMA
+/**
+ * find_next_best_node - find the next node to include in a sched_domain
+ * @node: node whose sched_domain we're building
+ * @used_nodes: nodes already in the sched_domain
+ *
+ * Find the next node to include in a given scheduling domain. Simply
+ * finds the closest node not already in the @used_nodes map.
+ *
+ * Should use nodemask_t.
+ */
+static int find_next_best_node(int node, unsigned long *used_nodes)
+{
+ int i, n, val, min_val, best_node = 0;
+
+ min_val = INT_MAX;
+
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ /* Start at @node */
+ n = (node + i) % MAX_NUMNODES;
+
+ if (!nr_cpus_node(n))
+ continue;
+
+ /* Skip already used nodes */
+ if (test_bit(n, used_nodes))
+ continue;
+
+ /* Simple min distance search */
+ val = node_distance(node, n);
+
+ if (val < min_val) {
+ min_val = val;
+ best_node = n;
+ }
+ }
+
+ set_bit(best_node, used_nodes);
+ return best_node;
+}
+
+/**
+ * sched_domain_node_span - get a cpumask for a node's sched_domain
+ * @node: node whose cpumask we're constructing
+ * @size: number of nodes to include in this span
+ *
+ * Given a node, construct a good cpumask for its sched_domain to span. It
+ * should be one that prevents unnecessary balancing, but also spreads tasks
+ * out optimally.
+ */
+static cpumask_t sched_domain_node_span(int node)
+{
+ int i;
+ cpumask_t span, nodemask;
+ DECLARE_BITMAP(used_nodes, MAX_NUMNODES);
+
+ cpus_clear(span);
+ bitmap_zero(used_nodes, MAX_NUMNODES);
+
+ nodemask = node_to_cpumask(node);
+ cpus_or(span, span, nodemask);
+ set_bit(node, used_nodes);
+
+ for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
+ int next_node = find_next_best_node(node, used_nodes);
+ nodemask = node_to_cpumask(next_node);
+ cpus_or(span, span, nodemask);
+ }
+
+ return span;
+}
+#endif
+
+/*
+ * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
+ * can switch it on easily if needed.
+ */
#ifdef CONFIG_SCHED_SMT
static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
static struct sched_group sched_group_cpus[NR_CPUS];
@@ -4891,46 +4965,45 @@
}
#ifdef CONFIG_NUMA
-
+/*
+ * The init_sched_build_groups can't handle what we want to do with node
+ * groups, so roll our own. Now each node has its own list of groups which
+ * gets dynamically allocated.
+ */
static DEFINE_PER_CPU(struct sched_domain, node_domains);
-static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static int cpu_to_node_group(int cpu)
+static struct sched_group **sched_group_nodes_bycpu[NR_CPUS];
+
+static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
+static struct sched_group *sched_group_allnodes_bycpu[NR_CPUS];
+
+static int cpu_to_allnodes_group(int cpu)
{
return cpu_to_node(cpu);
}
#endif
-#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
-/*
- * The domains setup code relies on siblings not spanning
- * multiple nodes. Make sure the architecture has a proper
- * siblings map:
- */
-static void check_sibling_maps(void)
-{
- int i, j;
-
- for_each_online_cpu(i) {
- for_each_cpu_mask(j, cpu_sibling_map[i]) {
- if (cpu_to_node(i) != cpu_to_node(j)) {
- printk(KERN_INFO "warning: CPU %d siblings map "
- "to different node - isolating "
- "them.\n", i);
- cpu_sibling_map[i] = cpumask_of_cpu(i);
- break;
- }
- }
- }
-}
-#endif
-
/*
* Build sched domains for a given set of cpus and attach the sched domains
* to the individual cpus
*/
-static void build_sched_domains(const cpumask_t *cpu_map)
+void build_sched_domains(const cpumask_t *cpu_map)
{
int i;
+#ifdef CONFIG_NUMA
+ struct sched_group **sched_group_nodes = NULL;
+ struct sched_group *sched_group_allnodes = NULL;
+
+ /*
+ * Allocate the per-node list of sched groups
+ */
+ sched_group_nodes = kmalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
+ GFP_ATOMIC);
+ if (!sched_group_nodes) {
+ printk(KERN_WARNING "Can not alloc sched group node list\n");
+ return;
+ }
+ sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes;
+#endif
/*
* Set up domains for cpus specified by the cpu_map.
@@ -4943,11 +5016,35 @@
cpus_and(nodemask, nodemask, *cpu_map);
#ifdef CONFIG_NUMA
+ if (cpus_weight(*cpu_map)
+ > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
+ if (!sched_group_allnodes) {
+ sched_group_allnodes
+ = kmalloc(sizeof(struct sched_group)
+ * MAX_NUMNODES,
+ GFP_KERNEL);
+ if (!sched_group_allnodes) {
+ printk(KERN_WARNING
+ "Can not alloc allnodes sched group\n");
+ break;
+ }
+ sched_group_allnodes_bycpu[i]
+ = sched_group_allnodes;
+ }
+ sd = &per_cpu(allnodes_domains, i);
+ *sd = SD_ALLNODES_INIT;
+ sd->span = *cpu_map;
+ group = cpu_to_allnodes_group(i);
+ sd->groups = &sched_group_allnodes[group];
+ p = sd;
+ } else
+ p = NULL;
+
sd = &per_cpu(node_domains, i);
- group = cpu_to_node_group(i);
*sd = SD_NODE_INIT;
- sd->span = *cpu_map;
- sd->groups = &sched_group_nodes[group];
+ sd->span = sched_domain_node_span(cpu_to_node(i));
+ sd->parent = p;
+ cpus_and(sd->span, sd->span, *cpu_map);
#endif
p = sd;
@@ -4972,7 +5069,7 @@
#ifdef CONFIG_SCHED_SMT
/* Set up CPU (sibling) groups */
- for_each_online_cpu(i) {
+ for_each_cpu_mask(i, *cpu_map) {
cpumask_t this_sibling_map = cpu_sibling_map[i];
cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
if (i != first_cpu(this_sibling_map))
@@ -4997,8 +5094,77 @@
#ifdef CONFIG_NUMA
/* Set up node groups */
- init_sched_build_groups(sched_group_nodes, *cpu_map,
- &cpu_to_node_group);
+ if (sched_group_allnodes)
+ init_sched_build_groups(sched_group_allnodes, *cpu_map,
+ &cpu_to_allnodes_group);
+
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ /* Set up node groups */
+ struct sched_group *sg, *prev;
+ cpumask_t nodemask = node_to_cpumask(i);
+ cpumask_t domainspan;
+ cpumask_t covered = CPU_MASK_NONE;
+ int j;
+
+ cpus_and(nodemask, nodemask, *cpu_map);
+ if (cpus_empty(nodemask)) {
+ sched_group_nodes[i] = NULL;
+ continue;
+ }
+
+ domainspan = sched_domain_node_span(i);
+ cpus_and(domainspan, domainspan, *cpu_map);
+
+ sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+ sched_group_nodes[i] = sg;
+ for_each_cpu_mask(j, nodemask) {
+ struct sched_domain *sd;
+ sd = &per_cpu(node_domains, j);
+ sd->groups = sg;
+ if (sd->groups == NULL) {
+ /* Turn off balancing if we have no groups */
+ sd->flags = 0;
+ }
+ }
+ if (!sg) {
+ printk(KERN_WARNING
+ "Can not alloc domain group for node %d\n", i);
+ continue;
+ }
+ sg->cpu_power = 0;
+ sg->cpumask = nodemask;
+ cpus_or(covered, covered, nodemask);
+ prev = sg;
+
+ for (j = 0; j < MAX_NUMNODES; j++) {
+ cpumask_t tmp, notcovered;
+ int n = (i + j) % MAX_NUMNODES;
+
+ cpus_complement(notcovered, covered);
+ cpus_and(tmp, notcovered, *cpu_map);
+ cpus_and(tmp, tmp, domainspan);
+ if (cpus_empty(tmp))
+ break;
+
+ nodemask = node_to_cpumask(n);
+ cpus_and(tmp, tmp, nodemask);
+ if (cpus_empty(tmp))
+ continue;
+
+ sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+ if (!sg) {
+ printk(KERN_WARNING
+ "Can not alloc domain group for node %d\n", j);
+ break;
+ }
+ sg->cpu_power = 0;
+ sg->cpumask = tmp;
+ cpus_or(covered, covered, tmp);
+ prev->next = sg;
+ prev = sg;
+ }
+ prev->next = sched_group_nodes[i];
+ }
#endif
/* Calculate CPU power for physical packages and nodes */
@@ -5017,14 +5183,46 @@
sd->groups->cpu_power = power;
#ifdef CONFIG_NUMA
- if (i == first_cpu(sd->groups->cpumask)) {
- /* Only add "power" once for each physical package. */
- sd = &per_cpu(node_domains, i);
- sd->groups->cpu_power += power;
+ sd = &per_cpu(allnodes_domains, i);
+ if (sd->groups) {
+ power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+ (cpus_weight(sd->groups->cpumask)-1) / 10;
+ sd->groups->cpu_power = power;
}
#endif
}
+#ifdef CONFIG_NUMA
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ struct sched_group *sg = sched_group_nodes[i];
+ int j;
+
+ if (sg == NULL)
+ continue;
+next_sg:
+ for_each_cpu_mask(j, sg->cpumask) {
+ struct sched_domain *sd;
+ int power;
+
+ sd = &per_cpu(phys_domains, j);
+ if (j != first_cpu(sd->groups->cpumask)) {
+ /*
+ * Only add "power" once for each
+ * physical package.
+ */
+ continue;
+ }
+ power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+ (cpus_weight(sd->groups->cpumask)-1) / 10;
+
+ sg->cpu_power += power;
+ }
+ sg = sg->next;
+ if (sg != sched_group_nodes[i])
+ goto next_sg;
+ }
+#endif
+
/* Attach the domains */
for_each_cpu_mask(i, *cpu_map) {
struct sched_domain *sd;
@@ -5039,13 +5237,10 @@
/*
* Set up scheduler domains and groups. Callers must hold the hotplug lock.
*/
-static void arch_init_sched_domains(cpumask_t *cpu_map)
+static void arch_init_sched_domains(const cpumask_t *cpu_map)
{
cpumask_t cpu_default_map;
-#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
- check_sibling_maps();
-#endif
/*
* Setup mask for cpus without special case scheduling requirements.
* For now this just excludes isolated cpus, but could be used to
@@ -5058,10 +5253,47 @@
static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
{
- /* Do nothing: everything is statically allocated. */
-}
+#ifdef CONFIG_NUMA
+ int i;
+ int cpu;
-#endif /* ARCH_HAS_SCHED_DOMAIN */
+ for_each_cpu_mask(cpu, *cpu_map) {
+ struct sched_group *sched_group_allnodes
+ = sched_group_allnodes_bycpu[cpu];
+ struct sched_group **sched_group_nodes
+ = sched_group_nodes_bycpu[cpu];
+
+ if (sched_group_allnodes) {
+ kfree(sched_group_allnodes);
+ sched_group_allnodes_bycpu[cpu] = NULL;
+ }
+
+ if (!sched_group_nodes)
+ continue;
+
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ cpumask_t nodemask = node_to_cpumask(i);
+ struct sched_group *oldsg, *sg = sched_group_nodes[i];
+
+ cpus_and(nodemask, nodemask, *cpu_map);
+ if (cpus_empty(nodemask))
+ continue;
+
+ if (sg == NULL)
+ continue;
+ sg = sg->next;
+next_sg:
+ oldsg = sg;
+ sg = sg->next;
+ kfree(oldsg);
+ if (oldsg != sched_group_nodes[i])
+ goto next_sg;
+ }
+ kfree(sched_group_nodes);
+ sched_group_nodes_bycpu[cpu] = NULL;
+ }
+#endif
+}
/*
* Detach sched domains from a group of cpus specified in cpu_map
diff --git a/kernel/signal.c b/kernel/signal.c
index d282fea..4980a07 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -678,7 +678,7 @@
/* forward decl */
static void do_notify_parent_cldstop(struct task_struct *tsk,
- struct task_struct *parent,
+ int to_self,
int why);
/*
@@ -729,14 +729,7 @@
p->signal->group_stop_count = 0;
p->signal->flags = SIGNAL_STOP_CONTINUED;
spin_unlock(&p->sighand->siglock);
- if (p->ptrace & PT_PTRACED)
- do_notify_parent_cldstop(p, p->parent,
- CLD_STOPPED);
- else
- do_notify_parent_cldstop(
- p->group_leader,
- p->group_leader->real_parent,
- CLD_STOPPED);
+ do_notify_parent_cldstop(p, (p->ptrace & PT_PTRACED), CLD_STOPPED);
spin_lock(&p->sighand->siglock);
}
rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
@@ -777,14 +770,7 @@
p->signal->flags = SIGNAL_STOP_CONTINUED;
p->signal->group_exit_code = 0;
spin_unlock(&p->sighand->siglock);
- if (p->ptrace & PT_PTRACED)
- do_notify_parent_cldstop(p, p->parent,
- CLD_CONTINUED);
- else
- do_notify_parent_cldstop(
- p->group_leader,
- p->group_leader->real_parent,
- CLD_CONTINUED);
+ do_notify_parent_cldstop(p, (p->ptrace & PT_PTRACED), CLD_CONTINUED);
spin_lock(&p->sighand->siglock);
} else {
/*
@@ -1380,16 +1366,16 @@
unsigned long flags;
int ret = 0;
- /*
- * We need the tasklist lock even for the specific
- * thread case (when we don't need to follow the group
- * lists) in order to avoid races with "p->sighand"
- * going away or changing from under us.
- */
BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
- read_lock(&tasklist_lock);
+ read_lock(&tasklist_lock);
+
+ if (unlikely(p->flags & PF_EXITING)) {
+ ret = -1;
+ goto out_err;
+ }
+
spin_lock_irqsave(&p->sighand->siglock, flags);
-
+
if (unlikely(!list_empty(&q->list))) {
/*
* If an SI_TIMER entry is already queue just increment
@@ -1399,7 +1385,7 @@
BUG();
q->info.si_overrun++;
goto out;
- }
+ }
/* Short-circuit ignored signals. */
if (sig_ignored(p, sig)) {
ret = 1;
@@ -1414,8 +1400,10 @@
out:
spin_unlock_irqrestore(&p->sighand->siglock, flags);
+out_err:
read_unlock(&tasklist_lock);
- return(ret);
+
+ return ret;
}
int
@@ -1542,14 +1530,20 @@
spin_unlock_irqrestore(&psig->siglock, flags);
}
-static void
-do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent,
- int why)
+static void do_notify_parent_cldstop(struct task_struct *tsk, int to_self, int why)
{
struct siginfo info;
unsigned long flags;
+ struct task_struct *parent;
struct sighand_struct *sighand;
+ if (to_self)
+ parent = tsk->parent;
+ else {
+ tsk = tsk->group_leader;
+ parent = tsk->real_parent;
+ }
+
info.si_signo = SIGCHLD;
info.si_errno = 0;
info.si_pid = tsk->pid;
@@ -1618,8 +1612,7 @@
!(current->ptrace & PT_ATTACHED)) &&
(likely(current->parent->signal != current->signal) ||
!unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) {
- do_notify_parent_cldstop(current, current->parent,
- CLD_TRAPPED);
+ do_notify_parent_cldstop(current, 1, CLD_TRAPPED);
read_unlock(&tasklist_lock);
schedule();
} else {
@@ -1668,25 +1661,25 @@
static void
finish_stop(int stop_count)
{
+ int to_self;
+
/*
* If there are no other threads in the group, or if there is
* a group stop in progress and we are the last to stop,
* report to the parent. When ptraced, every thread reports itself.
*/
- if (stop_count < 0 || (current->ptrace & PT_PTRACED)) {
- read_lock(&tasklist_lock);
- do_notify_parent_cldstop(current, current->parent,
- CLD_STOPPED);
- read_unlock(&tasklist_lock);
- }
- else if (stop_count == 0) {
- read_lock(&tasklist_lock);
- do_notify_parent_cldstop(current->group_leader,
- current->group_leader->real_parent,
- CLD_STOPPED);
- read_unlock(&tasklist_lock);
- }
+ if (stop_count < 0 || (current->ptrace & PT_PTRACED))
+ to_self = 1;
+ else if (stop_count == 0)
+ to_self = 0;
+ else
+ goto out;
+ read_lock(&tasklist_lock);
+ do_notify_parent_cldstop(current, to_self, CLD_STOPPED);
+ read_unlock(&tasklist_lock);
+
+out:
schedule();
/*
* Now we don't run again until continued.
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
new file mode 100644
index 0000000..7597620
--- /dev/null
+++ b/kernel/softlockup.c
@@ -0,0 +1,151 @@
+/*
+ * Detect Soft Lockups
+ *
+ * started by Ingo Molnar, (C) 2005, Red Hat
+ *
+ * this code detects soft lockups: incidents in where on a CPU
+ * the kernel does not reschedule for 10 seconds or more.
+ */
+
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+
+static DEFINE_SPINLOCK(print_lock);
+
+static DEFINE_PER_CPU(unsigned long, timestamp) = 0;
+static DEFINE_PER_CPU(unsigned long, print_timestamp) = 0;
+static DEFINE_PER_CPU(struct task_struct *, watchdog_task);
+
+static int did_panic = 0;
+static int softlock_panic(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ did_panic = 1;
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+ .notifier_call = softlock_panic,
+};
+
+void touch_softlockup_watchdog(void)
+{
+ per_cpu(timestamp, raw_smp_processor_id()) = jiffies;
+}
+EXPORT_SYMBOL(touch_softlockup_watchdog);
+
+/*
+ * This callback runs from the timer interrupt, and checks
+ * whether the watchdog thread has hung or not:
+ */
+void softlockup_tick(struct pt_regs *regs)
+{
+ int this_cpu = smp_processor_id();
+ unsigned long timestamp = per_cpu(timestamp, this_cpu);
+
+ if (per_cpu(print_timestamp, this_cpu) == timestamp)
+ return;
+
+ /* Do not cause a second panic when there already was one */
+ if (did_panic)
+ return;
+
+ if (time_after(jiffies, timestamp + 10*HZ)) {
+ per_cpu(print_timestamp, this_cpu) = timestamp;
+
+ spin_lock(&print_lock);
+ printk(KERN_ERR "BUG: soft lockup detected on CPU#%d!\n",
+ this_cpu);
+ show_regs(regs);
+ spin_unlock(&print_lock);
+ }
+}
+
+/*
+ * The watchdog thread - runs every second and touches the timestamp.
+ */
+static int watchdog(void * __bind_cpu)
+{
+ struct sched_param param = { .sched_priority = 99 };
+ int this_cpu = (long) __bind_cpu;
+
+ printk("softlockup thread %d started up.\n", this_cpu);
+
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+ current->flags |= PF_NOFREEZE;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * Run briefly once per second - if this gets delayed for
+ * more than 10 seconds then the debug-printout triggers
+ * in softlockup_tick():
+ */
+ while (!kthread_should_stop()) {
+ msleep_interruptible(1000);
+ touch_softlockup_watchdog();
+ }
+ __set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+/*
+ * Create/destroy watchdog threads as CPUs come and go:
+ */
+static int __devinit
+cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+ struct task_struct *p;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ BUG_ON(per_cpu(watchdog_task, hotcpu));
+ p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
+ if (IS_ERR(p)) {
+ printk("watchdog for %i failed\n", hotcpu);
+ return NOTIFY_BAD;
+ }
+ per_cpu(watchdog_task, hotcpu) = p;
+ kthread_bind(p, hotcpu);
+ break;
+ case CPU_ONLINE:
+
+ wake_up_process(per_cpu(watchdog_task, hotcpu));
+ break;
+#ifdef CONFIG_HOTPLUG_CPU
+ case CPU_UP_CANCELED:
+ /* Unbind so it can run. Fall thru. */
+ kthread_bind(per_cpu(watchdog_task, hotcpu), smp_processor_id());
+ case CPU_DEAD:
+ p = per_cpu(watchdog_task, hotcpu);
+ per_cpu(watchdog_task, hotcpu) = NULL;
+ kthread_stop(p);
+ break;
+#endif /* CONFIG_HOTPLUG_CPU */
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata cpu_nfb = {
+ .notifier_call = cpu_callback
+};
+
+__init void spawn_softlockup_task(void)
+{
+ void *cpu = (void *)(long)smp_processor_id();
+
+ cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+ register_cpu_notifier(&cpu_nfb);
+
+ notifier_chain_register(&panic_notifier_list, &panic_block);
+}
+
diff --git a/kernel/sys.c b/kernel/sys.c
index 0bcaed6..c80412b 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1711,7 +1711,6 @@
unsigned long arg4, unsigned long arg5)
{
long error;
- int sig;
error = security_task_prctl(option, arg2, arg3, arg4, arg5);
if (error)
@@ -1719,12 +1718,11 @@
switch (option) {
case PR_SET_PDEATHSIG:
- sig = arg2;
- if (!valid_signal(sig)) {
+ if (!valid_signal(arg2)) {
error = -EINVAL;
break;
}
- current->pdeath_signal = sig;
+ current->pdeath_signal = arg2;
break;
case PR_GET_PDEATHSIG:
error = put_user(current->pdeath_signal, (int __user *)arg2);
diff --git a/kernel/timer.c b/kernel/timer.c
index 5377f40..13e2b51 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -950,6 +950,7 @@
{
jiffies_64++;
update_times();
+ softlockup_tick(regs);
}
#ifdef __ARCH_WANT_SYS_ALARM
@@ -1428,7 +1429,7 @@
}
}
-static inline u64 time_interpolator_get_counter(void)
+static inline u64 time_interpolator_get_counter(int writelock)
{
unsigned int src = time_interpolator->source;
@@ -1442,6 +1443,15 @@
now = time_interpolator_get_cycles(src);
if (lcycle && time_after(lcycle, now))
return lcycle;
+
+ /* When holding the xtime write lock, there's no need
+ * to add the overhead of the cmpxchg. Readers are
+ * force to retry until the write lock is released.
+ */
+ if (writelock) {
+ time_interpolator->last_cycle = now;
+ return now;
+ }
/* Keep track of the last timer value returned. The use of cmpxchg here
* will cause contention in an SMP environment.
*/
@@ -1455,7 +1465,7 @@
void time_interpolator_reset(void)
{
time_interpolator->offset = 0;
- time_interpolator->last_counter = time_interpolator_get_counter();
+ time_interpolator->last_counter = time_interpolator_get_counter(1);
}
#define GET_TI_NSECS(count,i) (((((count) - i->last_counter) & (i)->mask) * (i)->nsec_per_cyc) >> (i)->shift)
@@ -1467,7 +1477,7 @@
return 0;
return time_interpolator->offset +
- GET_TI_NSECS(time_interpolator_get_counter(), time_interpolator);
+ GET_TI_NSECS(time_interpolator_get_counter(0), time_interpolator);
}
#define INTERPOLATOR_ADJUST 65536
@@ -1490,7 +1500,7 @@
* and the tuning logic insures that.
*/
- counter = time_interpolator_get_counter();
+ counter = time_interpolator_get_counter(1);
offset = time_interpolator->offset + GET_TI_NSECS(counter, time_interpolator);
if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index c7e36d4..91bacb1 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -308,10 +308,9 @@
struct workqueue_struct *wq;
struct task_struct *p;
- wq = kmalloc(sizeof(*wq), GFP_KERNEL);
+ wq = kzalloc(sizeof(*wq), GFP_KERNEL);
if (!wq)
return NULL;
- memset(wq, 0, sizeof(*wq));
wq->name = name;
/* We don't need the distraction of CPUs appearing and vanishing. */
@@ -499,7 +498,7 @@
case CPU_UP_PREPARE:
/* Create a new workqueue thread for it. */
list_for_each_entry(wq, &workqueues, list) {
- if (create_workqueue_thread(wq, hotcpu) < 0) {
+ if (!create_workqueue_thread(wq, hotcpu)) {
printk("workqueue for %i failed\n", hotcpu);
return NOTIFY_BAD;
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 299f7f3..3754c9a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -46,6 +46,25 @@
13 => 8 KB
12 => 4 KB
+config DETECT_SOFTLOCKUP
+ bool "Detect Soft Lockups"
+ depends on DEBUG_KERNEL
+ default y
+ help
+ Say Y here to enable the kernel to detect "soft lockups",
+ which are bugs that cause the kernel to loop in kernel
+ mode for more than 10 seconds, without giving other tasks a
+ chance to run.
+
+ When a soft-lockup is detected, the kernel will print the
+ current stack trace (which you should report), but the
+ system will stay locked up. This feature has negligible
+ overhead.
+
+ (Note that "hard lockups" are separate type of bugs that
+ can be detected via the NMI-watchdog, on platforms that
+ support it.)
+
config SCHEDSTATS
bool "Collect scheduler statistics"
depends on DEBUG_KERNEL && PROC_FS
diff --git a/lib/Makefile b/lib/Makefile
index 52f8338..3e2bd0d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -18,6 +18,7 @@
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
diff --git a/lib/klist.c b/lib/klist.c
index 738ab81..bb2f355 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -42,12 +42,23 @@
/**
* klist_init - Initialize a klist structure.
* @k: The klist we're initializing.
+ * @get: The get function for the embedding object (NULL if none)
+ * @put: The put function for the embedding object (NULL if none)
+ *
+ * Initialises the klist structure. If the klist_node structures are
+ * going to be embedded in refcounted objects (necessary for safe
+ * deletion) then the get/put arguments are used to initialise
+ * functions that take and release references on the embedding
+ * objects.
*/
-void klist_init(struct klist * k)
+void klist_init(struct klist * k, void (*get)(struct klist_node *),
+ void (*put)(struct klist_node *))
{
INIT_LIST_HEAD(&k->k_list);
spin_lock_init(&k->k_lock);
+ k->get = get;
+ k->put = put;
}
EXPORT_SYMBOL_GPL(klist_init);
@@ -74,16 +85,18 @@
init_completion(&n->n_removed);
kref_init(&n->n_ref);
n->n_klist = k;
+ if (k->get)
+ k->get(n);
}
/**
* klist_add_head - Initialize a klist_node and add it to front.
- * @k: klist it's going on.
* @n: node we're adding.
+ * @k: klist it's going on.
*/
-void klist_add_head(struct klist * k, struct klist_node * n)
+void klist_add_head(struct klist_node * n, struct klist * k)
{
klist_node_init(k, n);
add_head(k, n);
@@ -94,11 +107,11 @@
/**
* klist_add_tail - Initialize a klist_node and add it to back.
- * @k: klist it's going on.
* @n: node we're adding.
+ * @k: klist it's going on.
*/
-void klist_add_tail(struct klist * k, struct klist_node * n)
+void klist_add_tail(struct klist_node * n, struct klist * k)
{
klist_node_init(k, n);
add_tail(k, n);
@@ -110,9 +123,12 @@
static void klist_release(struct kref * kref)
{
struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+ void (*put)(struct klist_node *) = n->n_klist->put;
list_del(&n->n_node);
complete(&n->n_removed);
n->n_klist = NULL;
+ if (put)
+ put(n);
}
static int klist_dec_and_del(struct klist_node * n)
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 10bed1c..b972dd2 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2001 Momchil Velikov
* Portions Copyright (C) 2001 Christoph Hellwig
+ * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -51,7 +52,7 @@
};
struct radix_tree_path {
- struct radix_tree_node *node, **slot;
+ struct radix_tree_node *node;
int offset;
};
@@ -227,7 +228,7 @@
int radix_tree_insert(struct radix_tree_root *root,
unsigned long index, void *item)
{
- struct radix_tree_node *node = NULL, *tmp, **slot;
+ struct radix_tree_node *node = NULL, *slot;
unsigned int height, shift;
int offset;
int error;
@@ -240,38 +241,42 @@
return error;
}
- slot = &root->rnode;
+ slot = root->rnode;
height = root->height;
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
offset = 0; /* uninitialised var warning */
while (height > 0) {
- if (*slot == NULL) {
+ if (slot == NULL) {
/* Have to add a child node. */
- if (!(tmp = radix_tree_node_alloc(root)))
+ if (!(slot = radix_tree_node_alloc(root)))
return -ENOMEM;
- *slot = tmp;
- if (node)
+ if (node) {
+ node->slots[offset] = slot;
node->count++;
+ } else
+ root->rnode = slot;
}
/* Go a level down */
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
- node = *slot;
- slot = (struct radix_tree_node **)(node->slots + offset);
+ node = slot;
+ slot = node->slots[offset];
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
- if (*slot != NULL)
+ if (slot != NULL)
return -EEXIST;
+
if (node) {
node->count++;
+ node->slots[offset] = item;
BUG_ON(tag_get(node, 0, offset));
BUG_ON(tag_get(node, 1, offset));
- }
+ } else
+ root->rnode = item;
- *slot = item;
return 0;
}
EXPORT_SYMBOL(radix_tree_insert);
@@ -286,27 +291,25 @@
void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
{
unsigned int height, shift;
- struct radix_tree_node **slot;
+ struct radix_tree_node *slot;
height = root->height;
if (index > radix_tree_maxindex(height))
return NULL;
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
- slot = &root->rnode;
+ slot = root->rnode;
while (height > 0) {
- if (*slot == NULL)
+ if (slot == NULL)
return NULL;
- slot = (struct radix_tree_node **)
- ((*slot)->slots +
- ((index >> shift) & RADIX_TREE_MAP_MASK));
+ slot = slot->slots[(index >> shift) & RADIX_TREE_MAP_MASK];
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
- return *slot;
+ return slot;
}
EXPORT_SYMBOL(radix_tree_lookup);
@@ -326,27 +329,27 @@
unsigned long index, int tag)
{
unsigned int height, shift;
- struct radix_tree_node **slot;
+ struct radix_tree_node *slot;
height = root->height;
if (index > radix_tree_maxindex(height))
return NULL;
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
- slot = &root->rnode;
+ slot = root->rnode;
while (height > 0) {
int offset;
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
- tag_set(*slot, tag, offset);
- slot = (struct radix_tree_node **)((*slot)->slots + offset);
- BUG_ON(*slot == NULL);
+ tag_set(slot, tag, offset);
+ slot = slot->slots[offset];
+ BUG_ON(slot == NULL);
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
- return *slot;
+ return slot;
}
EXPORT_SYMBOL(radix_tree_tag_set);
@@ -367,6 +370,7 @@
unsigned long index, int tag)
{
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
+ struct radix_tree_node *slot;
unsigned int height, shift;
void *ret = NULL;
@@ -376,38 +380,37 @@
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
pathp->node = NULL;
- pathp->slot = &root->rnode;
+ slot = root->rnode;
while (height > 0) {
int offset;
- if (*pathp->slot == NULL)
+ if (slot == NULL)
goto out;
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
pathp[1].offset = offset;
- pathp[1].node = *pathp[0].slot;
- pathp[1].slot = (struct radix_tree_node **)
- (pathp[1].node->slots + offset);
+ pathp[1].node = slot;
+ slot = slot->slots[offset];
pathp++;
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
- ret = *pathp[0].slot;
+ ret = slot;
if (ret == NULL)
goto out;
do {
int idx;
- tag_clear(pathp[0].node, tag, pathp[0].offset);
+ tag_clear(pathp->node, tag, pathp->offset);
for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
- if (pathp[0].node->tags[tag][idx])
+ if (pathp->node->tags[tag][idx])
goto out;
}
pathp--;
- } while (pathp[0].node);
+ } while (pathp->node);
out:
return ret;
}
@@ -415,21 +418,22 @@
#ifndef __KERNEL__ /* Only the test harness uses this at present */
/**
- * radix_tree_tag_get - get a tag on a radix tree node
- * @root: radix tree root
- * @index: index key
- * @tag: tag index
+ * radix_tree_tag_get - get a tag on a radix tree node
+ * @root: radix tree root
+ * @index: index key
+ * @tag: tag index
*
- * Return the search tag corresponging to @index in the radix tree.
+ * Return values:
*
- * Returns zero if the tag is unset, or if there is no corresponding item
- * in the tree.
+ * 0: tag not present
+ * 1: tag present, set
+ * -1: tag present, unset
*/
int radix_tree_tag_get(struct radix_tree_root *root,
unsigned long index, int tag)
{
unsigned int height, shift;
- struct radix_tree_node **slot;
+ struct radix_tree_node *slot;
int saw_unset_tag = 0;
height = root->height;
@@ -437,12 +441,12 @@
return 0;
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
- slot = &root->rnode;
+ slot = root->rnode;
for ( ; ; ) {
int offset;
- if (*slot == NULL)
+ if (slot == NULL)
return 0;
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
@@ -451,15 +455,15 @@
* This is just a debug check. Later, we can bale as soon as
* we see an unset tag.
*/
- if (!tag_get(*slot, tag, offset))
+ if (!tag_get(slot, tag, offset))
saw_unset_tag = 1;
if (height == 1) {
- int ret = tag_get(*slot, tag, offset);
+ int ret = tag_get(slot, tag, offset);
BUG_ON(ret && saw_unset_tag);
- return ret;
+ return ret ? 1 : -1;
}
- slot = (struct radix_tree_node **)((*slot)->slots + offset);
+ slot = slot->slots[offset];
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
@@ -472,17 +476,21 @@
unsigned int max_items, unsigned long *next_index)
{
unsigned int nr_found = 0;
- unsigned int shift;
- unsigned int height = root->height;
+ unsigned int shift, height;
struct radix_tree_node *slot;
+ unsigned long i;
+
+ height = root->height;
+ if (height == 0)
+ goto out;
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
slot = root->rnode;
- while (height > 0) {
- unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
+ for ( ; height > 1; height--) {
- for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
+ for (i = (index >> shift) & RADIX_TREE_MAP_MASK ;
+ i < RADIX_TREE_MAP_SIZE; i++) {
if (slot->slots[i] != NULL)
break;
index &= ~((1UL << shift) - 1);
@@ -492,22 +500,20 @@
}
if (i == RADIX_TREE_MAP_SIZE)
goto out;
- height--;
- if (height == 0) { /* Bottom level: grab some items */
- unsigned long j = index & RADIX_TREE_MAP_MASK;
- for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
- index++;
- if (slot->slots[j]) {
- results[nr_found++] = slot->slots[j];
- if (nr_found == max_items)
- goto out;
- }
- }
- }
shift -= RADIX_TREE_MAP_SHIFT;
slot = slot->slots[i];
}
+
+ /* Bottom level: grab some items */
+ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
+ index++;
+ if (slot->slots[i]) {
+ results[nr_found++] = slot->slots[i];
+ if (nr_found == max_items)
+ goto out;
+ }
+ }
out:
*next_index = index;
return nr_found;
@@ -655,6 +661,7 @@
{
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
struct radix_tree_path *orig_pathp;
+ struct radix_tree_node *slot;
unsigned int height, shift;
void *ret = NULL;
char tags[RADIX_TREE_TAGS];
@@ -666,25 +673,23 @@
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
pathp->node = NULL;
- pathp->slot = &root->rnode;
+ slot = root->rnode;
- while (height > 0) {
+ for ( ; height > 0; height--) {
int offset;
- if (*pathp->slot == NULL)
+ if (slot == NULL)
goto out;
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
pathp[1].offset = offset;
- pathp[1].node = *pathp[0].slot;
- pathp[1].slot = (struct radix_tree_node **)
- (pathp[1].node->slots + offset);
+ pathp[1].node = slot;
+ slot = slot->slots[offset];
pathp++;
shift -= RADIX_TREE_MAP_SHIFT;
- height--;
}
- ret = *pathp[0].slot;
+ ret = slot;
if (ret == NULL)
goto out;
@@ -704,10 +709,10 @@
if (tags[tag])
continue;
- tag_clear(pathp[0].node, tag, pathp[0].offset);
+ tag_clear(pathp->node, tag, pathp->offset);
for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
- if (pathp[0].node->tags[tag][idx]) {
+ if (pathp->node->tags[tag][idx]) {
tags[tag] = 1;
nr_cleared_tags--;
break;
@@ -715,18 +720,19 @@
}
}
pathp--;
- } while (pathp[0].node && nr_cleared_tags);
+ } while (pathp->node && nr_cleared_tags);
- pathp = orig_pathp;
- *pathp[0].slot = NULL;
- while (pathp[0].node && --pathp[0].node->count == 0) {
- pathp--;
- BUG_ON(*pathp[0].slot == NULL);
- *pathp[0].slot = NULL;
- radix_tree_node_free(pathp[1].node);
+ /* Now free the nodes we do not need anymore */
+ for (pathp = orig_pathp; pathp->node; pathp--) {
+ pathp->node->slots[pathp->offset] = NULL;
+ if (--pathp->node->count)
+ goto out;
+
+ /* Node with zero slots in use so free it */
+ radix_tree_node_free(pathp->node);
}
- if (root->rnode == NULL)
- root->height = 0;
+ root->rnode = NULL;
+ root->height = 0;
out:
return ret;
}
diff --git a/arch/x86_64/kernel/semaphore.c b/lib/semaphore-sleepers.c
similarity index 93%
rename from arch/x86_64/kernel/semaphore.c
rename to lib/semaphore-sleepers.c
index 48f7c18..4d5f188 100644
--- a/arch/x86_64/kernel/semaphore.c
+++ b/lib/semaphore-sleepers.c
@@ -1,5 +1,5 @@
/*
- * x86_64 semaphore implementation.
+ * i386 and x86-64 semaphore implementation.
*
* (C) Copyright 1999 Linus Torvalds
*
@@ -14,9 +14,8 @@
*/
#include <linux/config.h>
#include <linux/sched.h>
+#include <linux/err.h>
#include <linux/init.h>
-#include <asm/errno.h>
-
#include <asm/semaphore.h>
/*
@@ -50,12 +49,12 @@
* we cannot lose wakeup events.
*/
-void __up(struct semaphore *sem)
+fastcall void __up(struct semaphore *sem)
{
wake_up(&sem->wait);
}
-void __sched __down(struct semaphore * sem)
+fastcall void __sched __down(struct semaphore * sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
@@ -92,7 +91,7 @@
tsk->state = TASK_RUNNING;
}
-int __sched __down_interruptible(struct semaphore * sem)
+fastcall int __sched __down_interruptible(struct semaphore * sem)
{
int retval = 0;
struct task_struct *tsk = current;
@@ -155,7 +154,7 @@
* single "cmpxchg" without failure cases,
* but then it wouldn't work on a 386.
*/
-int __down_trylock(struct semaphore * sem)
+fastcall int __down_trylock(struct semaphore * sem)
{
int sleepers;
unsigned long flags;
@@ -176,5 +175,3 @@
spin_unlock_irqrestore(&sem->wait.lock, flags);
return 1;
}
-
-
diff --git a/mm/Kconfig b/mm/Kconfig
index cd37993..4e9937a 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -89,3 +89,25 @@
config HAVE_MEMORY_PRESENT
def_bool y
depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM
+
+#
+# SPARSEMEM_EXTREME (which is the default) does some bootmem
+# allocations when memory_present() is called. If this can not
+# be done on your architecture, select this option. However,
+# statically allocating the mem_section[] array can potentially
+# consume vast quantities of .bss, so be careful.
+#
+# This option will also potentially produce smaller runtime code
+# with gcc 3.4 and later.
+#
+config SPARSEMEM_STATIC
+ def_bool n
+
+#
+# Architectecture platforms which require a two level mem_section in SPARSEMEM
+# must select this option. This is usually for architecture platforms with
+# an extremely sparse physical address space.
+#
+config SPARSEMEM_EXTREME
+ def_bool y
+ depends on SPARSEMEM && !SPARSEMEM_STATIC
diff --git a/mm/filemap.c b/mm/filemap.c
index c11418d..8861192 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -54,9 +54,8 @@
*
* ->i_mmap_lock (vmtruncate)
* ->private_lock (__free_pte->__set_page_dirty_buffers)
- * ->swap_list_lock
- * ->swap_device_lock (exclusive_swap_page, others)
- * ->mapping->tree_lock
+ * ->swap_lock (exclusive_swap_page, others)
+ * ->mapping->tree_lock
*
* ->i_sem
* ->i_mmap_lock (truncate->unmap_mapping_range)
@@ -86,7 +85,7 @@
* ->page_table_lock (anon_vma_prepare and various)
*
* ->page_table_lock
- * ->swap_device_lock (try_to_unmap_one)
+ * ->swap_lock (try_to_unmap_one)
* ->private_lock (try_to_unmap_one)
* ->tree_lock (try_to_unmap_one)
* ->zone.lru_lock (follow_page->mark_page_accessed)
@@ -1505,8 +1504,12 @@
return -EINVAL;
page = filemap_getpage(file, pgoff, nonblock);
+
+ /* XXX: This is wrong, a filesystem I/O error may have happened. Fix that as
+ * done in shmem_populate calling shmem_getpage */
if (!page && !nonblock)
return -ENOMEM;
+
if (page) {
err = install_page(mm, vma, addr, page, prot);
if (err) {
@@ -1514,6 +1517,9 @@
return err;
}
} else {
+ /* No page was found just because we can't read it in now (being
+ * here implies nonblock != 0), but the page may exist, so set
+ * the PTE to fault it in later. */
err = install_file_pte(mm, vma, addr, pgoff, prot);
if (err)
return err;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6bf720b..901ac52 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -360,8 +360,6 @@
ret = -ENOMEM;
goto out;
}
- if (! pte_none(*pte))
- hugetlb_clean_stale_pgtable(pte);
idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
diff --git a/mm/madvise.c b/mm/madvise.c
index c8c01a1..4454936 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -37,7 +37,7 @@
if (new_flags == vma->vm_flags) {
*prev = vma;
- goto success;
+ goto out;
}
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
@@ -62,6 +62,7 @@
goto out;
}
+success:
/*
* vm_flags is protected by the mmap_sem held in write mode.
*/
@@ -70,7 +71,6 @@
out:
if (error == -ENOMEM)
error = -EAGAIN;
-success:
return error;
}
@@ -237,8 +237,9 @@
* - different from the way of handling in mlock etc.
*/
vma = find_vma_prev(current->mm, start, &prev);
- if (!vma && prev)
- vma = prev->vm_next;
+ if (vma && start > vma->vm_start)
+ prev = vma;
+
for (;;) {
/* Still start < end. */
error = -ENOMEM;
diff --git a/mm/memory.c b/mm/memory.c
index a596c11..788a628 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -562,7 +562,8 @@
page->index > details->last_index))
continue;
}
- ptent = ptep_get_and_clear(tlb->mm, addr, pte);
+ ptent = ptep_get_and_clear_full(tlb->mm, addr, pte,
+ tlb->fullmm);
tlb_remove_tlb_entry(tlb, pte, addr);
if (unlikely(!page))
continue;
@@ -590,7 +591,7 @@
continue;
if (!pte_file(ptent))
free_swap_and_cache(pte_to_swp_entry(ptent));
- pte_clear(tlb->mm, addr, pte);
+ pte_clear_full(tlb->mm, addr, pte, tlb->fullmm);
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap(pte - 1);
}
@@ -1955,7 +1956,7 @@
* Fall back to the linear mapping if the fs does not support
* ->populate:
*/
- if (!vma->vm_ops || !vma->vm_ops->populate ||
+ if (!vma->vm_ops->populate ||
(write_access && !(vma->vm_flags & VM_SHARED))) {
pte_clear(mm, address, pte);
return do_no_page(mm, vma, address, write_access, pte, pmd);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b4eabab..13492d6 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -664,10 +664,10 @@
#endif
/* Return effective policy for a VMA */
-static struct mempolicy *
-get_vma_policy(struct vm_area_struct *vma, unsigned long addr)
+struct mempolicy *
+get_vma_policy(struct task_struct *task, struct vm_area_struct *vma, unsigned long addr)
{
- struct mempolicy *pol = current->mempolicy;
+ struct mempolicy *pol = task->mempolicy;
if (vma) {
if (vma->vm_ops && vma->vm_ops->get_policy)
@@ -786,7 +786,7 @@
struct page *
alloc_page_vma(unsigned int __nocast gfp, struct vm_area_struct *vma, unsigned long addr)
{
- struct mempolicy *pol = get_vma_policy(vma, addr);
+ struct mempolicy *pol = get_vma_policy(current, vma, addr);
cpuset_update_current_mems_allowed();
@@ -908,7 +908,7 @@
/* Find first node suitable for an allocation */
int mpol_first_node(struct vm_area_struct *vma, unsigned long addr)
{
- struct mempolicy *pol = get_vma_policy(vma, addr);
+ struct mempolicy *pol = get_vma_policy(current, vma, addr);
switch (pol->policy) {
case MPOL_DEFAULT:
@@ -928,7 +928,7 @@
/* Find secondary valid nodes for an allocation */
int mpol_node_valid(int nid, struct vm_area_struct *vma, unsigned long addr)
{
- struct mempolicy *pol = get_vma_policy(vma, addr);
+ struct mempolicy *pol = get_vma_policy(current, vma, addr);
switch (pol->policy) {
case MPOL_PREFERRED:
diff --git a/mm/mmap.c b/mm/mmap.c
index 4043194..12334ae 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -61,7 +61,7 @@
int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
int sysctl_overcommit_ratio = 50; /* default is 50% */
-int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
+int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
atomic_t vm_committed_space = ATOMIC_INIT(0);
/*
@@ -203,13 +203,6 @@
kmem_cache_free(vm_area_cachep, vma);
}
-/*
- * sys_brk() for the most part doesn't need the global kernel
- * lock, except when an application is doing something nasty
- * like trying to un-brk an area that has already been mapped
- * to a regular file. in this case, the unmapping will need
- * to invoke file system routines that need the global lock.
- */
asmlinkage unsigned long sys_brk(unsigned long brk)
{
unsigned long rlim, retval;
diff --git a/mm/mremap.c b/mm/mremap.c
index fc45dc9..a32fed4 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -141,6 +141,10 @@
if (dst) {
pte_t pte;
pte = ptep_clear_flush(vma, old_addr, src);
+ /* ZERO_PAGE can be dependant on virtual addr */
+ if (pfn_valid(pte_pfn(pte)) &&
+ pte_page(pte) == ZERO_PAGE(old_addr))
+ pte = pte_wrprotect(mk_pte(ZERO_PAGE(new_addr), new_vma->vm_page_prot));
set_pte_at(mm, new_addr, dst, pte);
} else
error = -ENOMEM;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 1e56076..5ec8da1 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -6,8 +6,8 @@
* for goading me into coding this file...
*
* The routines in this file are used to kill a process when
- * we're seriously out of memory. This gets called from kswapd()
- * in linux/mm/vmscan.c when we really run out of memory.
+ * we're seriously out of memory. This gets called from __alloc_pages()
+ * in mm/page_alloc.c when we really run out of memory.
*
* Since we won't call these routines often (on a well-configured
* machine) this file will double as a 'coding guide' and a signpost
@@ -20,13 +20,14 @@
#include <linux/swap.h>
#include <linux/timex.h>
#include <linux/jiffies.h>
+#include <linux/cpuset.h>
/* #define DEBUG */
/**
* oom_badness - calculate a numeric value for how bad this task has been
* @p: task struct of which task we should calculate
- * @p: current uptime in seconds
+ * @uptime: current uptime in seconds
*
* The formula used is relatively simple and documented inline in the
* function. The main rationale is that we want to select a good task
@@ -57,9 +58,9 @@
/*
* Processes which fork a lot of child processes are likely
- * a good choice. We add the vmsize of the childs if they
+ * a good choice. We add the vmsize of the children if they
* have an own mm. This prevents forking servers to flood the
- * machine with an endless amount of childs
+ * machine with an endless amount of children
*/
list_for_each(tsk, &p->children) {
struct task_struct *chld;
@@ -143,28 +144,36 @@
struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime);
- do_each_thread(g, p)
+ do_each_thread(g, p) {
+ unsigned long points;
+ int releasing;
+
/* skip the init task with pid == 1 */
- if (p->pid > 1 && p->oomkilladj != OOM_DISABLE) {
- unsigned long points;
+ if (p->pid == 1)
+ continue;
+ if (p->oomkilladj == OOM_DISABLE)
+ continue;
+ /* If p's nodes don't overlap ours, it won't help to kill p. */
+ if (!cpuset_excl_nodes_overlap(p))
+ continue;
- /*
- * This is in the process of releasing memory so wait it
- * to finish before killing some other task by mistake.
- */
- if ((unlikely(test_tsk_thread_flag(p, TIF_MEMDIE)) || (p->flags & PF_EXITING)) &&
- !(p->flags & PF_DEAD))
- return ERR_PTR(-1UL);
- if (p->flags & PF_SWAPOFF)
- return p;
+ /*
+ * This is in the process of releasing memory so for wait it
+ * to finish before killing some other task by mistake.
+ */
+ releasing = test_tsk_thread_flag(p, TIF_MEMDIE) ||
+ p->flags & PF_EXITING;
+ if (releasing && !(p->flags & PF_DEAD))
+ return ERR_PTR(-1UL);
+ if (p->flags & PF_SWAPOFF)
+ return p;
- points = badness(p, uptime.tv_sec);
- if (points > maxpoints || !chosen) {
- chosen = p;
- maxpoints = points;
- }
+ points = badness(p, uptime.tv_sec);
+ if (points > maxpoints || !chosen) {
+ chosen = p;
+ maxpoints = points;
}
- while_each_thread(g, p);
+ } while_each_thread(g, p);
return chosen;
}
@@ -189,7 +198,8 @@
return;
}
task_unlock(p);
- printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm);
+ printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n",
+ p->pid, p->comm);
/*
* We give our sacrificial lamb high priority and access to
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8d08837..3974fd8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -42,13 +42,13 @@
* MCD - HACK: Find somewhere to initialize this EARLY, or make this
* initializer cleaner
*/
-nodemask_t node_online_map = { { [0] = 1UL } };
+nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };
EXPORT_SYMBOL(node_online_map);
-nodemask_t node_possible_map = NODE_MASK_ALL;
+nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL;
EXPORT_SYMBOL(node_possible_map);
-struct pglist_data *pgdat_list;
-unsigned long totalram_pages;
-unsigned long totalhigh_pages;
+struct pglist_data *pgdat_list __read_mostly;
+unsigned long totalram_pages __read_mostly;
+unsigned long totalhigh_pages __read_mostly;
long nr_swap_pages;
/*
@@ -68,7 +68,7 @@
* Used by page_zone() to look up the address of the struct zone whose
* id is encoded in the upper bits of page->flags
*/
-struct zone *zone_table[1 << ZONETABLE_SHIFT];
+struct zone *zone_table[1 << ZONETABLE_SHIFT] __read_mostly;
EXPORT_SYMBOL(zone_table);
static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
@@ -329,7 +329,7 @@
1 << PG_writeback )))
bad_page(function, page);
if (PageDirty(page))
- ClearPageDirty(page);
+ __ClearPageDirty(page);
}
/*
@@ -806,11 +806,14 @@
classzone_idx = zone_idx(zones[0]);
restart:
- /* Go through the zonelist once, looking for a zone with enough free */
+ /*
+ * Go through the zonelist once, looking for a zone with enough free.
+ * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+ */
for (i = 0; (z = zones[i]) != NULL; i++) {
int do_reclaim = should_reclaim_zone(z, gfp_mask);
- if (!cpuset_zone_allowed(z))
+ if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
continue;
/*
@@ -845,6 +848,7 @@
*
* This is the last chance, in general, before the goto nopage.
* Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
+ * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
*/
for (i = 0; (z = zones[i]) != NULL; i++) {
if (!zone_watermark_ok(z, order, z->pages_min,
@@ -852,7 +856,7 @@
gfp_mask & __GFP_HIGH))
continue;
- if (wait && !cpuset_zone_allowed(z))
+ if (wait && !cpuset_zone_allowed(z, gfp_mask))
continue;
page = buffered_rmqueue(z, order, gfp_mask);
@@ -867,7 +871,7 @@
if (!(gfp_mask & __GFP_NOMEMALLOC)) {
/* go through the zonelist yet again, ignoring mins */
for (i = 0; (z = zones[i]) != NULL; i++) {
- if (!cpuset_zone_allowed(z))
+ if (!cpuset_zone_allowed(z, gfp_mask))
continue;
page = buffered_rmqueue(z, order, gfp_mask);
if (page)
@@ -903,7 +907,7 @@
gfp_mask & __GFP_HIGH))
continue;
- if (!cpuset_zone_allowed(z))
+ if (!cpuset_zone_allowed(z, gfp_mask))
continue;
page = buffered_rmqueue(z, order, gfp_mask);
@@ -922,7 +926,7 @@
classzone_idx, 0, 0))
continue;
- if (!cpuset_zone_allowed(z))
+ if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
continue;
page = buffered_rmqueue(z, order, gfp_mask);
@@ -1130,19 +1134,20 @@
DEFINE_PER_CPU(long, nr_pagecache_local) = 0;
#endif
-void __get_page_state(struct page_state *ret, int nr)
+void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask)
{
int cpu = 0;
memset(ret, 0, sizeof(*ret));
+ cpus_and(*cpumask, *cpumask, cpu_online_map);
- cpu = first_cpu(cpu_online_map);
+ cpu = first_cpu(*cpumask);
while (cpu < NR_CPUS) {
unsigned long *in, *out, off;
in = (unsigned long *)&per_cpu(page_states, cpu);
- cpu = next_cpu(cpu, cpu_online_map);
+ cpu = next_cpu(cpu, *cpumask);
if (cpu < NR_CPUS)
prefetch(&per_cpu(page_states, cpu));
@@ -1153,19 +1158,33 @@
}
}
-void get_page_state(struct page_state *ret)
+void get_page_state_node(struct page_state *ret, int node)
{
int nr;
+ cpumask_t mask = node_to_cpumask(node);
nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
nr /= sizeof(unsigned long);
- __get_page_state(ret, nr + 1);
+ __get_page_state(ret, nr+1, &mask);
+}
+
+void get_page_state(struct page_state *ret)
+{
+ int nr;
+ cpumask_t mask = CPU_MASK_ALL;
+
+ nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
+ nr /= sizeof(unsigned long);
+
+ __get_page_state(ret, nr + 1, &mask);
}
void get_full_page_state(struct page_state *ret)
{
- __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long));
+ cpumask_t mask = CPU_MASK_ALL;
+
+ __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask);
}
unsigned long __read_page_state(unsigned long offset)
@@ -1909,7 +1928,7 @@
zone->nr_scan_inactive = 0;
zone->nr_active = 0;
zone->nr_inactive = 0;
- atomic_set(&zone->reclaim_in_progress, -1);
+ atomic_set(&zone->reclaim_in_progress, 0);
if (!size)
continue;
diff --git a/mm/readahead.c b/mm/readahead.c
index b840e7c..d0b5003 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -540,6 +540,7 @@
{
ra->flags |= RA_FLAG_MISS;
ra->flags &= ~RA_FLAG_INCACHE;
+ ra->cache_hit = 0;
}
/*
diff --git a/mm/rmap.c b/mm/rmap.c
index 08ac5c7..450f524 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -34,9 +34,8 @@
* anon_vma->lock
* mm->page_table_lock
* zone->lru_lock (in mark_page_accessed)
- * swap_list_lock (in swap_free etc's swap_info_get)
+ * swap_lock (in swap_duplicate, swap_info_get)
* mmlist_lock (in mmput, drain_mmlist and others)
- * swap_device_lock (in swap_duplicate, swap_info_get)
* mapping->private_lock (in __set_page_dirty_buffers)
* inode_lock (in set_page_dirty's __mark_inode_dirty)
* sb_lock (within inode_lock in fs/fs-writeback.c)
@@ -290,8 +289,6 @@
pte_t *pte;
int referenced = 0;
- if (!get_mm_counter(mm, rss))
- goto out;
address = vma_address(page, vma);
if (address == -EFAULT)
goto out;
@@ -442,22 +439,19 @@
void page_add_anon_rmap(struct page *page,
struct vm_area_struct *vma, unsigned long address)
{
- struct anon_vma *anon_vma = vma->anon_vma;
- pgoff_t index;
-
BUG_ON(PageReserved(page));
- BUG_ON(!anon_vma);
inc_mm_counter(vma->vm_mm, anon_rss);
- anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
- index = (address - vma->vm_start) >> PAGE_SHIFT;
- index += vma->vm_pgoff;
- index >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-
if (atomic_inc_and_test(&page->_mapcount)) {
- page->index = index;
+ struct anon_vma *anon_vma = vma->anon_vma;
+
+ BUG_ON(!anon_vma);
+ anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
page->mapping = (struct address_space *) anon_vma;
+
+ page->index = linear_page_index(vma, address);
+
inc_page_state(nr_mapped);
}
/* else checking page index and mapping is racy */
@@ -518,8 +512,6 @@
pte_t pteval;
int ret = SWAP_AGAIN;
- if (!get_mm_counter(mm, rss))
- goto out;
address = vma_address(page, vma);
if (address == -EFAULT)
goto out;
@@ -532,6 +524,8 @@
* If the page is mlock()d, we cannot swap it out.
* If it's recently referenced (perhaps page_referenced
* skipped over this mm) then we should reactivate it.
+ *
+ * Pages belonging to VM_RESERVED regions should not happen here.
*/
if ((vma->vm_flags & (VM_LOCKED|VM_RESERVED)) ||
ptep_clear_flush_young(vma, address, pte)) {
@@ -767,8 +761,7 @@
if (vma->vm_flags & (VM_LOCKED|VM_RESERVED))
continue;
cursor = (unsigned long) vma->vm_private_data;
- while (get_mm_counter(vma->vm_mm, rss) &&
- cursor < max_nl_cursor &&
+ while ( cursor < max_nl_cursor &&
cursor < vma->vm_end - vma->vm_start) {
try_to_unmap_cluster(cursor, &mapcount, vma);
cursor += CLUSTER_SIZE;
diff --git a/mm/shmem.c b/mm/shmem.c
index 5a81b1e..db2c9e8d 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -45,7 +45,6 @@
#include <linux/swapops.h>
#include <linux/mempolicy.h>
#include <linux/namei.h>
-#include <linux/xattr.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <asm/pgtable.h>
@@ -179,10 +178,9 @@
static struct file_operations shmem_file_operations;
static struct inode_operations shmem_inode_operations;
static struct inode_operations shmem_dir_inode_operations;
-static struct inode_operations shmem_special_inode_operations;
static struct vm_operations_struct shmem_vm_ops;
-static struct backing_dev_info shmem_backing_dev_info = {
+static struct backing_dev_info shmem_backing_dev_info __read_mostly = {
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
.unplug_io_fn = default_unplug_io_fn,
@@ -1195,6 +1193,7 @@
err = shmem_getpage(inode, pgoff, &page, sgp, NULL);
if (err)
return err;
+ /* Page may still be null, but only if nonblock was set. */
if (page) {
mark_page_accessed(page);
err = install_page(mm, vma, addr, page, prot);
@@ -1202,7 +1201,10 @@
page_cache_release(page);
return err;
}
- } else if (nonblock) {
+ } else {
+ /* No page was found just because we can't read it in
+ * now (being here implies nonblock != 0), but the page
+ * may exist, so set the PTE to fault it in later. */
err = install_file_pte(mm, vma, addr, pgoff, prot);
if (err)
return err;
@@ -1296,7 +1298,6 @@
switch (mode & S_IFMT) {
default:
- inode->i_op = &shmem_special_inode_operations;
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
@@ -1800,12 +1801,6 @@
static struct inode_operations shmem_symlink_inline_operations = {
.readlink = generic_readlink,
.follow_link = shmem_follow_link_inline,
-#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .listxattr = generic_listxattr,
- .removexattr = generic_removexattr,
-#endif
};
static struct inode_operations shmem_symlink_inode_operations = {
@@ -1813,12 +1808,6 @@
.readlink = generic_readlink,
.follow_link = shmem_follow_link,
.put_link = shmem_put_link,
-#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .listxattr = generic_listxattr,
- .removexattr = generic_removexattr,
-#endif
};
static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
@@ -1938,12 +1927,6 @@
sb->s_fs_info = NULL;
}
-#ifdef CONFIG_TMPFS_XATTR
-static struct xattr_handler *shmem_xattr_handlers[];
-#else
-#define shmem_xattr_handlers NULL
-#endif
-
static int shmem_fill_super(struct super_block *sb,
void *data, int silent)
{
@@ -1994,7 +1977,6 @@
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = TMPFS_MAGIC;
sb->s_op = &shmem_ops;
- sb->s_xattr = shmem_xattr_handlers;
inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
if (!inode)
@@ -2083,12 +2065,6 @@
static struct inode_operations shmem_inode_operations = {
.truncate = shmem_truncate,
.setattr = shmem_notify_change,
-#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .listxattr = generic_listxattr,
- .removexattr = generic_removexattr,
-#endif
};
static struct inode_operations shmem_dir_inode_operations = {
@@ -2102,21 +2078,6 @@
.rmdir = shmem_rmdir,
.mknod = shmem_mknod,
.rename = shmem_rename,
-#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .listxattr = generic_listxattr,
- .removexattr = generic_removexattr,
-#endif
-#endif
-};
-
-static struct inode_operations shmem_special_inode_operations = {
-#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .listxattr = generic_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -2142,48 +2103,6 @@
};
-#ifdef CONFIG_TMPFS_SECURITY
-
-static size_t shmem_xattr_security_list(struct inode *inode, char *list, size_t list_len,
- const char *name, size_t name_len)
-{
- return security_inode_listsecurity(inode, list, list_len);
-}
-
-static int shmem_xattr_security_get(struct inode *inode, const char *name, void *buffer, size_t size)
-{
- if (strcmp(name, "") == 0)
- return -EINVAL;
- return security_inode_getsecurity(inode, name, buffer, size);
-}
-
-static int shmem_xattr_security_set(struct inode *inode, const char *name, const void *value, size_t size, int flags)
-{
- if (strcmp(name, "") == 0)
- return -EINVAL;
- return security_inode_setsecurity(inode, name, value, size, flags);
-}
-
-static struct xattr_handler shmem_xattr_security_handler = {
- .prefix = XATTR_SECURITY_PREFIX,
- .list = shmem_xattr_security_list,
- .get = shmem_xattr_security_get,
- .set = shmem_xattr_security_set,
-};
-
-#endif /* CONFIG_TMPFS_SECURITY */
-
-#ifdef CONFIG_TMPFS_XATTR
-
-static struct xattr_handler *shmem_xattr_handlers[] = {
-#ifdef CONFIG_TMPFS_SECURITY
- &shmem_xattr_security_handler,
-#endif
- NULL
-};
-
-#endif /* CONFIG_TMPFS_XATTR */
-
static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
diff --git a/mm/slab.c b/mm/slab.c
index c9e706d..d7c4443 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -189,6 +189,7 @@
* is less than 512 (PAGE_SIZE<<3), but greater than 256.
*/
+typedef unsigned int kmem_bufctl_t;
#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0)
#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1)
#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-2)
@@ -600,7 +601,7 @@
csizep++;
/*
- * Really subtile: The last entry with cs->cs_size==ULONG_MAX
+ * Really subtle: The last entry with cs->cs_size==ULONG_MAX
* has cs_{dma,}cachep==NULL. Thus no special case
* for large kmalloc calls required.
*/
@@ -2165,7 +2166,9 @@
objp = cache_alloc_refill(cachep, flags);
}
local_irq_restore(save_flags);
- objp = cache_alloc_debugcheck_after(cachep, flags, objp, __builtin_return_address(0));
+ objp = cache_alloc_debugcheck_after(cachep, flags, objp,
+ __builtin_return_address(0));
+ prefetchw(objp);
return objp;
}
@@ -2555,24 +2558,18 @@
EXPORT_SYMBOL(kmem_cache_free);
/**
- * kcalloc - allocate memory for an array. The memory is set to zero.
- * @n: number of elements.
- * @size: element size.
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
* @flags: the type of memory to allocate.
*/
-void *kcalloc(size_t n, size_t size, unsigned int __nocast flags)
+void *kzalloc(size_t size, unsigned int __nocast flags)
{
- void *ret = NULL;
-
- if (n != 0 && size > INT_MAX / n)
- return ret;
-
- ret = kmalloc(n * size, flags);
+ void *ret = kmalloc(size, flags);
if (ret)
- memset(ret, 0, n * size);
+ memset(ret, 0, size);
return ret;
}
-EXPORT_SYMBOL(kcalloc);
+EXPORT_SYMBOL(kzalloc);
/**
* kfree - free previously allocated memory
@@ -3073,20 +3070,24 @@
}
#endif
+/**
+ * ksize - get the actual amount of memory allocated for a given object
+ * @objp: Pointer to the object
+ *
+ * kmalloc may internally round up allocations and return more memory
+ * than requested. ksize() can be used to determine the actual amount of
+ * memory allocated. The caller may use this additional memory, even though
+ * a smaller amount of memory was initially specified with the kmalloc call.
+ * The caller must guarantee that objp points to a valid object previously
+ * allocated with either kmalloc() or kmem_cache_alloc(). The object
+ * must not be freed during the duration of the call.
+ */
unsigned int ksize(const void *objp)
{
- kmem_cache_t *c;
- unsigned long flags;
- unsigned int size = 0;
+ if (unlikely(objp == NULL))
+ return 0;
- if (likely(objp != NULL)) {
- local_irq_save(flags);
- c = GET_PAGE_CACHE(virt_to_page(objp));
- size = kmem_cache_size(c);
- local_irq_restore(flags);
- }
-
- return size;
+ return obj_reallen(GET_PAGE_CACHE(virt_to_page(objp)));
}
diff --git a/mm/sparse.c b/mm/sparse.c
index b54e304..347249a 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -6,6 +6,7 @@
#include <linux/mmzone.h>
#include <linux/bootmem.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
#include <asm/dma.h>
/*
@@ -13,9 +14,64 @@
*
* 1) mem_section - memory sections, mem_map's for valid memory
*/
-struct mem_section mem_section[NR_MEM_SECTIONS];
+#ifdef CONFIG_SPARSEMEM_EXTREME
+struct mem_section *mem_section[NR_SECTION_ROOTS]
+ ____cacheline_maxaligned_in_smp;
+#else
+struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
+ ____cacheline_maxaligned_in_smp;
+#endif
EXPORT_SYMBOL(mem_section);
+#ifdef CONFIG_SPARSEMEM_EXTREME
+static struct mem_section *sparse_index_alloc(int nid)
+{
+ struct mem_section *section = NULL;
+ unsigned long array_size = SECTIONS_PER_ROOT *
+ sizeof(struct mem_section);
+
+ section = alloc_bootmem_node(NODE_DATA(nid), array_size);
+
+ if (section)
+ memset(section, 0, array_size);
+
+ return section;
+}
+
+static int sparse_index_init(unsigned long section_nr, int nid)
+{
+ static spinlock_t index_init_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long root = SECTION_NR_TO_ROOT(section_nr);
+ struct mem_section *section;
+ int ret = 0;
+
+ if (mem_section[root])
+ return -EEXIST;
+
+ section = sparse_index_alloc(nid);
+ /*
+ * This lock keeps two different sections from
+ * reallocating for the same index
+ */
+ spin_lock(&index_init_lock);
+
+ if (mem_section[root]) {
+ ret = -EEXIST;
+ goto out;
+ }
+
+ mem_section[root] = section;
+out:
+ spin_unlock(&index_init_lock);
+ return ret;
+}
+#else /* !SPARSEMEM_EXTREME */
+static inline int sparse_index_init(unsigned long section_nr, int nid)
+{
+ return 0;
+}
+#endif
+
/* Record a memory area against a node. */
void memory_present(int nid, unsigned long start, unsigned long end)
{
@@ -24,8 +80,13 @@
start &= PAGE_SECTION_MASK;
for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
unsigned long section = pfn_to_section_nr(pfn);
- if (!mem_section[section].section_mem_map)
- mem_section[section].section_mem_map = SECTION_MARKED_PRESENT;
+ struct mem_section *ms;
+
+ sparse_index_init(section, nid);
+
+ ms = __nr_to_section(section);
+ if (!ms->section_mem_map)
+ ms->section_mem_map = SECTION_MARKED_PRESENT;
}
}
@@ -85,6 +146,7 @@
{
struct page *map;
int nid = early_pfn_to_nid(section_nr_to_pfn(pnum));
+ struct mem_section *ms = __nr_to_section(pnum);
map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
if (map)
@@ -96,7 +158,7 @@
return map;
printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__);
- mem_section[pnum].section_mem_map = 0;
+ ms->section_mem_map = 0;
return NULL;
}
@@ -114,8 +176,9 @@
continue;
map = sparse_early_mem_map_alloc(pnum);
- if (map)
- sparse_init_one_section(&mem_section[pnum], pnum, map);
+ if (!map)
+ continue;
+ sparse_init_one_section(__nr_to_section(pnum), pnum, map);
}
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4f25177..029e56e 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -124,6 +124,7 @@
BUG_ON(!PageLocked(page));
BUG_ON(!PageSwapCache(page));
BUG_ON(PageWriteback(page));
+ BUG_ON(PagePrivate(page));
radix_tree_delete(&swapper_space.page_tree, page->private);
page->private = 0;
@@ -196,11 +197,6 @@
{
swp_entry_t entry;
- BUG_ON(!PageSwapCache(page));
- BUG_ON(!PageLocked(page));
- BUG_ON(PageWriteback(page));
- BUG_ON(PagePrivate(page));
-
entry.val = page->private;
write_lock_irq(&swapper_space.tree_lock);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 60cd24a..4b6e8bf 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -31,7 +31,7 @@
#include <asm/tlbflush.h>
#include <linux/swapops.h>
-DEFINE_SPINLOCK(swaplock);
+DEFINE_SPINLOCK(swap_lock);
unsigned int nr_swapfiles;
long total_swap_pages;
static int swap_overflow;
@@ -51,13 +51,11 @@
/*
* We need this because the bdev->unplug_fn can sleep and we cannot
- * hold swap_list_lock while calling the unplug_fn. And swap_list_lock
+ * hold swap_lock while calling the unplug_fn. And swap_lock
* cannot be turned into a semaphore.
*/
static DECLARE_RWSEM(swap_unplug_sem);
-#define SWAPFILE_CLUSTER 256
-
void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page)
{
swp_entry_t entry;
@@ -84,116 +82,135 @@
up_read(&swap_unplug_sem);
}
-static inline int scan_swap_map(struct swap_info_struct *si)
-{
- unsigned long offset;
- /*
- * We try to cluster swap pages by allocating them
- * sequentially in swap. Once we've allocated
- * SWAPFILE_CLUSTER pages this way, however, we resort to
- * first-free allocation, starting a new cluster. This
- * prevents us from scattering swap pages all over the entire
- * swap partition, so that we reduce overall disk seek times
- * between swap pages. -- sct */
- if (si->cluster_nr) {
- while (si->cluster_next <= si->highest_bit) {
- offset = si->cluster_next++;
- if (si->swap_map[offset])
- continue;
- si->cluster_nr--;
- goto got_page;
- }
- }
- si->cluster_nr = SWAPFILE_CLUSTER;
+#define SWAPFILE_CLUSTER 256
+#define LATENCY_LIMIT 256
- /* try to find an empty (even not aligned) cluster. */
- offset = si->lowest_bit;
- check_next_cluster:
- if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)
- {
- unsigned long nr;
- for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)
- if (si->swap_map[nr])
- {
- offset = nr+1;
- goto check_next_cluster;
+static inline unsigned long scan_swap_map(struct swap_info_struct *si)
+{
+ unsigned long offset, last_in_cluster;
+ int latency_ration = LATENCY_LIMIT;
+
+ /*
+ * We try to cluster swap pages by allocating them sequentially
+ * in swap. Once we've allocated SWAPFILE_CLUSTER pages this
+ * way, however, we resort to first-free allocation, starting
+ * a new cluster. This prevents us from scattering swap pages
+ * all over the entire swap partition, so that we reduce
+ * overall disk seek times between swap pages. -- sct
+ * But we do now try to find an empty cluster. -Andrea
+ */
+
+ si->flags += SWP_SCANNING;
+ if (unlikely(!si->cluster_nr)) {
+ si->cluster_nr = SWAPFILE_CLUSTER - 1;
+ if (si->pages - si->inuse_pages < SWAPFILE_CLUSTER)
+ goto lowest;
+ spin_unlock(&swap_lock);
+
+ offset = si->lowest_bit;
+ last_in_cluster = offset + SWAPFILE_CLUSTER - 1;
+
+ /* Locate the first empty (unaligned) cluster */
+ for (; last_in_cluster <= si->highest_bit; offset++) {
+ if (si->swap_map[offset])
+ last_in_cluster = offset + SWAPFILE_CLUSTER;
+ else if (offset == last_in_cluster) {
+ spin_lock(&swap_lock);
+ si->cluster_next = offset-SWAPFILE_CLUSTER-1;
+ goto cluster;
}
- /* We found a completly empty cluster, so start
- * using it.
- */
- goto got_page;
+ if (unlikely(--latency_ration < 0)) {
+ cond_resched();
+ latency_ration = LATENCY_LIMIT;
+ }
+ }
+ spin_lock(&swap_lock);
+ goto lowest;
}
- /* No luck, so now go finegrined as usual. -Andrea */
- for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {
- if (si->swap_map[offset])
- continue;
- si->lowest_bit = offset+1;
- got_page:
+
+ si->cluster_nr--;
+cluster:
+ offset = si->cluster_next;
+ if (offset > si->highest_bit)
+lowest: offset = si->lowest_bit;
+checks: if (!(si->flags & SWP_WRITEOK))
+ goto no_page;
+ if (!si->highest_bit)
+ goto no_page;
+ if (!si->swap_map[offset]) {
if (offset == si->lowest_bit)
si->lowest_bit++;
if (offset == si->highest_bit)
si->highest_bit--;
- if (si->lowest_bit > si->highest_bit) {
+ si->inuse_pages++;
+ if (si->inuse_pages == si->pages) {
si->lowest_bit = si->max;
si->highest_bit = 0;
}
si->swap_map[offset] = 1;
- si->inuse_pages++;
- nr_swap_pages--;
- si->cluster_next = offset+1;
+ si->cluster_next = offset + 1;
+ si->flags -= SWP_SCANNING;
return offset;
}
- si->lowest_bit = si->max;
- si->highest_bit = 0;
+
+ spin_unlock(&swap_lock);
+ while (++offset <= si->highest_bit) {
+ if (!si->swap_map[offset]) {
+ spin_lock(&swap_lock);
+ goto checks;
+ }
+ if (unlikely(--latency_ration < 0)) {
+ cond_resched();
+ latency_ration = LATENCY_LIMIT;
+ }
+ }
+ spin_lock(&swap_lock);
+ goto lowest;
+
+no_page:
+ si->flags -= SWP_SCANNING;
return 0;
}
swp_entry_t get_swap_page(void)
{
- struct swap_info_struct * p;
- unsigned long offset;
- swp_entry_t entry;
- int type, wrapped = 0;
+ struct swap_info_struct *si;
+ pgoff_t offset;
+ int type, next;
+ int wrapped = 0;
- entry.val = 0; /* Out of memory */
- swap_list_lock();
- type = swap_list.next;
- if (type < 0)
- goto out;
+ spin_lock(&swap_lock);
if (nr_swap_pages <= 0)
- goto out;
+ goto noswap;
+ nr_swap_pages--;
- while (1) {
- p = &swap_info[type];
- if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) {
- swap_device_lock(p);
- offset = scan_swap_map(p);
- swap_device_unlock(p);
- if (offset) {
- entry = swp_entry(type,offset);
- type = swap_info[type].next;
- if (type < 0 ||
- p->prio != swap_info[type].prio) {
- swap_list.next = swap_list.head;
- } else {
- swap_list.next = type;
- }
- goto out;
- }
+ for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) {
+ si = swap_info + type;
+ next = si->next;
+ if (next < 0 ||
+ (!wrapped && si->prio != swap_info[next].prio)) {
+ next = swap_list.head;
+ wrapped++;
}
- type = p->next;
- if (!wrapped) {
- if (type < 0 || p->prio != swap_info[type].prio) {
- type = swap_list.head;
- wrapped = 1;
- }
- } else
- if (type < 0)
- goto out; /* out of swap space */
+
+ if (!si->highest_bit)
+ continue;
+ if (!(si->flags & SWP_WRITEOK))
+ continue;
+
+ swap_list.next = next;
+ offset = scan_swap_map(si);
+ if (offset) {
+ spin_unlock(&swap_lock);
+ return swp_entry(type, offset);
+ }
+ next = swap_list.next;
}
-out:
- swap_list_unlock();
- return entry;
+
+ nr_swap_pages++;
+noswap:
+ spin_unlock(&swap_lock);
+ return (swp_entry_t) {0};
}
static struct swap_info_struct * swap_info_get(swp_entry_t entry)
@@ -214,10 +231,7 @@
goto bad_offset;
if (!p->swap_map[offset])
goto bad_free;
- swap_list_lock();
- if (p->prio > swap_info[swap_list.next].prio)
- swap_list.next = type;
- swap_device_lock(p);
+ spin_lock(&swap_lock);
return p;
bad_free:
@@ -235,12 +249,6 @@
return NULL;
}
-static void swap_info_put(struct swap_info_struct * p)
-{
- swap_device_unlock(p);
- swap_list_unlock();
-}
-
static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
{
int count = p->swap_map[offset];
@@ -253,6 +261,8 @@
p->lowest_bit = offset;
if (offset > p->highest_bit)
p->highest_bit = offset;
+ if (p->prio > swap_info[swap_list.next].prio)
+ swap_list.next = p - swap_info;
nr_swap_pages++;
p->inuse_pages--;
}
@@ -271,7 +281,7 @@
p = swap_info_get(entry);
if (p) {
swap_entry_free(p, swp_offset(entry));
- swap_info_put(p);
+ spin_unlock(&swap_lock);
}
}
@@ -289,7 +299,7 @@
if (p) {
/* Subtract the 1 for the swap cache itself */
count = p->swap_map[swp_offset(entry)] - 1;
- swap_info_put(p);
+ spin_unlock(&swap_lock);
}
return count;
}
@@ -346,7 +356,7 @@
}
write_unlock_irq(&swapper_space.tree_lock);
}
- swap_info_put(p);
+ spin_unlock(&swap_lock);
if (retval) {
swap_free(entry);
@@ -369,7 +379,7 @@
if (p) {
if (swap_entry_free(p, swp_offset(entry)) == 1)
page = find_trylock_page(&swapper_space, entry.val);
- swap_info_put(p);
+ spin_unlock(&swap_lock);
}
if (page) {
int one_user;
@@ -531,17 +541,18 @@
* Scan swap_map from current position to next entry still in use.
* Recycle to start on reaching the end, returning 0 when empty.
*/
-static int find_next_to_unuse(struct swap_info_struct *si, int prev)
+static unsigned int find_next_to_unuse(struct swap_info_struct *si,
+ unsigned int prev)
{
- int max = si->max;
- int i = prev;
+ unsigned int max = si->max;
+ unsigned int i = prev;
int count;
/*
- * No need for swap_device_lock(si) here: we're just looking
+ * No need for swap_lock here: we're just looking
* for whether an entry is in use, not modifying it; false
* hits are okay, and sys_swapoff() has already prevented new
- * allocations from this area (while holding swap_list_lock()).
+ * allocations from this area (while holding swap_lock).
*/
for (;;) {
if (++i >= max) {
@@ -577,7 +588,7 @@
unsigned short swcount;
struct page *page;
swp_entry_t entry;
- int i = 0;
+ unsigned int i = 0;
int retval = 0;
int reset_overflow = 0;
int shmem;
@@ -731,9 +742,9 @@
* report them; but do report if we reset SWAP_MAP_MAX.
*/
if (*swap_map == SWAP_MAP_MAX) {
- swap_device_lock(si);
+ spin_lock(&swap_lock);
*swap_map = 1;
- swap_device_unlock(si);
+ spin_unlock(&swap_lock);
reset_overflow = 1;
}
@@ -797,9 +808,9 @@
}
/*
- * After a successful try_to_unuse, if no swap is now in use, we know we
- * can empty the mmlist. swap_list_lock must be held on entry and exit.
- * Note that mmlist_lock nests inside swap_list_lock, and an mm must be
+ * After a successful try_to_unuse, if no swap is now in use, we know
+ * we can empty the mmlist. swap_lock must be held on entry and exit.
+ * Note that mmlist_lock nests inside swap_lock, and an mm must be
* added to the mmlist just after page_duplicate - before would be racy.
*/
static void drain_mmlist(void)
@@ -832,9 +843,9 @@
offset < (se->start_page + se->nr_pages)) {
return se->start_block + (offset - se->start_page);
}
- lh = se->list.prev;
+ lh = se->list.next;
if (lh == &sis->extent_list)
- lh = lh->prev;
+ lh = lh->next;
se = list_entry(lh, struct swap_extent, list);
sis->curr_swap_extent = se;
BUG_ON(se == start_se); /* It *must* be present */
@@ -854,15 +865,13 @@
list_del(&se->list);
kfree(se);
}
- sis->nr_extents = 0;
}
/*
* Add a block range (and the corresponding page range) into this swapdev's
- * extent list. The extent list is kept sorted in block order.
+ * extent list. The extent list is kept sorted in page order.
*
- * This function rather assumes that it is called in ascending sector_t order.
- * It doesn't look for extent coalescing opportunities.
+ * This function rather assumes that it is called in ascending page order.
*/
static int
add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
@@ -872,16 +881,15 @@
struct swap_extent *new_se;
struct list_head *lh;
- lh = sis->extent_list.next; /* The highest-addressed block */
- while (lh != &sis->extent_list) {
+ lh = sis->extent_list.prev; /* The highest page extent */
+ if (lh != &sis->extent_list) {
se = list_entry(lh, struct swap_extent, list);
- if (se->start_block + se->nr_pages == start_block &&
- se->start_page + se->nr_pages == start_page) {
+ BUG_ON(se->start_page + se->nr_pages != start_page);
+ if (se->start_block + se->nr_pages == start_block) {
/* Merge it */
se->nr_pages += nr_pages;
return 0;
}
- lh = lh->next;
}
/*
@@ -894,16 +902,8 @@
new_se->nr_pages = nr_pages;
new_se->start_block = start_block;
- lh = sis->extent_list.prev; /* The lowest block */
- while (lh != &sis->extent_list) {
- se = list_entry(lh, struct swap_extent, list);
- if (se->start_block > start_block)
- break;
- lh = lh->prev;
- }
- list_add_tail(&new_se->list, lh);
- sis->nr_extents++;
- return 0;
+ list_add_tail(&new_se->list, &sis->extent_list);
+ return 1;
}
/*
@@ -926,7 +926,7 @@
* requirements, they are simply tossed out - we will never use those blocks
* for swapping.
*
- * For S_ISREG swapfiles we hold i_sem across the life of the swapon. This
+ * For S_ISREG swapfiles we set S_SWAPFILE across the life of the swapon. This
* prevents root from shooting her foot off by ftruncating an in-use swapfile,
* which will scribble on the fs.
*
@@ -937,7 +937,7 @@
* This is extremely effective. The average number of iterations in
* map_swap_page() has been measured at about 0.3 per page. - akpm.
*/
-static int setup_swap_extents(struct swap_info_struct *sis)
+static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
{
struct inode *inode;
unsigned blocks_per_page;
@@ -945,11 +945,15 @@
unsigned blkbits;
sector_t probe_block;
sector_t last_block;
+ sector_t lowest_block = -1;
+ sector_t highest_block = 0;
+ int nr_extents = 0;
int ret;
inode = sis->swap_file->f_mapping->host;
if (S_ISBLK(inode->i_mode)) {
ret = add_swap_extent(sis, 0, sis->max, 0);
+ *span = sis->pages;
goto done;
}
@@ -994,22 +998,32 @@
}
}
+ first_block >>= (PAGE_SHIFT - blkbits);
+ if (page_no) { /* exclude the header page */
+ if (first_block < lowest_block)
+ lowest_block = first_block;
+ if (first_block > highest_block)
+ highest_block = first_block;
+ }
+
/*
* We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
*/
- ret = add_swap_extent(sis, page_no, 1,
- first_block >> (PAGE_SHIFT - blkbits));
- if (ret)
+ ret = add_swap_extent(sis, page_no, 1, first_block);
+ if (ret < 0)
goto out;
+ nr_extents += ret;
page_no++;
probe_block += blocks_per_page;
reprobe:
continue;
}
- ret = 0;
+ ret = nr_extents;
+ *span = 1 + highest_block - lowest_block;
if (page_no == 0)
- ret = -EINVAL;
+ page_no = 1; /* force Empty message */
sis->max = page_no;
+ sis->pages = page_no - 1;
sis->highest_bit = page_no - 1;
done:
sis->curr_swap_extent = list_entry(sis->extent_list.prev,
@@ -1069,7 +1083,7 @@
mapping = victim->f_mapping;
prev = -1;
- swap_list_lock();
+ spin_lock(&swap_lock);
for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
p = swap_info + type;
if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) {
@@ -1080,14 +1094,14 @@
}
if (type < 0) {
err = -EINVAL;
- swap_list_unlock();
+ spin_unlock(&swap_lock);
goto out_dput;
}
if (!security_vm_enough_memory(p->pages))
vm_unacct_memory(p->pages);
else {
err = -ENOMEM;
- swap_list_unlock();
+ spin_unlock(&swap_lock);
goto out_dput;
}
if (prev < 0) {
@@ -1102,18 +1116,15 @@
nr_swap_pages -= p->pages;
total_swap_pages -= p->pages;
p->flags &= ~SWP_WRITEOK;
- swap_list_unlock();
+ spin_unlock(&swap_lock);
+
current->flags |= PF_SWAPOFF;
err = try_to_unuse(type);
current->flags &= ~PF_SWAPOFF;
- /* wait for any unplug function to finish */
- down_write(&swap_unplug_sem);
- up_write(&swap_unplug_sem);
-
if (err) {
/* re-insert swap space back into swap_list */
- swap_list_lock();
+ spin_lock(&swap_lock);
for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
if (p->prio >= swap_info[i].prio)
break;
@@ -1125,22 +1136,35 @@
nr_swap_pages += p->pages;
total_swap_pages += p->pages;
p->flags |= SWP_WRITEOK;
- swap_list_unlock();
+ spin_unlock(&swap_lock);
goto out_dput;
}
+
+ /* wait for any unplug function to finish */
+ down_write(&swap_unplug_sem);
+ up_write(&swap_unplug_sem);
+
+ destroy_swap_extents(p);
down(&swapon_sem);
- swap_list_lock();
+ spin_lock(&swap_lock);
drain_mmlist();
- swap_device_lock(p);
+
+ /* wait for anyone still in scan_swap_map */
+ p->highest_bit = 0; /* cuts scans short */
+ while (p->flags >= SWP_SCANNING) {
+ spin_unlock(&swap_lock);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ spin_lock(&swap_lock);
+ }
+
swap_file = p->swap_file;
p->swap_file = NULL;
p->max = 0;
swap_map = p->swap_map;
p->swap_map = NULL;
p->flags = 0;
- destroy_swap_extents(p);
- swap_device_unlock(p);
- swap_list_unlock();
+ spin_unlock(&swap_lock);
up(&swapon_sem);
vfree(swap_map);
inode = mapping->host;
@@ -1213,7 +1237,7 @@
file = ptr->swap_file;
len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
- seq_printf(swap, "%*s%s\t%d\t%ld\t%d\n",
+ seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",
len < 40 ? 40 - len : 1, " ",
S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t",
@@ -1272,7 +1296,9 @@
static int least_priority;
union swap_header *swap_header = NULL;
int swap_header_version;
- int nr_good_pages = 0;
+ unsigned int nr_good_pages = 0;
+ int nr_extents = 0;
+ sector_t span;
unsigned long maxpages = 1;
int swapfilesize;
unsigned short *swap_map;
@@ -1282,7 +1308,7 @@
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- swap_list_lock();
+ spin_lock(&swap_lock);
p = swap_info;
for (type = 0 ; type < nr_swapfiles ; type++,p++)
if (!(p->flags & SWP_USED))
@@ -1301,14 +1327,13 @@
* swp_entry_t or the architecture definition of a swap pte.
*/
if (type > swp_type(pte_to_swp_entry(swp_entry_to_pte(swp_entry(~0UL,0))))) {
- swap_list_unlock();
+ spin_unlock(&swap_lock);
goto out;
}
if (type >= nr_swapfiles)
nr_swapfiles = type+1;
INIT_LIST_HEAD(&p->extent_list);
p->flags = SWP_USED;
- p->nr_extents = 0;
p->swap_file = NULL;
p->old_block_size = 0;
p->swap_map = NULL;
@@ -1316,7 +1341,6 @@
p->highest_bit = 0;
p->cluster_nr = 0;
p->inuse_pages = 0;
- spin_lock_init(&p->sdev_lock);
p->next = -1;
if (swap_flags & SWAP_FLAG_PREFER) {
p->prio =
@@ -1324,7 +1348,7 @@
} else {
p->prio = --least_priority;
}
- swap_list_unlock();
+ spin_unlock(&swap_lock);
name = getname(specialfile);
error = PTR_ERR(name);
if (IS_ERR(name)) {
@@ -1426,6 +1450,8 @@
}
p->lowest_bit = 1;
+ p->cluster_next = 1;
+
/*
* Find out how many pages are allowed for a single swap
* device. There are two limiting factors: 1) the number of
@@ -1446,6 +1472,10 @@
p->highest_bit = maxpages - 1;
error = -EINVAL;
+ if (!maxpages)
+ goto bad_swap;
+ if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode))
+ goto bad_swap;
if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
goto bad_swap;
@@ -1470,35 +1500,40 @@
if (error)
goto bad_swap;
}
-
+
if (swapfilesize && maxpages > swapfilesize) {
printk(KERN_WARNING
"Swap area shorter than signature indicates\n");
error = -EINVAL;
goto bad_swap;
}
+ if (nr_good_pages) {
+ p->swap_map[0] = SWAP_MAP_BAD;
+ p->max = maxpages;
+ p->pages = nr_good_pages;
+ nr_extents = setup_swap_extents(p, &span);
+ if (nr_extents < 0) {
+ error = nr_extents;
+ goto bad_swap;
+ }
+ nr_good_pages = p->pages;
+ }
if (!nr_good_pages) {
printk(KERN_WARNING "Empty swap-file\n");
error = -EINVAL;
goto bad_swap;
}
- p->swap_map[0] = SWAP_MAP_BAD;
- p->max = maxpages;
- p->pages = nr_good_pages;
-
- error = setup_swap_extents(p);
- if (error)
- goto bad_swap;
down(&swapon_sem);
- swap_list_lock();
- swap_device_lock(p);
+ spin_lock(&swap_lock);
p->flags = SWP_ACTIVE;
nr_swap_pages += nr_good_pages;
total_swap_pages += nr_good_pages;
- printk(KERN_INFO "Adding %dk swap on %s. Priority:%d extents:%d\n",
- nr_good_pages<<(PAGE_SHIFT-10), name,
- p->prio, p->nr_extents);
+
+ printk(KERN_INFO "Adding %uk swap on %s. "
+ "Priority:%d extents:%d across:%lluk\n",
+ nr_good_pages<<(PAGE_SHIFT-10), name, p->prio,
+ nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10));
/* insert swap space into swap_list: */
prev = -1;
@@ -1514,8 +1549,7 @@
} else {
swap_info[prev].next = p - swap_info;
}
- swap_device_unlock(p);
- swap_list_unlock();
+ spin_unlock(&swap_lock);
up(&swapon_sem);
error = 0;
goto out;
@@ -1524,16 +1558,16 @@
set_blocksize(bdev, p->old_block_size);
bd_release(bdev);
}
+ destroy_swap_extents(p);
bad_swap_2:
- swap_list_lock();
+ spin_lock(&swap_lock);
swap_map = p->swap_map;
p->swap_file = NULL;
p->swap_map = NULL;
p->flags = 0;
if (!(swap_flags & SWAP_FLAG_PREFER))
++least_priority;
- swap_list_unlock();
- destroy_swap_extents(p);
+ spin_unlock(&swap_lock);
vfree(swap_map);
if (swap_file)
filp_close(swap_file, NULL);
@@ -1557,7 +1591,7 @@
unsigned int i;
unsigned long nr_to_be_unused = 0;
- swap_list_lock();
+ spin_lock(&swap_lock);
for (i = 0; i < nr_swapfiles; i++) {
if (!(swap_info[i].flags & SWP_USED) ||
(swap_info[i].flags & SWP_WRITEOK))
@@ -1566,7 +1600,7 @@
}
val->freeswap = nr_swap_pages + nr_to_be_unused;
val->totalswap = total_swap_pages + nr_to_be_unused;
- swap_list_unlock();
+ spin_unlock(&swap_lock);
}
/*
@@ -1587,7 +1621,7 @@
p = type + swap_info;
offset = swp_offset(entry);
- swap_device_lock(p);
+ spin_lock(&swap_lock);
if (offset < p->max && p->swap_map[offset]) {
if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {
p->swap_map[offset]++;
@@ -1599,7 +1633,7 @@
result = 1;
}
}
- swap_device_unlock(p);
+ spin_unlock(&swap_lock);
out:
return result;
@@ -1615,7 +1649,7 @@
}
/*
- * swap_device_lock prevents swap_map being freed. Don't grab an extra
+ * swap_lock prevents swap_map being freed. Don't grab an extra
* reference on the swaphandle, it doesn't matter if it becomes unused.
*/
int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
@@ -1631,7 +1665,7 @@
toff++, i--;
*offset = toff;
- swap_device_lock(swapdev);
+ spin_lock(&swap_lock);
do {
/* Don't read-ahead past the end of the swap area */
if (toff >= swapdev->max)
@@ -1644,6 +1678,6 @@
toff++;
ret++;
} while (--i);
- swap_device_unlock(swapdev);
+ spin_unlock(&swap_lock);
return ret;
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 8ff16a1..67b358e 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -158,8 +158,6 @@
return err;
}
-#define IOREMAP_MAX_ORDER (7 + PAGE_SHIFT) /* 128 pages */
-
struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end)
{
diff --git a/mm/vmscan.c b/mm/vmscan.c
index cfffe50..a740778 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -822,6 +822,8 @@
unsigned long nr_active;
unsigned long nr_inactive;
+ atomic_inc(&zone->reclaim_in_progress);
+
/*
* Add one to `nr_to_scan' just to make sure that the kernel will
* slowly sift through the active list.
@@ -861,6 +863,8 @@
}
throttle_vm_writeout();
+
+ atomic_dec(&zone->reclaim_in_progress);
}
/*
@@ -890,7 +894,7 @@
if (zone->present_pages == 0)
continue;
- if (!cpuset_zone_allowed(zone))
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
continue;
zone->temp_priority = sc->priority;
@@ -900,9 +904,7 @@
if (zone->all_unreclaimable && sc->priority != DEF_PRIORITY)
continue; /* Let kswapd poll it */
- atomic_inc(&zone->reclaim_in_progress);
shrink_zone(zone, sc);
- atomic_dec(&zone->reclaim_in_progress);
}
}
@@ -938,7 +940,7 @@
for (i = 0; zones[i] != NULL; i++) {
struct zone *zone = zones[i];
- if (!cpuset_zone_allowed(zone))
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
continue;
zone->temp_priority = DEF_PRIORITY;
@@ -984,7 +986,7 @@
for (i = 0; zones[i] != 0; i++) {
struct zone *zone = zones[i];
- if (!cpuset_zone_allowed(zone))
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
continue;
zone->prev_priority = zone->temp_priority;
@@ -1254,7 +1256,7 @@
return;
if (pgdat->kswapd_max_order < order)
pgdat->kswapd_max_order = order;
- if (!cpuset_zone_allowed(zone))
+ if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
return;
if (!waitqueue_active(&zone->zone_pgdat->kswapd_wait))
return;
@@ -1358,14 +1360,13 @@
sc.swap_cluster_max = SWAP_CLUSTER_MAX;
/* Don't reclaim the zone if there are other reclaimers active */
- if (!atomic_inc_and_test(&zone->reclaim_in_progress))
+ if (atomic_read(&zone->reclaim_in_progress) > 0)
goto out;
shrink_zone(zone, &sc);
total_reclaimed = sc.nr_reclaimed;
out:
- atomic_dec(&zone->reclaim_in_progress);
return total_reclaimed;
}
@@ -1375,6 +1376,9 @@
struct zone *z;
int i;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
if (node >= MAX_NUMNODES || !node_online(node))
return -EINVAL;
diff --git a/net/Kconfig b/net/Kconfig
index c07aafb..2bdd562 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -215,6 +215,7 @@
source "net/ax25/Kconfig"
source "net/irda/Kconfig"
source "net/bluetooth/Kconfig"
+source "net/ieee80211/Kconfig"
endif # if NET
endmenu # Networking
diff --git a/net/Makefile b/net/Makefile
index 7e6eff2..4aa2f46 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -44,6 +44,7 @@
obj-$(CONFIG_VLAN_8021Q) += 8021q/
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
+obj-$(CONFIG_IEEE80211) += ieee80211/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 4dbb5af..d89056e 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -21,6 +21,7 @@
#include "resources.h"
#include "signaling.h" /* for WAITING and sigd_attach */
+#include "common.h"
static DECLARE_MUTEX(ioctl_mutex);
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index ea43dfb..ed705dd 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1874,6 +1874,7 @@
static int ax25_info_show(struct seq_file *seq, void *v)
{
ax25_cb *ax25 = v;
+ char buf[11];
int k;
@@ -1885,13 +1886,13 @@
seq_printf(seq, "%8.8lx %s %s%s ",
(long) ax25,
ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
- ax2asc(&ax25->source_addr),
+ ax2asc(buf, &ax25->source_addr),
ax25->iamdigi? "*":"");
- seq_printf(seq, "%s", ax2asc(&ax25->dest_addr));
+ seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr));
for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
seq_printf(seq, ",%s%s",
- ax2asc(&ax25->digipeat->calls[k]),
+ ax2asc(buf, &ax25->digipeat->calls[k]),
ax25->digipeat->repeated[k]? "*":"");
}
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index f4fa6df..dca179d 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -36,9 +36,8 @@
/*
* ax25 -> ascii conversion
*/
-char *ax2asc(ax25_address *a)
+char *ax2asc(char *buf, ax25_address *a)
{
- static char buf[11];
char c, *s;
int n;
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index c288526..26b77d9 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -298,6 +298,8 @@
static int ax25_rt_seq_show(struct seq_file *seq, void *v)
{
+ char buf[11];
+
if (v == SEQ_START_TOKEN)
seq_puts(seq, "callsign dev mode digipeaters\n");
else {
@@ -308,7 +310,7 @@
if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
callsign = "default";
else
- callsign = ax2asc(&ax25_rt->callsign);
+ callsign = ax2asc(buf, &ax25_rt->callsign);
seq_printf(seq, "%-9s %-4s",
callsign,
@@ -328,7 +330,8 @@
if (ax25_rt->digipeat != NULL)
for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
- seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
+ seq_printf(seq, " %s",
+ ax2asc(buf, &ax25_rt->digipeat->calls[i]));
seq_puts(seq, "\n");
}
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index a8b3822..d53cc86 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -168,12 +168,14 @@
static int ax25_uid_seq_show(struct seq_file *seq, void *v)
{
+ char buf[11];
+
if (v == SEQ_START_TOKEN)
seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
else {
struct ax25_uid_assoc *pt = v;
- seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call));
+ seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call));
}
return 0;
}
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 289c1b5..404b761 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -695,7 +695,7 @@
return ret;
}
-static int ethtool_get_perm_addr(struct net_device *dev, void *useraddr)
+static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
{
struct ethtool_perm_addr epaddr;
u8 *data;
diff --git a/net/core/filter.c b/net/core/filter.c
index cd91a24..079c2ed 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -182,7 +182,7 @@
A = ntohl(*(u32 *)ptr);
continue;
}
- return 0;
+ break;
case BPF_LD|BPF_H|BPF_ABS:
k = fentry->k;
load_h:
@@ -191,7 +191,7 @@
A = ntohs(*(u16 *)ptr);
continue;
}
- return 0;
+ break;
case BPF_LD|BPF_B|BPF_ABS:
k = fentry->k;
load_b:
@@ -200,7 +200,7 @@
A = *(u8 *)ptr;
continue;
}
- return 0;
+ break;
case BPF_LD|BPF_W|BPF_LEN:
A = skb->len;
continue;
diff --git a/net/core/sock.c b/net/core/sock.c
index ccd10fd..ac63b56 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -341,11 +341,11 @@
sock_reset_flag(sk, SOCK_LINGER);
else {
#if (BITS_PER_LONG == 32)
- if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
+ if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;
else
#endif
- sk->sk_lingertime = ling.l_linger * HZ;
+ sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
sock_set_flag(sk, SOCK_LINGER);
}
break;
@@ -1529,6 +1529,8 @@
void proto_unregister(struct proto *prot)
{
write_lock(&proto_list_lock);
+ list_del(&prot->node);
+ write_unlock(&proto_list_lock);
if (prot->slab != NULL) {
kmem_cache_destroy(prot->slab);
@@ -1550,9 +1552,6 @@
kfree(name);
prot->twsk_slab = NULL;
}
-
- list_del(&prot->node);
- write_unlock(&proto_list_lock);
}
EXPORT_SYMBOL(proto_unregister);
@@ -1719,8 +1718,8 @@
EXPORT_SYMBOL(sock_wmalloc);
EXPORT_SYMBOL(sock_i_uid);
EXPORT_SYMBOL(sock_i_ino);
-#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(sysctl_optmem_max);
+#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(sysctl_rmem_max);
EXPORT_SYMBOL(sysctl_wmem_max);
#endif
diff --git a/net/core/wireless.c b/net/core/wireless.c
index 5caae23..d17f158 100644
--- a/net/core/wireless.c
+++ b/net/core/wireless.c
@@ -58,6 +58,13 @@
* o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
* Based on patch from Pavel Roskin <proski@gnu.org> :
* o Fix kernel data leak to user space in private handler handling
+ *
+ * v7 - 18.3.05 - Jean II
+ * o Remove (struct iw_point *)->pointer from events and streams
+ * o Remove spy_offset from struct iw_handler_def
+ * o Start deprecating dev->get_wireless_stats, output a warning
+ * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
+ * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
*/
/***************************** INCLUDES *****************************/
@@ -446,10 +453,14 @@
(dev->wireless_handlers->get_wireless_stats != NULL))
return dev->wireless_handlers->get_wireless_stats(dev);
- /* Old location, will be phased out in next WE */
- return (dev->get_wireless_stats ?
- dev->get_wireless_stats(dev) :
- (struct iw_statistics *) NULL);
+ /* Old location, field to be removed in next WE */
+ if(dev->get_wireless_stats) {
+ printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n",
+ dev->name);
+ return dev->get_wireless_stats(dev);
+ }
+ /* Not found */
+ return (struct iw_statistics *) NULL;
}
/* ---------------------------------------------------------------- */
@@ -541,16 +552,18 @@
dev->name, stats->status, stats->qual.qual,
stats->qual.updated & IW_QUAL_QUAL_UPDATED
? '.' : ' ',
- ((__u8) stats->qual.level),
+ ((__s32) stats->qual.level) -
+ ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
stats->qual.updated & IW_QUAL_LEVEL_UPDATED
? '.' : ' ',
- ((__u8) stats->qual.noise),
+ ((__s32) stats->qual.noise) -
+ ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
stats->qual.updated & IW_QUAL_NOISE_UPDATED
? '.' : ' ',
stats->discard.nwid, stats->discard.code,
stats->discard.fragment, stats->discard.retries,
stats->discard.misc, stats->miss.beacon);
- stats->qual.updated = 0;
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
}
}
@@ -593,6 +606,7 @@
int __init wireless_proc_init(void)
{
+ /* Create /proc/net/wireless entry */
if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
return -ENOMEM;
@@ -627,9 +641,9 @@
sizeof(struct iw_statistics)))
return -EFAULT;
- /* Check if we need to clear the update flag */
+ /* Check if we need to clear the updated flag */
if(wrq->u.data.flags != 0)
- stats->qual.updated = 0;
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
return 0;
} else
return -EOPNOTSUPP;
@@ -1161,10 +1175,11 @@
struct iw_event *event; /* Mallocated whole event */
int event_len; /* Its size */
int hdr_len; /* Size of the event header */
+ int wrqu_off = 0; /* Offset in wrqu */
/* Don't "optimise" the following variable, it will crash */
unsigned cmd_index; /* *MUST* be unsigned */
- /* Get the description of the IOCTL */
+ /* Get the description of the Event */
if(cmd <= SIOCIWLAST) {
cmd_index = cmd - SIOCIWFIRST;
if(cmd_index < standard_ioctl_num)
@@ -1207,6 +1222,8 @@
/* Calculate extra_len - extra is NULL for restricted events */
if(extra != NULL)
extra_len = wrqu->data.length * descr->token_size;
+ /* Always at an offset in wrqu */
+ wrqu_off = IW_EV_POINT_OFF;
#ifdef WE_EVENT_DEBUG
printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
#endif /* WE_EVENT_DEBUG */
@@ -1217,7 +1234,7 @@
event_len = hdr_len + extra_len;
#ifdef WE_EVENT_DEBUG
- printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
+ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len);
#endif /* WE_EVENT_DEBUG */
/* Create temporary buffer to hold the event */
@@ -1228,7 +1245,7 @@
/* Fill event */
event->len = event_len;
event->cmd = cmd;
- memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
+ memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
if(extra != NULL)
memcpy(((char *) event) + hdr_len, extra, extra_len);
@@ -1249,7 +1266,7 @@
* Now, the driver can delegate this task to Wireless Extensions.
* It needs to use those standard spy iw_handler in struct iw_handler_def,
* push data to us via wireless_spy_update() and include struct iw_spy_data
- * in its private part (and advertise it in iw_handler_def->spy_offset).
+ * in its private part (and export it in net_device->wireless_data->spy_data).
* One of the main advantage of centralising spy support here is that
* it becomes much easier to improve and extend it without having to touch
* the drivers. One example is the addition of the Spy-Threshold events.
@@ -1266,10 +1283,7 @@
/* This is the new way */
if(dev->wireless_data)
return(dev->wireless_data->spy_data);
-
- /* This is the old way. Doesn't work for multi-headed drivers.
- * It will be removed in the next version of WE. */
- return (dev->priv + dev->wireless_handlers->spy_offset);
+ return NULL;
}
/*------------------------------------------------------------------*/
@@ -1284,10 +1298,6 @@
struct iw_spy_data * spydata = get_spydata(dev);
struct sockaddr * address = (struct sockaddr *) extra;
- if(!dev->wireless_data)
- /* Help user know that driver needs updating */
- printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n",
- dev->name);
/* Make sure driver is not buggy or using the old API */
if(!spydata)
return -EOPNOTSUPP;
@@ -1318,7 +1328,7 @@
sizeof(struct iw_quality) * IW_MAX_SPY);
#ifdef WE_SPY_DEBUG
- printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
+ printk(KERN_DEBUG "iw_handler_set_spy() : wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length);
for (i = 0; i < wrqu->data.length; i++)
printk(KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X \n",
@@ -1371,7 +1381,7 @@
sizeof(struct iw_quality) * spydata->spy_number);
/* Reset updated flags. */
for(i = 0; i < spydata->spy_number; i++)
- spydata->spy_stat[i].updated = 0;
+ spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
return 0;
}
@@ -1486,7 +1496,7 @@
return;
#ifdef WE_SPY_DEBUG
- printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
+ printk(KERN_DEBUG "wireless_spy_update() : wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
#endif /* WE_SPY_DEBUG */
/* Update all records that match */
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 621680f..348f36b 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1876,8 +1876,27 @@
return mss_now;
}
+/*
+ * N.B. We get the timeout wrong here, but then we always did get it
+ * wrong before and this is another step along the road to correcting
+ * it. It ought to get updated each time we pass through the routine,
+ * but in practise it probably doesn't matter too much for now.
+ */
+static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk,
+ unsigned long datalen, int noblock,
+ int *errcode)
+{
+ struct sk_buff *skb = sock_alloc_send_skb(sk, datalen,
+ noblock, errcode);
+ if (skb) {
+ skb->protocol = __constant_htons(ETH_P_DNA_RT);
+ skb->pkt_type = PACKET_OUTGOING;
+ }
+ return skb;
+}
+
static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size)
+ struct msghdr *msg, size_t size)
{
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
@@ -1892,7 +1911,7 @@
struct dn_skb_cb *cb;
size_t len;
unsigned char fctype;
- long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+ long timeo;
if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT))
return -EOPNOTSUPP;
@@ -1900,18 +1919,21 @@
if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
return -EINVAL;
+ lock_sock(sk);
+ timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
/*
* The only difference between stream sockets and sequenced packet
* sockets is that the stream sockets always behave as if MSG_EOR
* has been set.
*/
if (sock->type == SOCK_STREAM) {
- if (flags & MSG_EOR)
- return -EINVAL;
+ if (flags & MSG_EOR) {
+ err = -EINVAL;
+ goto out;
+ }
flags |= MSG_EOR;
}
- lock_sock(sk);
err = dn_check_state(sk, addr, addr_len, &timeo, flags);
if (err)
@@ -1980,8 +2002,12 @@
/*
* Get a suitably sized skb.
+ * 64 is a bit of a hack really, but its larger than any
+ * link-layer headers and has served us well as a good
+ * guess as to their real length.
*/
- skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, timeo, &err);
+ skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER,
+ flags & MSG_DONTWAIT, &err);
if (err)
break;
@@ -1991,7 +2017,7 @@
cb = DN_SKB_CB(skb);
- skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
+ skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER);
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
err = -EFAULT;
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index e0bebf4..53633d3 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -137,69 +137,6 @@
}
/*
- * Wrapper for the above, for allocs of data skbs. We try and get the
- * whole size thats been asked for (plus 11 bytes of header). If this
- * fails, then we try for any size over 16 bytes for SOCK_STREAMS.
- */
-struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err)
-{
- int space;
- int len;
- struct sk_buff *skb = NULL;
-
- *err = 0;
-
- while(skb == NULL) {
- if (signal_pending(current)) {
- *err = sock_intr_errno(timeo);
- break;
- }
-
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- *err = EINVAL;
- break;
- }
-
- if (sk->sk_err)
- break;
-
- len = *size + 11;
- space = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
-
- if (space < len) {
- if ((sk->sk_socket->type == SOCK_STREAM) &&
- (space >= (16 + 11)))
- len = space;
- }
-
- if (space < len) {
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
- if (noblock) {
- *err = EWOULDBLOCK;
- break;
- }
-
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- SOCK_SLEEP_PRE(sk)
-
- if ((sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc)) <
- len)
- schedule();
-
- SOCK_SLEEP_POST(sk)
- continue;
- }
-
- if ((skb = dn_alloc_skb(sk, len, sk->sk_allocation)) == NULL)
- continue;
-
- *size = len - 11;
- }
-
- return skb;
-}
-
-/*
* Calculate persist timer based upon the smoothed round
* trip time and the variance. Backoff according to the
* nsp_backoff[] array.
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
new file mode 100644
index 0000000..58ed431
--- /dev/null
+++ b/net/ieee80211/Kconfig
@@ -0,0 +1,69 @@
+config IEEE80211
+ tristate "Generic IEEE 802.11 Networking Stack"
+ select NET_RADIO
+ ---help---
+ This option enables the hardware independent IEEE 802.11
+ networking stack.
+
+config IEEE80211_DEBUG
+ bool "Enable full debugging output"
+ depends on IEEE80211
+ ---help---
+ This option will enable debug tracing output for the
+ ieee80211 network stack.
+
+ This will result in the kernel module being ~70k larger. You
+ can control which debug output is sent to the kernel log by
+ setting the value in
+
+ /proc/net/ieee80211/debug_level
+
+ For example:
+
+ % echo 0x00000FFO > /proc/net/ieee80211/debug_level
+
+ For a list of values you can assign to debug_level, you
+ can look at the bit mask values in <net/ieee80211.h>
+
+ If you are not trying to debug or develop the ieee80211
+ subsystem, you most likely want to say N here.
+
+config IEEE80211_CRYPT_WEP
+ tristate "IEEE 802.11 WEP encryption (802.1x)"
+ depends on IEEE80211
+ select CRYPTO
+ select CRYPTO_ARC4
+ select CRC32
+ ---help---
+ Include software based cipher suites in support of IEEE
+ 802.11's WEP. This is needed for WEP as well as 802.1x.
+
+ This can be compiled as a modules and it will be called
+ "ieee80211_crypt_wep".
+
+config IEEE80211_CRYPT_CCMP
+ tristate "IEEE 802.11i CCMP support"
+ depends on IEEE80211
+ select CRYPTO
+ select CRYPTO_AES
+ ---help---
+ Include software based cipher suites in support of IEEE 802.11i
+ (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with CCMP enabled
+ networks.
+
+ This can be compiled as a modules and it will be called
+ "ieee80211_crypt_ccmp".
+
+config IEEE80211_CRYPT_TKIP
+ tristate "IEEE 802.11i TKIP encryption"
+ depends on IEEE80211
+ select CRYPTO
+ select CRYPTO_MICHAEL_MIC
+ ---help---
+ Include software based cipher suites in support of IEEE 802.11i
+ (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with TKIP enabled
+ networks.
+
+ This can be compiled as a modules and it will be called
+ "ieee80211_crypt_tkip".
+
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
new file mode 100644
index 0000000..a6ccac5
--- /dev/null
+++ b/net/ieee80211/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_IEEE80211) += ieee80211.o
+obj-$(CONFIG_IEEE80211) += ieee80211_crypt.o
+obj-$(CONFIG_IEEE80211_CRYPT_WEP) += ieee80211_crypt_wep.o
+obj-$(CONFIG_IEEE80211_CRYPT_CCMP) += ieee80211_crypt_ccmp.o
+obj-$(CONFIG_IEEE80211_CRYPT_TKIP) += ieee80211_crypt_tkip.o
+ieee80211-objs := \
+ ieee80211_module.o \
+ ieee80211_tx.o \
+ ieee80211_rx.o \
+ ieee80211_wx.o
+
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
new file mode 100644
index 0000000..61a9d92
--- /dev/null
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -0,0 +1,258 @@
+/*
+ * Host AP crypto routines
+ *
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/string.h>
+#include <asm/errno.h>
+
+#include <net/ieee80211.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("HostAP crypto");
+MODULE_LICENSE("GPL");
+
+struct ieee80211_crypto_alg {
+ struct list_head list;
+ struct ieee80211_crypto_ops *ops;
+};
+
+struct ieee80211_crypto {
+ struct list_head algs;
+ spinlock_t lock;
+};
+
+static struct ieee80211_crypto *hcrypt;
+
+void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
+{
+ struct list_head *ptr, *n;
+ struct ieee80211_crypt_data *entry;
+
+ for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
+ ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
+ entry = list_entry(ptr, struct ieee80211_crypt_data, list);
+
+ if (atomic_read(&entry->refcnt) != 0 && !force)
+ continue;
+
+ list_del(ptr);
+
+ if (entry->ops) {
+ entry->ops->deinit(entry->priv);
+ module_put(entry->ops->owner);
+ }
+ kfree(entry);
+ }
+}
+
+void ieee80211_crypt_deinit_handler(unsigned long data)
+{
+ struct ieee80211_device *ieee = (struct ieee80211_device *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+ ieee80211_crypt_deinit_entries(ieee, 0);
+ if (!list_empty(&ieee->crypt_deinit_list)) {
+ printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+ "deletion list\n", ieee->dev->name);
+ ieee->crypt_deinit_timer.expires = jiffies + HZ;
+ add_timer(&ieee->crypt_deinit_timer);
+ }
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+}
+
+void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
+ struct ieee80211_crypt_data **crypt)
+{
+ struct ieee80211_crypt_data *tmp;
+ unsigned long flags;
+
+ if (*crypt == NULL)
+ return;
+
+ tmp = *crypt;
+ *crypt = NULL;
+
+ /* must not run ops->deinit() while there may be pending encrypt or
+ * decrypt operations. Use a list of delayed deinits to avoid needing
+ * locking. */
+
+ spin_lock_irqsave(&ieee->lock, flags);
+ list_add(&tmp->list, &ieee->crypt_deinit_list);
+ if (!timer_pending(&ieee->crypt_deinit_timer)) {
+ ieee->crypt_deinit_timer.expires = jiffies + HZ;
+ add_timer(&ieee->crypt_deinit_timer);
+ }
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
+{
+ unsigned long flags;
+ struct ieee80211_crypto_alg *alg;
+
+ if (hcrypt == NULL)
+ return -1;
+
+ alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+ if (alg == NULL)
+ return -ENOMEM;
+
+ memset(alg, 0, sizeof(*alg));
+ alg->ops = ops;
+
+ spin_lock_irqsave(&hcrypt->lock, flags);
+ list_add(&alg->list, &hcrypt->algs);
+ spin_unlock_irqrestore(&hcrypt->lock, flags);
+
+ printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n",
+ ops->name);
+
+ return 0;
+}
+
+int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
+{
+ unsigned long flags;
+ struct list_head *ptr;
+ struct ieee80211_crypto_alg *del_alg = NULL;
+
+ if (hcrypt == NULL)
+ return -1;
+
+ spin_lock_irqsave(&hcrypt->lock, flags);
+ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
+ struct ieee80211_crypto_alg *alg =
+ (struct ieee80211_crypto_alg *)ptr;
+ if (alg->ops == ops) {
+ list_del(&alg->list);
+ del_alg = alg;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&hcrypt->lock, flags);
+
+ if (del_alg) {
+ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
+ "'%s'\n", ops->name);
+ kfree(del_alg);
+ }
+
+ return del_alg ? 0 : -1;
+}
+
+struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
+{
+ unsigned long flags;
+ struct list_head *ptr;
+ struct ieee80211_crypto_alg *found_alg = NULL;
+
+ if (hcrypt == NULL)
+ return NULL;
+
+ spin_lock_irqsave(&hcrypt->lock, flags);
+ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
+ struct ieee80211_crypto_alg *alg =
+ (struct ieee80211_crypto_alg *)ptr;
+ if (strcmp(alg->ops->name, name) == 0) {
+ found_alg = alg;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&hcrypt->lock, flags);
+
+ if (found_alg)
+ return found_alg->ops;
+ else
+ return NULL;
+}
+
+static void *ieee80211_crypt_null_init(int keyidx)
+{
+ return (void *)1;
+}
+static void ieee80211_crypt_null_deinit(void *priv)
+{
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_null = {
+ .name = "NULL",
+ .init = ieee80211_crypt_null_init,
+ .deinit = ieee80211_crypt_null_deinit,
+ .encrypt_mpdu = NULL,
+ .decrypt_mpdu = NULL,
+ .encrypt_msdu = NULL,
+ .decrypt_msdu = NULL,
+ .set_key = NULL,
+ .get_key = NULL,
+ .extra_prefix_len = 0,
+ .extra_postfix_len = 0,
+ .owner = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_init(void)
+{
+ int ret = -ENOMEM;
+
+ hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL);
+ if (!hcrypt)
+ goto out;
+
+ memset(hcrypt, 0, sizeof(*hcrypt));
+ INIT_LIST_HEAD(&hcrypt->algs);
+ spin_lock_init(&hcrypt->lock);
+
+ ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null);
+ if (ret < 0) {
+ kfree(hcrypt);
+ hcrypt = NULL;
+ }
+ out:
+ return ret;
+}
+
+static void __exit ieee80211_crypto_deinit(void)
+{
+ struct list_head *ptr, *n;
+
+ if (hcrypt == NULL)
+ return;
+
+ for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
+ ptr = n, n = ptr->next) {
+ struct ieee80211_crypto_alg *alg =
+ (struct ieee80211_crypto_alg *)ptr;
+ list_del(ptr);
+ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
+ "'%s' (deinit)\n", alg->ops->name);
+ kfree(alg);
+ }
+
+ kfree(hcrypt);
+}
+
+EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
+EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
+EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
+
+EXPORT_SYMBOL(ieee80211_register_crypto_ops);
+EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
+EXPORT_SYMBOL(ieee80211_get_crypto_ops);
+
+module_init(ieee80211_crypto_init);
+module_exit(ieee80211_crypto_deinit);
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
new file mode 100644
index 0000000..8fc13f4
--- /dev/null
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -0,0 +1,455 @@
+/*
+ * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
+ *
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <asm/string.h>
+#include <linux/wireless.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: CCMP");
+MODULE_LICENSE("GPL");
+
+#define AES_BLOCK_LEN 16
+#define CCMP_HDR_LEN 8
+#define CCMP_MIC_LEN 8
+#define CCMP_TK_LEN 16
+#define CCMP_PN_LEN 6
+
+struct ieee80211_ccmp_data {
+ u8 key[CCMP_TK_LEN];
+ int key_set;
+
+ u8 tx_pn[CCMP_PN_LEN];
+ u8 rx_pn[CCMP_PN_LEN];
+
+ u32 dot11RSNAStatsCCMPFormatErrors;
+ u32 dot11RSNAStatsCCMPReplays;
+ u32 dot11RSNAStatsCCMPDecryptErrors;
+
+ int key_idx;
+
+ struct crypto_tfm *tfm;
+
+ /* scratch buffers for virt_to_page() (crypto API) */
+ u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
+ tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
+ u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
+};
+
+static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
+ const u8 pt[16], u8 ct[16])
+{
+ struct scatterlist src, dst;
+
+ src.page = virt_to_page(pt);
+ src.offset = offset_in_page(pt);
+ src.length = AES_BLOCK_LEN;
+
+ dst.page = virt_to_page(ct);
+ dst.offset = offset_in_page(ct);
+ dst.length = AES_BLOCK_LEN;
+
+ crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
+}
+
+static void *ieee80211_ccmp_init(int key_idx)
+{
+ struct ieee80211_ccmp_data *priv;
+
+ priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+ if (priv == NULL)
+ goto fail;
+ memset(priv, 0, sizeof(*priv));
+ priv->key_idx = key_idx;
+
+ priv->tfm = crypto_alloc_tfm("aes", 0);
+ if (priv->tfm == NULL) {
+ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
+ "crypto API aes\n");
+ goto fail;
+ }
+
+ return priv;
+
+ fail:
+ if (priv) {
+ if (priv->tfm)
+ crypto_free_tfm(priv->tfm);
+ kfree(priv);
+ }
+
+ return NULL;
+}
+
+static void ieee80211_ccmp_deinit(void *priv)
+{
+ struct ieee80211_ccmp_data *_priv = priv;
+ if (_priv && _priv->tfm)
+ crypto_free_tfm(_priv->tfm);
+ kfree(priv);
+}
+
+static inline void xor_block(u8 * b, u8 * a, size_t len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ b[i] ^= a[i];
+}
+
+static void ccmp_init_blocks(struct crypto_tfm *tfm,
+ struct ieee80211_hdr *hdr,
+ u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0)
+{
+ u8 *pos, qc = 0;
+ size_t aad_len;
+ u16 fc;
+ int a4_included, qc_included;
+ u8 aad[2 * AES_BLOCK_LEN];
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS));
+ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
+ (WLAN_FC_GET_STYPE(fc) & 0x08));
+ aad_len = 22;
+ if (a4_included)
+ aad_len += 6;
+ if (qc_included) {
+ pos = (u8 *) & hdr->addr4;
+ if (a4_included)
+ pos += 6;
+ qc = *pos & 0x0f;
+ aad_len += 2;
+ }
+
+ /* CCM Initial Block:
+ * Flag (Include authentication header, M=3 (8-octet MIC),
+ * L=1 (2-octet Dlen))
+ * Nonce: 0x00 | A2 | PN
+ * Dlen */
+ b0[0] = 0x59;
+ b0[1] = qc;
+ memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
+ memcpy(b0 + 8, pn, CCMP_PN_LEN);
+ b0[14] = (dlen >> 8) & 0xff;
+ b0[15] = dlen & 0xff;
+
+ /* AAD:
+ * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
+ * A1 | A2 | A3
+ * SC with bits 4..15 (seq#) masked to zero
+ * A4 (if present)
+ * QC (if present)
+ */
+ pos = (u8 *) hdr;
+ aad[0] = 0; /* aad_len >> 8 */
+ aad[1] = aad_len & 0xff;
+ aad[2] = pos[0] & 0x8f;
+ aad[3] = pos[1] & 0xc7;
+ memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
+ pos = (u8 *) & hdr->seq_ctl;
+ aad[22] = pos[0] & 0x0f;
+ aad[23] = 0; /* all bits masked */
+ memset(aad + 24, 0, 8);
+ if (a4_included)
+ memcpy(aad + 24, hdr->addr4, ETH_ALEN);
+ if (qc_included) {
+ aad[a4_included ? 30 : 24] = qc;
+ /* rest of QC masked */
+ }
+
+ /* Start with the first block and AAD */
+ ieee80211_ccmp_aes_encrypt(tfm, b0, auth);
+ xor_block(auth, aad, AES_BLOCK_LEN);
+ ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
+ xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
+ ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
+ b0[0] &= 0x07;
+ b0[14] = b0[15] = 0;
+ ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
+}
+
+static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_ccmp_data *key = priv;
+ int data_len, i, blocks, last, len;
+ u8 *pos, *mic;
+ struct ieee80211_hdr *hdr;
+ u8 *b0 = key->tx_b0;
+ u8 *b = key->tx_b;
+ u8 *e = key->tx_e;
+ u8 *s0 = key->tx_s0;
+
+ if (skb_headroom(skb) < CCMP_HDR_LEN ||
+ skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
+ return -1;
+
+ data_len = skb->len - hdr_len;
+ pos = skb_push(skb, CCMP_HDR_LEN);
+ memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
+ pos += hdr_len;
+ mic = skb_put(skb, CCMP_MIC_LEN);
+
+ i = CCMP_PN_LEN - 1;
+ while (i >= 0) {
+ key->tx_pn[i]++;
+ if (key->tx_pn[i] != 0)
+ break;
+ i--;
+ }
+
+ *pos++ = key->tx_pn[5];
+ *pos++ = key->tx_pn[4];
+ *pos++ = 0;
+ *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
+ *pos++ = key->tx_pn[3];
+ *pos++ = key->tx_pn[2];
+ *pos++ = key->tx_pn[1];
+ *pos++ = key->tx_pn[0];
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
+
+ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+ last = data_len % AES_BLOCK_LEN;
+
+ for (i = 1; i <= blocks; i++) {
+ len = (i == blocks && last) ? last : AES_BLOCK_LEN;
+ /* Authentication */
+ xor_block(b, pos, len);
+ ieee80211_ccmp_aes_encrypt(key->tfm, b, b);
+ /* Encryption, with counter */
+ b0[14] = (i >> 8) & 0xff;
+ b0[15] = i & 0xff;
+ ieee80211_ccmp_aes_encrypt(key->tfm, b0, e);
+ xor_block(pos, e, len);
+ pos += len;
+ }
+
+ for (i = 0; i < CCMP_MIC_LEN; i++)
+ mic[i] = b[i] ^ s0[i];
+
+ return 0;
+}
+
+static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_ccmp_data *key = priv;
+ u8 keyidx, *pos;
+ struct ieee80211_hdr *hdr;
+ u8 *b0 = key->rx_b0;
+ u8 *b = key->rx_b;
+ u8 *a = key->rx_a;
+ u8 pn[6];
+ int i, blocks, last, len;
+ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
+ u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
+
+ if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
+ key->dot11RSNAStatsCCMPFormatErrors++;
+ return -1;
+ }
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ pos = skb->data + hdr_len;
+ keyidx = pos[3];
+ if (!(keyidx & (1 << 5))) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "CCMP: received packet without ExtIV"
+ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ }
+ key->dot11RSNAStatsCCMPFormatErrors++;
+ return -2;
+ }
+ keyidx >>= 6;
+ if (key->key_idx != keyidx) {
+ printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
+ "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
+ return -6;
+ }
+ if (!key->key_set) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
+ " with keyid=%d that does not have a configured"
+ " key\n", MAC_ARG(hdr->addr2), keyidx);
+ }
+ return -3;
+ }
+
+ pn[0] = pos[7];
+ pn[1] = pos[6];
+ pn[2] = pos[5];
+ pn[3] = pos[4];
+ pn[4] = pos[1];
+ pn[5] = pos[0];
+ pos += 8;
+
+ if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+ " previous PN %02x%02x%02x%02x%02x%02x "
+ "received PN %02x%02x%02x%02x%02x%02x\n",
+ MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
+ MAC_ARG(pn));
+ }
+ key->dot11RSNAStatsCCMPReplays++;
+ return -4;
+ }
+
+ ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
+ xor_block(mic, b, CCMP_MIC_LEN);
+
+ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+ last = data_len % AES_BLOCK_LEN;
+
+ for (i = 1; i <= blocks; i++) {
+ len = (i == blocks && last) ? last : AES_BLOCK_LEN;
+ /* Decrypt, with counter */
+ b0[14] = (i >> 8) & 0xff;
+ b0[15] = i & 0xff;
+ ieee80211_ccmp_aes_encrypt(key->tfm, b0, b);
+ xor_block(pos, b, len);
+ /* Authentication */
+ xor_block(a, pos, len);
+ ieee80211_ccmp_aes_encrypt(key->tfm, a, a);
+ pos += len;
+ }
+
+ if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "CCMP: decrypt failed: STA="
+ MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ }
+ key->dot11RSNAStatsCCMPDecryptErrors++;
+ return -5;
+ }
+
+ memcpy(key->rx_pn, pn, CCMP_PN_LEN);
+
+ /* Remove hdr and MIC */
+ memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
+ skb_pull(skb, CCMP_HDR_LEN);
+ skb_trim(skb, skb->len - CCMP_MIC_LEN);
+
+ return keyidx;
+}
+
+static int ieee80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
+{
+ struct ieee80211_ccmp_data *data = priv;
+ int keyidx;
+ struct crypto_tfm *tfm = data->tfm;
+
+ keyidx = data->key_idx;
+ memset(data, 0, sizeof(*data));
+ data->key_idx = keyidx;
+ data->tfm = tfm;
+ if (len == CCMP_TK_LEN) {
+ memcpy(data->key, key, CCMP_TK_LEN);
+ data->key_set = 1;
+ if (seq) {
+ data->rx_pn[0] = seq[5];
+ data->rx_pn[1] = seq[4];
+ data->rx_pn[2] = seq[3];
+ data->rx_pn[3] = seq[2];
+ data->rx_pn[4] = seq[1];
+ data->rx_pn[5] = seq[0];
+ }
+ crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN);
+ } else if (len == 0)
+ data->key_set = 0;
+ else
+ return -1;
+
+ return 0;
+}
+
+static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
+{
+ struct ieee80211_ccmp_data *data = priv;
+
+ if (len < CCMP_TK_LEN)
+ return -1;
+
+ if (!data->key_set)
+ return 0;
+ memcpy(key, data->key, CCMP_TK_LEN);
+
+ if (seq) {
+ seq[0] = data->tx_pn[5];
+ seq[1] = data->tx_pn[4];
+ seq[2] = data->tx_pn[3];
+ seq[3] = data->tx_pn[2];
+ seq[4] = data->tx_pn[1];
+ seq[5] = data->tx_pn[0];
+ }
+
+ return CCMP_TK_LEN;
+}
+
+static char *ieee80211_ccmp_print_stats(char *p, void *priv)
+{
+ struct ieee80211_ccmp_data *ccmp = priv;
+ p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
+ "tx_pn=%02x%02x%02x%02x%02x%02x "
+ "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "format_errors=%d replays=%d decrypt_errors=%d\n",
+ ccmp->key_idx, ccmp->key_set,
+ MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+ ccmp->dot11RSNAStatsCCMPFormatErrors,
+ ccmp->dot11RSNAStatsCCMPReplays,
+ ccmp->dot11RSNAStatsCCMPDecryptErrors);
+
+ return p;
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
+ .name = "CCMP",
+ .init = ieee80211_ccmp_init,
+ .deinit = ieee80211_ccmp_deinit,
+ .encrypt_mpdu = ieee80211_ccmp_encrypt,
+ .decrypt_mpdu = ieee80211_ccmp_decrypt,
+ .encrypt_msdu = NULL,
+ .decrypt_msdu = NULL,
+ .set_key = ieee80211_ccmp_set_key,
+ .get_key = ieee80211_ccmp_get_key,
+ .print_stats = ieee80211_ccmp_print_stats,
+ .extra_prefix_len = CCMP_HDR_LEN,
+ .extra_postfix_len = CCMP_MIC_LEN,
+ .owner = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_ccmp_init(void)
+{
+ return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp);
+}
+
+static void __exit ieee80211_crypto_ccmp_exit(void)
+{
+ ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
+}
+
+module_init(ieee80211_crypto_ccmp_init);
+module_exit(ieee80211_crypto_ccmp_exit);
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
new file mode 100644
index 0000000..d4f9164
--- /dev/null
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -0,0 +1,683 @@
+/*
+ * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
+ *
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <asm/string.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include <linux/crc32.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: TKIP");
+MODULE_LICENSE("GPL");
+
+struct ieee80211_tkip_data {
+#define TKIP_KEY_LEN 32
+ u8 key[TKIP_KEY_LEN];
+ int key_set;
+
+ u32 tx_iv32;
+ u16 tx_iv16;
+ u16 tx_ttak[5];
+ int tx_phase1_done;
+
+ u32 rx_iv32;
+ u16 rx_iv16;
+ u16 rx_ttak[5];
+ int rx_phase1_done;
+ u32 rx_iv32_new;
+ u16 rx_iv16_new;
+
+ u32 dot11RSNAStatsTKIPReplays;
+ u32 dot11RSNAStatsTKIPICVErrors;
+ u32 dot11RSNAStatsTKIPLocalMICFailures;
+
+ int key_idx;
+
+ struct crypto_tfm *tfm_arc4;
+ struct crypto_tfm *tfm_michael;
+
+ /* scratch buffers for virt_to_page() (crypto API) */
+ u8 rx_hdr[16], tx_hdr[16];
+};
+
+static void *ieee80211_tkip_init(int key_idx)
+{
+ struct ieee80211_tkip_data *priv;
+
+ priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+ if (priv == NULL)
+ goto fail;
+ memset(priv, 0, sizeof(*priv));
+ priv->key_idx = key_idx;
+
+ priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
+ if (priv->tfm_arc4 == NULL) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API arc4\n");
+ goto fail;
+ }
+
+ priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
+ if (priv->tfm_michael == NULL) {
+ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+ "crypto API michael_mic\n");
+ goto fail;
+ }
+
+ return priv;
+
+ fail:
+ if (priv) {
+ if (priv->tfm_michael)
+ crypto_free_tfm(priv->tfm_michael);
+ if (priv->tfm_arc4)
+ crypto_free_tfm(priv->tfm_arc4);
+ kfree(priv);
+ }
+
+ return NULL;
+}
+
+static void ieee80211_tkip_deinit(void *priv)
+{
+ struct ieee80211_tkip_data *_priv = priv;
+ if (_priv && _priv->tfm_michael)
+ crypto_free_tfm(_priv->tfm_michael);
+ if (_priv && _priv->tfm_arc4)
+ crypto_free_tfm(_priv->tfm_arc4);
+ kfree(priv);
+}
+
+static inline u16 RotR1(u16 val)
+{
+ return (val >> 1) | (val << 15);
+}
+
+static inline u8 Lo8(u16 val)
+{
+ return val & 0xff;
+}
+
+static inline u8 Hi8(u16 val)
+{
+ return val >> 8;
+}
+
+static inline u16 Lo16(u32 val)
+{
+ return val & 0xffff;
+}
+
+static inline u16 Hi16(u32 val)
+{
+ return val >> 16;
+}
+
+static inline u16 Mk16(u8 hi, u8 lo)
+{
+ return lo | (((u16) hi) << 8);
+}
+
+static inline u16 Mk16_le(u16 * v)
+{
+ return le16_to_cpu(*v);
+}
+
+static const u16 Sbox[256] = {
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+static inline u16 _S_(u16 v)
+{
+ u16 t = Sbox[Hi8(v)];
+ return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
+}
+
+#define PHASE1_LOOP_COUNT 8
+
+static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
+ u32 IV32)
+{
+ int i, j;
+
+ /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
+ TTAK[0] = Lo16(IV32);
+ TTAK[1] = Hi16(IV32);
+ TTAK[2] = Mk16(TA[1], TA[0]);
+ TTAK[3] = Mk16(TA[3], TA[2]);
+ TTAK[4] = Mk16(TA[5], TA[4]);
+
+ for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+ j = 2 * (i & 1);
+ TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
+ TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
+ TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
+ TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
+ TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
+ }
+}
+
+static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
+ u16 IV16)
+{
+ /* Make temporary area overlap WEP seed so that the final copy can be
+ * avoided on little endian hosts. */
+ u16 *PPK = (u16 *) & WEPSeed[4];
+
+ /* Step 1 - make copy of TTAK and bring in TSC */
+ PPK[0] = TTAK[0];
+ PPK[1] = TTAK[1];
+ PPK[2] = TTAK[2];
+ PPK[3] = TTAK[3];
+ PPK[4] = TTAK[4];
+ PPK[5] = TTAK[4] + IV16;
+
+ /* Step 2 - 96-bit bijective mixing using S-box */
+ PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
+ PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
+ PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
+ PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
+ PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
+ PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
+
+ PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
+ PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
+ PPK[2] += RotR1(PPK[1]);
+ PPK[3] += RotR1(PPK[2]);
+ PPK[4] += RotR1(PPK[3]);
+ PPK[5] += RotR1(PPK[4]);
+
+ /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
+ * WEPSeed[0..2] is transmitted as WEP IV */
+ WEPSeed[0] = Hi8(IV16);
+ WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
+ WEPSeed[2] = Lo8(IV16);
+ WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
+
+#ifdef __BIG_ENDIAN
+ {
+ int i;
+ for (i = 0; i < 6; i++)
+ PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
+ }
+#endif
+}
+
+static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ int len;
+ u8 rc4key[16], *pos, *icv;
+ struct ieee80211_hdr *hdr;
+ u32 crc;
+ struct scatterlist sg;
+
+ if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
+ skb->len < hdr_len)
+ return -1;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ if (!tkey->tx_phase1_done) {
+ tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
+ tkey->tx_iv32);
+ tkey->tx_phase1_done = 1;
+ }
+ tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
+
+ len = skb->len - hdr_len;
+ pos = skb_push(skb, 8);
+ memmove(pos, pos + 8, hdr_len);
+ pos += hdr_len;
+ icv = skb_put(skb, 4);
+
+ *pos++ = rc4key[0];
+ *pos++ = rc4key[1];
+ *pos++ = rc4key[2];
+ *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
+ *pos++ = tkey->tx_iv32 & 0xff;
+ *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
+ *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
+ *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
+
+ crc = ~crc32_le(~0, pos, len);
+ icv[0] = crc;
+ icv[1] = crc >> 8;
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+
+ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = len + 4;
+ crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
+
+ tkey->tx_iv16++;
+ if (tkey->tx_iv16 == 0) {
+ tkey->tx_phase1_done = 0;
+ tkey->tx_iv32++;
+ }
+
+ return 0;
+}
+
+static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ u8 rc4key[16];
+ u8 keyidx, *pos;
+ u32 iv32;
+ u16 iv16;
+ struct ieee80211_hdr *hdr;
+ u8 icv[4];
+ u32 crc;
+ struct scatterlist sg;
+ int plen;
+
+ if (skb->len < hdr_len + 8 + 4)
+ return -1;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ pos = skb->data + hdr_len;
+ keyidx = pos[3];
+ if (!(keyidx & (1 << 5))) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: received packet without ExtIV"
+ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ }
+ return -2;
+ }
+ keyidx >>= 6;
+ if (tkey->key_idx != keyidx) {
+ printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
+ "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
+ return -6;
+ }
+ if (!tkey->key_set) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+ " with keyid=%d that does not have a configured"
+ " key\n", MAC_ARG(hdr->addr2), keyidx);
+ }
+ return -3;
+ }
+ iv16 = (pos[0] << 8) | pos[2];
+ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+ pos += 8;
+
+ if (iv32 < tkey->rx_iv32 ||
+ (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ " previous TSC %08x%04x received TSC "
+ "%08x%04x\n", MAC_ARG(hdr->addr2),
+ tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
+ }
+ tkey->dot11RSNAStatsTKIPReplays++;
+ return -4;
+ }
+
+ if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
+ tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
+ tkey->rx_phase1_done = 1;
+ }
+ tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
+
+ plen = skb->len - hdr_len - 12;
+
+ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = plen + 4;
+ crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
+
+ crc = ~crc32_le(~0, pos, plen);
+ icv[0] = crc;
+ icv[1] = crc >> 8;
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+ if (memcmp(icv, pos + plen, 4) != 0) {
+ if (iv32 != tkey->rx_iv32) {
+ /* Previously cached Phase1 result was already lost, so
+ * it needs to be recalculated for the next packet. */
+ tkey->rx_phase1_done = 0;
+ }
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+ MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ }
+ tkey->dot11RSNAStatsTKIPICVErrors++;
+ return -5;
+ }
+
+ /* Update real counters only after Michael MIC verification has
+ * completed */
+ tkey->rx_iv32_new = iv32;
+ tkey->rx_iv16_new = iv16;
+
+ /* Remove IV and ICV */
+ memmove(skb->data + 8, skb->data, hdr_len);
+ skb_pull(skb, 8);
+ skb_trim(skb, skb->len - 4);
+
+ return keyidx;
+}
+
+static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
+ u8 * data, size_t data_len, u8 * mic)
+{
+ struct scatterlist sg[2];
+
+ if (tkey->tfm_michael == NULL) {
+ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+ return -1;
+ }
+ sg[0].page = virt_to_page(hdr);
+ sg[0].offset = offset_in_page(hdr);
+ sg[0].length = 16;
+
+ sg[1].page = virt_to_page(data);
+ sg[1].offset = offset_in_page(data);
+ sg[1].length = data_len;
+
+ crypto_digest_init(tkey->tfm_michael);
+ crypto_digest_setkey(tkey->tfm_michael, key, 8);
+ crypto_digest_update(tkey->tfm_michael, sg, 2);
+ crypto_digest_final(tkey->tfm_michael, mic);
+
+ return 0;
+}
+
+static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
+{
+ struct ieee80211_hdr *hdr11;
+
+ hdr11 = (struct ieee80211_hdr *)skb->data;
+ switch (le16_to_cpu(hdr11->frame_ctl) &
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case IEEE80211_FCTL_TODS:
+ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+ break;
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
+ break;
+ case 0:
+ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
+ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
+ break;
+ }
+
+ hdr[12] = 0; /* priority */
+ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
+}
+
+static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
+ void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ u8 *pos;
+
+ if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
+ printk(KERN_DEBUG "Invalid packet for Michael MIC add "
+ "(tailroom=%d hdr_len=%d skb->len=%d)\n",
+ skb_tailroom(skb), hdr_len, skb->len);
+ return -1;
+ }
+
+ michael_mic_hdr(skb, tkey->tx_hdr);
+ pos = skb_put(skb, 8);
+ if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
+ return -1;
+
+ return 0;
+}
+
+#if WIRELESS_EXT >= 18
+static void ieee80211_michael_mic_failure(struct net_device *dev,
+ struct ieee80211_hdr *hdr, int keyidx)
+{
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure ev;
+
+ /* TODO: needed parameters: count, keyid, key type, TSC */
+ memset(&ev, 0, sizeof(ev));
+ ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
+ if (hdr->addr1[0] & 0x01)
+ ev.flags |= IW_MICFAILURE_GROUP;
+ else
+ ev.flags |= IW_MICFAILURE_PAIRWISE;
+ ev.src_addr.sa_family = ARPHRD_ETHER;
+ memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(ev);
+ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
+}
+#elif WIRELESS_EXT >= 15
+static void ieee80211_michael_mic_failure(struct net_device *dev,
+ struct ieee80211_hdr *hdr, int keyidx)
+{
+ union iwreq_data wrqu;
+ char buf[128];
+
+ /* TODO: needed parameters: count, keyid, key type, TSC */
+ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr="
+ MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+ MAC_ARG(hdr->addr2));
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+}
+#else /* WIRELESS_EXT >= 15 */
+static inline void ieee80211_michael_mic_failure(struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ int keyidx)
+{
+}
+#endif /* WIRELESS_EXT >= 15 */
+
+static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
+ int hdr_len, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ u8 mic[8];
+
+ if (!tkey->key_set)
+ return -1;
+
+ michael_mic_hdr(skb, tkey->rx_hdr);
+ if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
+ return -1;
+ if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+ struct ieee80211_hdr *hdr;
+ hdr = (struct ieee80211_hdr *)skb->data;
+ printk(KERN_DEBUG "%s: Michael MIC verification failed for "
+ "MSDU from " MAC_FMT " keyidx=%d\n",
+ skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+ keyidx);
+ if (skb->dev)
+ ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
+ tkey->dot11RSNAStatsTKIPLocalMICFailures++;
+ return -1;
+ }
+
+ /* Update TSC counters for RX now that the packet verification has
+ * completed. */
+ tkey->rx_iv32 = tkey->rx_iv32_new;
+ tkey->rx_iv16 = tkey->rx_iv16_new;
+
+ skb_trim(skb, skb->len - 8);
+
+ return 0;
+}
+
+static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+ int keyidx;
+ struct crypto_tfm *tfm = tkey->tfm_michael;
+ struct crypto_tfm *tfm2 = tkey->tfm_arc4;
+
+ keyidx = tkey->key_idx;
+ memset(tkey, 0, sizeof(*tkey));
+ tkey->key_idx = keyidx;
+ tkey->tfm_michael = tfm;
+ tkey->tfm_arc4 = tfm2;
+ if (len == TKIP_KEY_LEN) {
+ memcpy(tkey->key, key, TKIP_KEY_LEN);
+ tkey->key_set = 1;
+ tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
+ if (seq) {
+ tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
+ (seq[3] << 8) | seq[2];
+ tkey->rx_iv16 = (seq[1] << 8) | seq[0];
+ }
+ } else if (len == 0)
+ tkey->key_set = 0;
+ else
+ return -1;
+
+ return 0;
+}
+
+static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
+{
+ struct ieee80211_tkip_data *tkey = priv;
+
+ if (len < TKIP_KEY_LEN)
+ return -1;
+
+ if (!tkey->key_set)
+ return 0;
+ memcpy(key, tkey->key, TKIP_KEY_LEN);
+
+ if (seq) {
+ /* Return the sequence number of the last transmitted frame. */
+ u16 iv16 = tkey->tx_iv16;
+ u32 iv32 = tkey->tx_iv32;
+ if (iv16 == 0)
+ iv32--;
+ iv16--;
+ seq[0] = tkey->tx_iv16;
+ seq[1] = tkey->tx_iv16 >> 8;
+ seq[2] = tkey->tx_iv32;
+ seq[3] = tkey->tx_iv32 >> 8;
+ seq[4] = tkey->tx_iv32 >> 16;
+ seq[5] = tkey->tx_iv32 >> 24;
+ }
+
+ return TKIP_KEY_LEN;
+}
+
+static char *ieee80211_tkip_print_stats(char *p, void *priv)
+{
+ struct ieee80211_tkip_data *tkip = priv;
+ p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
+ "tx_pn=%02x%02x%02x%02x%02x%02x "
+ "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "replays=%d icv_errors=%d local_mic_failures=%d\n",
+ tkip->key_idx, tkip->key_set,
+ (tkip->tx_iv32 >> 24) & 0xff,
+ (tkip->tx_iv32 >> 16) & 0xff,
+ (tkip->tx_iv32 >> 8) & 0xff,
+ tkip->tx_iv32 & 0xff,
+ (tkip->tx_iv16 >> 8) & 0xff,
+ tkip->tx_iv16 & 0xff,
+ (tkip->rx_iv32 >> 24) & 0xff,
+ (tkip->rx_iv32 >> 16) & 0xff,
+ (tkip->rx_iv32 >> 8) & 0xff,
+ tkip->rx_iv32 & 0xff,
+ (tkip->rx_iv16 >> 8) & 0xff,
+ tkip->rx_iv16 & 0xff,
+ tkip->dot11RSNAStatsTKIPReplays,
+ tkip->dot11RSNAStatsTKIPICVErrors,
+ tkip->dot11RSNAStatsTKIPLocalMICFailures);
+ return p;
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
+ .name = "TKIP",
+ .init = ieee80211_tkip_init,
+ .deinit = ieee80211_tkip_deinit,
+ .encrypt_mpdu = ieee80211_tkip_encrypt,
+ .decrypt_mpdu = ieee80211_tkip_decrypt,
+ .encrypt_msdu = ieee80211_michael_mic_add,
+ .decrypt_msdu = ieee80211_michael_mic_verify,
+ .set_key = ieee80211_tkip_set_key,
+ .get_key = ieee80211_tkip_get_key,
+ .print_stats = ieee80211_tkip_print_stats,
+ .extra_prefix_len = 4 + 4, /* IV + ExtIV */
+ .extra_postfix_len = 8 + 4, /* MIC + ICV */
+ .owner = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_tkip_init(void)
+{
+ return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
+}
+
+static void __exit ieee80211_crypto_tkip_exit(void)
+{
+ ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
+}
+
+module_init(ieee80211_crypto_tkip_init);
+module_exit(ieee80211_crypto_tkip_exit);
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
new file mode 100644
index 0000000..b4d2514
--- /dev/null
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -0,0 +1,258 @@
+/*
+ * Host AP crypt: host-based WEP encryption implementation for Host AP driver
+ *
+ * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <asm/string.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include <linux/crc32.h>
+
+MODULE_AUTHOR("Jouni Malinen");
+MODULE_DESCRIPTION("Host AP crypt: WEP");
+MODULE_LICENSE("GPL");
+
+struct prism2_wep_data {
+ u32 iv;
+#define WEP_KEY_LEN 13
+ u8 key[WEP_KEY_LEN + 1];
+ u8 key_len;
+ u8 key_idx;
+ struct crypto_tfm *tfm;
+};
+
+static void *prism2_wep_init(int keyidx)
+{
+ struct prism2_wep_data *priv;
+
+ priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+ if (priv == NULL)
+ goto fail;
+ memset(priv, 0, sizeof(*priv));
+ priv->key_idx = keyidx;
+
+ priv->tfm = crypto_alloc_tfm("arc4", 0);
+ if (priv->tfm == NULL) {
+ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
+ "crypto API arc4\n");
+ goto fail;
+ }
+
+ /* start WEP IV from a random value */
+ get_random_bytes(&priv->iv, 4);
+
+ return priv;
+
+ fail:
+ if (priv) {
+ if (priv->tfm)
+ crypto_free_tfm(priv->tfm);
+ kfree(priv);
+ }
+ return NULL;
+}
+
+static void prism2_wep_deinit(void *priv)
+{
+ struct prism2_wep_data *_priv = priv;
+ if (_priv && _priv->tfm)
+ crypto_free_tfm(_priv->tfm);
+ kfree(priv);
+}
+
+/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
+ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
+ * so the payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct prism2_wep_data *wep = priv;
+ u32 crc, klen, len;
+ u8 key[WEP_KEY_LEN + 3];
+ u8 *pos, *icv;
+ struct scatterlist sg;
+
+ if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
+ skb->len < hdr_len)
+ return -1;
+
+ len = skb->len - hdr_len;
+ pos = skb_push(skb, 4);
+ memmove(pos, pos + 4, hdr_len);
+ pos += hdr_len;
+
+ klen = 3 + wep->key_len;
+
+ wep->iv++;
+
+ /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
+ * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
+ * can be used to speedup attacks, so avoid using them. */
+ if ((wep->iv & 0xff00) == 0xff00) {
+ u8 B = (wep->iv >> 16) & 0xff;
+ if (B >= 3 && B < klen)
+ wep->iv += 0x0100;
+ }
+
+ /* Prepend 24-bit IV to RC4 key and TX frame */
+ *pos++ = key[0] = (wep->iv >> 16) & 0xff;
+ *pos++ = key[1] = (wep->iv >> 8) & 0xff;
+ *pos++ = key[2] = wep->iv & 0xff;
+ *pos++ = wep->key_idx << 6;
+
+ /* Copy rest of the WEP key (the secret part) */
+ memcpy(key + 3, wep->key, wep->key_len);
+
+ /* Append little-endian CRC32 and encrypt it to produce ICV */
+ crc = ~crc32_le(~0, pos, len);
+ icv = skb_put(skb, 4);
+ icv[0] = crc;
+ icv[1] = crc >> 8;
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+
+ crypto_cipher_setkey(wep->tfm, key, klen);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = len + 4;
+ crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
+
+ return 0;
+}
+
+/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
+ * the frame: IV (4 bytes), encrypted payload (including SNAP header),
+ * ICV (4 bytes). len includes both IV and ICV.
+ *
+ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
+ * failure. If frame is OK, IV and ICV will be removed.
+ */
+static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+ struct prism2_wep_data *wep = priv;
+ u32 crc, klen, plen;
+ u8 key[WEP_KEY_LEN + 3];
+ u8 keyidx, *pos, icv[4];
+ struct scatterlist sg;
+
+ if (skb->len < hdr_len + 8)
+ return -1;
+
+ pos = skb->data + hdr_len;
+ key[0] = *pos++;
+ key[1] = *pos++;
+ key[2] = *pos++;
+ keyidx = *pos++ >> 6;
+ if (keyidx != wep->key_idx)
+ return -1;
+
+ klen = 3 + wep->key_len;
+
+ /* Copy rest of the WEP key (the secret part) */
+ memcpy(key + 3, wep->key, wep->key_len);
+
+ /* Apply RC4 to data and compute CRC32 over decrypted data */
+ plen = skb->len - hdr_len - 8;
+
+ crypto_cipher_setkey(wep->tfm, key, klen);
+ sg.page = virt_to_page(pos);
+ sg.offset = offset_in_page(pos);
+ sg.length = plen + 4;
+ crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
+
+ crc = ~crc32_le(~0, pos, plen);
+ icv[0] = crc;
+ icv[1] = crc >> 8;
+ icv[2] = crc >> 16;
+ icv[3] = crc >> 24;
+ if (memcmp(icv, pos + plen, 4) != 0) {
+ /* ICV mismatch - drop frame */
+ return -2;
+ }
+
+ /* Remove IV and ICV */
+ memmove(skb->data + 4, skb->data, hdr_len);
+ skb_pull(skb, 4);
+ skb_trim(skb, skb->len - 4);
+
+ return 0;
+}
+
+static int prism2_wep_set_key(void *key, int len, u8 * seq, void *priv)
+{
+ struct prism2_wep_data *wep = priv;
+
+ if (len < 0 || len > WEP_KEY_LEN)
+ return -1;
+
+ memcpy(wep->key, key, len);
+ wep->key_len = len;
+
+ return 0;
+}
+
+static int prism2_wep_get_key(void *key, int len, u8 * seq, void *priv)
+{
+ struct prism2_wep_data *wep = priv;
+
+ if (len < wep->key_len)
+ return -1;
+
+ memcpy(key, wep->key, wep->key_len);
+
+ return wep->key_len;
+}
+
+static char *prism2_wep_print_stats(char *p, void *priv)
+{
+ struct prism2_wep_data *wep = priv;
+ p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
+ return p;
+}
+
+static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
+ .name = "WEP",
+ .init = prism2_wep_init,
+ .deinit = prism2_wep_deinit,
+ .encrypt_mpdu = prism2_wep_encrypt,
+ .decrypt_mpdu = prism2_wep_decrypt,
+ .encrypt_msdu = NULL,
+ .decrypt_msdu = NULL,
+ .set_key = prism2_wep_set_key,
+ .get_key = prism2_wep_get_key,
+ .print_stats = prism2_wep_print_stats,
+ .extra_prefix_len = 4, /* IV */
+ .extra_postfix_len = 4, /* ICV */
+ .owner = THIS_MODULE,
+};
+
+static int __init ieee80211_crypto_wep_init(void)
+{
+ return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
+}
+
+static void __exit ieee80211_crypto_wep_exit(void)
+{
+ ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
+}
+
+module_init(ieee80211_crypto_wep_init);
+module_exit(ieee80211_crypto_wep_exit);
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
new file mode 100644
index 0000000..03a4734
--- /dev/null
+++ b/net/ieee80211/ieee80211_module.c
@@ -0,0 +1,297 @@
+/*******************************************************************************
+
+ Copyright(c) 2004 Intel Corporation. All rights reserved.
+
+ Portions of this file are based on the WEP enablement code provided by the
+ Host AP project hostap-drivers v0.1.3
+ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ <jkmaline@cc.hut.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+#include <net/arp.h>
+
+#include <net/ieee80211.h>
+
+MODULE_DESCRIPTION("802.11 data/management/control stack");
+MODULE_AUTHOR
+ ("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>");
+MODULE_LICENSE("GPL");
+
+#define DRV_NAME "ieee80211"
+
+static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
+{
+ if (ieee->networks)
+ return 0;
+
+ ieee->networks =
+ kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
+ GFP_KERNEL);
+ if (!ieee->networks) {
+ printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
+ ieee->dev->name);
+ return -ENOMEM;
+ }
+
+ memset(ieee->networks, 0,
+ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
+
+ return 0;
+}
+
+static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
+{
+ if (!ieee->networks)
+ return;
+ kfree(ieee->networks);
+ ieee->networks = NULL;
+}
+
+static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
+{
+ int i;
+
+ INIT_LIST_HEAD(&ieee->network_free_list);
+ INIT_LIST_HEAD(&ieee->network_list);
+ for (i = 0; i < MAX_NETWORK_COUNT; i++)
+ list_add_tail(&ieee->networks[i].list,
+ &ieee->network_free_list);
+}
+
+struct net_device *alloc_ieee80211(int sizeof_priv)
+{
+ struct ieee80211_device *ieee;
+ struct net_device *dev;
+ int err;
+
+ IEEE80211_DEBUG_INFO("Initializing...\n");
+
+ dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
+ if (!dev) {
+ IEEE80211_ERROR("Unable to network device.\n");
+ goto failed;
+ }
+ ieee = netdev_priv(dev);
+ dev->hard_start_xmit = ieee80211_xmit;
+
+ ieee->dev = dev;
+
+ err = ieee80211_networks_allocate(ieee);
+ if (err) {
+ IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
+ goto failed;
+ }
+ ieee80211_networks_initialize(ieee);
+
+ /* Default fragmentation threshold is maximum payload size */
+ ieee->fts = DEFAULT_FTS;
+ ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
+ ieee->open_wep = 1;
+
+ /* Default to enabling full open WEP with host based encrypt/decrypt */
+ ieee->host_encrypt = 1;
+ ieee->host_decrypt = 1;
+ ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
+
+ INIT_LIST_HEAD(&ieee->crypt_deinit_list);
+ init_timer(&ieee->crypt_deinit_timer);
+ ieee->crypt_deinit_timer.data = (unsigned long)ieee;
+ ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
+
+ spin_lock_init(&ieee->lock);
+
+ ieee->wpa_enabled = 0;
+ ieee->tkip_countermeasures = 0;
+ ieee->drop_unencrypted = 0;
+ ieee->privacy_invoked = 0;
+ ieee->ieee802_1x = 1;
+
+ return dev;
+
+ failed:
+ if (dev)
+ free_netdev(dev);
+ return NULL;
+}
+
+void free_ieee80211(struct net_device *dev)
+{
+ struct ieee80211_device *ieee = netdev_priv(dev);
+
+ int i;
+
+ del_timer_sync(&ieee->crypt_deinit_timer);
+ ieee80211_crypt_deinit_entries(ieee, 1);
+
+ for (i = 0; i < WEP_KEYS; i++) {
+ struct ieee80211_crypt_data *crypt = ieee->crypt[i];
+ if (crypt) {
+ if (crypt->ops) {
+ crypt->ops->deinit(crypt->priv);
+ module_put(crypt->ops->owner);
+ }
+ kfree(crypt);
+ ieee->crypt[i] = NULL;
+ }
+ }
+
+ ieee80211_networks_free(ieee);
+ free_netdev(dev);
+}
+
+#ifdef CONFIG_IEEE80211_DEBUG
+
+static int debug = 0;
+u32 ieee80211_debug_level = 0;
+struct proc_dir_entry *ieee80211_proc = NULL;
+
+static int show_debug_level(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
+}
+
+static int store_debug_level(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+{
+ char buf[] = "0x00000000";
+ char *p = (char *)buf;
+ unsigned long val;
+
+ if (count > sizeof(buf) - 1)
+ count = sizeof(buf) - 1;
+
+ if (copy_from_user(buf, buffer, count))
+ return count;
+ buf[count] = 0;
+ /*
+ * what a FPOS... What, sscanf(buf, "%i", &val) would be too
+ * scary?
+ */
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ p++;
+ if (p[0] == 'x' || p[0] == 'X')
+ p++;
+ val = simple_strtoul(p, &p, 16);
+ } else
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ ieee80211_debug_level = val;
+
+ return strlen(buf);
+}
+
+static int __init ieee80211_init(void)
+{
+ struct proc_dir_entry *e;
+
+ ieee80211_debug_level = debug;
+ ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
+ if (ieee80211_proc == NULL) {
+ IEEE80211_ERROR("Unable to create " DRV_NAME
+ " proc directory\n");
+ return -EIO;
+ }
+ e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
+ ieee80211_proc);
+ if (!e) {
+ remove_proc_entry(DRV_NAME, proc_net);
+ ieee80211_proc = NULL;
+ return -EIO;
+ }
+ e->read_proc = show_debug_level;
+ e->write_proc = store_debug_level;
+ e->data = NULL;
+
+ return 0;
+}
+
+static void __exit ieee80211_exit(void)
+{
+ if (ieee80211_proc) {
+ remove_proc_entry("debug_level", ieee80211_proc);
+ remove_proc_entry(DRV_NAME, proc_net);
+ ieee80211_proc = NULL;
+ }
+}
+
+#include <linux/moduleparam.h>
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+
+module_exit(ieee80211_exit);
+module_init(ieee80211_init);
+#endif
+
+const char *escape_essid(const char *essid, u8 essid_len)
+{
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (ieee80211_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else {
+ *d++ = *s++;
+ }
+ }
+ *d = '\0';
+ return escaped;
+}
+
+EXPORT_SYMBOL(alloc_ieee80211);
+EXPORT_SYMBOL(free_ieee80211);
+EXPORT_SYMBOL(escape_essid);
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
new file mode 100644
index 0000000..f7dcd85
--- /dev/null
+++ b/net/ieee80211/ieee80211_rx.c
@@ -0,0 +1,1193 @@
+/*
+ * Original code based Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3 - hostap.o module, common routines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004, Intel 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+
+#include <net/ieee80211.h>
+
+static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+ struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+ skb->dev = ieee->dev;
+ skb->mac.raw = skb->data;
+ skb_pull(skb, ieee80211_get_hdrlen(fc));
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_80211_RAW);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct
+ ieee80211_device
+ *ieee,
+ unsigned int seq,
+ unsigned int frag,
+ u8 * src,
+ u8 * dst)
+{
+ struct ieee80211_frag_entry *entry;
+ int i;
+
+ for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
+ entry = &ieee->frag_cache[i];
+ if (entry->skb != NULL &&
+ time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
+ IEEE80211_DEBUG_FRAG("expiring fragment cache entry "
+ "seq=%u last_frag=%u\n",
+ entry->seq, entry->last_frag);
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+ }
+
+ if (entry->skb != NULL && entry->seq == seq &&
+ (entry->last_frag + 1 == frag || frag == -1) &&
+ memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
+ memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *hdr)
+{
+ struct sk_buff *skb = NULL;
+ u16 sc;
+ unsigned int frag, seq;
+ struct ieee80211_frag_entry *entry;
+
+ sc = le16_to_cpu(hdr->seq_ctl);
+ frag = WLAN_GET_SEQ_FRAG(sc);
+ seq = WLAN_GET_SEQ_SEQ(sc);
+
+ if (frag == 0) {
+ /* Reserve enough space to fit maximum frame length */
+ skb = dev_alloc_skb(ieee->dev->mtu +
+ sizeof(struct ieee80211_hdr) +
+ 8 /* LLC */ +
+ 2 /* alignment */ +
+ 8 /* WEP */ + ETH_ALEN /* WDS */ );
+ if (skb == NULL)
+ return NULL;
+
+ entry = &ieee->frag_cache[ieee->frag_next_idx];
+ ieee->frag_next_idx++;
+ if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)
+ ieee->frag_next_idx = 0;
+
+ if (entry->skb != NULL)
+ dev_kfree_skb_any(entry->skb);
+
+ entry->first_frag_time = jiffies;
+ entry->seq = seq;
+ entry->last_frag = frag;
+ entry->skb = skb;
+ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
+ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
+ } else {
+ /* received a fragment of a frame for which the head fragment
+ * should have already been received */
+ entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,
+ hdr->addr1);
+ if (entry != NULL) {
+ entry->last_frag = frag;
+ skb = entry->skb;
+ }
+ }
+
+ return skb;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *hdr)
+{
+ u16 sc;
+ unsigned int seq;
+ struct ieee80211_frag_entry *entry;
+
+ sc = le16_to_cpu(hdr->seq_ctl);
+ seq = WLAN_GET_SEQ_SEQ(sc);
+
+ entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2,
+ hdr->addr1);
+
+ if (entry == NULL) {
+ IEEE80211_DEBUG_FRAG("could not invalidate fragment cache "
+ "entry (seq=%u)\n", seq);
+ return -1;
+ }
+
+ entry->skb = NULL;
+ return 0;
+}
+
+#ifdef NOT_YET
+/* ieee80211_rx_frame_mgtmt
+ *
+ * Responsible for handling management control frames
+ *
+ * Called by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats, u16 type,
+ u16 stype)
+{
+ if (ieee->iw_mode == IW_MODE_MASTER) {
+ printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
+ ieee->dev->name);
+ return 0;
+/*
+ hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *)
+ skb->data);*/
+ }
+
+ if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
+ if (stype == WLAN_FC_STYPE_BEACON &&
+ ieee->iw_mode == IW_MODE_MASTER) {
+ struct sk_buff *skb2;
+ /* Process beacon frames also in kernel driver to
+ * update STA(AP) table statistics */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2)
+ hostap_rx(skb2->dev, skb2, rx_stats);
+ }
+
+ /* send management frames to the user space daemon for
+ * processing */
+ ieee->apdevstats.rx_packets++;
+ ieee->apdevstats.rx_bytes += skb->len;
+ prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
+ return 0;
+ }
+
+ if (ieee->iw_mode == IW_MODE_MASTER) {
+ if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
+ printk(KERN_DEBUG "%s: unknown management frame "
+ "(type=0x%02x, stype=0x%02x) dropped\n",
+ skb->dev->name, type, stype);
+ return -1;
+ }
+
+ hostap_rx(skb->dev, skb, rx_stats);
+ return 0;
+ }
+
+ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
+ "received in non-Host AP mode\n", skb->dev->name);
+ return -1;
+}
+#endif
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
+/* Called by ieee80211_rx_frame_decrypt */
+static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
+ struct sk_buff *skb)
+{
+ struct net_device *dev = ieee->dev;
+ u16 fc, ethertype;
+ struct ieee80211_hdr *hdr;
+ u8 *pos;
+
+ if (skb->len < 24)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ /* check that the frame is unicast frame to us */
+ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 &&
+ memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
+ /* ToDS frame with own addr BSSID and DA */
+ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS &&
+ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
+ /* FromDS frame with own addr as DA */
+ } else
+ return 0;
+
+ if (skb->len < 24 + 8)
+ return 0;
+
+ /* check for port access entity Ethernet type */
+ pos = skb->data + 24;
+ ethertype = (pos[6] << 8) | pos[7];
+ if (ethertype == ETH_P_PAE)
+ return 1;
+
+ return 0;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+#ifdef CONFIG_IEEE80211_CRYPT_TKIP
+ if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+ "received packet from " MAC_FMT "\n",
+ ieee->dev->name, MAC_ARG(hdr->addr2));
+ }
+ return -1;
+ }
+#endif
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT
+ ") res=%d\n", MAC_ARG(hdr->addr2), res);
+ if (res == -2)
+ IEEE80211_DEBUG_DROP("Decryption failed ICV "
+ "mismatch (key %d)\n",
+ skb->data[hdrlen + 3] >> 6);
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ return -1;
+ }
+
+ return res;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static inline int
+ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
+ struct sk_buff *skb, int keyidx,
+ struct ieee80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
+ " (SA=" MAC_FMT " keyidx=%d)\n",
+ ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* All received frames are sent to this function. @skb contains the frame in
+ * IEEE 802.11 format, i.e., in the format it was sent over air.
+ * This function is called only as a tasklet (software IRQ). */
+int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats)
+{
+ struct net_device *dev = ieee->dev;
+ struct ieee80211_hdr *hdr;
+ size_t hdrlen;
+ u16 fc, type, stype, sc;
+ struct net_device_stats *stats;
+ unsigned int frag;
+ u8 *payload;
+ u16 ethertype;
+#ifdef NOT_YET
+ struct net_device *wds = NULL;
+ struct sk_buff *skb2 = NULL;
+ struct net_device *wds = NULL;
+ int frame_authorized = 0;
+ int from_assoc_ap = 0;
+ void *sta = NULL;
+#endif
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ struct ieee80211_crypt_data *crypt = NULL;
+ int keyidx = 0;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ stats = &ieee->stats;
+
+ if (skb->len < 10) {
+ printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
+ goto rx_dropped;
+ }
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+ sc = le16_to_cpu(hdr->seq_ctl);
+ frag = WLAN_GET_SEQ_FRAG(sc);
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+#ifdef NOT_YET
+#if WIRELESS_EXT > 15
+ /* Put this code here so that we avoid duplicating it in all
+ * Rx paths. - Jean II */
+#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
+ /* If spy monitoring on */
+ if (iface->spy_data.spy_number > 0) {
+ struct iw_quality wstats;
+ wstats.level = rx_stats->signal;
+ wstats.noise = rx_stats->noise;
+ wstats.updated = 6; /* No qual value */
+ /* Update spy records */
+ wireless_spy_update(dev, hdr->addr2, &wstats);
+ }
+#endif /* IW_WIRELESS_SPY */
+#endif /* WIRELESS_EXT > 15 */
+ hostap_update_rx_stats(local->ap, hdr, rx_stats);
+#endif
+
+#if WIRELESS_EXT > 15
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ ieee80211_monitor_rx(ieee, skb, rx_stats);
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ return 1;
+ }
+#endif
+
+ if (ieee->host_decrypt) {
+ int idx = 0;
+ if (skb->len >= hdrlen + 3)
+ idx = skb->data[hdrlen + 3] >> 6;
+ crypt = ieee->crypt[idx];
+#ifdef NOT_YET
+ sta = NULL;
+
+ /* Use station specific key to override default keys if the
+ * receiver address is a unicast address ("individual RA"). If
+ * bcrx_sta_key parameter is set, station specific key is used
+ * even with broad/multicast targets (this is against IEEE
+ * 802.11, but makes it easier to use different keys with
+ * stations that do not support WEP key mapping). */
+
+ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
+ (void)hostap_handle_sta_crypto(local, hdr, &crypt,
+ &sta);
+#endif
+
+ /* allow NULL decrypt to indicate an station specific override
+ * for default encryption */
+ if (crypt && (crypt->ops == NULL ||
+ crypt->ops->decrypt_mpdu == NULL))
+ crypt = NULL;
+
+ if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
+ /* This seems to be triggered by some (multicast?)
+ * frames from other than current BSS, so just drop the
+ * frames silently instead of filling system log with
+ * these reports. */
+ IEEE80211_DEBUG_DROP("Decryption failed (not set)"
+ " (SA=" MAC_FMT ")\n",
+ MAC_ARG(hdr->addr2));
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ goto rx_dropped;
+ }
+ }
+#ifdef NOT_YET
+ if (type != WLAN_FC_TYPE_DATA) {
+ if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
+ fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
+ (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
+ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
+ "from " MAC_FMT "\n", dev->name,
+ MAC_ARG(hdr->addr2));
+ /* TODO: could inform hostapd about this so that it
+ * could send auth failure report */
+ goto rx_dropped;
+ }
+
+ if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
+ goto rx_dropped;
+ else
+ goto rx_exit;
+ }
+#endif
+
+ /* Data frame - extract src/dst addresses */
+ if (skb->len < IEEE80211_3ADDR_LEN)
+ goto rx_dropped;
+
+ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr3, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_TODS:
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ if (skb->len < IEEE80211_4ADDR_LEN)
+ goto rx_dropped;
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr4, ETH_ALEN);
+ break;
+ case 0:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ break;
+ }
+
+#ifdef NOT_YET
+ if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
+ goto rx_dropped;
+ if (wds) {
+ skb->dev = dev = wds;
+ stats = hostap_get_stats(dev);
+ }
+
+ if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
+ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS && ieee->stadev
+ && memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) {
+ /* Frame from BSSID of the AP for which we are a client */
+ skb->dev = dev = ieee->stadev;
+ stats = hostap_get_stats(dev);
+ from_assoc_ap = 1;
+ }
+#endif
+
+ dev->last_rx = jiffies;
+
+#ifdef NOT_YET
+ if ((ieee->iw_mode == IW_MODE_MASTER ||
+ ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
+ switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
+ wds != NULL)) {
+ case AP_RX_CONTINUE_NOT_AUTHORIZED:
+ frame_authorized = 0;
+ break;
+ case AP_RX_CONTINUE:
+ frame_authorized = 1;
+ break;
+ case AP_RX_DROP:
+ goto rx_dropped;
+ case AP_RX_EXIT:
+ goto rx_exit;
+ }
+ }
+#endif
+
+ /* Nullfunc frames may have PS-bit set, so they must be passed to
+ * hostap_handle_sta_rx() before being dropped here. */
+ if (stype != IEEE80211_STYPE_DATA &&
+ stype != IEEE80211_STYPE_DATA_CFACK &&
+ stype != IEEE80211_STYPE_DATA_CFPOLL &&
+ stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
+ if (stype != IEEE80211_STYPE_NULLFUNC)
+ IEEE80211_DEBUG_DROP("RX: dropped data frame "
+ "with no data (type=0x%02x, "
+ "subtype=0x%02x, len=%d)\n",
+ type, stype, skb->len);
+ goto rx_dropped;
+ }
+
+ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
+
+ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* skb: hdr + (possibly fragmented) plaintext payload */
+ // PR: FIXME: hostap has additional conditions in the "if" below:
+ // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+ int flen;
+ struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
+ IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
+
+ if (!frag_skb) {
+ IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG,
+ "Rx cannot get skb from fragment "
+ "cache (morefrag=%d seq=%u frag=%u)\n",
+ (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
+ WLAN_GET_SEQ_SEQ(sc), frag);
+ goto rx_dropped;
+ }
+
+ flen = skb->len;
+ if (frag != 0)
+ flen -= hdrlen;
+
+ if (frag_skb->tail + flen > frag_skb->end) {
+ printk(KERN_WARNING "%s: host decrypted and "
+ "reassembled frame did not fit skb\n",
+ dev->name);
+ ieee80211_frag_cache_invalidate(ieee, hdr);
+ goto rx_dropped;
+ }
+
+ if (frag == 0) {
+ /* copy first fragment (including full headers) into
+ * beginning of the fragment cache skb */
+ memcpy(skb_put(frag_skb, flen), skb->data, flen);
+ } else {
+ /* append frame payload to the end of the fragment
+ * cache skb */
+ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
+ flen);
+ }
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+
+ if (fc & IEEE80211_FCTL_MOREFRAGS) {
+ /* more fragments expected - leave the skb in fragment
+ * cache for now; it will be delivered to upper layers
+ * after all fragments have been received */
+ goto rx_exit;
+ }
+
+ /* this was the last fragment and the frame will be
+ * delivered, so remove skb from fragment cache */
+ skb = frag_skb;
+ hdr = (struct ieee80211_hdr *)skb->data;
+ ieee80211_frag_cache_invalidate(ieee, hdr);
+ }
+
+ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
+ * encrypted/authenticated */
+ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
+ if ( /*ieee->ieee802_1x && */
+ ieee80211_is_eapol_frame(ieee, skb)) {
+ /* pass unencrypted EAPOL frames even if encryption is
+ * configured */
+ } else {
+ IEEE80211_DEBUG_DROP("encryption configured, but RX "
+ "frame not encrypted (SA=" MAC_FMT
+ ")\n", MAC_ARG(hdr->addr2));
+ goto rx_dropped;
+ }
+ }
+
+ if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
+ !ieee80211_is_eapol_frame(ieee, skb)) {
+ IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
+ "frame from " MAC_FMT
+ " (drop_unencrypted=1)\n",
+ MAC_ARG(hdr->addr2));
+ goto rx_dropped;
+ }
+
+ /* skb: hdr + (possible reassembled) full plaintext payload */
+
+ payload = skb->data + hdrlen;
+ ethertype = (payload[6] << 8) | payload[7];
+
+#ifdef NOT_YET
+ /* If IEEE 802.1X is used, check whether the port is authorized to send
+ * the received frame. */
+ if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
+ if (ethertype == ETH_P_PAE) {
+ printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
+ dev->name);
+ if (ieee->hostapd && ieee->apdev) {
+ /* Send IEEE 802.1X frames to the user
+ * space daemon for processing */
+ prism2_rx_80211(ieee->apdev, skb, rx_stats,
+ PRISM2_RX_MGMT);
+ ieee->apdevstats.rx_packets++;
+ ieee->apdevstats.rx_bytes += skb->len;
+ goto rx_exit;
+ }
+ } else if (!frame_authorized) {
+ printk(KERN_DEBUG "%s: dropped frame from "
+ "unauthorized port (IEEE 802.1X): "
+ "ethertype=0x%04x\n", dev->name, ethertype);
+ goto rx_dropped;
+ }
+ }
+#endif
+
+ /* convert hdr + possible LLC headers into Ethernet header */
+ if (skb->len - hdrlen >= 8 &&
+ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
+ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and
+ * replace EtherType */
+ skb_pull(skb, hdrlen + SNAP_SIZE);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ } else {
+ u16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ skb_pull(skb, hdrlen);
+ len = htons(skb->len);
+ memcpy(skb_push(skb, 2), &len, 2);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ }
+
+#ifdef NOT_YET
+ if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
+ /* Non-standard frame: get addr4 from its bogus location after
+ * the payload */
+ memcpy(skb->data + ETH_ALEN,
+ skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+ skb_trim(skb, skb->len - ETH_ALEN);
+ }
+#endif
+
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+#ifdef NOT_YET
+ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
+ if (dst[0] & 0x01) {
+ /* copy multicast frame both to the higher layers and
+ * to the wireless media */
+ ieee->ap->bridged_multicast++;
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ printk(KERN_DEBUG "%s: skb_clone failed for "
+ "multicast frame\n", dev->name);
+ } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
+ /* send frame directly to the associated STA using
+ * wireless media and not passing to higher layers */
+ ieee->ap->bridged_unicast++;
+ skb2 = skb;
+ skb = NULL;
+ }
+ }
+
+ if (skb2 != NULL) {
+ /* send to wireless media */
+ skb2->protocol = __constant_htons(ETH_P_802_3);
+ skb2->mac.raw = skb2->nh.raw = skb2->data;
+ /* skb2->nh.raw = skb2->data + ETH_HLEN; */
+ skb2->dev = dev;
+ dev_queue_xmit(skb2);
+ }
+#endif
+
+ if (skb) {
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
+ netif_rx(skb);
+ }
+
+ rx_exit:
+#ifdef NOT_YET
+ if (sta)
+ hostap_handle_sta_release(sta);
+#endif
+ return 1;
+
+ rx_dropped:
+ stats->rx_dropped++;
+
+ /* Returning 0 indicates to caller that we have not handled the SKB--
+ * so it is still allocated and can be used again by underlying
+ * hardware as a DMA target */
+ return 0;
+}
+
+#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
+
+static inline int ieee80211_is_ofdm_rate(u8 rate)
+{
+ switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
+ case IEEE80211_OFDM_RATE_6MB:
+ case IEEE80211_OFDM_RATE_9MB:
+ case IEEE80211_OFDM_RATE_12MB:
+ case IEEE80211_OFDM_RATE_18MB:
+ case IEEE80211_OFDM_RATE_24MB:
+ case IEEE80211_OFDM_RATE_36MB:
+ case IEEE80211_OFDM_RATE_48MB:
+ case IEEE80211_OFDM_RATE_54MB:
+ return 1;
+ }
+ return 0;
+}
+
+static inline int ieee80211_network_init(struct ieee80211_device *ieee,
+ struct ieee80211_probe_response
+ *beacon,
+ struct ieee80211_network *network,
+ struct ieee80211_rx_stats *stats)
+{
+#ifdef CONFIG_IEEE80211_DEBUG
+ char rates_str[64];
+ char *p;
+#endif
+ struct ieee80211_info_element *info_element;
+ u16 left;
+ u8 i;
+
+ /* Pull out fixed field data */
+ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
+ network->capability = beacon->capability;
+ network->last_scanned = jiffies;
+ network->time_stamp[0] = beacon->time_stamp[0];
+ network->time_stamp[1] = beacon->time_stamp[1];
+ network->beacon_interval = beacon->beacon_interval;
+ /* Where to pull this? beacon->listen_interval; */
+ network->listen_interval = 0x0A;
+ network->rates_len = network->rates_ex_len = 0;
+ network->last_associate = 0;
+ network->ssid_len = 0;
+ network->flags = 0;
+ network->atim_window = 0;
+
+ if (stats->freq == IEEE80211_52GHZ_BAND) {
+ /* for A band (No DS info) */
+ network->channel = stats->received_channel;
+ } else
+ network->flags |= NETWORK_HAS_CCK;
+
+ network->wpa_ie_len = 0;
+ network->rsn_ie_len = 0;
+
+ info_element = &beacon->info_element;
+ left = stats->len - ((void *)info_element - (void *)beacon);
+ while (left >= sizeof(struct ieee80211_info_element_hdr)) {
+ if (sizeof(struct ieee80211_info_element_hdr) +
+ info_element->len > left) {
+ IEEE80211_DEBUG_SCAN
+ ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n",
+ info_element->len +
+ sizeof(struct ieee80211_info_element), left);
+ return 1;
+ }
+
+ switch (info_element->id) {
+ case MFIE_TYPE_SSID:
+ if (ieee80211_is_empty_essid(info_element->data,
+ info_element->len)) {
+ network->flags |= NETWORK_EMPTY_ESSID;
+ break;
+ }
+
+ network->ssid_len = min(info_element->len,
+ (u8) IW_ESSID_MAX_SIZE);
+ memcpy(network->ssid, info_element->data,
+ network->ssid_len);
+ if (network->ssid_len < IW_ESSID_MAX_SIZE)
+ memset(network->ssid + network->ssid_len, 0,
+ IW_ESSID_MAX_SIZE - network->ssid_len);
+
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n",
+ network->ssid, network->ssid_len);
+ break;
+
+ case MFIE_TYPE_RATES:
+#ifdef CONFIG_IEEE80211_DEBUG
+ p = rates_str;
+#endif
+ network->rates_len =
+ min(info_element->len, MAX_RATES_LENGTH);
+ for (i = 0; i < network->rates_len; i++) {
+ network->rates[i] = info_element->data[i];
+#ifdef CONFIG_IEEE80211_DEBUG
+ p += snprintf(p,
+ sizeof(rates_str) - (p -
+ rates_str),
+ "%02X ", network->rates[i]);
+#endif
+ if (ieee80211_is_ofdm_rate
+ (info_element->data[i])) {
+ network->flags |= NETWORK_HAS_OFDM;
+ if (info_element->data[i] &
+ IEEE80211_BASIC_RATE_MASK)
+ network->flags &=
+ ~NETWORK_HAS_CCK;
+ }
+ }
+
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n",
+ rates_str, network->rates_len);
+ break;
+
+ case MFIE_TYPE_RATES_EX:
+#ifdef CONFIG_IEEE80211_DEBUG
+ p = rates_str;
+#endif
+ network->rates_ex_len =
+ min(info_element->len, MAX_RATES_EX_LENGTH);
+ for (i = 0; i < network->rates_ex_len; i++) {
+ network->rates_ex[i] = info_element->data[i];
+#ifdef CONFIG_IEEE80211_DEBUG
+ p += snprintf(p,
+ sizeof(rates_str) - (p -
+ rates_str),
+ "%02X ", network->rates[i]);
+#endif
+ if (ieee80211_is_ofdm_rate
+ (info_element->data[i])) {
+ network->flags |= NETWORK_HAS_OFDM;
+ if (info_element->data[i] &
+ IEEE80211_BASIC_RATE_MASK)
+ network->flags &=
+ ~NETWORK_HAS_CCK;
+ }
+ }
+
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
+ rates_str, network->rates_ex_len);
+ break;
+
+ case MFIE_TYPE_DS_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n",
+ info_element->data[0]);
+ if (stats->freq == IEEE80211_24GHZ_BAND)
+ network->channel = info_element->data[0];
+ break;
+
+ case MFIE_TYPE_FH_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_CF_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_TIM:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_TIM: ignored\n");
+ break;
+
+ case MFIE_TYPE_IBSS_SET:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_CHALLENGE:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n");
+ break;
+
+ case MFIE_TYPE_GENERIC:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n",
+ info_element->len);
+ if (info_element->len >= 4 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x01) {
+ network->wpa_ie_len = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(network->wpa_ie, info_element,
+ network->wpa_ie_len);
+ }
+ break;
+
+ case MFIE_TYPE_RSN:
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n",
+ info_element->len);
+ network->rsn_ie_len = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(network->rsn_ie, info_element,
+ network->rsn_ie_len);
+ break;
+
+ default:
+ IEEE80211_DEBUG_SCAN("unsupported IE %d\n",
+ info_element->id);
+ break;
+ }
+
+ left -= sizeof(struct ieee80211_info_element_hdr) +
+ info_element->len;
+ info_element = (struct ieee80211_info_element *)
+ &info_element->data[info_element->len];
+ }
+
+ network->mode = 0;
+ if (stats->freq == IEEE80211_52GHZ_BAND)
+ network->mode = IEEE_A;
+ else {
+ if (network->flags & NETWORK_HAS_OFDM)
+ network->mode |= IEEE_G;
+ if (network->flags & NETWORK_HAS_CCK)
+ network->mode |= IEEE_B;
+ }
+
+ if (network->mode == 0) {
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+ "network.\n",
+ escape_essid(network->ssid,
+ network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 1;
+ }
+
+ if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
+ network->flags |= NETWORK_EMPTY_ESSID;
+
+ memcpy(&network->stats, stats, sizeof(network->stats));
+
+ return 0;
+}
+
+static inline int is_same_network(struct ieee80211_network *src,
+ struct ieee80211_network *dst)
+{
+ /* A network is only a duplicate if the channel, BSSID, and ESSID
+ * all match. We treat all <hidden> with the same BSSID and channel
+ * as one network */
+ return ((src->ssid_len == dst->ssid_len) &&
+ (src->channel == dst->channel) &&
+ !memcmp(src->bssid, dst->bssid, ETH_ALEN) &&
+ !memcmp(src->ssid, dst->ssid, src->ssid_len));
+}
+
+static inline void update_network(struct ieee80211_network *dst,
+ struct ieee80211_network *src)
+{
+ memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
+ dst->capability = src->capability;
+ memcpy(dst->rates, src->rates, src->rates_len);
+ dst->rates_len = src->rates_len;
+ memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
+ dst->rates_ex_len = src->rates_ex_len;
+
+ dst->mode = src->mode;
+ dst->flags = src->flags;
+ dst->time_stamp[0] = src->time_stamp[0];
+ dst->time_stamp[1] = src->time_stamp[1];
+
+ dst->beacon_interval = src->beacon_interval;
+ dst->listen_interval = src->listen_interval;
+ dst->atim_window = src->atim_window;
+
+ memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
+ dst->wpa_ie_len = src->wpa_ie_len;
+ memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
+ dst->rsn_ie_len = src->rsn_ie_len;
+
+ dst->last_scanned = jiffies;
+ /* dst->last_associate is not overwritten */
+}
+
+static inline void ieee80211_process_probe_response(struct ieee80211_device
+ *ieee,
+ struct
+ ieee80211_probe_response
+ *beacon,
+ struct ieee80211_rx_stats
+ *stats)
+{
+ struct ieee80211_network network;
+ struct ieee80211_network *target;
+ struct ieee80211_network *oldest = NULL;
+#ifdef CONFIG_IEEE80211_DEBUG
+ struct ieee80211_info_element *info_element = &beacon->info_element;
+#endif
+ unsigned long flags;
+
+ IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT
+ "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ escape_essid(info_element->data,
+ info_element->len),
+ MAC_ARG(beacon->header.addr3),
+ (beacon->capability & (1 << 0xf)) ? '1' : '0',
+ (beacon->capability & (1 << 0xe)) ? '1' : '0',
+ (beacon->capability & (1 << 0xd)) ? '1' : '0',
+ (beacon->capability & (1 << 0xc)) ? '1' : '0',
+ (beacon->capability & (1 << 0xb)) ? '1' : '0',
+ (beacon->capability & (1 << 0xa)) ? '1' : '0',
+ (beacon->capability & (1 << 0x9)) ? '1' : '0',
+ (beacon->capability & (1 << 0x8)) ? '1' : '0',
+ (beacon->capability & (1 << 0x7)) ? '1' : '0',
+ (beacon->capability & (1 << 0x6)) ? '1' : '0',
+ (beacon->capability & (1 << 0x5)) ? '1' : '0',
+ (beacon->capability & (1 << 0x4)) ? '1' : '0',
+ (beacon->capability & (1 << 0x3)) ? '1' : '0',
+ (beacon->capability & (1 << 0x2)) ? '1' : '0',
+ (beacon->capability & (1 << 0x1)) ? '1' : '0',
+ (beacon->capability & (1 << 0x0)) ? '1' : '0');
+
+ if (ieee80211_network_init(ieee, beacon, &network, stats)) {
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+ escape_essid(info_element->data,
+ info_element->len),
+ MAC_ARG(beacon->header.addr3),
+ WLAN_FC_GET_STYPE(beacon->header.
+ frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP ?
+ "PROBE RESPONSE" : "BEACON");
+ return;
+ }
+
+ /* The network parsed correctly -- so now we scan our known networks
+ * to see if we can find it in our list.
+ *
+ * NOTE: This search is definitely not optimized. Once its doing
+ * the "right thing" we'll optimize it for efficiency if
+ * necessary */
+
+ /* Search for this entry in the list and update it if it is
+ * already there. */
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ list_for_each_entry(target, &ieee->network_list, list) {
+ if (is_same_network(target, &network))
+ break;
+
+ if ((oldest == NULL) ||
+ (target->last_scanned < oldest->last_scanned))
+ oldest = target;
+ }
+
+ /* If we didn't find a match, then get a new network slot to initialize
+ * with this beacon's information */
+ if (&target->list == &ieee->network_list) {
+ if (list_empty(&ieee->network_free_list)) {
+ /* If there are no more slots, expire the oldest */
+ list_del(&oldest->list);
+ target = oldest;
+ IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+ "network list.\n",
+ escape_essid(target->ssid,
+ target->ssid_len),
+ MAC_ARG(target->bssid));
+ } else {
+ /* Otherwise just pull from the free list */
+ target = list_entry(ieee->network_free_list.next,
+ struct ieee80211_network, list);
+ list_del(ieee->network_free_list.next);
+ }
+
+#ifdef CONFIG_IEEE80211_DEBUG
+ IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+ escape_essid(network.ssid,
+ network.ssid_len),
+ MAC_ARG(network.bssid),
+ WLAN_FC_GET_STYPE(beacon->header.
+ frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP ?
+ "PROBE RESPONSE" : "BEACON");
+#endif
+ memcpy(target, &network, sizeof(*target));
+ list_add_tail(&target->list, &ieee->network_list);
+ } else {
+ IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+ escape_essid(target->ssid,
+ target->ssid_len),
+ MAC_ARG(target->bssid),
+ WLAN_FC_GET_STYPE(beacon->header.
+ frame_ctl) ==
+ IEEE80211_STYPE_PROBE_RESP ?
+ "PROBE RESPONSE" : "BEACON");
+ update_network(target, &network);
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+}
+
+void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *header,
+ struct ieee80211_rx_stats *stats)
+{
+ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+ case IEEE80211_STYPE_ASSOC_RESP:
+ IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ break;
+
+ case IEEE80211_STYPE_REASSOC_RESP:
+ IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ break;
+
+ case IEEE80211_STYPE_PROBE_RESP:
+ IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ IEEE80211_DEBUG_SCAN("Probe response\n");
+ ieee80211_process_probe_response(ieee,
+ (struct
+ ieee80211_probe_response *)
+ header, stats);
+ break;
+
+ case IEEE80211_STYPE_BEACON:
+ IEEE80211_DEBUG_MGMT("received BEACON (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ IEEE80211_DEBUG_SCAN("Beacon\n");
+ ieee80211_process_probe_response(ieee,
+ (struct
+ ieee80211_probe_response *)
+ header, stats);
+ break;
+
+ default:
+ IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ IEEE80211_WARNING("%s: Unknown management packet: %d\n",
+ ieee->dev->name,
+ WLAN_FC_GET_STYPE(header->frame_ctl));
+ break;
+ }
+}
+
+EXPORT_SYMBOL(ieee80211_rx_mgt);
+EXPORT_SYMBOL(ieee80211_rx);
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
new file mode 100644
index 0000000..c9aaff3
--- /dev/null
+++ b/net/ieee80211/ieee80211_tx.c
@@ -0,0 +1,428 @@
+/******************************************************************************
+
+ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+#include <linux/compiler.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+
+#include <net/ieee80211.h>
+
+/*
+
+802.11 Data Frame
+
+ ,-------------------------------------------------------------------.
+Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
+ |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
+ | | tion | (BSSID) | | | ence | data | |
+ `--------------------------------------------------| |------'
+Total: 28 non-data bytes `----.----'
+ |
+ .- 'Frame data' expands to <---------------------------'
+ |
+ V
+ ,---------------------------------------------------.
+Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
+ |------|------|---------|----------|------|---------|
+Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
+ | DSAP | SSAP | | | | Packet |
+ | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
+ `-----------------------------------------| |
+Total: 8 non-data bytes `----.----'
+ |
+ .- 'IP Packet' expands, if WEP enabled, to <--'
+ |
+ V
+ ,-----------------------.
+Bytes | 4 | 0-2296 | 4 |
+ |-----|-----------|-----|
+Desc. | IV | Encrypted | ICV |
+ | | IP Packet | |
+ `-----------------------'
+Total: 8 non-data bytes
+
+802.3 Ethernet Data Frame
+
+ ,-----------------------------------------.
+Bytes | 6 | 6 | 2 | Variable | 4 |
+ |-------|-------|------|-----------|------|
+Desc. | Dest. | Source| Type | IP Packet | fcs |
+ | MAC | MAC | | | |
+ `-----------------------------------------'
+Total: 18 non-data bytes
+
+In the event that fragmentation is required, the incoming payload is split into
+N parts of size ieee->fts. The first fragment contains the SNAP header and the
+remaining packets are just data.
+
+If encryption is enabled, each fragment payload size is reduced by enough space
+to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
+So if you have 1500 bytes of payload with ieee->fts set to 500 without
+encryption it will take 3 frames. With WEP it will take 4 frames as the
+payload of each frame is reduced to 492 bytes.
+
+* SKB visualization
+*
+* ,- skb->data
+* |
+* | ETHERNET HEADER ,-<-- PAYLOAD
+* | | 14 bytes from skb->data
+* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
+* | | | |
+* |,-Dest.--. ,--Src.---. | | |
+* | 6 bytes| | 6 bytes | | | |
+* v | | | | | |
+* 0 | v 1 | v | v 2
+* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+* ^ | ^ | ^ |
+* | | | | | |
+* | | | | `T' <---- 2 bytes for Type
+* | | | |
+* | | '---SNAP--' <-------- 6 bytes for SNAP
+* | |
+* `-IV--' <-------------------- 4 bytes for IV (WEP)
+*
+* SNAP HEADER
+*
+*/
+
+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+
+static inline int ieee80211_put_snap(u8 * data, u16 h_proto)
+{
+ struct ieee80211_snap_hdr *snap;
+ u8 *oui;
+
+ snap = (struct ieee80211_snap_hdr *)data;
+ snap->dsap = 0xaa;
+ snap->ssap = 0xaa;
+ snap->ctrl = 0x03;
+
+ if (h_proto == 0x8137 || h_proto == 0x80f3)
+ oui = P802_1H_OUI;
+ else
+ oui = RFC1042_OUI;
+ snap->oui[0] = oui[0];
+ snap->oui[1] = oui[1];
+ snap->oui[2] = oui[2];
+
+ *(u16 *) (data + SNAP_SIZE) = htons(h_proto);
+
+ return SNAP_SIZE + sizeof(u16);
+}
+
+static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
+ struct sk_buff *frag, int hdr_len)
+{
+ struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
+ int res;
+
+#ifdef CONFIG_IEEE80211_CRYPT_TKIP
+ struct ieee80211_hdr *header;
+
+ if (ieee->tkip_countermeasures &&
+ crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
+ header = (struct ieee80211_hdr *)frag->data;
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+ "TX packet to " MAC_FMT "\n",
+ ieee->dev->name, MAC_ARG(header->addr1));
+ }
+ return -1;
+ }
+#endif
+ /* To encrypt, frame format is:
+ * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
+
+ // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption.
+ /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
+ * call both MSDU and MPDU encryption functions from here. */
+ atomic_inc(&crypt->refcnt);
+ res = 0;
+ if (crypt->ops->encrypt_msdu)
+ res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv);
+ if (res == 0 && crypt->ops->encrypt_mpdu)
+ res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
+
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
+ ieee->dev->name, frag->len);
+ ieee->ieee_stats.tx_discards++;
+ return -1;
+ }
+
+ return 0;
+}
+
+void ieee80211_txb_free(struct ieee80211_txb *txb)
+{
+ int i;
+ if (unlikely(!txb))
+ return;
+ for (i = 0; i < txb->nr_frags; i++)
+ if (txb->fragments[i])
+ dev_kfree_skb_any(txb->fragments[i]);
+ kfree(txb);
+}
+
+static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
+ int gfp_mask)
+{
+ struct ieee80211_txb *txb;
+ int i;
+ txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
+ gfp_mask);
+ if (!txb)
+ return NULL;
+
+ memset(txb, 0, sizeof(struct ieee80211_txb));
+ txb->nr_frags = nr_frags;
+ txb->frag_size = txb_size;
+
+ for (i = 0; i < nr_frags; i++) {
+ txb->fragments[i] = dev_alloc_skb(txb_size);
+ if (unlikely(!txb->fragments[i])) {
+ i--;
+ break;
+ }
+ }
+ if (unlikely(i != nr_frags)) {
+ while (i >= 0)
+ dev_kfree_skb_any(txb->fragments[i--]);
+ kfree(txb);
+ return NULL;
+ }
+ return txb;
+}
+
+/* SKBs are added to the ieee->tx_queue. */
+int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_device *ieee = netdev_priv(dev);
+ struct ieee80211_txb *txb = NULL;
+ struct ieee80211_hdr *frag_hdr;
+ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
+ unsigned long flags;
+ struct net_device_stats *stats = &ieee->stats;
+ int ether_type, encrypt;
+ int bytes, fc, hdr_len;
+ struct sk_buff *skb_frag;
+ struct ieee80211_hdr header = { /* Ensure zero initialized */
+ .duration_id = 0,
+ .seq_ctl = 0
+ };
+ u8 dest[ETH_ALEN], src[ETH_ALEN];
+
+ struct ieee80211_crypt_data *crypt;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ /* If there is no driver handler to take the TXB, dont' bother
+ * creating it... */
+ if (!ieee->hard_start_xmit) {
+ printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
+ goto success;
+ }
+
+ if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
+ printk(KERN_WARNING "%s: skb too small (%d).\n",
+ ieee->dev->name, skb->len);
+ goto success;
+ }
+
+ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
+
+ crypt = ieee->crypt[ieee->tx_keyidx];
+
+ encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
+ ieee->host_encrypt && crypt && crypt->ops;
+
+ if (!encrypt && ieee->ieee802_1x &&
+ ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
+ stats->tx_dropped++;
+ goto success;
+ }
+
+ /* Save source and destination addresses */
+ memcpy(&dest, skb->data, ETH_ALEN);
+ memcpy(&src, skb->data + ETH_ALEN, ETH_ALEN);
+
+ /* Advance the SKB to the start of the payload */
+ skb_pull(skb, sizeof(struct ethhdr));
+
+ /* Determine total amount of storage required for TXB packets */
+ bytes = skb->len + SNAP_SIZE + sizeof(u16);
+
+ if (encrypt)
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
+ IEEE80211_FCTL_PROTECTED;
+ else
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+
+ if (ieee->iw_mode == IW_MODE_INFRA) {
+ fc |= IEEE80211_FCTL_TODS;
+ /* To DS: Addr1 = BSSID, Addr2 = SA,
+ Addr3 = DA */
+ memcpy(&header.addr1, ieee->bssid, ETH_ALEN);
+ memcpy(&header.addr2, &src, ETH_ALEN);
+ memcpy(&header.addr3, &dest, ETH_ALEN);
+ } else if (ieee->iw_mode == IW_MODE_ADHOC) {
+ /* not From/To DS: Addr1 = DA, Addr2 = SA,
+ Addr3 = BSSID */
+ memcpy(&header.addr1, dest, ETH_ALEN);
+ memcpy(&header.addr2, src, ETH_ALEN);
+ memcpy(&header.addr3, ieee->bssid, ETH_ALEN);
+ }
+ header.frame_ctl = cpu_to_le16(fc);
+ hdr_len = IEEE80211_3ADDR_LEN;
+
+ /* Determine fragmentation size based on destination (multicast
+ * and broadcast are not fragmented) */
+ if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest))
+ frag_size = MAX_FRAG_THRESHOLD;
+ else
+ frag_size = ieee->fts;
+
+ /* Determine amount of payload per fragment. Regardless of if
+ * this stack is providing the full 802.11 header, one will
+ * eventually be affixed to this fragment -- so we must account for
+ * it when determining the amount of payload space. */
+ bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN;
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ bytes_per_frag -= IEEE80211_FCS_LEN;
+
+ /* Each fragment may need to have room for encryptiong pre/postfix */
+ if (encrypt)
+ bytes_per_frag -= crypt->ops->extra_prefix_len +
+ crypt->ops->extra_postfix_len;
+
+ /* Number of fragments is the total bytes_per_frag /
+ * payload_per_fragment */
+ nr_frags = bytes / bytes_per_frag;
+ bytes_last_frag = bytes % bytes_per_frag;
+ if (bytes_last_frag)
+ nr_frags++;
+ else
+ bytes_last_frag = bytes_per_frag;
+
+ /* When we allocate the TXB we allocate enough space for the reserve
+ * and full fragment bytes (bytes_per_frag doesn't include prefix,
+ * postfix, header, FCS, etc.) */
+ txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
+ if (unlikely(!txb)) {
+ printk(KERN_WARNING "%s: Could not allocate TXB\n",
+ ieee->dev->name);
+ goto failed;
+ }
+ txb->encrypted = encrypt;
+ txb->payload_size = bytes;
+
+ for (i = 0; i < nr_frags; i++) {
+ skb_frag = txb->fragments[i];
+
+ if (encrypt)
+ skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
+
+ frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
+ memcpy(frag_hdr, &header, hdr_len);
+
+ /* If this is not the last fragment, then add the MOREFRAGS
+ * bit to the frame control */
+ if (i != nr_frags - 1) {
+ frag_hdr->frame_ctl =
+ cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
+ bytes = bytes_per_frag;
+ } else {
+ /* The last fragment takes the remaining length */
+ bytes = bytes_last_frag;
+ }
+
+ /* Put a SNAP header on the first fragment */
+ if (i == 0) {
+ ieee80211_put_snap(skb_put
+ (skb_frag, SNAP_SIZE + sizeof(u16)),
+ ether_type);
+ bytes -= SNAP_SIZE + sizeof(u16);
+ }
+
+ memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
+
+ /* Advance the SKB... */
+ skb_pull(skb, bytes);
+
+ /* Encryption routine will move the header forward in order
+ * to insert the IV between the header and the payload */
+ if (encrypt)
+ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ skb_put(skb_frag, 4);
+ }
+
+ success:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+ dev_kfree_skb_any(skb);
+
+ if (txb) {
+ if ((*ieee->hard_start_xmit) (txb, dev) == 0) {
+ stats->tx_packets++;
+ stats->tx_bytes += txb->payload_size;
+ return 0;
+ }
+ ieee80211_txb_free(txb);
+ }
+
+ return 0;
+
+ failed:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ netif_stop_queue(dev);
+ stats->tx_errors++;
+ return 1;
+
+}
+
+EXPORT_SYMBOL(ieee80211_txb_free);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
new file mode 100644
index 0000000..94882f3
--- /dev/null
+++ b/net/ieee80211/ieee80211_wx.c
@@ -0,0 +1,468 @@
+/******************************************************************************
+
+ Copyright(c) 2004 Intel Corporation. All rights reserved.
+
+ Portions of this file are based on the WEP enablement code provided by the
+ Host AP project hostap-drivers v0.1.3
+ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ <jkmaline@cc.hut.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+#include <net/ieee80211.h>
+#include <linux/wireless.h>
+
+static const char *ieee80211_modes[] = {
+ "?", "a", "b", "ab", "g", "ag", "bg", "abg"
+};
+
+#define MAX_CUSTOM_LEN 64
+static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
+ char *start, char *stop,
+ struct ieee80211_network *network)
+{
+ char custom[MAX_CUSTOM_LEN];
+ char *p;
+ struct iw_event iwe;
+ int i, j;
+ u8 max_rate, rate;
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
+
+ /* Remaining entries will be displayed in the order we provide them */
+
+ /* Add the ESSID */
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ if (network->flags & NETWORK_EMPTY_ESSID) {
+ iwe.u.data.length = sizeof("<hidden>");
+ start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
+ } else {
+ iwe.u.data.length = min(network->ssid_len, (u8) 32);
+ start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
+ }
+
+ /* Add the protocol name */
+ iwe.cmd = SIOCGIWNAME;
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
+ ieee80211_modes[network->mode]);
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+ if (network->capability & WLAN_CAPABILITY_ESS)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
+ }
+
+ /* Add frequency/channel */
+ iwe.cmd = SIOCGIWFREQ;
+/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
+ iwe.u.freq.e = 3; */
+ iwe.u.freq.m = network->channel;
+ iwe.u.freq.e = 0;
+ iwe.u.freq.i = 0;
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (network->capability & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
+
+ /* Add basic and extended rates */
+ max_rate = 0;
+ p = custom;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+ for (i = 0, j = 0; i < network->rates_len;) {
+ if (j < network->rates_ex_len &&
+ ((network->rates_ex[j] & 0x7F) <
+ (network->rates[i] & 0x7F)))
+ rate = network->rates_ex[j++] & 0x7F;
+ else
+ rate = network->rates[i++] & 0x7F;
+ if (rate > max_rate)
+ max_rate = rate;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+ }
+ for (; j < network->rates_ex_len; j++) {
+ rate = network->rates_ex[j] & 0x7F;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+ if (rate > max_rate)
+ max_rate = rate;
+ }
+
+ iwe.cmd = SIOCGIWRATE;
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = max_rate * 500000;
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
+
+ iwe.cmd = IWEVCUSTOM;
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(start, stop, &iwe, custom);
+
+ /* Add quality statistics */
+ /* TODO: Fix these values... */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = network->stats.signal;
+ iwe.u.qual.level = network->stats.rssi;
+ iwe.u.qual.noise = network->stats.noise;
+ iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
+ if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
+ iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
+ if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
+ iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
+ if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
+ iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
+
+ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
+
+ iwe.cmd = IWEVCUSTOM;
+ p = custom;
+
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(start, stop, &iwe, custom);
+
+ if (ieee->wpa_enabled && network->wpa_ie_len) {
+ char buf[MAX_WPA_IE_LEN * 2 + 30];
+
+ u8 *p = buf;
+ p += sprintf(p, "wpa_ie=");
+ for (i = 0; i < network->wpa_ie_len; i++) {
+ p += sprintf(p, "%02x", network->wpa_ie[i]);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ iwe.u.data.length = strlen(buf);
+ start = iwe_stream_add_point(start, stop, &iwe, buf);
+ }
+
+ if (ieee->wpa_enabled && network->rsn_ie_len) {
+ char buf[MAX_WPA_IE_LEN * 2 + 30];
+
+ u8 *p = buf;
+ p += sprintf(p, "rsn_ie=");
+ for (i = 0; i < network->rsn_ie_len; i++) {
+ p += sprintf(p, "%02x", network->rsn_ie[i]);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ iwe.u.data.length = strlen(buf);
+ start = iwe_stream_add_point(start, stop, &iwe, buf);
+ }
+
+ /* Add EXTRA: Age to display seconds since last beacon/probe response
+ * for given network. */
+ iwe.cmd = IWEVCUSTOM;
+ p = custom;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ " Last beacon: %lums ago",
+ (jiffies - network->last_scanned) / (HZ / 100));
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(start, stop, &iwe, custom);
+
+ return start;
+}
+
+int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_network *network;
+ unsigned long flags;
+
+ char *ev = extra;
+ char *stop = ev + IW_SCAN_MAX_DATA;
+ int i = 0;
+
+ IEEE80211_DEBUG_WX("Getting scan\n");
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ list_for_each_entry(network, &ieee->network_list, list) {
+ i++;
+ if (ieee->scan_age == 0 ||
+ time_after(network->last_scanned + ieee->scan_age, jiffies))
+ ev = ipw2100_translate_scan(ieee, ev, stop, network);
+ else
+ IEEE80211_DEBUG_SCAN("Not showing network '%s ("
+ MAC_FMT ")' due to age (%lums).\n",
+ escape_essid(network->ssid,
+ network->ssid_len),
+ MAC_ARG(network->bssid),
+ (jiffies -
+ network->last_scanned) / (HZ /
+ 100));
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+ wrqu->data.length = ev - extra;
+ wrqu->data.flags = 0;
+
+ IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
+
+ return 0;
+}
+
+int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ struct iw_point *erq = &(wrqu->encoding);
+ struct net_device *dev = ieee->dev;
+ struct ieee80211_security sec = {
+ .flags = 0
+ };
+ int i, key, key_provided, len;
+ struct ieee80211_crypt_data **crypt;
+
+ IEEE80211_DEBUG_WX("SET_ENCODE\n");
+
+ key = erq->flags & IW_ENCODE_INDEX;
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ key_provided = 1;
+ } else {
+ key_provided = 0;
+ key = ieee->tx_keyidx;
+ }
+
+ IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
+ "provided" : "default");
+
+ crypt = &ieee->crypt[key];
+
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ if (key_provided && *crypt) {
+ IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
+ key);
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
+ } else
+ IEEE80211_DEBUG_WX("Disabling encryption.\n");
+
+ /* Check all the keys to see if any are still configured,
+ * and if no key index was provided, de-init them all */
+ for (i = 0; i < WEP_KEYS; i++) {
+ if (ieee->crypt[i] != NULL) {
+ if (key_provided)
+ break;
+ ieee80211_crypt_delayed_deinit(ieee,
+ &ieee->crypt[i]);
+ }
+ }
+
+ if (i == WEP_KEYS) {
+ sec.enabled = 0;
+ sec.level = SEC_LEVEL_0;
+ sec.flags |= SEC_ENABLED | SEC_LEVEL;
+ }
+
+ goto done;
+ }
+
+ sec.enabled = 1;
+ sec.flags |= SEC_ENABLED;
+
+ if (*crypt != NULL && (*crypt)->ops != NULL &&
+ strcmp((*crypt)->ops->name, "WEP") != 0) {
+ /* changing to use WEP; deinit previously used algorithm
+ * on this key */
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
+ }
+
+ if (*crypt == NULL) {
+ struct ieee80211_crypt_data *new_crypt;
+
+ /* take WEP into use */
+ new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
+ GFP_KERNEL);
+ if (new_crypt == NULL)
+ return -ENOMEM;
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
+ new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+ if (!new_crypt->ops) {
+ request_module("ieee80211_crypt_wep");
+ new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+ }
+
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+ new_crypt->priv = new_crypt->ops->init(key);
+
+ if (!new_crypt->ops || !new_crypt->priv) {
+ kfree(new_crypt);
+ new_crypt = NULL;
+
+ printk(KERN_WARNING "%s: could not initialize WEP: "
+ "load module ieee80211_crypt_wep\n", dev->name);
+ return -EOPNOTSUPP;
+ }
+ *crypt = new_crypt;
+ }
+
+ /* If a new key was provided, set it up */
+ if (erq->length > 0) {
+ len = erq->length <= 5 ? 5 : 13;
+ memcpy(sec.keys[key], keybuf, erq->length);
+ if (len > erq->length)
+ memset(sec.keys[key] + erq->length, 0,
+ len - erq->length);
+ IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
+ key, escape_essid(sec.keys[key], len),
+ erq->length, len);
+ sec.key_sizes[key] = len;
+ (*crypt)->ops->set_key(sec.keys[key], len, NULL,
+ (*crypt)->priv);
+ sec.flags |= (1 << key);
+ /* This ensures a key will be activated if no key is
+ * explicitely set */
+ if (key == sec.active_key)
+ sec.flags |= SEC_ACTIVE_KEY;
+ } else {
+ len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
+ NULL, (*crypt)->priv);
+ if (len == 0) {
+ /* Set a default key of all 0 */
+ IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
+ key);
+ memset(sec.keys[key], 0, 13);
+ (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
+ (*crypt)->priv);
+ sec.key_sizes[key] = 13;
+ sec.flags |= (1 << key);
+ }
+
+ /* No key data - just set the default TX key index */
+ if (key_provided) {
+ IEEE80211_DEBUG_WX
+ ("Setting key %d to default Tx key.\n", key);
+ ieee->tx_keyidx = key;
+ sec.active_key = key;
+ sec.flags |= SEC_ACTIVE_KEY;
+ }
+ }
+
+ done:
+ ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
+ sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
+ sec.flags |= SEC_AUTH_MODE;
+ IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
+ "OPEN" : "SHARED KEY");
+
+ /* For now we just support WEP, so only set that security level...
+ * TODO: When WPA is added this is one place that needs to change */
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
+
+ if (ieee->set_security)
+ ieee->set_security(dev, &sec);
+
+ /* Do not reset port if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. If your hardware requires a reset after WEP
+ * configuration (for example... Prism2), implement the reset_port in
+ * the callbacks structures used to initialize the 802.11 stack. */
+ if (ieee->reset_on_keychange &&
+ ieee->iw_mode != IW_MODE_INFRA &&
+ ieee->reset_port && ieee->reset_port(dev)) {
+ printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ struct iw_point *erq = &(wrqu->encoding);
+ int len, key;
+ struct ieee80211_crypt_data *crypt;
+
+ IEEE80211_DEBUG_WX("GET_ENCODE\n");
+
+ key = erq->flags & IW_ENCODE_INDEX;
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ } else
+ key = ieee->tx_keyidx;
+
+ crypt = ieee->crypt[key];
+ erq->flags = key + 1;
+
+ if (crypt == NULL || crypt->ops == NULL) {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ return 0;
+ }
+
+ if (strcmp(crypt->ops->name, "WEP") != 0) {
+ /* only WEP is supported with wireless extensions, so just
+ * report that encryption is used */
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_ENABLED;
+ return 0;
+ }
+
+ len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
+ erq->length = (len >= 0 ? len : 0);
+
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ if (ieee->open_wep)
+ erq->flags |= IW_ENCODE_OPEN;
+ else
+ erq->flags |= IW_ENCODE_RESTRICTED;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(ieee80211_wx_get_scan);
+EXPORT_SYMBOL(ieee80211_wx_set_encode);
+EXPORT_SYMBOL(ieee80211_wx_get_encode);
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 514c85b..035ad2c 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -263,10 +263,8 @@
error:
if (ahp) {
- if (ahp->work_icv)
- kfree(ahp->work_icv);
- if (ahp->tfm)
- crypto_free_tfm(ahp->tfm);
+ kfree(ahp->work_icv);
+ crypto_free_tfm(ahp->tfm);
kfree(ahp);
}
return -EINVAL;
@@ -279,14 +277,10 @@
if (!ahp)
return;
- if (ahp->work_icv) {
- kfree(ahp->work_icv);
- ahp->work_icv = NULL;
- }
- if (ahp->tfm) {
- crypto_free_tfm(ahp->tfm);
- ahp->tfm = NULL;
- }
+ kfree(ahp->work_icv);
+ ahp->work_icv = NULL;
+ crypto_free_tfm(ahp->tfm);
+ ahp->tfm = NULL;
kfree(ahp);
}
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index b31ffc5..1b5a09d 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -343,22 +343,14 @@
if (!esp)
return;
- if (esp->conf.tfm) {
- crypto_free_tfm(esp->conf.tfm);
- esp->conf.tfm = NULL;
- }
- if (esp->conf.ivec) {
- kfree(esp->conf.ivec);
- esp->conf.ivec = NULL;
- }
- if (esp->auth.tfm) {
- crypto_free_tfm(esp->auth.tfm);
- esp->auth.tfm = NULL;
- }
- if (esp->auth.work_icv) {
- kfree(esp->auth.work_icv);
- esp->auth.work_icv = NULL;
- }
+ crypto_free_tfm(esp->conf.tfm);
+ esp->conf.tfm = NULL;
+ kfree(esp->conf.ivec);
+ esp->conf.ivec = NULL;
+ crypto_free_tfm(esp->auth.tfm);
+ esp->auth.tfm = NULL;
+ kfree(esp->auth.work_icv);
+ esp->auth.work_icv = NULL;
kfree(esp);
}
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 9e6e683..e7d26d9 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -457,7 +457,7 @@
if (pskb_pull(skb, ihl) == NULL)
goto err;
- if (pskb_trim(skb, end-offset))
+ if (pskb_trim_rcsum(skb, end-offset))
goto err;
/* Find out which fragments are in front and at the back of us
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index dcb7ee6..fc718df 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -345,8 +345,7 @@
for_each_cpu(cpu) {
struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu);
- if (tfm)
- crypto_free_tfm(tfm);
+ crypto_free_tfm(tfm);
}
free_percpu(tfms);
}
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 63e1066..953129d 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -54,6 +54,7 @@
#include <linux/major.h>
#include <linux/root_dev.h>
#include <linux/delay.h>
+#include <linux/nfs_fs.h>
#include <net/arp.h>
#include <net/ip.h>
#include <net/ipconfig.h>
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index e046f55..30aa8e2 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -34,6 +34,7 @@
config IP_NF_CONNTRACK_MARK
bool 'Connection mark tracking support'
+ depends on IP_NF_CONNTRACK
help
This option enables support for connection marks, used by the
`CONNMARK' target and `connmark' match. Similar to the mark value
@@ -85,6 +86,25 @@
To compile it as a module, choose M here. If unsure, say Y.
+config IP_NF_NETBIOS_NS
+ tristate "NetBIOS name service protocol support (EXPERIMENTAL)"
+ depends on IP_NF_CONNTRACK && EXPERIMENTAL
+ help
+ NetBIOS name service requests are sent as broadcast messages from an
+ unprivileged port and responded to with unicast messages to the
+ same port. This make them hard to firewall properly because connection
+ tracking doesn't deal with broadcasts. This helper tracks locally
+ originating NetBIOS name service requests and the corresponding
+ responses. It relies on correct IP address configuration, specifically
+ netmask and broadcast address. When properly configured, the output
+ of "ip address show" should look similar to this:
+
+ $ ip -4 address show eth0
+ 4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
+ inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_TFTP
tristate "TFTP protocol support"
depends on IP_NF_CONNTRACK
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index a7bd38f..1ba0db7 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -21,6 +21,7 @@
obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
# NAT helpers
obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
index be4c9eb..dc20881 100644
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -108,6 +108,7 @@
}
exp->expectfn = NULL;
+ exp->flags = 0;
exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
exp->tuple.src.u.tcp.port = 0;
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index a064860..19cba16 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -197,7 +197,7 @@
/* ip_conntrack_expect helper functions */
-static void unlink_expect(struct ip_conntrack_expect *exp)
+void ip_ct_unlink_expect(struct ip_conntrack_expect *exp)
{
ASSERT_WRITE_LOCK(&ip_conntrack_lock);
IP_NF_ASSERT(!timer_pending(&exp->timeout));
@@ -207,18 +207,12 @@
ip_conntrack_expect_put(exp);
}
-void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp)
-{
- unlink_expect(exp);
- ip_conntrack_expect_put(exp);
-}
-
static void expectation_timed_out(unsigned long ul_expect)
{
struct ip_conntrack_expect *exp = (void *)ul_expect;
write_lock_bh(&ip_conntrack_lock);
- unlink_expect(exp);
+ ip_ct_unlink_expect(exp);
write_unlock_bh(&ip_conntrack_lock);
ip_conntrack_expect_put(exp);
}
@@ -264,10 +258,14 @@
master ct never got confirmed, we'd hold a reference to it
and weird things would happen to future packets). */
if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
- && is_confirmed(i->master)
- && del_timer(&i->timeout)) {
- unlink_expect(i);
- return i;
+ && is_confirmed(i->master)) {
+ if (i->flags & IP_CT_EXPECT_PERMANENT) {
+ atomic_inc(&i->use);
+ return i;
+ } else if (del_timer(&i->timeout)) {
+ ip_ct_unlink_expect(i);
+ return i;
+ }
}
}
return NULL;
@@ -284,7 +282,7 @@
list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) {
if (i->master == ct && del_timer(&i->timeout)) {
- unlink_expect(i);
+ ip_ct_unlink_expect(i);
ip_conntrack_expect_put(i);
}
}
@@ -925,7 +923,7 @@
/* choose the the oldest expectation to evict */
list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
if (expect_matches(i, exp) && del_timer(&i->timeout)) {
- unlink_expect(i);
+ ip_ct_unlink_expect(i);
write_unlock_bh(&ip_conntrack_lock);
ip_conntrack_expect_put(i);
return;
@@ -934,6 +932,9 @@
write_unlock_bh(&ip_conntrack_lock);
}
+/* We don't increase the master conntrack refcount for non-fulfilled
+ * conntracks. During the conntrack destruction, the expectations are
+ * always killed before the conntrack itself */
struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
{
struct ip_conntrack_expect *new;
@@ -944,17 +945,14 @@
return NULL;
}
new->master = me;
- atomic_inc(&new->master->ct_general.use);
atomic_set(&new->use, 1);
return new;
}
void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
{
- if (atomic_dec_and_test(&exp->use)) {
- ip_conntrack_put(exp->master);
+ if (atomic_dec_and_test(&exp->use))
kmem_cache_free(ip_conntrack_expect_cachep, exp);
- }
}
static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
@@ -982,7 +980,7 @@
list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
if (i->master == master) {
if (del_timer(&i->timeout)) {
- unlink_expect(i);
+ ip_ct_unlink_expect(i);
ip_conntrack_expect_put(i);
}
break;
@@ -1099,7 +1097,7 @@
/* Get rid of expectations */
list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
if (exp->master->helper == me && del_timer(&exp->timeout)) {
- unlink_expect(exp);
+ ip_ct_unlink_expect(exp);
ip_conntrack_expect_put(exp);
}
}
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 3a2627d..1b79ec3 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -421,6 +421,7 @@
{ 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
exp->expectfn = NULL;
+ exp->flags = 0;
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index 25438ee..d7a8a98 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -221,6 +221,7 @@
{ { 0, { 0 } },
{ 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
exp->expectfn = NULL;
+ exp->flags = 0;
if (ip_nat_irc_hook)
ret = ip_nat_irc_hook(pskb, ctinfo,
addr_beg_p - ib_ptr,
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
new file mode 100644
index 0000000..2b5cf9c
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
@@ -0,0 +1,131 @@
+/*
+ * NetBIOS name service broadcast connection tracking helper
+ *
+ * (c) 2005 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 helper tracks locally originating NetBIOS name service
+ * requests by issuing permanent expectations (valid until
+ * timing out) matching all reply connections from the
+ * destination network. The only NetBIOS specific thing is
+ * actually the port number.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <net/route.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
+MODULE_LICENSE("GPL");
+
+static unsigned int timeout = 3;
+module_param(timeout, int, 0600);
+MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
+
+static int help(struct sk_buff **pskb,
+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+{
+ struct ip_conntrack_expect *exp;
+ struct iphdr *iph = (*pskb)->nh.iph;
+ struct udphdr _uh, *uh;
+ struct rtable *rt = (struct rtable *)(*pskb)->dst;
+ struct in_device *in_dev;
+ u_int32_t mask = 0;
+
+ /* we're only interested in locally generated packets */
+ if ((*pskb)->sk == NULL)
+ goto out;
+ if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST))
+ goto out;
+ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
+ goto out;
+
+ rcu_read_lock();
+ in_dev = __in_dev_get(rt->u.dst.dev);
+ if (in_dev != NULL) {
+ for_primary_ifa(in_dev) {
+ if (ifa->ifa_broadcast == iph->daddr) {
+ mask = ifa->ifa_mask;
+ break;
+ }
+ } endfor_ifa(in_dev);
+ }
+ rcu_read_unlock();
+
+ if (mask == 0)
+ goto out;
+
+ uh = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_uh), &_uh);
+ BUG_ON(uh == NULL);
+
+ exp = ip_conntrack_expect_alloc(ct);
+ if (exp == NULL)
+ goto out;
+ memset(&exp->tuple, 0, sizeof(exp->tuple));
+ exp->tuple.src.ip = iph->daddr & mask;
+ exp->tuple.dst.ip = iph->saddr;
+ exp->tuple.dst.u.udp.port = uh->source;
+ exp->tuple.dst.protonum = IPPROTO_UDP;
+
+ memset(&exp->mask, 0, sizeof(exp->mask));
+ exp->mask.src.ip = mask;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.udp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+
+ exp->expectfn = NULL;
+ exp->flags = IP_CT_EXPECT_PERMANENT;
+
+ ip_conntrack_expect_related(exp);
+ ip_conntrack_expect_put(exp);
+
+ ip_ct_refresh_acct(ct, ctinfo, NULL, timeout * HZ);
+out:
+ return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper helper = {
+ .name = "netbios-ns",
+ .tuple = {
+ .src.u.udp.port = __constant_htons(137),
+ .dst.protonum = IPPROTO_UDP,
+ },
+ .mask = {
+ .src.u.udp.port = 0xFFFF,
+ .dst.protonum = 0xFF,
+ },
+ .max_expected = 1,
+ .me = THIS_MODULE,
+ .help = help,
+};
+
+static int __init init(void)
+{
+ helper.timeout = timeout;
+ return ip_conntrack_helper_register(&helper);
+}
+
+static void __exit fini(void)
+{
+ ip_conntrack_helper_unregister(&helper);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index a4e9278..15aef35 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1349,8 +1349,10 @@
list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
list) {
if (exp->master->helper == h
- && del_timer(&exp->timeout))
- __ip_ct_expect_unlink_destroy(exp);
+ && del_timer(&exp->timeout)) {
+ ip_ct_unlink_expect(exp);
+ ip_conntrack_expect_put(exp);
+ }
}
write_unlock(&ip_conntrack_lock);
} else {
@@ -1358,8 +1360,10 @@
write_lock_bh(&ip_conntrack_lock);
list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
list) {
- if (del_timer(&exp->timeout))
- __ip_ct_expect_unlink_destroy(exp);
+ if (del_timer(&exp->timeout)) {
+ ip_ct_unlink_expect(exp);
+ ip_conntrack_expect_put(exp);
+ }
}
write_unlock_bh(&ip_conntrack_lock);
}
@@ -1413,6 +1417,7 @@
}
exp->expectfn = NULL;
+ exp->flags = 0;
exp->master = ct;
memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index f23ef1f..1985abc 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -349,6 +349,7 @@
return 0;
nfattr_failure:
+ read_unlock_bh(&tcp_lock);
return -1;
}
#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index ee5895a..ae3e3e6 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -998,7 +998,7 @@
EXPORT_SYMBOL(ip_conntrack_unexpect_related);
EXPORT_SYMBOL_GPL(ip_conntrack_expect_list);
EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find);
-EXPORT_SYMBOL_GPL(__ip_ct_expect_unlink_destroy);
+EXPORT_SYMBOL_GPL(ip_ct_unlink_expect);
EXPORT_SYMBOL(ip_conntrack_tuple_taken);
EXPORT_SYMBOL(ip_ct_gather_frags);
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
index f8ff170..d2b5905 100644
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
@@ -75,6 +75,7 @@
exp->mask.dst.u.udp.port = 0xffff;
exp->mask.dst.protonum = 0xff;
exp->expectfn = NULL;
+ exp->flags = 0;
DEBUGP("expect: ");
DUMP_TUPLE(&exp->tuple);
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index 60d70fa..cb66b8b 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -255,6 +255,27 @@
return ip_nat_setup_info(conntrack, &range, hooknum);
}
+unsigned int
+alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
+ struct ip_nat_info *info,
+ unsigned int hooknum)
+{
+ u_int32_t ip
+ = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+ ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+ : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
+ u_int16_t all
+ = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+ ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+ : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
+ struct ip_nat_range range
+ = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
+
+ DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
+ conntrack, NIPQUAD(ip));
+ return ip_nat_setup_info(conntrack, &range, hooknum);
+}
+
int ip_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 89db052..0ff368b 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -123,8 +123,12 @@
if (!ip_nat_initialized(ct, maniptype)) {
unsigned int ret;
- /* LOCAL_IN hook doesn't have a chain! */
- if (hooknum == NF_IP_LOCAL_IN)
+ if (unlikely(is_confirmed(ct)))
+ /* NAT module was loaded late */
+ ret = alloc_null_binding_confirmed(ct, info,
+ hooknum);
+ else if (hooknum == NF_IP_LOCAL_IN)
+ /* LOCAL_IN hook doesn't have a chain! */
ret = alloc_null_binding(ct, info, hooknum);
else
ret = ip_nat_rule_find(pskb, hooknum,
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 2d05caf..7d38913 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -144,7 +144,7 @@
memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
c->num_total_nodes = i->num_total_nodes;
c->num_local_nodes = i->num_local_nodes;
- memcpy(&c->local_nodes, &i->local_nodes, sizeof(&c->local_nodes));
+ memcpy(&c->local_nodes, &i->local_nodes, sizeof(c->local_nodes));
c->hash_mode = i->hash_mode;
c->hash_initval = i->hash_initval;
atomic_set(&c->refcount, 1);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 02fdda6..f3f0013 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -552,8 +552,7 @@
tcp_mark_push(tp, skb);
goto new_segment;
}
- if (sk->sk_forward_alloc < copy &&
- !sk_stream_mem_schedule(sk, copy, 0))
+ if (!sk_stream_wmem_schedule(sk, copy))
goto wait_for_memory;
if (can_coalesce) {
@@ -770,19 +769,23 @@
if (off == PAGE_SIZE) {
put_page(page);
TCP_PAGE(sk) = page = NULL;
+ off = 0;
}
- }
+ } else
+ off = 0;
+
+ if (copy > PAGE_SIZE - off)
+ copy = PAGE_SIZE - off;
+
+ if (!sk_stream_wmem_schedule(sk, copy))
+ goto wait_for_memory;
if (!page) {
/* Allocate new cache page. */
if (!(page = sk_stream_alloc_page(sk)))
goto wait_for_memory;
- off = 0;
}
- if (copy > PAGE_SIZE - off)
- copy = PAGE_SIZE - off;
-
/* Time to copy data. We are close to
* the end! */
err = skb_copy_to_page(sk, from, skb, page,
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1afb080..29222b96 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -923,14 +923,6 @@
int flag = 0;
int i;
- /* So, SACKs for already sent large segments will be lost.
- * Not good, but alternative is to resegment the queue. */
- if (sk->sk_route_caps & NETIF_F_TSO) {
- sk->sk_route_caps &= ~NETIF_F_TSO;
- sock_set_flag(sk, SOCK_NO_LARGESEND);
- tp->mss_cache = tp->mss_cache;
- }
-
if (!tp->sacked_out)
tp->fackets_out = 0;
prior_fackets = tp->fackets_out;
@@ -978,20 +970,40 @@
flag |= FLAG_DATA_LOST;
sk_stream_for_retrans_queue(skb, sk) {
- u8 sacked = TCP_SKB_CB(skb)->sacked;
- int in_sack;
+ int in_sack, pcount;
+ u8 sacked;
/* The retransmission queue is always in order, so
* we can short-circuit the walk early.
*/
- if(!before(TCP_SKB_CB(skb)->seq, end_seq))
+ if (!before(TCP_SKB_CB(skb)->seq, end_seq))
break;
- fack_count += tcp_skb_pcount(skb);
+ pcount = tcp_skb_pcount(skb);
+
+ if (pcount > 1 &&
+ (after(start_seq, TCP_SKB_CB(skb)->seq) ||
+ before(end_seq, TCP_SKB_CB(skb)->end_seq))) {
+ unsigned int pkt_len;
+
+ if (after(start_seq, TCP_SKB_CB(skb)->seq))
+ pkt_len = (start_seq -
+ TCP_SKB_CB(skb)->seq);
+ else
+ pkt_len = (end_seq -
+ TCP_SKB_CB(skb)->seq);
+ if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size))
+ break;
+ pcount = tcp_skb_pcount(skb);
+ }
+
+ fack_count += pcount;
in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
!before(end_seq, TCP_SKB_CB(skb)->end_seq);
+ sacked = TCP_SKB_CB(skb)->sacked;
+
/* Account D-SACK for retransmitted packet. */
if ((dup_sack && in_sack) &&
(sacked & TCPCB_RETRANS) &&
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 75b6811..6094db5 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -428,11 +428,11 @@
* packet to the list. This won't be called frequently, I hope.
* Remember, these are still headerless SKBs at this point.
*/
-static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now)
+int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *buff;
- int nsize;
+ int nsize, old_factor;
u16 flags;
nsize = skb_headlen(skb) - len;
@@ -490,18 +490,29 @@
tp->left_out -= tcp_skb_pcount(skb);
}
+ old_factor = tcp_skb_pcount(skb);
+
/* Fix up tso_factor for both original and new SKB. */
tcp_set_skb_tso_segs(sk, skb, mss_now);
tcp_set_skb_tso_segs(sk, buff, mss_now);
- if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
- tp->lost_out += tcp_skb_pcount(skb);
- tp->left_out += tcp_skb_pcount(skb);
- }
+ /* If this packet has been sent out already, we must
+ * adjust the various packet counters.
+ */
+ if (after(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) {
+ int diff = old_factor - tcp_skb_pcount(skb) -
+ tcp_skb_pcount(buff);
- if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) {
- tp->lost_out += tcp_skb_pcount(buff);
- tp->left_out += tcp_skb_pcount(buff);
+ tp->packets_out -= diff;
+ if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
+ tp->lost_out -= diff;
+ tp->left_out -= diff;
+ }
+ if (diff > 0) {
+ tp->fackets_out -= diff;
+ if ((int)tp->fackets_out < 0)
+ tp->fackets_out = 0;
+ }
}
/* Link BUFF into the send queue. */
@@ -1350,12 +1361,6 @@
if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {
if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
BUG();
-
- if (sk->sk_route_caps & NETIF_F_TSO) {
- sk->sk_route_caps &= ~NETIF_F_TSO;
- sock_set_flag(sk, SOCK_NO_LARGESEND);
- }
-
if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
return -ENOMEM;
}
@@ -1370,22 +1375,8 @@
return -EAGAIN;
if (skb->len > cur_mss) {
- int old_factor = tcp_skb_pcount(skb);
- int diff;
-
if (tcp_fragment(sk, skb, cur_mss, cur_mss))
return -ENOMEM; /* We'll try again later. */
-
- /* New SKB created, account for it. */
- diff = old_factor - tcp_skb_pcount(skb) -
- tcp_skb_pcount(skb->next);
- tp->packets_out -= diff;
-
- if (diff > 0) {
- tp->fackets_out -= diff;
- if ((int)tp->fackets_out < 0)
- tp->fackets_out = 0;
- }
}
/* Collapse two adjacent packets if worthwhile and we can. */
@@ -1993,12 +1984,6 @@
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
if (tcp_fragment(sk, skb, seg_size, mss))
return -1;
- /* SWS override triggered forced fragmentation.
- * Disable TSO, the connection is too sick. */
- if (sk->sk_route_caps & NETIF_F_TSO) {
- sock_set_flag(sk, SOCK_NO_LARGESEND);
- sk->sk_route_caps &= ~NETIF_F_TSO;
- }
} else if (!tcp_skb_pcount(skb))
tcp_set_skb_tso_segs(sk, skb, mss);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 937ad32..6d6fb74 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3593,10 +3593,8 @@
rtnl_unlock();
#ifdef CONFIG_IPV6_PRIVACY
- if (likely(md5_tfm != NULL)) {
- crypto_free_tfm(md5_tfm);
- md5_tfm = NULL;
- }
+ crypto_free_tfm(md5_tfm);
+ md5_tfm = NULL;
#endif
#ifdef CONFIG_PROC_FS
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 0ebfad9..f362973 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -401,10 +401,8 @@
error:
if (ahp) {
- if (ahp->work_icv)
- kfree(ahp->work_icv);
- if (ahp->tfm)
- crypto_free_tfm(ahp->tfm);
+ kfree(ahp->work_icv);
+ crypto_free_tfm(ahp->tfm);
kfree(ahp);
}
return -EINVAL;
@@ -417,14 +415,10 @@
if (!ahp)
return;
- if (ahp->work_icv) {
- kfree(ahp->work_icv);
- ahp->work_icv = NULL;
- }
- if (ahp->tfm) {
- crypto_free_tfm(ahp->tfm);
- ahp->tfm = NULL;
- }
+ kfree(ahp->work_icv);
+ ahp->work_icv = NULL;
+ crypto_free_tfm(ahp->tfm);
+ ahp->tfm = NULL;
kfree(ahp);
}
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index e8bff9d..9b27460 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -276,22 +276,14 @@
if (!esp)
return;
- if (esp->conf.tfm) {
- crypto_free_tfm(esp->conf.tfm);
- esp->conf.tfm = NULL;
- }
- if (esp->conf.ivec) {
- kfree(esp->conf.ivec);
- esp->conf.ivec = NULL;
- }
- if (esp->auth.tfm) {
- crypto_free_tfm(esp->auth.tfm);
- esp->auth.tfm = NULL;
- }
- if (esp->auth.work_icv) {
- kfree(esp->auth.work_icv);
- esp->auth.work_icv = NULL;
- }
+ crypto_free_tfm(esp->conf.tfm);
+ esp->conf.tfm = NULL;
+ kfree(esp->conf.ivec);
+ esp->conf.ivec = NULL;
+ crypto_free_tfm(esp->auth.tfm);
+ esp->auth.tfm = NULL;
+ kfree(esp->auth.work_icv);
+ esp->auth.work_icv = NULL;
kfree(esp);
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 5176fc6..fa8f1bb 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -549,7 +549,7 @@
read_lock(&raw_v6_lock);
if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr,
- skb->dev->ifindex))) {
+ IP6CB(skb)->iif))) {
rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
sk = sk_next(sk);
}
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 135383e..85bfbc6 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -341,8 +341,7 @@
for_each_cpu(cpu) {
struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu);
- if (tfm)
- crypto_free_tfm(tfm);
+ crypto_free_tfm(tfm);
}
free_percpu(tfms);
}
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 7a58632..ed3a76b 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -166,7 +166,7 @@
if (sk == NULL)
goto out;
- sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex);
+ sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
while (sk) {
delivered = 1;
@@ -178,7 +178,7 @@
rawv6_rcv(sk, clone);
}
sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
- skb->dev->ifindex);
+ IP6CB(skb)->iif);
}
out:
read_unlock(&raw_v6_lock);
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c
index 343c5d4..ca7d358 100644
--- a/net/irda/irlan/irlan_filter.c
+++ b/net/irda/irlan/irlan_filter.c
@@ -27,6 +27,7 @@
#include <linux/seq_file.h>
#include <net/irda/irlan_common.h>
+#include <net/irda/irlan_filter.h>
/*
* Function irlan_filter_request (self, skb)
diff --git a/net/irda/qos.c b/net/irda/qos.c
index df732d5..ddfb5c5 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -37,6 +37,7 @@
#include <net/irda/parameters.h>
#include <net/irda/qos.h>
#include <net/irda/irlap.h>
+#include <net/irda/irlap_frame.h>
/*
* Maximum values of the baud rate we negociate with the other end.
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index e089f17..49a3900 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -344,14 +344,14 @@
} while(nfnl && nfnl->sk_receive_queue.qlen);
}
-void __exit nfnetlink_exit(void)
+static void __exit nfnetlink_exit(void)
{
printk("Removing netfilter NETLINK layer.\n");
sock_release(nfnl->sk_socket);
return;
}
-int __init nfnetlink_init(void)
+static int __init nfnetlink_init(void)
{
printk("Netfilter messages via NETLINK v%s.\n", nfversion);
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index e3a5285..f81fe8c 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -76,17 +76,6 @@
static DEFINE_RWLOCK(instances_lock);
-u_int64_t htonll(u_int64_t in)
-{
- u_int64_t out;
- int i;
-
- for (i = 0; i < sizeof(u_int64_t); i++)
- ((u_int8_t *)&out)[sizeof(u_int64_t)-1] = ((u_int8_t *)&in)[i];
-
- return out;
-}
-
#define INSTANCE_BUCKETS 16
static struct hlist_head instance_table[INSTANCE_BUCKETS];
@@ -382,6 +371,12 @@
break;
case NFQNL_COPY_PACKET:
+ if (entry->skb->ip_summed == CHECKSUM_HW &&
+ (*errp = skb_checksum_help(entry->skb,
+ entry->info->outdev == NULL))) {
+ spin_unlock_bh(&queue->lock);
+ return NULL;
+ }
if (queue->copy_range == 0
|| queue->copy_range > entry->skb->len)
data_len = entry->skb->len;
@@ -497,8 +492,8 @@
if (entry->skb->tstamp.off_sec) {
struct nfqnl_msg_packet_timestamp ts;
- ts.sec = htonll(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec);
- ts.usec = htonll(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec);
+ ts.sec = cpu_to_be64(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec);
+ ts.usec = cpu_to_be64(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec);
NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
}
@@ -647,7 +642,7 @@
if (!skb_make_writable(&e->skb, data_len))
return -ENOMEM;
memcpy(e->skb->data, data, data_len);
-
+ e->skb->ip_summed = CHECKSUM_NONE;
return 0;
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 62435ff..a64e1d5 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -398,24 +398,13 @@
if (nl_table[protocol].registered &&
try_module_get(nl_table[protocol].module))
module = nl_table[protocol].module;
- else
- err = -EPROTONOSUPPORT;
groups = nl_table[protocol].groups;
netlink_unlock_table();
- if (err || (err = __netlink_create(sock, protocol) < 0))
+ if ((err = __netlink_create(sock, protocol) < 0))
goto out_module;
nlk = nlk_sk(sock->sk);
-
- nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL);
- if (nlk->groups == NULL) {
- err = -ENOMEM;
- goto out_module;
- }
- memset(nlk->groups, 0, NLGRPSZ(groups));
- nlk->ngroups = groups;
-
nlk->module = module;
out:
return err;
@@ -534,6 +523,29 @@
nlk->subscriptions = subscriptions;
}
+static int netlink_alloc_groups(struct sock *sk)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+ unsigned int groups;
+ int err = 0;
+
+ netlink_lock_table();
+ groups = nl_table[sk->sk_protocol].groups;
+ if (!nl_table[sk->sk_protocol].registered)
+ err = -ENOENT;
+ netlink_unlock_table();
+
+ if (err)
+ return err;
+
+ nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL);
+ if (nlk->groups == NULL)
+ return -ENOMEM;
+ memset(nlk->groups, 0, NLGRPSZ(groups));
+ nlk->ngroups = groups;
+ return 0;
+}
+
static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
struct sock *sk = sock->sk;
@@ -545,8 +557,15 @@
return -EINVAL;
/* Only superuser is allowed to listen multicasts */
- if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_RECV))
- return -EPERM;
+ if (nladdr->nl_groups) {
+ if (!netlink_capable(sock, NL_NONROOT_RECV))
+ return -EPERM;
+ if (nlk->groups == NULL) {
+ err = netlink_alloc_groups(sk);
+ if (err)
+ return err;
+ }
+ }
if (nlk->pid) {
if (nladdr->nl_pid != nlk->pid)
@@ -559,7 +578,7 @@
return err;
}
- if (!nladdr->nl_groups && !(u32)nlk->groups[0])
+ if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
return 0;
netlink_table_grab();
@@ -620,7 +639,7 @@
nladdr->nl_groups = netlink_group_mask(nlk->dst_group);
} else {
nladdr->nl_pid = nlk->pid;
- nladdr->nl_groups = nlk->groups[0];
+ nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
}
return 0;
}
@@ -976,6 +995,11 @@
if (!netlink_capable(sock, NL_NONROOT_RECV))
return -EPERM;
+ if (nlk->groups == NULL) {
+ err = netlink_alloc_groups(sk);
+ if (err)
+ return err;
+ }
if (!val || val - 1 >= nlk->ngroups)
return -EINVAL;
netlink_table_grab();
@@ -1483,8 +1507,7 @@
s,
s->sk_protocol,
nlk->pid,
- nlk->flags & NETLINK_KERNEL_SOCKET ?
- 0 : (unsigned int)nlk->groups[0],
+ nlk->groups ? (u32)nlk->groups[0] : 0,
atomic_read(&s->sk_rmem_alloc),
atomic_read(&s->sk_wmem_alloc),
nlk->cb,
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 4b53de9..f4578c7 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1261,6 +1261,7 @@
struct net_device *dev;
struct nr_sock *nr;
const char *devname;
+ char buf[11];
if (v == SEQ_START_TOKEN)
seq_puts(seq,
@@ -1276,11 +1277,11 @@
else
devname = dev->name;
- seq_printf(seq, "%-9s ", ax2asc(&nr->user_addr));
- seq_printf(seq, "%-9s ", ax2asc(&nr->dest_addr));
+ seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr));
+ seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr));
seq_printf(seq,
"%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n",
- ax2asc(&nr->source_addr),
+ ax2asc(buf, &nr->source_addr),
devname,
nr->my_index,
nr->my_id,
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 7a86b36..b3b9097 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -881,6 +881,7 @@
static int nr_node_show(struct seq_file *seq, void *v)
{
+ char buf[11];
int i;
if (v == SEQ_START_TOKEN)
@@ -890,7 +891,7 @@
struct nr_node *nr_node = v;
nr_node_lock(nr_node);
seq_printf(seq, "%-9s %-7s %d %d",
- ax2asc(&nr_node->callsign),
+ ax2asc(buf, &nr_node->callsign),
(nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
nr_node->which + 1,
nr_node->count);
@@ -964,6 +965,7 @@
static int nr_neigh_show(struct seq_file *seq, void *v)
{
+ char buf[11];
int i;
if (v == SEQ_START_TOKEN)
@@ -973,7 +975,7 @@
seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d",
nr_neigh->number,
- ax2asc(&nr_neigh->callsign),
+ ax2asc(buf, &nr_neigh->callsign),
nr_neigh->dev ? nr_neigh->dev->name : "???",
nr_neigh->quality,
nr_neigh->locked,
@@ -983,7 +985,7 @@
if (nr_neigh->digipeat != NULL) {
for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
seq_printf(seq, " %s",
- ax2asc(&nr_neigh->digipeat->calls[i]));
+ ax2asc(buf, &nr_neigh->digipeat->calls[i]));
}
seq_puts(seq, "\n");
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ba99709..8690f17 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1535,8 +1535,7 @@
static void packet_mm_open(struct vm_area_struct *vma)
{
struct file *file = vma->vm_file;
- struct inode *inode = file->f_dentry->d_inode;
- struct socket * sock = SOCKET_I(inode);
+ struct socket * sock = file->private_data;
struct sock *sk = sock->sk;
if (sk)
@@ -1546,8 +1545,7 @@
static void packet_mm_close(struct vm_area_struct *vma)
{
struct file *file = vma->vm_file;
- struct inode *inode = file->f_dentry->d_inode;
- struct socket * sock = SOCKET_I(inode);
+ struct socket * sock = file->private_data;
struct sock *sk = sock->sk;
if (sk)
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index c6e59f8..3077878 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1363,6 +1363,8 @@
static int rose_info_show(struct seq_file *seq, void *v)
{
+ char buf[11];
+
if (v == SEQ_START_TOKEN)
seq_puts(seq,
"dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n");
@@ -1380,12 +1382,12 @@
seq_printf(seq, "%-10s %-9s ",
rose2asc(&rose->dest_addr),
- ax2asc(&rose->dest_call));
+ ax2asc(buf, &rose->dest_call));
if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
callsign = "??????-?";
else
- callsign = ax2asc(&rose->source_call);
+ callsign = ax2asc(buf, &rose->source_call);
seq_printf(seq,
"%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 4510cd76..e556d92 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -851,6 +851,7 @@
unsigned char cause, diagnostic;
struct net_device *dev;
int len, res = 0;
+ char buf[11];
#if 0
if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
@@ -876,7 +877,7 @@
if (rose_neigh == NULL) {
printk("rose_route : unknown neighbour or device %s\n",
- ax2asc(&ax25->dest_addr));
+ ax2asc(buf, &ax25->dest_addr));
goto out;
}
@@ -1178,6 +1179,7 @@
static int rose_neigh_show(struct seq_file *seq, void *v)
{
+ char buf[11];
int i;
if (v == SEQ_START_TOKEN)
@@ -1189,7 +1191,7 @@
/* if (!rose_neigh->loopback) { */
seq_printf(seq, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu",
rose_neigh->number,
- (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->callsign),
+ (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
rose_neigh->dev ? rose_neigh->dev->name : "???",
rose_neigh->count,
rose_neigh->use,
@@ -1200,7 +1202,7 @@
if (rose_neigh->digipeat != NULL) {
for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
- seq_printf(seq, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+ seq_printf(seq, " %s", ax2asc(buf, &rose_neigh->digipeat->calls[i]));
}
seq_puts(seq, "\n");
@@ -1260,6 +1262,8 @@
static int rose_route_show(struct seq_file *seq, void *v)
{
+ char buf[11];
+
if (v == SEQ_START_TOKEN)
seq_puts(seq,
"lci address callsign neigh <-> lci address callsign neigh\n");
@@ -1271,7 +1275,7 @@
"%3.3X %-10s %-9s %05d ",
rose_route->lci1,
rose2asc(&rose_route->src_addr),
- ax2asc(&rose_route->src_call),
+ ax2asc(buf, &rose_route->src_call),
rose_route->neigh1->number);
else
seq_puts(seq,
@@ -1282,7 +1286,7 @@
"%3.3X %-10s %-9s %05d\n",
rose_route->lci2,
rose2asc(&rose_route->dest_addr),
- ax2asc(&rose_route->dest_call),
+ ax2asc(buf, &rose_route->dest_call),
rose_route->neigh2->number);
else
seq_puts(seq,
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index a29a3a9..02891ce 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -400,6 +400,7 @@
{
unsigned char *p = buffer + 1;
char *callsign;
+ char buf[11];
int len, nb;
/* National Facilities */
@@ -456,7 +457,7 @@
*p++ = FAC_CCITT_DEST_NSAP;
- callsign = ax2asc(&rose->dest_call);
+ callsign = ax2asc(buf, &rose->dest_call);
*p++ = strlen(callsign) + 10;
*p++ = (strlen(callsign) + 9) * 2; /* ??? */
@@ -471,7 +472,7 @@
*p++ = FAC_CCITT_SRC_NSAP;
- callsign = ax2asc(&rose->source_call);
+ callsign = ax2asc(buf, &rose->source_call);
*p++ = strlen(callsign) + 10;
*p++ = (strlen(callsign) + 9) * 2; /* ??? */
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index e47ac0d..e22ccd6 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -193,8 +193,7 @@
sctp_unhash_endpoint(ep);
/* Free up the HMAC transform. */
- if (sctp_sk(ep->base.sk)->hmac)
- sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
+ sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
/* Cleanup. */
sctp_inq_free(&ep->base.inqueue);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 4454afe..91ec8c9 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4194,8 +4194,7 @@
sctp_release_sock(sk);
return err;
cleanup:
- if (tfm)
- sctp_crypto_free_tfm(tfm);
+ sctp_crypto_free_tfm(tfm);
goto out;
}
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index dc48934..75b28dd 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -42,6 +42,7 @@
*/
#include <net/sctp/structs.h>
+#include <net/sctp/sctp.h>
#include <linux/sysctl.h>
static ctl_handler sctp_sysctl_jiffies_ms;
diff --git a/net/socket.c b/net/socket.c
index 94fe638..e1bd5d84 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -667,7 +667,7 @@
}
iocb->private = x;
x->kiocb = iocb;
- sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode);
+ sock = iocb->ki_filp->private_data;
x->async_msg.msg_name = NULL;
x->async_msg.msg_namelen = 0;
@@ -709,7 +709,7 @@
}
iocb->private = x;
x->kiocb = iocb;
- sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode);
+ sock = iocb->ki_filp->private_data;
x->async_msg.msg_name = NULL;
x->async_msg.msg_namelen = 0;
@@ -732,7 +732,7 @@
struct socket *sock;
int flags;
- sock = SOCKET_I(file->f_dentry->d_inode);
+ sock = file->private_data;
flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
if (more)
@@ -741,14 +741,14 @@
return sock->ops->sendpage(sock, page, offset, size, flags);
}
-static int sock_readv_writev(int type, struct inode * inode,
+static int sock_readv_writev(int type,
struct file * file, const struct iovec * iov,
long count, size_t size)
{
struct msghdr msg;
struct socket *sock;
- sock = SOCKET_I(inode);
+ sock = file->private_data;
msg.msg_name = NULL;
msg.msg_namelen = 0;
@@ -775,7 +775,7 @@
int i;
for (i = 0 ; i < count ; i++)
tot_len += vector[i].iov_len;
- return sock_readv_writev(VERIFY_WRITE, file->f_dentry->d_inode,
+ return sock_readv_writev(VERIFY_WRITE,
file, vector, count, tot_len);
}
@@ -786,7 +786,7 @@
int i;
for (i = 0 ; i < count ; i++)
tot_len += vector[i].iov_len;
- return sock_readv_writev(VERIFY_READ, file->f_dentry->d_inode,
+ return sock_readv_writev(VERIFY_READ,
file, vector, count, tot_len);
}
@@ -840,7 +840,7 @@
void __user *argp = (void __user *)arg;
int pid, err;
- sock = SOCKET_I(file->f_dentry->d_inode);
+ sock = file->private_data;
if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
err = dev_ioctl(cmd, argp);
} else
@@ -939,13 +939,13 @@
/*
* We can't return errors to poll, so it's either yes or no.
*/
- sock = SOCKET_I(file->f_dentry->d_inode);
+ sock = file->private_data;
return sock->ops->poll(file, sock, wait);
}
static int sock_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct socket *sock = SOCKET_I(file->f_dentry->d_inode);
+ struct socket *sock = file->private_data;
return sock->ops->mmap(file, sock, vma);
}
@@ -995,7 +995,7 @@
return -ENOMEM;
}
- sock = SOCKET_I(filp->f_dentry->d_inode);
+ sock = filp->private_data;
if ((sk=sock->sk) == NULL) {
kfree(fna);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 5a7265a..ee6ae74 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -160,7 +160,7 @@
" unsupported checksum %d", cksumtype);
goto out;
}
- if (!(tfm = crypto_alloc_tfm(cksumname, 0)))
+ if (!(tfm = crypto_alloc_tfm(cksumname, CRYPTO_TFM_REQ_MAY_SLEEP)))
goto out;
cksum->len = crypto_tfm_alg_digestsize(tfm);
if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL)
@@ -199,8 +199,7 @@
crypto_digest_final(tfm, cksum->data);
code = 0;
out:
- if (tfm)
- crypto_free_tfm(tfm);
+ crypto_free_tfm(tfm);
return code;
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index cf72651..606a8a8 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -185,12 +185,9 @@
gss_delete_sec_context_kerberos(void *internal_ctx) {
struct krb5_ctx *kctx = internal_ctx;
- if (kctx->seq)
- crypto_free_tfm(kctx->seq);
- if (kctx->enc)
- crypto_free_tfm(kctx->enc);
- if (kctx->mech_used.data)
- kfree(kctx->mech_used.data);
+ crypto_free_tfm(kctx->seq);
+ crypto_free_tfm(kctx->enc);
+ kfree(kctx->mech_used.data);
kfree(kctx);
}
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index dad0599..6c97d61 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -214,14 +214,10 @@
gss_delete_sec_context_spkm3(void *internal_ctx) {
struct spkm3_ctx *sctx = internal_ctx;
- if(sctx->derived_integ_key)
- crypto_free_tfm(sctx->derived_integ_key);
- if(sctx->derived_conf_key)
- crypto_free_tfm(sctx->derived_conf_key);
- if(sctx->share_key.data)
- kfree(sctx->share_key.data);
- if(sctx->mech_used.data)
- kfree(sctx->mech_used.data);
+ crypto_free_tfm(sctx->derived_integ_key);
+ crypto_free_tfm(sctx->derived_conf_key);
+ kfree(sctx->share_key.data);
+ kfree(sctx->mech_used.data);
kfree(sctx);
}
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 5c8fe3b..e330819 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -250,6 +250,7 @@
}
static struct cache_detail rsi_cache = {
+ .owner = THIS_MODULE,
.hash_size = RSI_HASHMAX,
.hash_table = rsi_table,
.name = "auth.rpcsec.init",
@@ -436,6 +437,7 @@
}
static struct cache_detail rsc_cache = {
+ .owner = THIS_MODULE,
.hash_size = RSC_HASHMAX,
.hash_table = rsc_table,
.name = "auth.rpcsec.context",
@@ -1074,7 +1076,9 @@
void
gss_svc_shutdown(void)
{
- cache_unregister(&rsc_cache);
- cache_unregister(&rsi_cache);
+ if (cache_unregister(&rsc_cache))
+ printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");
+ if (cache_unregister(&rsi_cache))
+ printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");
svc_auth_unregister(RPC_AUTH_GSS);
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 900f5bc..f509e99 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -177,7 +177,7 @@
cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
if (cd->proc_ent) {
struct proc_dir_entry *p;
- cd->proc_ent->owner = THIS_MODULE;
+ cd->proc_ent->owner = cd->owner;
cd->channel_ent = cd->content_ent = NULL;
p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
@@ -185,7 +185,7 @@
cd->flush_ent = p;
if (p) {
p->proc_fops = &cache_flush_operations;
- p->owner = THIS_MODULE;
+ p->owner = cd->owner;
p->data = cd;
}
@@ -195,7 +195,7 @@
cd->channel_ent = p;
if (p) {
p->proc_fops = &cache_file_operations;
- p->owner = THIS_MODULE;
+ p->owner = cd->owner;
p->data = cd;
}
}
@@ -205,7 +205,7 @@
cd->content_ent = p;
if (p) {
p->proc_fops = &content_file_operations;
- p->owner = THIS_MODULE;
+ p->owner = cd->owner;
p->data = cd;
}
}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index fe1a73c..ded6c63 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -3,7 +3,7 @@
*
* Userland/kernel interface for rpcauth_gss.
* Code shamelessly plagiarized from fs/nfsd/nfsctl.c
- * and fs/driverfs/inode.c
+ * and fs/sysfs/inode.c
*
* Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no>
*
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 9b67dc1..4979f22 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -35,13 +35,13 @@
int i, j;
seq_printf(seq,
- "net %d %d %d %d\n",
+ "net %u %u %u %u\n",
statp->netcnt,
statp->netudpcnt,
statp->nettcpcnt,
statp->nettcpconn);
seq_printf(seq,
- "rpc %d %d %d\n",
+ "rpc %u %u %u\n",
statp->rpccnt,
statp->rpcretrans,
statp->rpcauthrefresh);
@@ -50,10 +50,10 @@
const struct rpc_version *vers = prog->version[i];
if (!vers)
continue;
- seq_printf(seq, "proc%d %d",
+ seq_printf(seq, "proc%u %u",
vers->number, vers->nrprocs);
for (j = 0; j < vers->nrprocs; j++)
- seq_printf(seq, " %d",
+ seq_printf(seq, " %u",
vers->procs[j].p_count);
seq_putc(seq, '\n');
}
@@ -83,13 +83,13 @@
int i, j;
seq_printf(seq,
- "net %d %d %d %d\n",
+ "net %u %u %u %u\n",
statp->netcnt,
statp->netudpcnt,
statp->nettcpcnt,
statp->nettcpconn);
seq_printf(seq,
- "rpc %d %d %d %d %d\n",
+ "rpc %u %u %u %u %u\n",
statp->rpccnt,
statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
statp->rpcbadfmt,
@@ -99,9 +99,9 @@
for (i = 0; i < prog->pg_nvers; i++) {
if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
continue;
- seq_printf(seq, "proc%d %d", i, vers->vs_nproc);
+ seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
for (j = 0; j < vers->vs_nproc; j++, proc++)
- seq_printf(seq, " %d", proc->pc_count);
+ seq_printf(seq, " %u", proc->pc_count);
seq_putc(seq, '\n');
}
}
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 62a0734..ed48ff0 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -176,8 +176,10 @@
{
unregister_rpc_pipefs();
rpc_destroy_mempool();
- cache_unregister(&auth_domain_cache);
- cache_unregister(&ip_map_cache);
+ if (cache_unregister(&auth_domain_cache))
+ printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n");
+ if (cache_unregister(&ip_map_cache))
+ printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
#ifdef RPC_DEBUG
rpc_unregister_sysctl();
#endif
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index bde8147..dda4f0c 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -143,6 +143,7 @@
struct cache_detail auth_domain_cache = {
+ .owner = THIS_MODULE,
.hash_size = DN_HASHMAX,
.hash_table = auth_domain_table,
.name = "auth.domain",
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index d6baf6f..cac2e77 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -242,6 +242,7 @@
struct cache_detail ip_map_cache = {
+ .owner = THIS_MODULE,
.hash_size = IP_HASHMAX,
.hash_table = ip_table,
.name = "auth.unix.ip",
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
new file mode 100644
index 0000000..9087273
--- /dev/null
+++ b/scripts/Kbuild.include
@@ -0,0 +1,96 @@
+####
+# kbuild: Generic definitions
+
+# Convinient variables
+comma := ,
+empty :=
+space := $(empty) $(empty)
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
+
+###
+# filechk is used to check if the content of a generated file is updated.
+# Sample usage:
+# define filechk_sample
+# echo $KERNELRELEASE
+# endef
+# version.h : Makefile
+# $(call filechk,sample)
+# The rule defined shall write to stdout the content of the new file.
+# The existing file will be compared with the new one.
+# - If no file exist it is created
+# - If the content differ the new file is used
+# - If they are equal no change, and no timestamp update
+# - stdin is piped in from the first prerequisite ($<) so one has
+# to specify a valid file as first prerequisite (often the kbuild file)
+define filechk
+ $(Q)set -e; \
+ echo ' CHK $@'; \
+ mkdir -p $(dir $@); \
+ $(filechk_$(1)) < $< > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ echo ' UPD $@'; \
+ mv -f $@.tmp $@; \
+ fi
+endef
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
+# Usage:
+# $(Q)$(MAKE) $(build)=dir
+build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+
+# If quiet is set, only print short version of command
+cmd = @$(if $($(quiet)cmd_$(1)),\
+ echo ' $(subst ','\'',$($(quiet)cmd_$(1)))' &&) $(cmd_$(1))
+
+###
+# if_changed - execute command if any prerequisite is newer than
+# target, or command line has changed
+# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
+# including used config symbols
+# if_changed_rule - as if_changed but execute rule instead
+# See Documentation/kbuild/makefiles.txt for more info
+
+ifneq ($(KBUILD_NOCMDDEP),1)
+# Check if both arguments has same arguments. Result in empty string if equal
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
+endif
+
+# echo command. Short version is $(quiet) equals quiet, otherwise full command
+echo-cmd = $(if $($(quiet)cmd_$(1)), \
+ echo ' $(subst ','\'',$($(quiet)cmd_$(1)))';)
+
+# function to only execute the passed command if necessary
+# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
+# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
+#
+if_changed = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
+ @set -e; \
+ $(echo-cmd) \
+ $(cmd_$(1)); \
+ echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
+
+# execute the command and also postprocess generated .d dependencies
+# file
+if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
+ $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
+ @set -e; \
+ $(echo-cmd) \
+ $(cmd_$(1)); \
+ scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
+ rm -f $(depfile); \
+ mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
+
+# Usage: $(call if_changed_rule,foo)
+# will check if $(cmd_foo) changed, or any of the prequisites changed,
+# and if so will execute $(rule_foo)
+if_changed_rule = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
+ @set -e; \
+ $(rule_$(1)))
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 76ba6be..506e3f3 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -10,8 +10,11 @@
# Read .config if it exist, otherwise ignore
-include .config
-include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
+include scripts/Kbuild.include
include scripts/Makefile.lib
ifdef host-progs
@@ -169,7 +172,7 @@
-T $(@D)/.tmp_$(@F:.o=.ver); \
rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
else \
- mv $(@D)/.tmp_$(@F) $@; \
+ mv -f $(@D)/.tmp_$(@F) $@; \
fi;
endif
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index ff3e87d..8974ea5 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -7,7 +7,14 @@
.PHONY: __clean
__clean:
-include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
+# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
# Figure out what we need to build from the various variables
# ==========================================================================
@@ -87,8 +94,3 @@
# If quiet is set, only print short version of command
cmd = @$(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
-
-# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
-# Usage:
-# $(Q)$(MAKE) $(clean)=dir
-clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 2821a2b..2d51970 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -98,7 +98,8 @@
# Create executable from a single .c file
# host-csingle -> Executable
quiet_cmd_host-csingle = HOSTCC $@
- cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(HOST_LOADLIBES) -o $@ $<
+ cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
+ $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
$(host-csingle): %: %.c FORCE
$(call if_changed_dep,host-csingle)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 7cf75cc..0f81dcf 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -1,13 +1,3 @@
-# ===========================================================================
-# kbuild: Generic definitions
-# ===========================================================================
-
-# Standard vars
-
-comma := ,
-empty :=
-space := $(empty) $(empty)
-
# Backward compatibility - to be removed...
extra-y += $(EXTRA_TARGETS)
# Figure out what we need to build from the various variables
@@ -84,10 +74,6 @@
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
obj-dirs := $(addprefix $(obj)/,$(obj-dirs))
-# The temporary file to save gcc -MD generated dependencies must not
-# contain a comma
-depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
-
# These flags are needed for modversions and compiling, so we define them here
# already
# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will
@@ -179,89 +165,4 @@
quiet_cmd_gzip = GZIP $@
cmd_gzip = gzip -f -9 < $< > $@
-# ===========================================================================
-# Generic stuff
-# ===========================================================================
-
-ifneq ($(KBUILD_NOCMDDEP),1)
-# Check if both arguments has same arguments. Result in empty string if equal
-# User may override this check using make KBUILD_NOCMDDEP=1
-arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
-
-endif
-
-# echo command. Short version is $(quiet) equals quiet, otherwise full command
-echo-cmd = $(if $($(quiet)cmd_$(1)), \
- echo ' $(subst ','\'',$($(quiet)cmd_$(1)))';)
-
-# function to only execute the passed command if necessary
-# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
-# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
-#
-if_changed = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
- @set -e; \
- $(echo-cmd) \
- $(cmd_$(1)); \
- echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd)
-
-
-# execute the command and also postprocess generated .d dependencies
-# file
-
-if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
- $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
- @set -e; \
- $(echo-cmd) \
- $(cmd_$(1)); \
- scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \
- rm -f $(depfile); \
- mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
-
-# Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
-
-if_changed_rule = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
- @set -e; \
- $(rule_$(1)))
-
-# If quiet is set, only print short version of command
-
-cmd = @$(if $($(quiet)cmd_$(1)),echo ' $(subst ','\'',$($(quiet)cmd_$(1)))' &&) $(cmd_$(1))
-
-# $(call descend,<dir>,<target>)
-# Recursively call a sub-make in <dir> with target <target>
-# Usage is deprecated, because make do not see this as an invocation of make.
-descend =$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=$(1) $(2)
-
-# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
-# Usage:
-# $(Q)$(MAKE) $(build)=dir
-build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
-
-# filechk is used to check if the content of a generated file is updated.
-# Sample usage:
-# define filechk_sample
-# echo $KERNELRELEASE
-# endef
-# version.h : Makefile
-# $(call filechk,sample)
-# The rule defined shall write to stdout the content of the new file.
-# The existing file will be compared with the new one.
-# - If no file exist it is created
-# - If the content differ the new file is used
-# - If they are equal no change, and no timestamp update
-
-define filechk
- $(Q)set -e; \
- echo ' CHK $@'; \
- mkdir -p $(dir $@); \
- $(filechk_$(1)) $(2) > $@.tmp; \
- if [ -r $@ ] && cmp -s $@ $@.tmp; then \
- rm -f $@.tmp; \
- else \
- echo ' UPD $@'; \
- mv -f $@.tmp $@; \
- fi
-endef
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index 85d6494..23fd1bd 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -5,7 +5,7 @@
.PHONY: __modinst
__modinst:
-include scripts/Makefile.lib
+include scripts/Kbuild.include
#
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 94b550e..0c4f3a9 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -36,6 +36,7 @@
_modpost: __modpost
include .config
+include scripts/Kbuild.include
include scripts/Makefile.lib
symverfile := $(objtree)/Module.symvers
diff --git a/scripts/conmakehash.c b/scripts/conmakehash.c
index 93dd23f2..e0c6891 100644
--- a/scripts/conmakehash.c
+++ b/scripts/conmakehash.c
@@ -33,7 +33,7 @@
int getunicode(char **p0)
{
- unsigned char *p = *p0;
+ char *p = *p0;
while (*p == ' ' || *p == '\t')
p++;
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index d3d2e53..d591578 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -24,75 +24,37 @@
*
*/
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-/* maximum token length used. It doesn't pay to increase it a lot, because
- * very long substrings probably don't repeat themselves too often. */
-#define MAX_TOK_SIZE 11
#define KSYM_NAME_LEN 127
-/* we use only a subset of the complete symbol table to gather the token count,
- * to speed up compression, at the expense of a little compression ratio */
-#define WORKING_SET 1024
-
-/* first find the best token only on the list of tokens that would profit more
- * than GOOD_BAD_THRESHOLD. Only if this list is empty go to the "bad" list.
- * Increasing this value will put less tokens on the "good" list, so the search
- * is faster. However, if the good list runs out of tokens, we must painfully
- * search the bad list. */
-#define GOOD_BAD_THRESHOLD 10
-
-/* token hash parameters */
-#define HASH_BITS 18
-#define HASH_TABLE_SIZE (1 << HASH_BITS)
-#define HASH_MASK (HASH_TABLE_SIZE - 1)
-#define HASH_BASE_OFFSET 2166136261U
-#define HASH_FOLD(a) ((a)&(HASH_MASK))
-
-/* flags to mark symbols */
-#define SYM_FLAG_VALID 1
-#define SYM_FLAG_SAMPLED 2
struct sym_entry {
unsigned long long addr;
- char type;
- unsigned char flags;
- unsigned char len;
+ unsigned int len;
unsigned char *sym;
};
static struct sym_entry *table;
-static int size, cnt;
+static unsigned int table_size, table_cnt;
static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
static int all_symbols = 0;
static char symbol_prefix_char = '\0';
-struct token {
- unsigned char data[MAX_TOK_SIZE];
- unsigned char len;
- /* profit: the number of bytes that could be saved by inserting this
- * token into the table */
- int profit;
- struct token *next; /* next token on the hash list */
- struct token *right; /* next token on the good/bad list */
- struct token *left; /* previous token on the good/bad list */
- struct token *smaller; /* token that is less one letter than this one */
- };
-
-struct token bad_head, good_head;
-struct token *hash_table[HASH_TABLE_SIZE];
+int token_profit[0x10000];
/* the table that holds the result of the compression */
-unsigned char best_table[256][MAX_TOK_SIZE+1];
+unsigned char best_table[256][2];
unsigned char best_table_len[256];
-static void
-usage(void)
+static void usage(void)
{
fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
exit(1);
@@ -102,21 +64,19 @@
* This ignores the intensely annoying "mapping symbols" found
* in ARM ELF files: $a, $t and $d.
*/
-static inline int
-is_arm_mapping_symbol(const char *str)
+static inline int is_arm_mapping_symbol(const char *str)
{
return str[0] == '$' && strchr("atd", str[1])
&& (str[2] == '\0' || str[2] == '.');
}
-static int
-read_symbol(FILE *in, struct sym_entry *s)
+static int read_symbol(FILE *in, struct sym_entry *s)
{
char str[500];
- char *sym;
+ char *sym, stype;
int rc;
- rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str);
+ rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
if (rc != 3) {
if (rc != EOF) {
/* skip line */
@@ -143,7 +103,7 @@
_sextratext = s->addr;
else if (strcmp(sym, "_eextratext") == 0)
_eextratext = s->addr;
- else if (toupper(s->type) == 'A')
+ else if (toupper(stype) == 'A')
{
/* Keep these useful absolute symbols */
if (strcmp(sym, "__kernel_syscall_via_break") &&
@@ -153,22 +113,24 @@
return -1;
}
- else if (toupper(s->type) == 'U' ||
+ else if (toupper(stype) == 'U' ||
is_arm_mapping_symbol(sym))
return -1;
+ /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
+ else if (str[0] == '$')
+ return -1;
/* include the type field in the symbol name, so that it gets
* compressed together */
s->len = strlen(str) + 1;
- s->sym = (char *) malloc(s->len + 1);
- strcpy(s->sym + 1, str);
- s->sym[0] = s->type;
+ s->sym = malloc(s->len + 1);
+ strcpy((char *)s->sym + 1, str);
+ s->sym[0] = stype;
return 0;
}
-static int
-symbol_valid(struct sym_entry *s)
+static int symbol_valid(struct sym_entry *s)
{
/* Symbols which vary between passes. Passes 1 and 2 must have
* identical symbol lists. The kallsyms_* symbols below are only added
@@ -207,37 +169,36 @@
* move then they may get dropped in pass 2, which breaks the
* kallsyms rules.
*/
- if ((s->addr == _etext && strcmp(s->sym + offset, "_etext")) ||
- (s->addr == _einittext && strcmp(s->sym + offset, "_einittext")) ||
- (s->addr == _eextratext && strcmp(s->sym + offset, "_eextratext")))
+ if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
+ (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
+ (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
return 0;
}
/* Exclude symbols which vary between passes. */
- if (strstr(s->sym + offset, "_compiled."))
+ if (strstr((char *)s->sym + offset, "_compiled."))
return 0;
for (i = 0; special_symbols[i]; i++)
- if( strcmp(s->sym + offset, special_symbols[i]) == 0 )
+ if( strcmp((char *)s->sym + offset, special_symbols[i]) == 0 )
return 0;
return 1;
}
-static void
-read_map(FILE *in)
+static void read_map(FILE *in)
{
while (!feof(in)) {
- if (cnt >= size) {
- size += 10000;
- table = realloc(table, sizeof(*table) * size);
+ if (table_cnt >= table_size) {
+ table_size += 10000;
+ table = realloc(table, sizeof(*table) * table_size);
if (!table) {
fprintf(stderr, "out of memory\n");
exit (1);
}
}
- if (read_symbol(in, &table[cnt]) == 0)
- cnt++;
+ if (read_symbol(in, &table[table_cnt]) == 0)
+ table_cnt++;
}
}
@@ -281,10 +242,9 @@
return total;
}
-static void
-write_src(void)
+static void write_src(void)
{
- int i, k, off, valid;
+ unsigned int i, k, off;
unsigned int best_idx[256];
unsigned int *markers;
char buf[KSYM_NAME_LEN+1];
@@ -301,33 +261,24 @@
printf(".data\n");
output_label("kallsyms_addresses");
- valid = 0;
- for (i = 0; i < cnt; i++) {
- if (table[i].flags & SYM_FLAG_VALID) {
- printf("\tPTR\t%#llx\n", table[i].addr);
- valid++;
- }
+ for (i = 0; i < table_cnt; i++) {
+ printf("\tPTR\t%#llx\n", table[i].addr);
}
printf("\n");
output_label("kallsyms_num_syms");
- printf("\tPTR\t%d\n", valid);
+ printf("\tPTR\t%d\n", table_cnt);
printf("\n");
/* table of offset markers, that give the offset in the compressed stream
* every 256 symbols */
- markers = (unsigned int *) malloc(sizeof(unsigned int)*((valid + 255) / 256));
+ markers = (unsigned int *) malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
output_label("kallsyms_names");
- valid = 0;
off = 0;
- for (i = 0; i < cnt; i++) {
-
- if (!table[i].flags & SYM_FLAG_VALID)
- continue;
-
- if ((valid & 0xFF) == 0)
- markers[valid >> 8] = off;
+ for (i = 0; i < table_cnt; i++) {
+ if ((i & 0xFF) == 0)
+ markers[i >> 8] = off;
printf("\t.byte 0x%02x", table[i].len);
for (k = 0; k < table[i].len; k++)
@@ -335,12 +286,11 @@
printf("\n");
off += table[i].len + 1;
- valid++;
}
printf("\n");
output_label("kallsyms_markers");
- for (i = 0; i < ((valid + 255) >> 8); i++)
+ for (i = 0; i < ((table_cnt + 255) >> 8); i++)
printf("\tPTR\t%d\n", markers[i]);
printf("\n");
@@ -350,7 +300,7 @@
off = 0;
for (i = 0; i < 256; i++) {
best_idx[i] = off;
- expand_symbol(best_table[i],best_table_len[i],buf);
+ expand_symbol(best_table[i], best_table_len[i], buf);
printf("\t.asciz\t\"%s\"\n", buf);
off += strlen(buf) + 1;
}
@@ -365,153 +315,13 @@
/* table lookup compression functions */
-static inline unsigned int rehash_token(unsigned int hash, unsigned char data)
-{
- return ((hash * 16777619) ^ data);
-}
-
-static unsigned int hash_token(unsigned char *data, int len)
-{
- unsigned int hash=HASH_BASE_OFFSET;
- int i;
-
- for (i = 0; i < len; i++)
- hash = rehash_token(hash, data[i]);
-
- return HASH_FOLD(hash);
-}
-
-/* find a token given its data and hash value */
-static struct token *find_token_hash(unsigned char *data, int len, unsigned int hash)
-{
- struct token *ptr;
-
- ptr = hash_table[hash];
-
- while (ptr) {
- if ((ptr->len == len) && (memcmp(ptr->data, data, len) == 0))
- return ptr;
- ptr=ptr->next;
- }
-
- return NULL;
-}
-
-static inline void insert_token_in_group(struct token *head, struct token *ptr)
-{
- ptr->right = head->right;
- ptr->right->left = ptr;
- head->right = ptr;
- ptr->left = head;
-}
-
-static inline void remove_token_from_group(struct token *ptr)
-{
- ptr->left->right = ptr->right;
- ptr->right->left = ptr->left;
-}
-
-
-/* build the counts for all the tokens that start with "data", and have lenghts
- * from 2 to "len" */
-static void learn_token(unsigned char *data, int len)
-{
- struct token *ptr,*last_ptr;
- int i, newprofit;
- unsigned int hash = HASH_BASE_OFFSET;
- unsigned int hashes[MAX_TOK_SIZE + 1];
-
- if (len > MAX_TOK_SIZE)
- len = MAX_TOK_SIZE;
-
- /* calculate and store the hash values for all the sub-tokens */
- hash = rehash_token(hash, data[0]);
- for (i = 2; i <= len; i++) {
- hash = rehash_token(hash, data[i-1]);
- hashes[i] = HASH_FOLD(hash);
- }
-
- last_ptr = NULL;
- ptr = NULL;
-
- for (i = len; i >= 2; i--) {
- hash = hashes[i];
-
- if (!ptr) ptr = find_token_hash(data, i, hash);
-
- if (!ptr) {
- /* create a new token entry */
- ptr = (struct token *) malloc(sizeof(*ptr));
-
- memcpy(ptr->data, data, i);
- ptr->len = i;
-
- /* when we create an entry, it's profit is 0 because
- * we also take into account the size of the token on
- * the compressed table. We then subtract GOOD_BAD_THRESHOLD
- * so that the test to see if this token belongs to
- * the good or bad list, is a comparison to zero */
- ptr->profit = -GOOD_BAD_THRESHOLD;
-
- ptr->next = hash_table[hash];
- hash_table[hash] = ptr;
-
- insert_token_in_group(&bad_head, ptr);
-
- ptr->smaller = NULL;
- } else {
- newprofit = ptr->profit + (ptr->len - 1);
- /* check to see if this token needs to be moved to a
- * different list */
- if((ptr->profit < 0) && (newprofit >= 0)) {
- remove_token_from_group(ptr);
- insert_token_in_group(&good_head,ptr);
- }
- ptr->profit = newprofit;
- }
-
- if (last_ptr) last_ptr->smaller = ptr;
- last_ptr = ptr;
-
- ptr = ptr->smaller;
- }
-}
-
-/* decrease the counts for all the tokens that start with "data", and have lenghts
- * from 2 to "len". This function is much simpler than learn_token because we have
- * more guarantees (tho tokens exist, the ->smaller pointer is set, etc.)
- * The two separate functions exist only because of compression performance */
-static void forget_token(unsigned char *data, int len)
-{
- struct token *ptr;
- int i, newprofit;
- unsigned int hash=0;
-
- if (len > MAX_TOK_SIZE) len = MAX_TOK_SIZE;
-
- hash = hash_token(data, len);
- ptr = find_token_hash(data, len, hash);
-
- for (i = len; i >= 2; i--) {
-
- newprofit = ptr->profit - (ptr->len - 1);
- if ((ptr->profit >= 0) && (newprofit < 0)) {
- remove_token_from_group(ptr);
- insert_token_in_group(&bad_head, ptr);
- }
- ptr->profit=newprofit;
-
- ptr=ptr->smaller;
- }
-}
-
/* count all the possible tokens in a symbol */
static void learn_symbol(unsigned char *symbol, int len)
{
int i;
for (i = 0; i < len - 1; i++)
- learn_token(symbol + i, len - i);
+ token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
}
/* decrease the count for all the possible tokens in a symbol */
@@ -520,117 +330,90 @@
int i;
for (i = 0; i < len - 1; i++)
- forget_token(symbol + i, len - i);
+ token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
}
-/* set all the symbol flags and do the initial token count */
+/* remove all the invalid symbols from the table and do the initial token count */
static void build_initial_tok_table(void)
{
- int i, use_it, valid;
+ unsigned int i, pos;
- valid = 0;
- for (i = 0; i < cnt; i++) {
- table[i].flags = 0;
+ pos = 0;
+ for (i = 0; i < table_cnt; i++) {
if ( symbol_valid(&table[i]) ) {
- table[i].flags |= SYM_FLAG_VALID;
- valid++;
+ if (pos != i)
+ table[pos] = table[i];
+ learn_symbol(table[pos].sym, table[pos].len);
+ pos++;
}
}
-
- use_it = 0;
- for (i = 0; i < cnt; i++) {
-
- /* subsample the available symbols. This method is almost like
- * a Bresenham's algorithm to get uniformly distributed samples
- * across the symbol table */
- if (table[i].flags & SYM_FLAG_VALID) {
-
- use_it += WORKING_SET;
-
- if (use_it >= valid) {
- table[i].flags |= SYM_FLAG_SAMPLED;
- use_it -= valid;
- }
- }
- if (table[i].flags & SYM_FLAG_SAMPLED)
- learn_symbol(table[i].sym, table[i].len);
- }
+ table_cnt = pos;
}
/* replace a given token in all the valid symbols. Use the sampled symbols
* to update the counts */
-static void compress_symbols(unsigned char *str, int tlen, int idx)
+static void compress_symbols(unsigned char *str, int idx)
{
- int i, len, learn, size;
- unsigned char *p;
+ unsigned int i, len, size;
+ unsigned char *p1, *p2;
- for (i = 0; i < cnt; i++) {
-
- if (!(table[i].flags & SYM_FLAG_VALID)) continue;
+ for (i = 0; i < table_cnt; i++) {
len = table[i].len;
- learn = 0;
- p = table[i].sym;
+ p1 = table[i].sym;
+
+ /* find the token on the symbol */
+ p2 = memmem(p1, len, str, 2);
+ if (!p2) continue;
+
+ /* decrease the counts for this symbol's tokens */
+ forget_symbol(table[i].sym, len);
+
+ size = len;
do {
+ *p2 = idx;
+ p2++;
+ size -= (p2 - p1);
+ memmove(p2, p2 + 1, size);
+ p1 = p2;
+ len--;
+
+ if (size < 2) break;
+
/* find the token on the symbol */
- p = (unsigned char *) strstr((char *) p, (char *) str);
- if (!p) break;
+ p2 = memmem(p1, size, str, 2);
- if (!learn) {
- /* if this symbol was used to count, decrease it */
- if (table[i].flags & SYM_FLAG_SAMPLED)
- forget_symbol(table[i].sym, len);
- learn = 1;
- }
+ } while (p2);
- *p = idx;
- size = (len - (p - table[i].sym)) - tlen + 1;
- memmove(p + 1, p + tlen, size);
- p++;
- len -= tlen - 1;
+ table[i].len = len;
- } while (size >= tlen);
-
- if(learn) {
- table[i].len = len;
- /* if this symbol was used to count, learn it again */
- if(table[i].flags & SYM_FLAG_SAMPLED)
- learn_symbol(table[i].sym, len);
- }
+ /* increase the counts for this symbol's new tokens */
+ learn_symbol(table[i].sym, len);
}
}
/* search the token with the maximum profit */
-static struct token *find_best_token(void)
+static int find_best_token(void)
{
- struct token *ptr,*best,*head;
- int bestprofit;
+ int i, best, bestprofit;
bestprofit=-10000;
+ best = 0;
- /* failsafe: if the "good" list is empty search from the "bad" list */
- if(good_head.right == &good_head) head = &bad_head;
- else head = &good_head;
-
- ptr = head->right;
- best = NULL;
- while (ptr != head) {
- if (ptr->profit > bestprofit) {
- bestprofit = ptr->profit;
- best = ptr;
+ for (i = 0; i < 0x10000; i++) {
+ if (token_profit[i] > bestprofit) {
+ best = i;
+ bestprofit = token_profit[i];
}
- ptr = ptr->right;
}
-
return best;
}
/* this is the core of the algorithm: calculate the "best" table */
static void optimize_result(void)
{
- struct token *best;
- int i;
+ int i, best;
/* using the '\0' symbol last allows compress_symbols to use standard
* fast string functions */
@@ -644,14 +427,12 @@
best = find_best_token();
/* place it in the "best" table */
- best_table_len[i] = best->len;
- memcpy(best_table[i], best->data, best_table_len[i]);
- /* zero terminate the token so that we can use strstr
- in compress_symbols */
- best_table[i][best_table_len[i]]='\0';
+ best_table_len[i] = 2;
+ best_table[i][0] = best & 0xFF;
+ best_table[i][1] = (best >> 8) & 0xFF;
/* replace this token in all the valid symbols */
- compress_symbols(best_table[i], best_table_len[i], i);
+ compress_symbols(best_table[i], i);
}
}
}
@@ -659,39 +440,28 @@
/* start by placing the symbols that are actually used on the table */
static void insert_real_symbols_in_table(void)
{
- int i, j, c;
+ unsigned int i, j, c;
memset(best_table, 0, sizeof(best_table));
memset(best_table_len, 0, sizeof(best_table_len));
- for (i = 0; i < cnt; i++) {
- if (table[i].flags & SYM_FLAG_VALID) {
- for (j = 0; j < table[i].len; j++) {
- c = table[i].sym[j];
- best_table[c][0]=c;
- best_table_len[c]=1;
- }
+ for (i = 0; i < table_cnt; i++) {
+ for (j = 0; j < table[i].len; j++) {
+ c = table[i].sym[j];
+ best_table[c][0]=c;
+ best_table_len[c]=1;
}
}
}
static void optimize_token_table(void)
{
- memset(hash_table, 0, sizeof(hash_table));
-
- good_head.left = &good_head;
- good_head.right = &good_head;
-
- bad_head.left = &bad_head;
- bad_head.right = &bad_head;
-
build_initial_tok_table();
insert_real_symbols_in_table();
/* When valid symbol is not registered, exit to error */
- if (good_head.left == good_head.right &&
- bad_head.left == bad_head.right) {
+ if (!table_cnt) {
fprintf(stderr, "No valid symbol.\n");
exit(1);
}
@@ -700,8 +470,7 @@
}
-int
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
if (argc >= 2) {
int i;
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 09abb89..2fcb244 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -27,8 +27,20 @@
xgettext --default-domain=linux \
--add-comments --keyword=_ --keyword=N_ \
--files-from=scripts/kconfig/POTFILES.in \
- -o scripts/kconfig/linux.pot
- scripts/kconfig/kxgettext arch/$(ARCH)/Kconfig >> scripts/kconfig/linux.pot
+ --output scripts/kconfig/config.pot
+ $(Q)ln -fs Kconfig_i386 arch/um/Kconfig_arch
+ $(Q)for i in `ls arch/`; \
+ do \
+ scripts/kconfig/kxgettext arch/$$i/Kconfig \
+ | msguniq -o scripts/kconfig/linux_$${i}.pot; \
+ done
+ $(Q)msgcat scripts/kconfig/config.pot \
+ `find scripts/kconfig/ -type f -name linux_*.pot` \
+ --output scripts/kconfig/linux_raw.pot
+ $(Q)msguniq --sort-by-file scripts/kconfig/linux_raw.pot \
+ --output scripts/kconfig/linux.pot
+ $(Q)rm -f arch/um/Kconfig_arch
+ $(Q)rm -f scripts/kconfig/linux_*.pot scripts/kconfig/config.pot
.PHONY: randconfig allyesconfig allnoconfig allmodconfig defconfig
diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c
index 1c88d7c..abee55c 100644
--- a/scripts/kconfig/kxgettext.c
+++ b/scripts/kconfig/kxgettext.c
@@ -14,6 +14,11 @@
{
char *bfp = bf;
int multiline = strchr(text, '\n') != NULL;
+ int eol = 0;
+ int textlen = strlen(text);
+
+ if ((textlen > 0) && (text[textlen-1] == '\n'))
+ eol = 1;
*bfp++ = '"';
--len;
@@ -43,7 +48,7 @@
--len;
}
- if (multiline)
+ if (multiline && eol)
bfp -= 3;
*bfp++ = '"';
@@ -179,7 +184,11 @@
{
struct file_line *fl = self->files;
- printf("\n#: %s:%d", fl->file, fl->lineno);
+ putchar('\n');
+ if (self->option != NULL)
+ printf("# %s:00000\n", self->option);
+
+ printf("#: %s:%d", fl->file, fl->lineno);
fl = fl->next;
while (fl != NULL) {
@@ -187,9 +196,6 @@
fl = fl->next;
}
- if (self->option != NULL)
- printf(", %s:00000", self->option);
-
putchar('\n');
}
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 8b84c42..c3d2578 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -59,7 +59,7 @@
void menu_end_entry(void);
void menu_add_dep(struct expr *dep);
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
-void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_finalize(struct menu *parent);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 8c59b21..5cfa6c4 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -136,9 +136,9 @@
return prop;
}
-void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
{
- menu_add_prop(type, prompt, NULL, dep);
+ return menu_add_prop(type, prompt, NULL, dep);
}
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index f163d8d..ff4fcc0 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -1531,7 +1531,7 @@
{
menu_add_entry(NULL);
- menu_add_prop(P_MENU, yyvsp[-1].string, NULL, NULL);
+ menu_add_prompt(P_MENU, yyvsp[-1].string, NULL);
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
;}
break;
@@ -1586,7 +1586,7 @@
{
menu_add_entry(NULL);
- menu_add_prop(P_COMMENT, yyvsp[-1].string, NULL, NULL);
+ menu_add_prompt(P_COMMENT, yyvsp[-1].string, NULL);
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
;}
break;
@@ -1640,7 +1640,7 @@
case 86:
{
- menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr);
+ menu_add_prompt(P_PROMPT, yyvsp[-1].string, yyvsp[0].expr);
;}
break;
@@ -1925,7 +1925,7 @@
sym_init();
menu_init();
modules_sym = sym_lookup("MODULES", 0);
- rootmenu.prompt = menu_add_prop(P_MENU, "Linux Kernel Configuration", NULL, NULL);
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
//zconfdebug = 1;
zconfparse();
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 54460f8..e1a0f45 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -342,7 +342,7 @@
menu: T_MENU prompt T_EOL
{
menu_add_entry(NULL);
- menu_add_prop(P_MENU, $2, NULL, NULL);
+ menu_add_prompt(P_MENU, $2, NULL);
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
};
@@ -392,7 +392,7 @@
comment: T_COMMENT prompt T_EOL
{
menu_add_entry(NULL);
- menu_add_prop(P_COMMENT, $2, NULL, NULL);
+ menu_add_prompt(P_COMMENT, $2, NULL);
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
};
@@ -443,7 +443,7 @@
/* empty */
| prompt if_expr
{
- menu_add_prop(P_PROMPT, $1, NULL, $2);
+ menu_add_prompt(P_PROMPT, $1, $2);
};
prompt: T_WORD
@@ -487,7 +487,7 @@
sym_init();
menu_init();
modules_sym = sym_lookup("MODULES", 0);
- rootmenu.prompt = menu_add_prop(P_MENU, "Linux Kernel Configuration", NULL, NULL);
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
//zconfdebug = 1;
zconfparse();
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 0835dc2..8aaf74e6 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1665,11 +1665,17 @@
}
sub process_file($) {
- my ($file) = "$ENV{'SRCTREE'}@_";
+ my $file;
my $identifier;
my $func;
my $initial_section_counter = $section_counter;
+ if (defined($ENV{'SRCTREE'})) {
+ $file = "$ENV{'SRCTREE'}" . "/" . "@_";
+ }
+ else {
+ $file = "@_";
+ }
if (defined($source_map{$file})) {
$file = $source_map{$file};
}
diff --git a/scripts/lxdialog/dialog.h b/scripts/lxdialog/dialog.h
index c571548..eb63e1b 100644
--- a/scripts/lxdialog/dialog.h
+++ b/scripts/lxdialog/dialog.h
@@ -163,7 +163,7 @@
int dialog_checklist (const char *title, const char *prompt, int height,
int width, int list_height, int item_no,
const char * const * items, int flag);
-extern unsigned char dialog_input_result[];
+extern char dialog_input_result[];
int dialog_inputbox (const char *title, const char *prompt, int height,
int width, const char *init);
diff --git a/scripts/lxdialog/inputbox.c b/scripts/lxdialog/inputbox.c
index fa7bebc..074d2d6 100644
--- a/scripts/lxdialog/inputbox.c
+++ b/scripts/lxdialog/inputbox.c
@@ -21,7 +21,7 @@
#include "dialog.h"
-unsigned char dialog_input_result[MAX_LEN + 1];
+char dialog_input_result[MAX_LEN + 1];
/*
* Print the termination buttons
@@ -48,7 +48,7 @@
{
int i, x, y, box_y, box_x, box_width;
int input_x = 0, scroll = 0, key = 0, button = -1;
- unsigned char *instr = dialog_input_result;
+ char *instr = dialog_input_result;
WINDOW *dialog;
/* center dialog box on screen */
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index 8d118d1..d7b8a38 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -1,7 +1,8 @@
TARGET=$1
ARCH=$2
SMP=$3
-CC=$4
+PREEMPT=$4
+CC=$5
# If compile.h exists already and we don't own autoconf.h
# (i.e. we're not the same user who did make *config), don't
@@ -26,8 +27,10 @@
UTS_VERSION="#$VERSION"
-if [ -n "$SMP" ] ; then UTS_VERSION="$UTS_VERSION SMP"; fi
-UTS_VERSION="$UTS_VERSION `LC_ALL=C LANG=C date`"
+CONFIG_FLAGS=""
+if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
+if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
+UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS `LC_ALL=C LANG=C date`"
# Truncate to maximum length
@@ -37,7 +40,8 @@
# Generate a temporary compile.h
( echo /\* This file is auto generated, version $VERSION \*/
-
+ if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
+
echo \#define UTS_MACHINE \"$ARCH\"
echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index 1112347..43271a1 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -252,9 +252,9 @@
}
/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
-static int parse_file(const signed char *fname, struct md4_ctx *md)
+static int parse_file(const char *fname, struct md4_ctx *md)
{
- signed char *file;
+ char *file;
unsigned long i, len;
file = grab_file(fname, &len);
@@ -332,7 +332,7 @@
Sum all files in the same dir or subdirs.
*/
while ((line = get_next_line(&pos, file, flen)) != NULL) {
- signed char* p = line;
+ char* p = line;
if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
check_files = 1;
continue;
@@ -458,7 +458,7 @@
close(fd);
}
-static int strip_rcs_crap(signed char *version)
+static int strip_rcs_crap(char *version)
{
unsigned int len, full_len;
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
index 3b1f2ef..f3e7e8e 100644
--- a/scripts/package/Makefile
+++ b/scripts/package/Makefile
@@ -59,7 +59,7 @@
$(CONFIG_SHELL) $(MKSPEC) prebuilt > $@
binrpm-pkg: $(objtree)/binkernel.spec
- $(MAKE)
+ $(MAKE) KBUILD_SRC=
set -e; \
$(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
set -e; \
@@ -74,16 +74,30 @@
#
.PHONY: deb-pkg
deb-pkg:
- $(MAKE)
+ $(MAKE) KBUILD_SRC=
$(CONFIG_SHELL) $(srctree)/scripts/package/builddeb
clean-dirs += $(objtree)/debian/
+# tarball targets
+# ---------------------------------------------------------------------------
+.PHONY: tar%pkg
+tar%pkg:
+ $(MAKE)
+ $(CONFIG_SHELL) $(srctree)/scripts/package/buildtar $@
+
+clean-dirs += $(objtree)/tar-install/
+
+
# Help text displayed when executing 'make help'
# ---------------------------------------------------------------------------
help:
- @echo ' rpm-pkg - Build the kernel as an RPM package'
- @echo ' binrpm-pkg - Build an rpm package containing the compiled kernel & modules'
- @echo ' deb-pkg - Build the kernel as an deb package'
+ @echo ' rpm-pkg - Build the kernel as an RPM package'
+ @echo ' binrpm-pkg - Build an rpm package containing the compiled kernel'
+ @echo ' and modules'
+ @echo ' deb-pkg - Build the kernel as an deb package'
+ @echo ' tar-pkg - Build the kernel as an uncompressed tarball'
+ @echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
+ @echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball'
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index c279b63..6edb29f 100644
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -14,18 +14,38 @@
# Some variables and settings used throughout the script
version=$KERNELRELEASE
tmpdir="$objtree/debian/tmp"
+packagename=linux-$version
+
+if [ "$ARCH" == "um" ] ; then
+ packagename=user-mode-linux-$version
+fi
# Setup the directory structure
rm -rf "$tmpdir"
mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot"
+if [ "$ARCH" == "um" ] ; then
+ mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/share/doc/$packagename" "$tmpdir/usr/bin"
+fi
# Build and install the kernel
-cp System.map "$tmpdir/boot/System.map-$version"
-cp .config "$tmpdir/boot/config-$version"
-cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+if [ "$ARCH" == "um" ] ; then
+ $MAKE linux
+ cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
+ cp .config "$tmpdir/usr/share/doc/$packagename/config"
+ gzip "$tmpdir/usr/share/doc/$packagename/config"
+ cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version"
+else
+ cp System.map "$tmpdir/boot/System.map-$version"
+ cp .config "$tmpdir/boot/config-$version"
+ cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+fi
if grep -q '^CONFIG_MODULES=y' .config ; then
- INSTALL_MOD_PATH="$tmpdir" make modules_install
+ INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install
+ if [ "$ARCH" == "um" ] ; then
+ mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
+ rmdir "$tmpdir/lib/modules/$version"
+ fi
fi
# Install the maintainer scripts
@@ -53,6 +73,8 @@
EOF
# Generate a control file
+if [ "$ARCH" == "um" ]; then
+
cat <<EOF > debian/control
Source: linux
Section: base
@@ -60,12 +82,34 @@
Maintainer: $name
Standards-Version: 3.6.1
-Package: linux-$version
+Package: $packagename
+Architecture: any
+Description: User Mode Linux kernel, version $version
+ User-mode Linux is a port of the Linux kernel to its own system call
+ interface. It provides a kind of virtual machine, which runs Linux
+ as a user process under another Linux kernel. This is useful for
+ kernel development, sandboxes, jails, experimentation, and
+ many other things.
+ .
+ This package contains the Linux kernel, modules and corresponding other
+ files version $version
+EOF
+
+else
+cat <<EOF > debian/control
+Source: linux
+Section: base
+Priority: optional
+Maintainer: $name
+Standards-Version: 3.6.1
+
+Package: $packagename
Architecture: any
Description: Linux kernel, version $version
This package contains the Linux kernel, modules and corresponding other
- files version $version.
+ files version $version
EOF
+fi
# Fix some ownership and permissions
chown -R root:root "$tmpdir"
diff --git a/scripts/package/buildtar b/scripts/package/buildtar
new file mode 100644
index 0000000..d8fffe6
--- /dev/null
+++ b/scripts/package/buildtar
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+#
+# buildtar 0.0.3
+#
+# (C) 2004-2005 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
+#
+# This script is used to compile a tarball from the currently
+# prepared kernel. Based upon the builddeb script from
+# Wichert Akkerman <wichert@wiggy.net>.
+#
+
+set -e
+
+#
+# Some variables and settings used throughout the script
+#
+version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}${EXTRANAME}"
+tmpdir="${objtree}/tar-install"
+tarball="${objtree}/linux-${version}.tar"
+
+
+#
+# Figure out how to compress, if requested at all
+#
+case "${1}" in
+ tar-pkg)
+ compress="cat"
+ file_ext=""
+ ;;
+ targz-pkg)
+ compress="gzip -c9"
+ file_ext=".gz"
+ ;;
+ tarbz2-pkg)
+ compress="bzip2 -c9"
+ file_ext=".bz2"
+ ;;
+ *)
+ echo "Unknown tarball target \"${1}\" requested, please add it to ${0}." >&2
+ exit 1
+ ;;
+esac
+
+
+#
+# Clean-up and re-create the temporary directory
+#
+rm -rf -- "${tmpdir}"
+mkdir -p -- "${tmpdir}/boot"
+
+
+#
+# Try to install modules
+#
+if ! make INSTALL_MOD_PATH="${tmpdir}" modules_install; then
+ echo "" >&2
+ echo "Ignoring error at module_install time, since that could be" >&2
+ echo "a result of missing local modutils/module-init-tools," >&2
+ echo "or you just didn't compile in module support at all..." >&2
+ echo "" >&2
+fi
+
+
+#
+# Install basic kernel files
+#
+cp -v -- System.map "${tmpdir}/boot/System.map-${version}"
+cp -v -- .config "${tmpdir}/boot/config-${version}"
+cp -v -- vmlinux "${tmpdir}/boot/vmlinux-${version}"
+
+
+#
+# Install arch-specific kernel image(s)
+#
+case "${ARCH}" in
+ i386)
+ [ -f arch/i386/boot/bzImage ] && cp -v -- arch/i386/boot/bzImage "${tmpdir}/boot/vmlinuz-${version}"
+ ;;
+ alpha)
+ [ -f arch/alpha/boot/vmlinux.gz ] && cp -v -- arch/alpha/boot/vmlinux.gz "${tmpdir}/boot/vmlinuz-${version}"
+ ;;
+ vax)
+ [ -f vmlinux.SYS ] && cp -v -- vmlinux.SYS "${tmpdir}/boot/vmlinux-${version}.SYS"
+ [ -f vmlinux.dsk ] && cp -v -- vmlinux.dsk "${tmpdir}/boot/vmlinux-${version}.dsk"
+ ;;
+ *)
+ [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${version}"
+ echo "" >&2
+ echo '** ** ** WARNING ** ** **' >&2
+ echo "" >&2
+ echo "Your architecture did not define any architecture-dependant files" >&2
+ echo "to be placed into the tarball. Please add those to ${0} ..." >&2
+ echo "" >&2
+ sleep 5
+ ;;
+esac
+
+
+#
+# Create the tarball
+#
+(
+ cd "${tmpdir}"
+ tar cf - . | ${compress} > "${tarball}${file_ext}"
+)
+
+echo "Tarball successfully created in ${tarball}${file_ext}"
+
+exit 0
+
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index 6e7a58f..0b10387 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -62,10 +62,19 @@
fi
echo "%install"
+echo "%ifarch ia64"
+echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
+echo "%else"
echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
+echo "%endif"
echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install'
+echo "%ifarch ia64"
+echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
+echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
+echo "%else"
echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
+echo "%endif"
echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
diff --git a/scripts/reference_discarded.pl b/scripts/reference_discarded.pl
index d5cabb8..f04f627 100644
--- a/scripts/reference_discarded.pl
+++ b/scripts/reference_discarded.pl
@@ -96,6 +96,7 @@
$from !~ /\.debug_ranges$/ &&
$from !~ /\.debug_line$/ &&
$from !~ /\.debug_frame$/ &&
+ $from !~ /\.debug_loc$/ &&
$from !~ /\.exitcall\.exit$/ &&
$from !~ /\.eh_frame$/ &&
$from !~ /\.stab$/)) {
diff --git a/scripts/reference_init.pl b/scripts/reference_init.pl
index 9a24084..7f6960b 100644
--- a/scripts/reference_init.pl
+++ b/scripts/reference_init.pl
@@ -98,6 +98,7 @@
$from !~ /\.pdr$/ &&
$from !~ /\__param$/ &&
$from !~ /\.altinstructions/ &&
+ $from !~ /\.eh_frame/ &&
$from !~ /\.debug_/)) {
printf("Error: %s %s refers to %s\n", $object, $from, $line);
}
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
new file mode 100644
index 0000000..7c805c8
--- /dev/null
+++ b/scripts/setlocalversion
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+# Copyright 2004 - Ryan Anderson <ryan@michonline.com> GPL v2
+
+use strict;
+use warnings;
+use Digest::MD5;
+require 5.006;
+
+if (@ARGV != 1) {
+ print <<EOT;
+Usage: setlocalversion <srctree>
+EOT
+ exit(1);
+}
+
+my ($srctree) = @ARGV;
+chdir($srctree);
+
+my @LOCALVERSIONS = ();
+
+# We are going to use the following commands to try and determine if this
+# repository is at a Version boundary (i.e, 2.6.10 vs 2.6.10 + some patches) We
+# currently assume that all meaningful version boundaries are marked by a tag.
+# We don't care what the tag is, just that something exists.
+
+# Git/Cogito store the top-of-tree "commit" in .git/HEAD
+# A list of known tags sits in .git/refs/tags/
+#
+# The simple trick here is to just compare the two of these, and if we get a
+# match, return nothing, otherwise, return a subset of the SHA-1 hash in
+# .git/HEAD
+
+sub do_git_checks {
+ open(H,"<.git/HEAD") or return;
+ my $head = <H>;
+ chomp $head;
+ close(H);
+
+ opendir(D,".git/refs/tags") or return;
+ foreach my $tagfile (grep !/^\.{1,2}$/, readdir(D)) {
+ open(F,"<.git/refs/tags/" . $tagfile) or return;
+ my $tag = <F>;
+ chomp $tag;
+ close(F);
+ return if ($tag eq $head);
+ }
+ closedir(D);
+
+ push @LOCALVERSIONS, "g" . substr($head,0,8);
+}
+
+if ( -d ".git") {
+ do_git_checks();
+}
+
+printf "-%s\n", join("-",@LOCALVERSIONS) if (scalar @LOCALVERSIONS > 0);
diff --git a/scripts/ver_linux b/scripts/ver_linux
index a28c279..beb43ef7 100755
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -25,9 +25,11 @@
'/BFD/{print "binutils ",$NF} \
/^GNU/{print "binutils ",$4}'
-fdformat --version | awk -F\- '{print "util-linux ", $NF}'
+echo -n "util-linux "
+fdformat --version | awk '{print $NF}' | sed -e s/^util-linux-// -e s/\)$//
-mount --version | awk -F\- '{print "mount ", $NF}'
+echo -n "mount "
+mount --version | awk '{print $NF}' | sed -e s/^mount-// -e s/\)$//
depmod -V 2>&1 | awk 'NR==1 {print "module-init-tools ",$NF}'
diff --git a/security/seclvl.c b/security/seclvl.c
index c8e87b2..96b1f21 100644
--- a/security/seclvl.c
+++ b/security/seclvl.c
@@ -321,7 +321,7 @@
"bytes.\n", len, PAGE_SIZE);
return -ENOMEM;
}
- tfm = crypto_alloc_tfm("sha1", 0);
+ tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
if (tfm == NULL) {
seclvl_printk(0, KERN_ERR,
"Failed to load transform for SHA1\n");
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 4515024..cf6020f 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -490,7 +490,7 @@
}
static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
- struct in6_addr *addr, u16 port,
+ struct in6_addr *addr, __be16 port,
char *name1, char *name2)
{
if (!ipv6_addr_any(addr))
@@ -501,7 +501,7 @@
}
static inline void avc_print_ipv4_addr(struct audit_buffer *ab, u32 addr,
- u16 port, char *name1, char *name2)
+ __be16 port, char *name1, char *name2)
{
if (addr)
audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 71c0a19..5f016c9 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -23,10 +23,11 @@
#define POLICYDB_VERSION_NLCLASS 18
#define POLICYDB_VERSION_VALIDATETRANS 19
#define POLICYDB_VERSION_MLS 19
+#define POLICYDB_VERSION_AVTAB 20
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_MLS
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
extern int selinux_enabled;
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index f238c03..dde094f 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -58,6 +58,7 @@
{
int hvalue;
struct avtab_node *prev, *cur, *newnode;
+ u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
if (!h)
return -EINVAL;
@@ -69,7 +70,7 @@
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
- (datum->specified & cur->datum.specified))
+ (specified & cur->key.specified))
return -EEXIST;
if (key->source_type < cur->key.source_type)
break;
@@ -98,6 +99,7 @@
{
int hvalue;
struct avtab_node *prev, *cur, *newnode;
+ u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
if (!h)
return NULL;
@@ -108,7 +110,7 @@
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
- (datum->specified & cur->datum.specified))
+ (specified & cur->key.specified))
break;
if (key->source_type < cur->key.source_type)
break;
@@ -125,10 +127,11 @@
return newnode;
}
-struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
{
int hvalue;
struct avtab_node *cur;
+ u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
if (!h)
return NULL;
@@ -138,7 +141,7 @@
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
- (specified & cur->datum.specified))
+ (specified & cur->key.specified))
return &cur->datum;
if (key->source_type < cur->key.source_type)
@@ -159,10 +162,11 @@
* conjunction with avtab_search_next_node()
*/
struct avtab_node*
-avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
+avtab_search_node(struct avtab *h, struct avtab_key *key)
{
int hvalue;
struct avtab_node *cur;
+ u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
if (!h)
return NULL;
@@ -172,7 +176,7 @@
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
- (specified & cur->datum.specified))
+ (specified & cur->key.specified))
return cur;
if (key->source_type < cur->key.source_type)
@@ -196,11 +200,12 @@
if (!node)
return NULL;
+ specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
for (cur = node->next; cur; cur = cur->next) {
if (node->key.source_type == cur->key.source_type &&
node->key.target_type == cur->key.target_type &&
node->key.target_class == cur->key.target_class &&
- (specified & cur->datum.specified))
+ (specified & cur->key.specified))
return cur;
if (node->key.source_type < cur->key.source_type)
@@ -278,76 +283,129 @@
max_chain_len);
}
-int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
+static uint16_t spec_order[] = {
+ AVTAB_ALLOWED,
+ AVTAB_AUDITDENY,
+ AVTAB_AUDITALLOW,
+ AVTAB_TRANSITION,
+ AVTAB_CHANGE,
+ AVTAB_MEMBER
+};
+
+int avtab_read_item(void *fp, u32 vers, struct avtab *a,
+ int (*insertf)(struct avtab *a, struct avtab_key *k,
+ struct avtab_datum *d, void *p),
+ void *p)
{
- u32 buf[7];
- u32 items, items2;
- int rc;
+ __le16 buf16[4];
+ u16 enabled;
+ __le32 buf32[7];
+ u32 items, items2, val;
+ struct avtab_key key;
+ struct avtab_datum datum;
+ int i, rc;
- memset(avkey, 0, sizeof(struct avtab_key));
- memset(avdatum, 0, sizeof(struct avtab_datum));
+ memset(&key, 0, sizeof(struct avtab_key));
+ memset(&datum, 0, sizeof(struct avtab_datum));
- rc = next_entry(buf, fp, sizeof(u32));
+ if (vers < POLICYDB_VERSION_AVTAB) {
+ rc = next_entry(buf32, fp, sizeof(u32));
+ if (rc < 0) {
+ printk(KERN_ERR "security: avtab: truncated entry\n");
+ return -1;
+ }
+ items2 = le32_to_cpu(buf32[0]);
+ if (items2 > ARRAY_SIZE(buf32)) {
+ printk(KERN_ERR "security: avtab: entry overflow\n");
+ return -1;
+
+ }
+ rc = next_entry(buf32, fp, sizeof(u32)*items2);
+ if (rc < 0) {
+ printk(KERN_ERR "security: avtab: truncated entry\n");
+ return -1;
+ }
+ items = 0;
+
+ val = le32_to_cpu(buf32[items++]);
+ key.source_type = (u16)val;
+ if (key.source_type != val) {
+ printk("security: avtab: truncated source type\n");
+ return -1;
+ }
+ val = le32_to_cpu(buf32[items++]);
+ key.target_type = (u16)val;
+ if (key.target_type != val) {
+ printk("security: avtab: truncated target type\n");
+ return -1;
+ }
+ val = le32_to_cpu(buf32[items++]);
+ key.target_class = (u16)val;
+ if (key.target_class != val) {
+ printk("security: avtab: truncated target class\n");
+ return -1;
+ }
+
+ val = le32_to_cpu(buf32[items++]);
+ enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
+
+ if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
+ printk("security: avtab: null entry\n");
+ return -1;
+ }
+ if ((val & AVTAB_AV) &&
+ (val & AVTAB_TYPE)) {
+ printk("security: avtab: entry has both access vectors and types\n");
+ return -1;
+ }
+
+ for (i = 0; i < sizeof(spec_order)/sizeof(u16); i++) {
+ if (val & spec_order[i]) {
+ key.specified = spec_order[i] | enabled;
+ datum.data = le32_to_cpu(buf32[items++]);
+ rc = insertf(a, &key, &datum, p);
+ if (rc) return rc;
+ }
+ }
+
+ if (items != items2) {
+ printk("security: avtab: entry only had %d items, expected %d\n", items2, items);
+ return -1;
+ }
+ return 0;
+ }
+
+ rc = next_entry(buf16, fp, sizeof(u16)*4);
if (rc < 0) {
- printk(KERN_ERR "security: avtab: truncated entry\n");
- goto bad;
+ printk("security: avtab: truncated entry\n");
+ return -1;
}
- items2 = le32_to_cpu(buf[0]);
- if (items2 > ARRAY_SIZE(buf)) {
- printk(KERN_ERR "security: avtab: entry overflow\n");
- goto bad;
- }
- rc = next_entry(buf, fp, sizeof(u32)*items2);
- if (rc < 0) {
- printk(KERN_ERR "security: avtab: truncated entry\n");
- goto bad;
- }
+
items = 0;
- avkey->source_type = le32_to_cpu(buf[items++]);
- avkey->target_type = le32_to_cpu(buf[items++]);
- avkey->target_class = le32_to_cpu(buf[items++]);
- avdatum->specified = le32_to_cpu(buf[items++]);
- if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
- printk(KERN_ERR "security: avtab: null entry\n");
- goto bad;
- }
- if ((avdatum->specified & AVTAB_AV) &&
- (avdatum->specified & AVTAB_TYPE)) {
- printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
- goto bad;
- }
- if (avdatum->specified & AVTAB_AV) {
- if (avdatum->specified & AVTAB_ALLOWED)
- avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
- if (avdatum->specified & AVTAB_AUDITDENY)
- avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
- if (avdatum->specified & AVTAB_AUDITALLOW)
- avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
- } else {
- if (avdatum->specified & AVTAB_TRANSITION)
- avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
- if (avdatum->specified & AVTAB_CHANGE)
- avtab_change(avdatum) = le32_to_cpu(buf[items++]);
- if (avdatum->specified & AVTAB_MEMBER)
- avtab_member(avdatum) = le32_to_cpu(buf[items++]);
- }
- if (items != items2) {
- printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
- items2, items);
- goto bad;
- }
+ key.source_type = le16_to_cpu(buf16[items++]);
+ key.target_type = le16_to_cpu(buf16[items++]);
+ key.target_class = le16_to_cpu(buf16[items++]);
+ key.specified = le16_to_cpu(buf16[items++]);
- return 0;
-bad:
- return -1;
+ rc = next_entry(buf32, fp, sizeof(u32));
+ if (rc < 0) {
+ printk("security: avtab: truncated entry\n");
+ return -1;
+ }
+ datum.data = le32_to_cpu(*buf32);
+ return insertf(a, &key, &datum, p);
}
-int avtab_read(struct avtab *a, void *fp, u32 config)
+static int avtab_insertf(struct avtab *a, struct avtab_key *k,
+ struct avtab_datum *d, void *p)
+{
+ return avtab_insert(a, k, d);
+}
+
+int avtab_read(struct avtab *a, void *fp, u32 vers)
{
int rc;
- struct avtab_key avkey;
- struct avtab_datum avdatum;
- u32 buf[1];
+ __le32 buf[1];
u32 nel, i;
@@ -363,16 +421,14 @@
goto bad;
}
for (i = 0; i < nel; i++) {
- if (avtab_read_item(fp, &avdatum, &avkey)) {
- rc = -EINVAL;
- goto bad;
- }
- rc = avtab_insert(a, &avkey, &avdatum);
+ rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
if (rc) {
if (rc == -ENOMEM)
printk(KERN_ERR "security: avtab: out of memory\n");
- if (rc == -EEXIST)
+ else if (rc == -EEXIST)
printk(KERN_ERR "security: avtab: duplicate entry\n");
+ else
+ rc = -EINVAL;
goto bad;
}
}
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 519d4f6..0a90d93 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -21,12 +21,9 @@
#define _SS_AVTAB_H_
struct avtab_key {
- u32 source_type; /* source type */
- u32 target_type; /* target type */
- u32 target_class; /* target object class */
-};
-
-struct avtab_datum {
+ u16 source_type; /* source type */
+ u16 target_type; /* target type */
+ u16 target_class; /* target object class */
#define AVTAB_ALLOWED 1
#define AVTAB_AUDITALLOW 2
#define AVTAB_AUDITDENY 4
@@ -35,15 +32,13 @@
#define AVTAB_MEMBER 32
#define AVTAB_CHANGE 64
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
-#define AVTAB_ENABLED 0x80000000 /* reserved for used in cond_avtab */
- u32 specified; /* what fields are specified */
- u32 data[3]; /* access vectors or types */
-#define avtab_allowed(x) (x)->data[0]
-#define avtab_auditdeny(x) (x)->data[1]
-#define avtab_auditallow(x) (x)->data[2]
-#define avtab_transition(x) (x)->data[0]
-#define avtab_change(x) (x)->data[1]
-#define avtab_member(x) (x)->data[2]
+#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */
+#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
+ u16 specified; /* what field is specified */
+};
+
+struct avtab_datum {
+ u32 data; /* access vector or type value */
};
struct avtab_node {
@@ -58,17 +53,21 @@
};
int avtab_init(struct avtab *);
-struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
+struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);
-int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
-int avtab_read(struct avtab *a, void *fp, u32 config);
+int avtab_read_item(void *fp, uint32_t vers, struct avtab *a,
+ int (*insert)(struct avtab *a, struct avtab_key *k,
+ struct avtab_datum *d, void *p),
+ void *p);
+
+int avtab_read(struct avtab *a, void *fp, u32 vers);
struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
struct avtab_datum *datum);
-struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
+struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key);
struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index e2057f5..daf2880 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -100,18 +100,18 @@
/* turn the rules on or off */
for (cur = node->true_list; cur != NULL; cur = cur->next) {
if (new_state <= 0) {
- cur->node->datum.specified &= ~AVTAB_ENABLED;
+ cur->node->key.specified &= ~AVTAB_ENABLED;
} else {
- cur->node->datum.specified |= AVTAB_ENABLED;
+ cur->node->key.specified |= AVTAB_ENABLED;
}
}
for (cur = node->false_list; cur != NULL; cur = cur->next) {
/* -1 or 1 */
if (new_state) {
- cur->node->datum.specified &= ~AVTAB_ENABLED;
+ cur->node->key.specified &= ~AVTAB_ENABLED;
} else {
- cur->node->datum.specified |= AVTAB_ENABLED;
+ cur->node->key.specified |= AVTAB_ENABLED;
}
}
}
@@ -216,7 +216,8 @@
{
char *key = NULL;
struct cond_bool_datum *booldatum;
- u32 buf[3], len;
+ __le32 buf[3];
+ u32 len;
int rc;
booldatum = kmalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
@@ -252,21 +253,104 @@
return -1;
}
-static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list,
- struct cond_av_list *other)
+struct cond_insertf_data
{
- struct cond_av_list *list, *last = NULL, *cur;
- struct avtab_key key;
- struct avtab_datum datum;
+ struct policydb *p;
+ struct cond_av_list *other;
+ struct cond_av_list *head;
+ struct cond_av_list *tail;
+};
+
+static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
+{
+ struct cond_insertf_data *data = ptr;
+ struct policydb *p = data->p;
+ struct cond_av_list *other = data->other, *list, *cur;
struct avtab_node *node_ptr;
- int rc;
- u32 buf[1], i, len;
u8 found;
+
+ /*
+ * For type rules we have to make certain there aren't any
+ * conflicting rules by searching the te_avtab and the
+ * cond_te_avtab.
+ */
+ if (k->specified & AVTAB_TYPE) {
+ if (avtab_search(&p->te_avtab, k)) {
+ printk("security: type rule already exists outside of a conditional.");
+ goto err;
+ }
+ /*
+ * If we are reading the false list other will be a pointer to
+ * the true list. We can have duplicate entries if there is only
+ * 1 other entry and it is in our true list.
+ *
+ * If we are reading the true list (other == NULL) there shouldn't
+ * be any other entries.
+ */
+ if (other) {
+ node_ptr = avtab_search_node(&p->te_cond_avtab, k);
+ if (node_ptr) {
+ if (avtab_search_node_next(node_ptr, k->specified)) {
+ printk("security: too many conflicting type rules.");
+ goto err;
+ }
+ found = 0;
+ for (cur = other; cur != NULL; cur = cur->next) {
+ if (cur->node == node_ptr) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printk("security: conflicting type rules.\n");
+ goto err;
+ }
+ }
+ } else {
+ if (avtab_search(&p->te_cond_avtab, k)) {
+ printk("security: conflicting type rules when adding type rule for true.\n");
+ goto err;
+ }
+ }
+ }
+
+ node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
+ if (!node_ptr) {
+ printk("security: could not insert rule.");
+ goto err;
+ }
+
+ list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
+ if (!list)
+ goto err;
+ memset(list, 0, sizeof(*list));
+
+ list->node = node_ptr;
+ if (!data->head)
+ data->head = list;
+ else
+ data->tail->next = list;
+ data->tail = list;
+ return 0;
+
+err:
+ cond_av_list_destroy(data->head);
+ data->head = NULL;
+ return -1;
+}
+
+static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
+{
+ int i, rc;
+ __le32 buf[1];
+ u32 len;
+ struct cond_insertf_data data;
+
*ret_list = NULL;
len = 0;
- rc = next_entry(buf, fp, sizeof buf);
+ rc = next_entry(buf, fp, sizeof(u32));
if (rc < 0)
return -1;
@@ -275,79 +359,19 @@
return 0;
}
+ data.p = p;
+ data.other = other;
+ data.head = NULL;
+ data.tail = NULL;
for (i = 0; i < len; i++) {
- if (avtab_read_item(fp, &datum, &key))
- goto err;
-
- /*
- * For type rules we have to make certain there aren't any
- * conflicting rules by searching the te_avtab and the
- * cond_te_avtab.
- */
- if (datum.specified & AVTAB_TYPE) {
- if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) {
- printk("security: type rule already exists outside of a conditional.");
- goto err;
- }
- /*
- * If we are reading the false list other will be a pointer to
- * the true list. We can have duplicate entries if there is only
- * 1 other entry and it is in our true list.
- *
- * If we are reading the true list (other == NULL) there shouldn't
- * be any other entries.
- */
- if (other) {
- node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE);
- if (node_ptr) {
- if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) {
- printk("security: too many conflicting type rules.");
- goto err;
- }
- found = 0;
- for (cur = other; cur != NULL; cur = cur->next) {
- if (cur->node == node_ptr) {
- found = 1;
- break;
- }
- }
- if (!found) {
- printk("security: conflicting type rules.");
- goto err;
- }
- }
- } else {
- if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) {
- printk("security: conflicting type rules when adding type rule for true.");
- goto err;
- }
- }
- }
- node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum);
- if (!node_ptr) {
- printk("security: could not insert rule.");
- goto err;
- }
-
- list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
- if (!list)
- goto err;
- memset(list, 0, sizeof(struct cond_av_list));
-
- list->node = node_ptr;
- if (i == 0)
- *ret_list = list;
- else
- last->next = list;
- last = list;
+ rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data);
+ if (rc)
+ return rc;
}
+ *ret_list = data.head;
return 0;
-err:
- cond_av_list_destroy(*ret_list);
- *ret_list = NULL;
- return -1;
}
static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
@@ -366,7 +390,8 @@
static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
{
- u32 buf[2], len, i;
+ __le32 buf[2];
+ u32 len, i;
int rc;
struct cond_expr *expr = NULL, *last = NULL;
@@ -424,7 +449,8 @@
int cond_read_list(struct policydb *p, void *fp)
{
struct cond_node *node, *last = NULL;
- u32 buf[1], i, len;
+ __le32 buf[1];
+ u32 i, len;
int rc;
rc = next_entry(buf, fp, sizeof buf);
@@ -452,6 +478,7 @@
return 0;
err:
cond_list_destroy(p->cond_list);
+ p->cond_list = NULL;
return -1;
}
@@ -465,22 +492,22 @@
if(!ctab || !key || !avd)
return;
- for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL;
- node = avtab_search_node_next(node, AVTAB_AV)) {
- if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
- (node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
- avd->allowed |= avtab_allowed(&node->datum);
- if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
- (node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
+ for(node = avtab_search_node(ctab, key); node != NULL;
+ node = avtab_search_node_next(node, key->specified)) {
+ if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+ avd->allowed |= node->datum.data;
+ if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
/* Since a '0' in an auditdeny mask represents a
* permission we do NOT want to audit (dontaudit), we use
* the '&' operand to ensure that all '0's in the mask
* are retained (much unlike the allow and auditallow cases).
*/
- avd->auditdeny &= avtab_auditdeny(&node->datum);
- if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
- (node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
- avd->auditallow |= avtab_auditallow(&node->datum);
+ avd->auditdeny &= node->datum.data;
+ if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
+ avd->auditallow |= node->datum.data;
}
return;
}
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index d8ce9cc..d515154 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -196,8 +196,9 @@
{
int rc;
struct ebitmap_node *n, *l;
- u32 buf[3], mapsize, count, i;
- u64 map;
+ __le32 buf[3];
+ u32 mapsize, count, i;
+ __le64 map;
ebitmap_init(e);
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 4713702..8bf4105 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -32,11 +32,41 @@
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
+static inline unsigned int ebitmap_start(struct ebitmap *e,
+ struct ebitmap_node **n)
+{
+ *n = e->node;
+ return ebitmap_startbit(e);
+}
+
static inline void ebitmap_init(struct ebitmap *e)
{
memset(e, 0, sizeof(*e));
}
+static inline unsigned int ebitmap_next(struct ebitmap_node **n,
+ unsigned int bit)
+{
+ if ((bit == ((*n)->startbit + MAPSIZE - 1)) &&
+ (*n)->next) {
+ *n = (*n)->next;
+ return (*n)->startbit;
+ }
+
+ return (bit+1);
+}
+
+static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ if (n->map & (MAPBIT << (bit - n->startbit)))
+ return 1;
+ return 0;
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index d4c32c3..aaefac2 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -27,6 +27,7 @@
int mls_compute_context_len(struct context * context)
{
int i, l, len, range;
+ struct ebitmap_node *node;
if (!selinux_mls_enabled)
return 0;
@@ -36,24 +37,24 @@
range = 0;
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
- for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
- if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+ ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
+ if (ebitmap_node_get_bit(node, i)) {
if (range) {
range++;
continue;
}
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
+ len += strlen(policydb.p_cat_val_to_name[i]) + 1;
range++;
} else {
if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
+ len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
range = 0;
}
}
/* Handle case where last category is the end of range */
if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
+ len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
@@ -77,6 +78,7 @@
{
char *scontextp;
int i, l, range, wrote_sep;
+ struct ebitmap_node *node;
if (!selinux_mls_enabled)
return;
@@ -94,8 +96,8 @@
scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
/* categories */
- for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
- if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
+ ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
+ if (ebitmap_node_get_bit(node, i)) {
if (range) {
range++;
continue;
@@ -106,8 +108,8 @@
wrote_sep = 1;
} else
*scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[i]);
+ scontextp += strlen(policydb.p_cat_val_to_name[i]);
range++;
} else {
if (range > 1) {
@@ -116,8 +118,8 @@
else
*scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
+ scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
}
range = 0;
}
@@ -130,8 +132,8 @@
else
*scontextp++ = ',';
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
+ strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
+ scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
}
if (l == 0) {
@@ -157,6 +159,7 @@
{
struct level_datum *levdatum;
struct user_datum *usrdatum;
+ struct ebitmap_node *node;
int i, l;
if (!selinux_mls_enabled)
@@ -179,11 +182,11 @@
if (!levdatum)
return 0;
- for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
- if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
+ ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
+ if (ebitmap_node_get_bit(node, i)) {
if (i > p->p_cats.nprim)
return 0;
- if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
+ if (!ebitmap_get_bit(&levdatum->level->cat, i))
/*
* Category may not be associated with
* sensitivity in low level.
@@ -468,6 +471,7 @@
struct level_datum *levdatum;
struct cat_datum *catdatum;
struct ebitmap bitmap;
+ struct ebitmap_node *node;
int l, i;
if (!selinux_mls_enabled)
@@ -482,12 +486,12 @@
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
- for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
- if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
+ ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
+ if (ebitmap_node_get_bit(node, i)) {
int rc;
catdatum = hashtab_search(newp->p_cats.table,
- oldp->p_cat_val_to_name[i - 1]);
+ oldp->p_cat_val_to_name[i]);
if (!catdatum)
return -EINVAL;
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 785c33c..0a75832 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -91,6 +91,11 @@
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_AVTAB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -584,6 +589,9 @@
struct ocontext *c, *ctmp;
struct genfs *g, *gtmp;
int i;
+ struct role_allow *ra, *lra = NULL;
+ struct role_trans *tr, *ltr = NULL;
+ struct range_trans *rt, *lrt = NULL;
for (i = 0; i < SYM_NUM; i++) {
hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
@@ -624,6 +632,28 @@
cond_policydb_destroy(p);
+ for (tr = p->role_tr; tr; tr = tr->next) {
+ if (ltr) kfree(ltr);
+ ltr = tr;
+ }
+ if (ltr) kfree(ltr);
+
+ for (ra = p->role_allow; ra; ra = ra -> next) {
+ if (lra) kfree(lra);
+ lra = ra;
+ }
+ if (lra) kfree(lra);
+
+ for (rt = p->range_tr; rt; rt = rt -> next) {
+ if (lrt) kfree(lrt);
+ lrt = rt;
+ }
+ if (lrt) kfree(lrt);
+
+ for (i = 0; i < p->p_types.nprim; i++)
+ ebitmap_destroy(&p->type_attr_map[i]);
+ kfree(p->type_attr_map);
+
return;
}
@@ -714,7 +744,8 @@
*/
static int mls_read_range_helper(struct mls_range *r, void *fp)
{
- u32 buf[2], items;
+ __le32 buf[2];
+ u32 items;
int rc;
rc = next_entry(buf, fp, sizeof(u32));
@@ -775,7 +806,7 @@
struct policydb *p,
void *fp)
{
- u32 buf[3];
+ __le32 buf[3];
int rc;
rc = next_entry(buf, fp, sizeof buf);
@@ -815,7 +846,8 @@
char *key = NULL;
struct perm_datum *perdatum;
int rc;
- u32 buf[2], len;
+ __le32 buf[2];
+ u32 len;
perdatum = kmalloc(sizeof(*perdatum), GFP_KERNEL);
if (!perdatum) {
@@ -855,7 +887,8 @@
{
char *key = NULL;
struct common_datum *comdatum;
- u32 buf[4], len, nel;
+ __le32 buf[4];
+ u32 len, nel;
int i, rc;
comdatum = kmalloc(sizeof(*comdatum), GFP_KERNEL);
@@ -909,7 +942,8 @@
{
struct constraint_node *c, *lc;
struct constraint_expr *e, *le;
- u32 buf[3], nexpr;
+ __le32 buf[3];
+ u32 nexpr;
int rc, i, j, depth;
lc = NULL;
@@ -993,7 +1027,8 @@
{
char *key = NULL;
struct class_datum *cladatum;
- u32 buf[6], len, len2, ncons, nel;
+ __le32 buf[6];
+ u32 len, len2, ncons, nel;
int i, rc;
cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL);
@@ -1087,7 +1122,8 @@
char *key = NULL;
struct role_datum *role;
int rc;
- u32 buf[2], len;
+ __le32 buf[2];
+ u32 len;
role = kmalloc(sizeof(*role), GFP_KERNEL);
if (!role) {
@@ -1147,7 +1183,8 @@
char *key = NULL;
struct type_datum *typdatum;
int rc;
- u32 buf[3], len;
+ __le32 buf[3];
+ u32 len;
typdatum = kmalloc(sizeof(*typdatum),GFP_KERNEL);
if (!typdatum) {
@@ -1191,7 +1228,7 @@
*/
static int mls_read_level(struct mls_level *lp, void *fp)
{
- u32 buf[1];
+ __le32 buf[1];
int rc;
memset(lp, 0, sizeof(*lp));
@@ -1219,7 +1256,8 @@
char *key = NULL;
struct user_datum *usrdatum;
int rc;
- u32 buf[2], len;
+ __le32 buf[2];
+ u32 len;
usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL);
if (!usrdatum) {
@@ -1273,7 +1311,8 @@
char *key = NULL;
struct level_datum *levdatum;
int rc;
- u32 buf[2], len;
+ __le32 buf[2];
+ u32 len;
levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
if (!levdatum) {
@@ -1324,7 +1363,8 @@
char *key = NULL;
struct cat_datum *catdatum;
int rc;
- u32 buf[3], len;
+ __le32 buf[3];
+ u32 len;
catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
if (!catdatum) {
@@ -1387,7 +1427,8 @@
struct ocontext *l, *c, *newc;
struct genfs *genfs_p, *genfs, *newgenfs;
int i, j, rc;
- u32 buf[8], len, len2, config, nprim, nel, nel2;
+ __le32 buf[8];
+ u32 len, len2, config, nprim, nel, nel2;
char *policydb_str;
struct policydb_compat_info *info;
struct range_trans *rt, *lrt;
@@ -1403,17 +1444,14 @@
if (rc < 0)
goto bad;
- for (i = 0; i < 2; i++)
- buf[i] = le32_to_cpu(buf[i]);
-
- if (buf[0] != POLICYDB_MAGIC) {
+ if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
printk(KERN_ERR "security: policydb magic number 0x%x does "
"not match expected magic number 0x%x\n",
- buf[0], POLICYDB_MAGIC);
+ le32_to_cpu(buf[0]), POLICYDB_MAGIC);
goto bad;
}
- len = buf[1];
+ len = le32_to_cpu(buf[1]);
if (len != strlen(POLICYDB_STRING)) {
printk(KERN_ERR "security: policydb string length %d does not "
"match expected length %Zu\n",
@@ -1448,19 +1486,17 @@
rc = next_entry(buf, fp, sizeof(u32)*4);
if (rc < 0)
goto bad;
- for (i = 0; i < 4; i++)
- buf[i] = le32_to_cpu(buf[i]);
- p->policyvers = buf[0];
+ p->policyvers = le32_to_cpu(buf[0]);
if (p->policyvers < POLICYDB_VERSION_MIN ||
p->policyvers > POLICYDB_VERSION_MAX) {
printk(KERN_ERR "security: policydb version %d does not match "
"my version range %d-%d\n",
- buf[0], POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+ le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
goto bad;
}
- if ((buf[1] & POLICYDB_CONFIG_MLS)) {
+ if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
if (ss_initialized && !selinux_mls_enabled) {
printk(KERN_ERR "Cannot switch between non-MLS and MLS "
"policies\n");
@@ -1489,9 +1525,11 @@
goto bad;
}
- if (buf[2] != info->sym_num || buf[3] != info->ocon_num) {
+ if (le32_to_cpu(buf[2]) != info->sym_num ||
+ le32_to_cpu(buf[3]) != info->ocon_num) {
printk(KERN_ERR "security: policydb table sizes (%d,%d) do "
- "not match mine (%d,%d)\n", buf[2], buf[3],
+ "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
+ le32_to_cpu(buf[3]),
info->sym_num, info->ocon_num);
goto bad;
}
@@ -1511,7 +1549,7 @@
p->symtab[i].nprim = nprim;
}
- rc = avtab_read(&p->te_avtab, fp, config);
+ rc = avtab_read(&p->te_avtab, fp, p->policyvers);
if (rc)
goto bad;
@@ -1825,6 +1863,21 @@
}
}
+ p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL);
+ if (!p->type_attr_map)
+ goto bad;
+
+ for (i = 0; i < p->p_types.nprim; i++) {
+ ebitmap_init(&p->type_attr_map[i]);
+ if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
+ if (ebitmap_read(&p->type_attr_map[i], fp))
+ goto bad;
+ }
+ /* add the type itself as the degenerate case */
+ if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
+ goto bad;
+ }
+
rc = 0;
out:
return rc;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 2470e2a..b134071 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -237,6 +237,9 @@
/* range transitions */
struct range_trans *range_tr;
+ /* type -> attribute reverse mapping */
+ struct ebitmap *type_attr_map;
+
unsigned int policyvers;
};
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 0141204..92b89dc 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -266,8 +266,11 @@
struct constraint_node *constraint;
struct role_allow *ra;
struct avtab_key avkey;
- struct avtab_datum *avdatum;
+ struct avtab_node *node;
struct class_datum *tclass_datum;
+ struct ebitmap *sattr, *tattr;
+ struct ebitmap_node *snode, *tnode;
+ unsigned int i, j;
/*
* Remap extended Netlink classes for old policy versions.
@@ -300,21 +303,34 @@
* If a specific type enforcement rule was defined for
* this permission check, then use it.
*/
- avkey.source_type = scontext->type;
- avkey.target_type = tcontext->type;
avkey.target_class = tclass;
- avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_AV);
- if (avdatum) {
- if (avdatum->specified & AVTAB_ALLOWED)
- avd->allowed = avtab_allowed(avdatum);
- if (avdatum->specified & AVTAB_AUDITDENY)
- avd->auditdeny = avtab_auditdeny(avdatum);
- if (avdatum->specified & AVTAB_AUDITALLOW)
- avd->auditallow = avtab_auditallow(avdatum);
- }
+ avkey.specified = AVTAB_AV;
+ sattr = &policydb.type_attr_map[scontext->type - 1];
+ tattr = &policydb.type_attr_map[tcontext->type - 1];
+ ebitmap_for_each_bit(sattr, snode, i) {
+ if (!ebitmap_node_get_bit(snode, i))
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+ avkey.source_type = i + 1;
+ avkey.target_type = j + 1;
+ for (node = avtab_search_node(&policydb.te_avtab, &avkey);
+ node != NULL;
+ node = avtab_search_node_next(node, avkey.specified)) {
+ if (node->key.specified == AVTAB_ALLOWED)
+ avd->allowed |= node->datum.data;
+ else if (node->key.specified == AVTAB_AUDITALLOW)
+ avd->auditallow |= node->datum.data;
+ else if (node->key.specified == AVTAB_AUDITDENY)
+ avd->auditdeny &= node->datum.data;
+ }
- /* Check conditional av table for additional permissions */
- cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+ /* Check conditional av table for additional permissions */
+ cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+
+ }
+ }
/*
* Remove any permissions prohibited by a constraint (this includes
@@ -797,7 +813,6 @@
struct avtab_key avkey;
struct avtab_datum *avdatum;
struct avtab_node *node;
- unsigned int type_change = 0;
int rc = 0;
if (!ss_initialized) {
@@ -862,33 +877,23 @@
avkey.source_type = scontext->type;
avkey.target_type = tcontext->type;
avkey.target_class = tclass;
- avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE);
+ avkey.specified = specified;
+ avdatum = avtab_search(&policydb.te_avtab, &avkey);
/* If no permanent rule, also check for enabled conditional rules */
if(!avdatum) {
- node = avtab_search_node(&policydb.te_cond_avtab, &avkey, specified);
+ node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
for (; node != NULL; node = avtab_search_node_next(node, specified)) {
- if (node->datum.specified & AVTAB_ENABLED) {
+ if (node->key.specified & AVTAB_ENABLED) {
avdatum = &node->datum;
break;
}
}
}
- type_change = (avdatum && (avdatum->specified & specified));
- if (type_change) {
+ if (avdatum) {
/* Use the type from the type transition/member/change rule. */
- switch (specified) {
- case AVTAB_TRANSITION:
- newcontext.type = avtab_transition(avdatum);
- break;
- case AVTAB_MEMBER:
- newcontext.type = avtab_member(avdatum);
- break;
- case AVTAB_CHANGE:
- newcontext.type = avtab_change(avdatum);
- break;
- }
+ newcontext.type = avdatum->data;
}
/* Check for class-specific changes. */
@@ -1502,6 +1507,7 @@
struct user_datum *user;
struct role_datum *role;
struct av_decision avd;
+ struct ebitmap_node *rnode, *tnode;
int rc = 0, i, j;
if (!ss_initialized) {
@@ -1532,13 +1538,13 @@
}
memset(mysids, 0, maxnel*sizeof(*mysids));
- for (i = ebitmap_startbit(&user->roles); i < ebitmap_length(&user->roles); i++) {
- if (!ebitmap_get_bit(&user->roles, i))
+ ebitmap_for_each_bit(&user->roles, rnode, i) {
+ if (!ebitmap_node_get_bit(rnode, i))
continue;
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- for (j = ebitmap_startbit(&role->types); j < ebitmap_length(&role->types); j++) {
- if (!ebitmap_get_bit(&role->types, j))
+ ebitmap_for_each_bit(&role->types, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
continue;
usercon.type = j+1;
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 103f136..4ef6dd0 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -2,12 +2,14 @@
# Makefile for ALSA
#
-snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
-snd-aaci-objs := aaci.o devdma.o
-snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
-snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o
+snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
+
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
-obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
-obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
+snd-aaci-objs := aaci.o devdma.o
+
+obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
+snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
+
+obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
+snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 08cc3dd..9887703 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -821,7 +821,7 @@
static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
{
- void *base = aaci->base + AACI_CSCH1;
+ void __iomem *base = aaci->base + AACI_CSCH1;
int i;
writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR);
@@ -877,7 +877,7 @@
aaci->playback.fifo = aaci->base + AACI_DR1;
for (i = 0; i < 4; i++) {
- void *base = aaci->base + i * 0x14;
+ void __iomem *base = aaci->base + i * 0x14;
writel(0, base + AACI_IE);
writel(0, base + AACI_TXCR);
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h
index d752e64..b2f969b 100644
--- a/sound/arm/aaci.h
+++ b/sound/arm/aaci.h
@@ -200,8 +200,8 @@
struct aaci_runtime {
- void *base;
- void *fifo;
+ void __iomem *base;
+ void __iomem *fifo;
struct ac97_pcm *pcm;
int pcm_open;
@@ -223,7 +223,7 @@
struct aaci {
struct amba_device *dev;
snd_card_t *card;
- void *base;
+ void __iomem *base;
unsigned int fifosize;
/* AC'97 */
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 1622893..291b476 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -116,15 +116,21 @@
return _snd_kmalloc(size, flags);
}
+void *snd_hidden_kzalloc(size_t size, unsigned int __nocast flags)
+{
+ void *ret = _snd_kmalloc(size, flags);
+ if (ret)
+ memset(ret, 0, size);
+ return ret;
+}
+EXPORT_SYMBOL(snd_hidden_kzalloc);
+
void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags)
{
void *ret = NULL;
if (n != 0 && size > INT_MAX / n)
return ret;
- ret = _snd_kmalloc(n * size, flags);
- if (ret)
- memset(ret, 0, n * size);
- return ret;
+ return snd_hidden_kzalloc(n * size, flags);
}
void snd_hidden_kfree(const void *obj)
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index be4ea60..5c39483 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -15,7 +15,8 @@
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
- depends on SND && ISAPNP
+ depends on SND && PNP && ISA
+ select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -80,7 +81,8 @@
config SND_ES968
tristate "Generic ESS ES968 driver"
- depends on SND && ISAPNP
+ depends on SND && PNP && ISA
+ select ISAPNP
select SND_MPU401_UART
select SND_PCM
help
@@ -160,7 +162,7 @@
config SND_INTERWAVE
tristate "AMD InterWave, Gravis UltraSound PnP"
- depends on SND
+ depends on SND && PNP && ISA
select SND_RAWMIDI
select SND_CS4231_LIB
select SND_GUS_SYNTH
@@ -175,7 +177,7 @@
config SND_INTERWAVE_STB
tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
- depends on SND
+ depends on SND && PNP && ISA
select SND_RAWMIDI
select SND_CS4231_LIB
select SND_GUS_SYNTH
@@ -291,7 +293,8 @@
config SND_ALS100
tristate "Avance Logic ALS100/ALS120"
- depends on SND && ISAPNP
+ depends on SND && PNP && ISA
+ select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -304,7 +307,8 @@
config SND_AZT2320
tristate "Aztech Systems AZT2320"
- depends on SND && ISAPNP
+ depends on SND && PNP && ISA
+ select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_CS4231_LIB
@@ -328,7 +332,8 @@
config SND_DT019X
tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
- depends on SND && ISAPNP
+ depends on SND && PNP && ISA
+ select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
diff --git a/sound/oss/os.h b/sound/oss/os.h
index d6b9629..80dce32 100644
--- a/sound/oss/os.h
+++ b/sound/oss/os.h
@@ -19,9 +19,6 @@
#include <linux/ioport.h>
#include <asm/page.h>
#include <asm/system.h>
-#ifdef __alpha__
-#include <asm/segment.h>
-#endif
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index ce6c9fa..4943299 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2249,7 +2249,7 @@
return -ENXIO;
}
- if ((codec = kcalloc(1, sizeof(*codec), GFP_KERNEL)) == NULL) {
+ if ((codec = kzalloc(sizeof(*codec), GFP_KERNEL)) == NULL) {
pci_disable_device(pci);
return -ENOMEM;
}
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 904d173..188df08 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1427,7 +1427,7 @@
snd_atiixp_aclink_down(chip);
snd_atiixp_chip_stop(chip);
- pci_set_power_state(chip->pci, 3);
+ pci_set_power_state(chip->pci, PCI_D3hot);
pci_disable_device(chip->pci);
return 0;
}
@@ -1438,7 +1438,7 @@
int i;
pci_enable_device(chip->pci);
- pci_set_power_state(chip->pci, 0);
+ pci_set_power_state(chip->pci, PCI_D0);
pci_set_master(chip->pci);
snd_atiixp_aclink_reset(chip);
diff --git a/usr/Kconfig b/usr/Kconfig
new file mode 100644
index 0000000..07727f3
--- /dev/null
+++ b/usr/Kconfig
@@ -0,0 +1,46 @@
+#
+# Configuration for initramfs
+#
+
+config INITRAMFS_SOURCE
+ string "Initramfs source file(s)"
+ default ""
+ help
+ This can be either a single cpio archive with a .cpio suffix or a
+ space-separated list of directories and files for building the
+ initramfs image. A cpio archive should contain a filesystem archive
+ to be used as an initramfs image. Directories should contain a
+ filesystem layout to be included in the initramfs image. Files
+ should contain entries according to the format described by the
+ "usr/gen_init_cpio" program in the kernel tree.
+
+ When multiple directories and files are specified then the
+ initramfs image will be the aggregate of all of them.
+
+ See <file:Documentation/early-userspace/README for more details.
+
+ If you are not sure, leave it blank.
+
+config INITRAMFS_ROOT_UID
+ int "User ID to map to 0 (user root)"
+ depends on INITRAMFS_SOURCE!=""
+ default "0"
+ help
+ This setting is only meaningful if the INITRAMFS_SOURCE is
+ contains a directory. Setting this user ID (UID) to something
+ other than "0" will cause all files owned by that UID to be
+ owned by user root in the initial ramdisk image.
+
+ If you are not sure, leave it set to "0".
+
+config INITRAMFS_ROOT_GID
+ int "Group ID to map to 0 (group root)"
+ depends on INITRAMFS_SOURCE!=""
+ default "0"
+ help
+ This setting is only meaningful if the INITRAMFS_SOURCE is
+ contains a directory. Setting this group ID (GID) to something
+ other than "0" will cause all files owned by that GID to be
+ owned by group root in the initial ramdisk image.
+
+ If you are not sure, leave it set to "0".
diff --git a/usr/Makefile b/usr/Makefile
index 248d555..e2129cb 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -27,7 +27,7 @@
filechk_initramfs_list = $(CONFIG_SHELL) \
$(srctree)/scripts/gen_initramfs_list.sh $(gen_initramfs_args) $(quotefixed_initramfs_source)
-$(obj)/initramfs_list: FORCE
+$(obj)/initramfs_list: $(obj)/Makefile FORCE
$(call filechk,initramfs_list)
quiet_cmd_cpio = CPIO $@